diff --git a/core/src/main/assets/messages/actors/actors.properties b/core/src/main/assets/messages/actors/actors.properties index 0cbc4a95f..f684b0226 100644 --- a/core/src/main/assets/messages/actors/actors.properties +++ b/core/src/main/assets/messages/actors/actors.properties @@ -595,12 +595,12 @@ actors.hero.talent.projectile_momentum.desc=_+1:_ While freerunning, the Freerun actors.hero.talent.speedy_stealth.title=speedy stealth actors.hero.talent.speedy_stealth.desc=_+1:_ The Freerunner gains 2 stacks of momentum per turn while he is invisible.\n\n_+2:_ In addition to the benefits of +1, freerunning no longer counts down while the Freerunner is invisible.\n\n_+3:_ In addition to the benefits of +1 and +2, the Freerunner moves at 2x speed while invisible, regardless of whether he is freerunning or not. -actors.hero.talent.smoke_bomb_1.title=TODO NAME -actors.hero.talent.smoke_bomb_1.desc=TODO DESC -actors.hero.talent.smoke_bomb_2.title=TODO NAME -actors.hero.talent.smoke_bomb_2.desc=TODO DESC -actors.hero.talent.smoke_bomb_3.title=TODO NAME -actors.hero.talent.smoke_bomb_3.desc=TODO DESC +actors.hero.talent.hasty_retreat.title=hasty retreat +actors.hero.talent.hasty_retreat.desc=_+1:_ After blinking the Rogue gains _2 turns_ of haste and invisibility.\n\n_+2:_ After blinking the Rogue gains _4 turns_ of haste and invisibility.\n\n_+3:_ After blinking the Rogue gains _6 turns_ of haste and invisibility.\n\n_+4:_ After blinking the Rogue gains _8 turns_ of haste and invisibility. +actors.hero.talent.body_replacement.title=body replacement +actors.hero.talent.body_replacement.desc=_+1:_ After blinking, the Rogue leaves a wooden decoy behind that has _30 health and 1-5 armor_.\n\n_+2:_ After blinking, the Rogue leaves a wooden decoy behind that has _60 health and 2-10 armor_.\n\n_+3:_ After blinking, the Rogue leaves a wooden decoy behind that has _90 health and 3-15 armor_.\n\n_+4:_ After blinking, the Rogue leaves a wooden decoy behind that has _120 health and 4-20 armor_.\n\nOnly one decoy can be active at a time. +actors.hero.talent.shadow_step.title=shadow step +actors.hero.talent.shadow_step.desc=_+1:_ If the rogue uses smoke bomb while invisible, it occurs instantly and has a _24% reduced_ charge cost, but it also doesn't blind enemies or trigger other talents.\n\n_+2:_ If the rogue uses smoke bomb while invisible, it occurs instantly and has a _42% reduced_ charge cost, but it also doesn't blind enemies or trigger other talents.\n\n_+3:_ If the rogue uses smoke bomb while invisible, it occurs instantly and has a _56% reduced_ charge cost, but it also doesn't blind enemies or trigger other talents.\n\n_+4:_ If the rogue uses smoke bomb while invisible, it occurs instantly and has a _67% reduced_ charge cost, but it also doesn't blind enemies or trigger other talents. actors.hero.talent.smoke_bomb_4.title=TODO NAME actors.hero.talent.smoke_bomb_4.desc=TODO DESC diff --git a/core/src/main/assets/sprites/ninja_log.png b/core/src/main/assets/sprites/ninja_log.png new file mode 100644 index 000000000..4f7ca25f0 Binary files /dev/null and b/core/src/main/assets/sprites/ninja_log.png differ diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Talent.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Talent.java index 63ac138df..d87591e6e 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Talent.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Talent.java @@ -113,7 +113,7 @@ public enum Talent { //Freerunner T3 EVASIVE_ARMOR(78, 3), PROJECTILE_MOMENTUM(79, 3), SPEEDY_STEALTH(80, 3), //Smoke Bomb T4 - SMOKE_BOMB_1(81, 4), SMOKE_BOMB_2(82, 4), SMOKE_BOMB_3(83, 4), SMOKE_BOMB_4(84, 4), + HASTY_RETREAT(81, 4), BODY_REPLACEMENT(82, 4), SHADOW_STEP(83, 4), SMOKE_BOMB_4(84, 4), //??? T4 ROGUE_2_1(85, 4), ROGUE_2_2(86, 4), ROGUE_2_3(87, 4), ROGUE_2_4(88, 4), //??? T4 diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/rogue/SmokeBomb.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/rogue/SmokeBomb.java index aadbe5676..62ad4e5b6 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/rogue/SmokeBomb.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/rogue/SmokeBomb.java @@ -27,11 +27,13 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Blindness; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Haste; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Invisibility; 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.actors.mobs.Mob; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.NPC; import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter; import com.shatteredpixel.shatteredpixeldungeon.effects.Speck; import com.shatteredpixel.shatteredpixeldungeon.items.Item; @@ -39,10 +41,13 @@ import com.shatteredpixel.shatteredpixeldungeon.items.armor.ClassArmor; import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfTeleportation; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; +import com.shatteredpixel.shatteredpixeldungeon.sprites.MobSprite; import com.shatteredpixel.shatteredpixeldungeon.utils.BArray; import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; +import com.watabou.noosa.TextureFilm; import com.watabou.noosa.audio.Sample; import com.watabou.utils.PathFinder; +import com.watabou.utils.Random; public class SmokeBomb extends ArmorAbility { @@ -51,6 +56,16 @@ public class SmokeBomb extends ArmorAbility { return Messages.get(this, "prompt"); } + @Override + public float chargeUse(Hero hero) { + if (!hero.hasTalent(Talent.SHADOW_STEP) || hero.invisible <= 0){ + return super.chargeUse(hero); + } else { + //reduced charge cost by 24%/42%/56%/67% + return (float)(35f * Math.pow(0.76, hero.pointsInTalent(Talent.SHADOW_STEP))); + } + } + @Override protected void activate(ClassArmor armor, Hero hero, Integer target) { if (target != null) { @@ -65,17 +80,38 @@ public class SmokeBomb extends ArmorAbility { return; } - armor.charge -= 35; + armor.charge -= chargeUse(hero); Item.updateQuickslot(); - for (Mob mob : Dungeon.level.mobs.toArray(new Mob[0])) { - if (Dungeon.level.adjacent(mob.pos, hero.pos) && mob.alignment != Char.Alignment.ALLY) { - Buff.prolong( mob, Blindness.class, Blindness.DURATION/2f ); - if (mob.state == mob.HUNTING) mob.state = mob.WANDERING; - mob.sprite.emitter().burst( Speck.factory( Speck.LIGHT ), 4 ); + boolean shadowStepping = hero.invisible > 0 && hero.hasTalent(Talent.SHADOW_STEP); + + if (!shadowStepping) { + for (Mob mob : Dungeon.level.mobs.toArray(new Mob[0])) { + if (Dungeon.level.adjacent(mob.pos, hero.pos) && mob.alignment != Char.Alignment.ALLY) { + Buff.prolong(mob, Blindness.class, Blindness.DURATION / 2f); + if (mob.state == mob.HUNTING) mob.state = mob.WANDERING; + mob.sprite.emitter().burst(Speck.factory(Speck.LIGHT), 4); + } + } + + if (hero.hasTalent(Talent.BODY_REPLACEMENT)) { + for (Char ch : Actor.chars()){ + if (ch instanceof NinjaLog){ + ch.die(null); + } + } + + NinjaLog n = new NinjaLog(); + n.pos = hero.pos; + GameScene.add(n); + } + + if (hero.hasTalent(Talent.HASTY_RETREAT)){ + int duration = 2*hero.pointsInTalent(Talent.HASTY_RETREAT); + Buff.affect(hero, Haste.class, duration); + Buff.affect(hero, Invisibility.class, duration); } } - Buff.affect(hero, Invisibility.class, Invisibility.DURATION/2f); CellEmitter.get( hero.pos ).burst( Speck.factory( Speck.WOOL ), 10 ); ScrollOfTeleportation.appear( hero, target ); @@ -84,12 +120,72 @@ public class SmokeBomb extends ArmorAbility { Dungeon.observe(); GameScene.updateFog(); - hero.spendAndNext( Actor.TICK ); + if (!shadowStepping) { + hero.spendAndNext(Actor.TICK); + } else { + hero.next(); + } } } @Override public Talent[] talents() { - return new Talent[]{Talent.SMOKE_BOMB_1, Talent.SMOKE_BOMB_2, Talent.SMOKE_BOMB_3, Talent.SMOKE_BOMB_4}; + return new Talent[]{Talent.HASTY_RETREAT, Talent.BODY_REPLACEMENT, Talent.SHADOW_STEP, Talent.SMOKE_BOMB_4}; + } + + public static class NinjaLog extends NPC { + + { + spriteClass = NinjaLogSprite.class; + defenseSkill = 0; + + properties.add(Property.INORGANIC); //wood is organic, but this is accurate for game logic + + alignment = Alignment.ALLY; + + HP = HT = 30*Dungeon.hero.pointsInTalent(Talent.BODY_REPLACEMENT); + } + + @Override + public int drRoll() { + return Random.NormalIntRange(Dungeon.hero.pointsInTalent(Talent.BODY_REPLACEMENT), + 5*Dungeon.hero.pointsInTalent(Talent.BODY_REPLACEMENT)); + } + + } + + public static class NinjaLogSprite extends MobSprite { + + public NinjaLogSprite(){ + super(); + + texture("sprites/ninja_log.png"); + + TextureFilm frames = new TextureFilm( texture, 11, 12 ); + + idle = new Animation( 0, true ); + idle.frames( frames, 0 ); + + run = idle.clone(); + attack = idle.clone(); + zap = attack.clone(); + + die = new Animation( 12, false ); + die.frames( frames, 1, 2, 3, 4 ); + + play( idle ); + + } + + @Override + public void showAlert() { + //do nothing + } + + @Override + public int blood() { + return 0xFF966400; + } + } }