From 0272216f9a1432a8a561d340946e61fb29667c22 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Mon, 17 May 2021 20:53:28 -0400 Subject: [PATCH] v0.9.3: implemented the ratmogrify ability --- .../assets/messages/actors/actors.properties | 21 +- .../actors/hero/Talent.java | 4 +- .../actors/hero/abilities/Ratmogrify.java | 193 +++++++++++++++++- .../actors/mobs/Mob.java | 4 +- .../actors/mobs/Monk.java | 2 +- .../actors/mobs/Rat.java | 5 +- .../actors/mobs/RipperDemon.java | 2 +- .../actors/mobs/Statue.java | 2 +- .../actors/mobs/Thief.java | 2 +- .../actors/mobs/npcs/MirrorImage.java | 2 +- .../actors/mobs/npcs/RatKing.java | 4 + .../items/artifacts/DriedRose.java | 2 +- 12 files changed, 221 insertions(+), 22 deletions(-) diff --git a/core/src/main/assets/messages/actors/actors.properties b/core/src/main/assets/messages/actors/actors.properties index 1db3abaa3..edea17ec7 100644 --- a/core/src/main/assets/messages/actors/actors.properties +++ b/core/src/main/assets/messages/actors/actors.properties @@ -378,8 +378,12 @@ actors.hero.abilities.huntress.spirithawk.short_desc=The Huntress summons a _Spi actors.hero.abilities.huntress.spirithawk.desc=TODO actors.hero.abilities.ratmogrify.name=ratmogrify -actors.hero.abilities.ratmogrify.short_desc=The hero _ratmogrifies_ an enemy! This temporarily turns them into a rat with weakened attack power and no abilities. +actors.hero.abilities.ratmogrify.cant_transform=You can't ratmogrify that! +actors.hero.abilities.ratmogrify.too_strong=That enemy is too strong to ratmogrify! +actors.hero.abilities.ratmogrify.short_desc=The hero _Ratmogrifies_ an enemy! This turns them into a rat with no abilities, but also no loot. actors.hero.abilities.ratmogrify.desc=TODO +actors.hero.abilities.ratmogrify$transmograt.name=ratmogrified %s +actors.hero.abilities.ratmogrify$transmograt.desc=TODO actors.hero.hero.name=you actors.hero.hero.leave=You can't leave yet, the rest of the dungeon awaits below! @@ -689,12 +693,12 @@ actors.hero.talent.huntress_3_3.desc=TODO DESC actors.hero.talent.heroic_energy.title=heroic energy actors.hero.talent.heroic_energy.desc=_+1:_ The hero's armor ability has a _13% reduced_ charge cost.\n\n_+2:_ The hero's armor ability has a _24% reduced_ charge cost.\n\n_+3:_ The hero's armor ability has a _34% reduced_ charge cost.\n\n_+4:_ The hero's armor ability has a _43% reduced_ charge cost -actors.hero.talent.rk_1.title=TODO NAME -actors.hero.talent.rk_1.desc=TODO DESC -actors.hero.talent.rk_2.title=TODO NAME -actors.hero.talent.rk_2.desc=TODO DESC -actors.hero.talent.rk_3.title=TODO NAME -actors.hero.talent.rk_3.desc=TODO DESC +actors.hero.talent.ratsistance.title=ratsistance +actors.hero.talent.ratsistance.desc=_+1:_ Hostile ratmogrified enemies deal _-10% damage_.\n\n_+2:_ Hostile ratmogrified enemies deal _-20% damage_.\n\n_+3:_ Hostile ratmogrified enemies deal _-30% damage_.\n\n_+4:_ Hostile ratmogrified enemies deal _-40% damage_. +actors.hero.talent.ratlomacy.title=ratlomacy +actors.hero.talent.ratlomacy.desc=_+1:_ Using ratmogrify on a ratmogrified enemy makes them permanently friendly.\n\n_+2:_ Using ratmogrify on a ratmogrified enemy makes them permanently friendly and gives them _2 turns_ of adrenaline.\n\n_+3:_ Using ratmogrify on a ratmogrified enemy makes them permanently friendly and gives them _4 turns_ of adrenaline.\n\n_+4:_ Using ratmogrify on a ratmogrified enemy makes them permanently friendly and gives them _6 turns_ of adrenaline. +actors.hero.talent.ratforcements.title=ratforcements +actors.hero.talent.ratforcements.desc=_+1:_ Using ratmogrify on yourself _spawns 1_ ally marsupial rat next to you.\n\n_+2:_ Using ratmogrify on yourself _spawns 2_ ally marsupial rats next to you.\n\n_+3:_ Using ratmogrify on yourself _spawns 3_ ally marsupial rats next to you.\n\n_+4:_ Using ratmogrify on yourself _spawns 4_ ally marsupial rats next to you. @@ -753,7 +757,8 @@ actors.mobs.npcs.ratking.confused=Wha... Where am I? My kingdom needs me! actors.mobs.npcs.ratking.crown_clothes=Put some clothes on! You're in no state to talk to royalty! actors.mobs.npcs.ratking.crown_desc=Oooh, is that crown for me!? It looks much shinier than mine, so I graciously accept!\n\nIn fact, I think I can offer you something as a reward for this crown. A tremendous power befitting a hero such as yourself! Would you like that? actors.mobs.npcs.ratking.crown_yes=Of course! -actors.mobs.npcs.ratking.crown_no=I'm not so sure... +actors.mobs.npcs.ratking.crown_info=Tell me more first. +actors.mobs.npcs.ratking.crown_no=I'd rather not... actors.mobs.npcs.ratking.crown_thankyou=Hehehe, thank you! Now go and make your king proud! actors.mobs.npcs.ratking.crown_fine=Fine! It's not like I wanted it anyway... actors.mobs.npcs.ratking.crown_after=Enjoying your new armor? No take-backsies! 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 5161c9b12..eecf67e24 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 @@ -138,8 +138,8 @@ public enum Talent { //universal T4 HEROIC_ENERGY(123, 4), - //??? T4 - RK_1(125, 4), RK_2(126, 4), RK_3(127, 4); + //Ratmogrify T4 + RATSISTANCE(125, 4), RATLOMACY(126, 4), RATFORCEMENTS(127, 4); public static class ImprovisedProjectileCooldown extends FlavourBuff{}; public static class LethalMomentumTracker extends FlavourBuff{}; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/Ratmogrify.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/Ratmogrify.java index ab964f003..f1cc753bf 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/Ratmogrify.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/Ratmogrify.java @@ -1,18 +1,207 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities; +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.Adrenaline; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Rat; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.MirrorImage; +import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter; +import com.shatteredpixel.shatteredpixeldungeon.effects.Speck; 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.RatSprite; +import com.shatteredpixel.shatteredpixeldungeon.ui.TargetHealthIndicator; +import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; +import com.watabou.noosa.audio.Sample; +import com.watabou.utils.Bundle; +import com.watabou.utils.PathFinder; +import com.watabou.utils.Random; + +import java.util.ArrayList; public class Ratmogrify extends ArmorAbility { + @Override + protected String targetingPrompt() { + return Messages.get(this, "prompt"); + } + @Override protected void activate(ClassArmor armor, Hero hero, Integer target) { - //TODO + + if (target == null){ + return; + } + + Char ch = Actor.findChar(target); + + if (ch == null) { + GLog.w(Messages.get(this, "no_target")); + return; + } else if (ch == hero){ + if (!hero.hasTalent(Talent.RATFORCEMENTS)){ + GLog.w(Messages.get(this, "self_target")); + } else { + ArrayList spawnPoints = new ArrayList<>(); + + for (int i = 0; i < PathFinder.NEIGHBOURS8.length; i++) { + int p = hero.pos + PathFinder.NEIGHBOURS8[i]; + if (Actor.findChar( p ) == null && Dungeon.level.passable[p]) { + spawnPoints.add( p ); + } + } + + int ratsToSpawn = hero.pointsInTalent(Talent.RATFORCEMENTS); + + while (ratsToSpawn > 0 && spawnPoints.size() > 0) { + int index = Random.index( spawnPoints ); + + Rat rat = new Rat(); + rat.alignment = Char.Alignment.ALLY; + rat.state = rat.HUNTING; + GameScene.add( rat ); + ScrollOfTeleportation.appear( rat, spawnPoints.get( index ) ); + + spawnPoints.remove( index ); + ratsToSpawn--; + } + + } + } else if (ch.alignment != Char.Alignment.ENEMY || !(ch instanceof Mob) || ch instanceof Rat){ + GLog.w(Messages.get(this, "cant_transform")); + return; + } else if (ch instanceof TransmogRat){ + if (((TransmogRat) ch).allied || !hero.hasTalent(Talent.RATLOMACY)){ + GLog.w(Messages.get(this, "cant_transform")); + return; + } else { + ((TransmogRat) ch).makeAlly(); + ch.sprite.emitter().start(Speck.factory(Speck.HEART), 0.2f, 5); + Sample.INSTANCE.play(Assets.Sounds.TELEPORT); + if (hero.pointsInTalent(Talent.RATLOMACY) > 1){ + Buff.affect(ch, Adrenaline.class, 2*(hero.pointsInTalent(Talent.RATLOMACY)-1)); + } + } + } else if (Char.hasProp(ch, Char.Property.MINIBOSS) || Char.hasProp(ch, Char.Property.BOSS)){ + GLog.w(Messages.get(this, "too_strong")); + } else { + TransmogRat rat = new TransmogRat(); + rat.setup((Mob)ch); + rat.pos = ch.pos; + + Actor.remove( ch ); + ch.sprite.killAndErase(); + Dungeon.level.mobs.remove(ch); + + GameScene.add(rat); + + TargetHealthIndicator.instance.target(null); + CellEmitter.get(rat.pos).burst(Speck.factory(Speck.WOOL), 4); + Sample.INSTANCE.play(Assets.Sounds.PUFF); + } + + armor.charge -= chargeUse(hero); + armor.updateQuickslot(); + hero.spendAndNext(Actor.TICK); + } @Override public Talent[] talents() { - return new Talent[]{ Talent.RK_1, Talent.RK_2, Talent.RK_3, Talent.HEROIC_ENERGY}; + return new Talent[]{ Talent.RATSISTANCE, Talent.RATLOMACY, Talent.RATFORCEMENTS, Talent.HEROIC_ENERGY}; + } + + public static class TransmogRat extends Mob { + + { + spriteClass = RatSprite.class; + + maxLvl = -2; + } + + private Mob original; + private boolean allied; + + public void setup(Mob original) { + this.original = original; + + HP = original.HP; + HT = original.HT; + + defenseSkill = original.defenseSkill; + + EXP = original.EXP; + + if (original.state == original.SLEEPING) { + state = SLEEPING; + } else if (original.state == original.HUNTING) { + state = HUNTING; + } else { + state = WANDERING; + } + + } + + public void makeAlly() { + allied = true; + alignment = Alignment.ALLY; + } + + public int attackSkill(Char target) { + return original.attackSkill(target); + } + + public int drRoll() { + return original.drRoll(); + } + + @Override + public int damageRoll() { + int damage = original.damageRoll(); + if (!allied && Dungeon.hero.hasTalent(Talent.RATSISTANCE)){ + damage = Math.round(damage * (1f - .1f*Dungeon.hero.pointsInTalent(Talent.RATSISTANCE))); + } + return damage; + } + + @Override + public float attackDelay() { + return original.attackDelay(); + } + + @Override + public String name() { + return Messages.get(this, "name", original.name()); + } + + private static final String ORIGINAL = "original"; + private static final String ALLIED = "allied"; + + @Override + public void storeInBundle(Bundle bundle) { + super.storeInBundle(bundle); + bundle.put(ORIGINAL, original); + bundle.put(ALLIED, allied); + } + + @Override + public void restoreFromBundle(Bundle bundle) { + super.restoreFromBundle(bundle); + + original = (Mob) bundle.get(ORIGINAL); + defenseSkill = original.defenseSkill; + EXP = original.EXP; + + allied = bundle.getBoolean(ALLIED); + if (allied) alignment = Alignment.ALLY; + } } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java index 5d3b06d18..71ff8bd1b 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java @@ -100,7 +100,7 @@ public abstract class Mob extends Char { protected int target = -1; - protected int defenseSkill = 0; + public int defenseSkill = 0; public int EXP = 1; public int maxLvl = Hero.MAX_LEVEL; @@ -518,7 +518,7 @@ public abstract class Mob extends Char { sprite.add( CharSprite.State.PARALYSED ); } - protected float attackDelay() { + public float attackDelay() { float delay = 1f; if ( buff(Adrenaline.class) != null) delay /= 1.5f; return delay; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Monk.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Monk.java index 51f5798a7..4c1875f77 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Monk.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Monk.java @@ -62,7 +62,7 @@ public class Monk extends Mob { } @Override - protected float attackDelay() { + public float attackDelay() { return super.attackDelay()*0.5f; } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Rat.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Rat.java index cd9dc27b6..f85d825e5 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Rat.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Rat.java @@ -40,8 +40,9 @@ public class Rat extends Mob { @Override protected boolean act() { - if (Dungeon.hero.armorAbility instanceof Ratmogrify){ - alignment = Alignment.NEUTRAL; + if (Dungeon.level.heroFOV[pos] && Dungeon.hero.armorAbility instanceof Ratmogrify){ + alignment = Alignment.ALLY; + if (state == SLEEPING) state = WANDERING; } return super.act(); } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/RipperDemon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/RipperDemon.java index daea1326c..826a5a81b 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/RipperDemon.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/RipperDemon.java @@ -77,7 +77,7 @@ public class RipperDemon extends Mob { } @Override - protected float attackDelay() { + public float attackDelay() { return super.attackDelay()*0.5f; } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Statue.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Statue.java index ae7681b24..1ab6279e6 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Statue.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Statue.java @@ -94,7 +94,7 @@ public class Statue extends Mob { } @Override - protected float attackDelay() { + public float attackDelay() { return super.attackDelay()*weapon.speedFactor( this ); } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Thief.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Thief.java index 2159015b7..9356f6263 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Thief.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Thief.java @@ -87,7 +87,7 @@ public class Thief extends Mob { } @Override - protected float attackDelay() { + public float attackDelay() { return super.attackDelay()*0.5f; } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/MirrorImage.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/MirrorImage.java index a64fc7b77..92773bf09 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/MirrorImage.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/MirrorImage.java @@ -129,7 +129,7 @@ public class MirrorImage extends NPC { } @Override - protected float attackDelay() { + public float attackDelay() { return hero.attackDelay(); //handles ring of furor } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/RatKing.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/RatKing.java index 244ac2a54..698129139 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/RatKing.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/RatKing.java @@ -29,6 +29,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.KingsCrown; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.sprites.RatKingSprite; +import com.shatteredpixel.shatteredpixeldungeon.windows.WndInfoArmorAbility; import com.shatteredpixel.shatteredpixeldungeon.windows.WndOptions; import com.watabou.noosa.Game; import com.watabou.utils.Callback; @@ -126,6 +127,7 @@ public class RatKing extends NPC { Messages.titleCase(name()), Messages.get(RatKing.class, "crown_desc"), Messages.get(RatKing.class, "crown_yes"), + Messages.get(RatKing.class, "crown_info"), Messages.get(RatKing.class, "crown_no") ){ @Override @@ -134,6 +136,8 @@ public class RatKing extends NPC { crown.upgradeArmor(Dungeon.hero, Dungeon.hero.belongings.armor, new Ratmogrify()); ((RatKingSprite)sprite).resetAnims(); yell(Messages.get(RatKing.class, "crown_thankyou")); + } else if (index == 1) { + GameScene.show(new WndInfoArmorAbility(Dungeon.hero.heroClass, new Ratmogrify())); } else { yell(Messages.get(RatKing.class, "crown_fine")); } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/DriedRose.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/DriedRose.java index 796c8e313..3af696dcd 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/DriedRose.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/DriedRose.java @@ -604,7 +604,7 @@ public class DriedRose extends Artifact { } @Override - protected float attackDelay() { + public float attackDelay() { float delay = super.attackDelay(); if (rose != null && rose.weapon != null){ delay *= rose.weapon.speedFactor(this);