v0.9.3: implemented the warp beacon ability
This commit is contained in:
@@ -354,9 +354,17 @@ actors.hero.abilities.mage.wildmagic.name=wild magic
|
||||
actors.hero.abilities.mage.wildmagic.no_wands=You have no wands to zap with!
|
||||
actors.hero.abilities.mage.wildmagic.short_desc=The Mage unleashes the _Wild Magic_ contained in his wands, randomly firing them multiple times at a chosen target over a single turn.
|
||||
actors.hero.abilities.mage.wildmagic.desc=TODO
|
||||
actors.hero.abilities.mage.magicalchains.name=magical chains
|
||||
actors.hero.abilities.mage.magicalchains.short_desc=The Mage throws out _Magical Chains_, which affect every enemy he has used magic on recently.
|
||||
actors.hero.abilities.mage.magicalchains.desc=TODO
|
||||
actors.hero.abilities.mage.warpbeacon.name=warp beacon
|
||||
actors.hero.abilities.mage.warpbeacon.depths=You can't warp between depths!
|
||||
actors.hero.abilities.mage.warpbeacon.locked_floor=You cannot leave a locked floor!
|
||||
actors.hero.abilities.mage.warpbeacon.too_far=That location is too far!
|
||||
actors.hero.abilities.mage.warpbeacon.invalid_beacon=You can't place a beacon there!
|
||||
actors.hero.abilities.mage.warpbeacon.window_desc=Your beacon is currently placed on floor %d.
|
||||
actors.hero.abilities.mage.warpbeacon.window_tele=teleport to beacon
|
||||
actors.hero.abilities.mage.warpbeacon.window_clear=clear beacon
|
||||
actors.hero.abilities.mage.warpbeacon.window_cancel=cancel
|
||||
actors.hero.abilities.mage.warpbeacon.short_desc=The Mage places a _Warping Beacon_ at his current location, which he can instantly teleport back to.
|
||||
actors.hero.abilities.mage.warpbeacon.desc=TODO
|
||||
actors.hero.abilities.rogue.smokebomb.name=smoke bomb
|
||||
actors.hero.abilities.rogue.smokebomb.fov=You can only jump to an empty location in your field of view
|
||||
actors.hero.abilities.rogue.smokebomb.prompt=Choose a location to jump to
|
||||
@@ -570,12 +578,12 @@ actors.hero.talent.fire_everything.desc=_+1:_ Wild magic now fires _5 times_, up
|
||||
actors.hero.talent.conserved_magic.title=conserved magic
|
||||
actors.hero.talent.conserved_magic.desc=_+1:_ Each zap from wild magic now uses _0.71 charges_, instead of 1.\n\n_+2:_ Each zap from wild magic now uses _0.50 charges_, instead of 1.\n\n_+3:_ Each zap from wild magic now uses _0.35 charges_, instead of 1.\n\n_+4:_ Each zap from wild magic now uses _0.25 charges_, instead of 1.
|
||||
|
||||
actors.hero.talent.mage_3_1.title=TODO NAME
|
||||
actors.hero.talent.mage_3_1.desc=_+1:_ \n\n_+2:_ \n\n_+3:_ \n\n_+4:_
|
||||
actors.hero.talent.mage_3_2.title=TODO NAME
|
||||
actors.hero.talent.mage_3_2.desc=TODO DESC
|
||||
actors.hero.talent.mage_3_3.title=TODO NAME
|
||||
actors.hero.talent.mage_3_3.desc=TODO DESC
|
||||
actors.hero.talent.telefrag.title=Telefrag
|
||||
actors.hero.talent.telefrag.desc=_+1:_ If the Mage warps into another character he deals _10-15 damage_ to it, but also takes _5 damage_.\n\n_+2:_ If the Mage warps into another character he deals _20-30 damage_ to it, but also takes _8 damage_.\n\n_+3:_ If the Mage warps into another character he deals _30-45 damage_ to it, but also takes _12 damage_.\n\n_+4:_ If the Mage warps into another character he deals _40-60 damage_ to it, but also takes _15 damage_.\n\nThe hero cannot be killed by this talent, the self damage can be reduced by magic resisting effects.
|
||||
actors.hero.talent.remote_beacon.title=Remote Beacon
|
||||
actors.hero.talent.remote_beacon.desc=_+1:_ The Mage can place a beacon at any location within _3 tiles_.\n\n_+2:_ The Mage can place a beacon at any location within _6 tiles_.\n\n_+3:_ The Mage can place a beacon at any location within _9 tiles_.\n\n_+4:_ The Mage can place a beacon at any location within _12 tiles_.\n\nThe Mage cannot place beacons in locations that are inaccessible
|
||||
actors.hero.talent.longrange_warp.title=Longrange Warp
|
||||
actors.hero.talent.longrange_warp.desc=_+1:_ The Mage can now warp between floors, at _150% charge cost_.\n\n_+2:_ The Mage can now warp between floors, at _117% charge cost_.\n\n_+3:_ The Mage can now warp between floors, at _83% charge cost_.\n\n_+4:_ The Mage can now warp between floors, at _50% charge cost_.\n\nThe Mage cannot use longrange warp to leave a locked floor.
|
||||
|
||||
#rogue
|
||||
actors.hero.talent.cached_rations.title=cached rations
|
||||
|
||||
@@ -31,7 +31,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.huntress.N
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.huntress.SpiritHawk;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.huntress.SpectralBlades;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.mage.WildMagic;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.mage.MagicalChains;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.mage.WarpBeacon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.mage.ElementalBlast;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.rogue.DeathMark;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.rogue.ShadowClone;
|
||||
@@ -213,7 +213,7 @@ public enum HeroClass {
|
||||
case WARRIOR: default:
|
||||
return new ArmorAbility[]{new HeroicLeap(), new Shockwave(), new Endure()};
|
||||
case MAGE:
|
||||
return new ArmorAbility[]{new ElementalBlast(), new WildMagic(), new MagicalChains()};
|
||||
return new ArmorAbility[]{new ElementalBlast(), new WildMagic(), new WarpBeacon()};
|
||||
case ROGUE:
|
||||
return new ArmorAbility[]{new SmokeBomb(), new DeathMark(), new ShadowClone()};
|
||||
case HUNTRESS:
|
||||
|
||||
@@ -102,8 +102,8 @@ public enum Talent {
|
||||
BLAST_RADIUS(49, 4), ELEMENTAL_POWER(50, 4), REACTIVE_BARRIER(51, 4),
|
||||
//Wild Magic T4
|
||||
WILD_POWER(52, 4), FIRE_EVERYTHING(53, 4), CONSERVED_MAGIC(54, 4),
|
||||
//??? T4
|
||||
MAGE_3_1(55, 4), MAGE_3_2(56, 4), MAGE_3_3(57, 4),
|
||||
//Warp Beacon T4
|
||||
TELEFRAG(55, 4), REMOTE_BEACON(56, 4), LONGRANGE_WARP(57, 4),
|
||||
|
||||
//Rogue T1
|
||||
CACHED_RATIONS(64), THIEFS_INTUITION(65), SUCKER_PUNCH(66), PROTECTIVE_SHADOWS(67),
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2015 Oleg Dolya
|
||||
*
|
||||
* Shattered Pixel Dungeon
|
||||
* Copyright (C) 2014-2021 Evan Debenham
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.mage;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.ArmorAbility;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.armor.ClassArmor;
|
||||
|
||||
public class MagicalChains extends ArmorAbility {
|
||||
|
||||
@Override
|
||||
protected void activate(ClassArmor armor, Hero hero, Integer target) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public Talent[] talents() {
|
||||
return new Talent[]{Talent.MAGE_3_1, Talent.MAGE_3_2, Talent.MAGE_3_3, Talent.HEROIC_ENERGY};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2015 Oleg Dolya
|
||||
*
|
||||
* Shattered Pixel Dungeon
|
||||
* Copyright (C) 2014-2021 Evan Debenham
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.mage;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Assets;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.LockedFloor;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.ArmorAbility;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.MagicMissile;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Pushing;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.armor.ClassArmor;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.EtherealChains;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.TimekeepersHourglass;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfTeleportation;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.plants.Swiftthistle;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.InterlevelScene;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.BArray;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.windows.WndOptions;
|
||||
import com.watabou.noosa.Game;
|
||||
import com.watabou.noosa.Image;
|
||||
import com.watabou.noosa.audio.Sample;
|
||||
import com.watabou.noosa.particles.Emitter;
|
||||
import com.watabou.utils.Bundle;
|
||||
import com.watabou.utils.PathFinder;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class WarpBeacon extends ArmorAbility {
|
||||
|
||||
@Override
|
||||
protected String targetingPrompt() {
|
||||
if (Dungeon.hero.buff(WarpBeaconTracker.class) == null
|
||||
&& Dungeon.hero.hasTalent(Talent.REMOTE_BEACON)){
|
||||
return Messages.get(this, "prompt");
|
||||
}
|
||||
return super.targetingPrompt();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate(ClassArmor armor, Hero hero, Integer target) {
|
||||
if (target == null){
|
||||
return;
|
||||
}
|
||||
|
||||
if (hero.buff(WarpBeaconTracker.class) != null){
|
||||
final WarpBeaconTracker tracker = hero.buff(WarpBeaconTracker.class);
|
||||
|
||||
GameScene.show( new WndOptions(
|
||||
new Image(hero.sprite),
|
||||
Messages.titleCase(name()),
|
||||
Messages.get(WarpBeacon.class, "window_desc", tracker.depth),
|
||||
Messages.get(WarpBeacon.class, "window_tele"),
|
||||
Messages.get(WarpBeacon.class, "window_clear"),
|
||||
Messages.get(WarpBeacon.class, "window_cancel")){
|
||||
|
||||
@Override
|
||||
protected void onSelect(int index) {
|
||||
if (index == 0){
|
||||
|
||||
if (tracker.depth != Dungeon.depth && !hero.hasTalent(Talent.LONGRANGE_WARP)){
|
||||
GLog.w( Messages.get(WarpBeacon.class, "depths") );
|
||||
return;
|
||||
}
|
||||
|
||||
float chargeNeeded = chargeUse(hero);
|
||||
|
||||
if (tracker.depth != Dungeon.depth){
|
||||
chargeNeeded *= 1.833f - 0.333f*Dungeon.hero.pointsInTalent(Talent.LONGRANGE_WARP);
|
||||
}
|
||||
|
||||
if (armor.charge < chargeNeeded){
|
||||
GLog.w( Messages.get(ClassArmor.class, "low_charge") );
|
||||
return;
|
||||
}
|
||||
|
||||
if (tracker.depth == Dungeon.depth){
|
||||
Char existing = Actor.findChar(tracker.pos);
|
||||
|
||||
if (existing != null){
|
||||
if (hero.hasTalent(Talent.TELEFRAG)){
|
||||
int heroHP = hero.HP + hero.shielding();
|
||||
int heroDmg = Math.round(1.666f + 3.333f*hero.pointsInTalent(Talent.TELEFRAG));
|
||||
hero.damage(Math.min(heroDmg, heroHP-1), WarpBeacon.this);
|
||||
|
||||
int damage = Random.NormalIntRange(10*hero.pointsInTalent(Talent.TELEFRAG), 15*hero.pointsInTalent(Talent.TELEFRAG));
|
||||
existing.sprite.flash();
|
||||
existing.sprite.bloodBurstA(existing.sprite.center(), damage);
|
||||
existing.damage(damage, WarpBeacon.this);
|
||||
|
||||
Sample.INSTANCE.play(Assets.Sounds.HIT_CRUSH);
|
||||
Sample.INSTANCE.play(Assets.Sounds.HIT_STRONG);
|
||||
}
|
||||
|
||||
if (existing.isAlive()){
|
||||
ArrayList<Integer> candidates = new ArrayList<>();
|
||||
for (int n : PathFinder.NEIGHBOURS8) {
|
||||
int cell = target + n;
|
||||
if (!Dungeon.level.solid[cell] && Actor.findChar( cell ) == null
|
||||
&& (!Char.hasProp(existing, Char.Property.LARGE) || Dungeon.level.openSpace[cell])) {
|
||||
candidates.add( cell );
|
||||
}
|
||||
}
|
||||
Random.shuffle(candidates);
|
||||
if (!candidates.isEmpty()){
|
||||
Actor.addDelayed( new Pushing( existing, existing.pos, candidates.get(0) ), -1 );
|
||||
|
||||
existing.pos = candidates.get(0);
|
||||
Dungeon.level.occupyCell(existing);
|
||||
hero.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ScrollOfTeleportation.appear(hero, tracker.pos);
|
||||
Dungeon.observe();
|
||||
|
||||
} else {
|
||||
|
||||
if (hero.buff(LockedFloor.class) != null){
|
||||
GLog.w( Messages.get(WarpBeacon.class, "locked_floor") );
|
||||
return;
|
||||
}
|
||||
|
||||
Buff buff = Dungeon.hero.buff(TimekeepersHourglass.timeFreeze.class);
|
||||
if (buff != null) buff.detach();
|
||||
buff = Dungeon.hero.buff(Swiftthistle.TimeBubble.class);
|
||||
if (buff != null) buff.detach();
|
||||
|
||||
InterlevelScene.mode = InterlevelScene.Mode.RETURN;
|
||||
InterlevelScene.returnDepth = tracker.depth;
|
||||
InterlevelScene.returnPos = tracker.pos;
|
||||
Game.switchScene( InterlevelScene.class );
|
||||
}
|
||||
|
||||
} else if (index == 1){
|
||||
hero.buff(WarpBeaconTracker.class).detach();
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
} else {
|
||||
if (!Dungeon.level.mapped[target] && !Dungeon.level.visited[target]){
|
||||
return;
|
||||
}
|
||||
|
||||
if (Dungeon.level.distance(hero.pos, target) > 3*hero.pointsInTalent(Talent.REMOTE_BEACON)){
|
||||
GLog.w( Messages.get(WarpBeacon.class, "too_far") );
|
||||
return;
|
||||
}
|
||||
|
||||
PathFinder.buildDistanceMap(target, BArray.or(Dungeon.level.passable, Dungeon.level.avoid, null));
|
||||
if (Dungeon.level.pit[target] ||
|
||||
(Dungeon.level.solid[target] && !Dungeon.level.passable[target]) ||
|
||||
PathFinder.distance[hero.pos] == Integer.MAX_VALUE){
|
||||
GLog.w( Messages.get(WarpBeacon.class, "invalid_beacon") );
|
||||
return;
|
||||
}
|
||||
|
||||
WarpBeaconTracker tracker = new WarpBeaconTracker();
|
||||
tracker.pos = target;
|
||||
tracker.depth = Dungeon.depth;
|
||||
tracker.attachTo(hero);
|
||||
|
||||
hero.sprite.operate(target);
|
||||
Sample.INSTANCE.play(Assets.Sounds.TELEPORT);
|
||||
hero.spendAndNext(Actor.TICK);
|
||||
}
|
||||
}
|
||||
|
||||
public static class WarpBeaconTracker extends Buff {
|
||||
|
||||
int pos;
|
||||
int depth;
|
||||
|
||||
Emitter e;
|
||||
|
||||
@Override
|
||||
public void fx(boolean on) {
|
||||
if (on && depth == Dungeon.depth) {
|
||||
e = CellEmitter.center(pos);
|
||||
e.pour(MagicMissile.WardParticle.UP, 0.05f);
|
||||
}
|
||||
else if (e != null) e.on = false;
|
||||
}
|
||||
|
||||
public static final String POS = "pos";
|
||||
public static final String DEPTH = "depth";
|
||||
|
||||
@Override
|
||||
public void storeInBundle(Bundle bundle) {
|
||||
super.storeInBundle(bundle);
|
||||
bundle.put(POS, pos);
|
||||
bundle.put(DEPTH, depth);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreFromBundle(Bundle bundle) {
|
||||
super.restoreFromBundle(bundle);
|
||||
pos = bundle.getInt(POS);
|
||||
depth = bundle.getInt(DEPTH);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Talent[] talents() {
|
||||
return new Talent[]{Talent.TELEFRAG, Talent.REMOTE_BEACON, Talent.LONGRANGE_WARP, Talent.HEROIC_ENERGY};
|
||||
}
|
||||
}
|
||||
@@ -134,6 +134,7 @@ public class DeathMark extends ArmorAbility {
|
||||
if (!target.isAlive()){
|
||||
target.sprite.flash();
|
||||
target.sprite.bloodBurstA(target.sprite.center(), target.HT*2);
|
||||
Sample.INSTANCE.play(Assets.Sounds.HIT_STAB);
|
||||
Sample.INSTANCE.play(Assets.Sounds.HIT_STRONG);
|
||||
target.die(this);
|
||||
int shld = Math.round(initialHP * (0.1f*Dungeon.hero.pointsInTalent(Talent.DEATHLY_DURABILITY)));
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Hex;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.MagicalSleep;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Vulnerable;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Weakness;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.mage.WarpBeacon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.DM100;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Eye;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Shaman;
|
||||
@@ -78,6 +79,8 @@ public class AntiMagic extends Armor.Glyph {
|
||||
RESISTS.add( WandOfPrismaticLight.class );
|
||||
RESISTS.add( WandOfTransfusion.class );
|
||||
RESISTS.add( WandOfWarding.Ward.class );
|
||||
|
||||
RESISTS.add( WarpBeacon.class );
|
||||
|
||||
RESISTS.add( DM100.LightningBolt.class );
|
||||
RESISTS.add( Shaman.EarthenBolt.class );
|
||||
|
||||
Reference in New Issue
Block a user