From e3833aadec698aad4295f910782ec0c5e3071e8b Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Sun, 1 Jul 2018 16:13:04 -0400 Subject: [PATCH] v0.7.0: rebalanced scroll of mirror image --- .../actors/mobs/npcs/MirrorImage.java | 145 ++++++++++++++---- .../items/scrolls/ScrollOfMirrorImage.java | 6 +- .../sprites/MirrorSprite.java | 2 +- .../messages/actors/actors.properties | 2 +- .../messages/items/items.properties | 2 +- 5 files changed, 125 insertions(+), 32 deletions(-) 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 13ae607df..7c66bb0c0 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 @@ -22,79 +22,164 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; +import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.CorrosiveGas; import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.ToxicGas; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Burning; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Invisibility; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.MirrorSprite; +import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator; import com.watabou.utils.Bundle; +import com.watabou.utils.Random; public class MirrorImage extends NPC { { spriteClass = MirrorSprite.class; + HP = HT = 1; + defenseSkill = 0; + alignment = Alignment.ALLY; state = HUNTING; + + //before other mobs + actPriority = MOB_PRIO + 1; } - public int tier; + private Hero hero; + private int heroID; + public int armTier; - private int attack; - private int damage; + @Override + protected boolean act() { + + if ( hero == null ){ + hero = (Hero)Actor.findById(heroID); + if ( hero == null ){ + die(null); + sprite.killAndErase(); + return true; + } + } + + if (hero.tier() != armTier){ + armTier = hero.tier(); + ((MirrorSprite)sprite).updateArmor( armTier ); + } + + return super.act(); + } - private static final String TIER = "tier"; - private static final String ATTACK = "attack"; - private static final String DAMAGE = "damage"; + private static final String HEROID = "hero_id"; @Override public void storeInBundle( Bundle bundle ) { super.storeInBundle( bundle ); - bundle.put( TIER, tier ); - bundle.put( ATTACK, attack ); - bundle.put( DAMAGE, damage ); + bundle.put( HEROID, heroID ); } @Override public void restoreFromBundle( Bundle bundle ) { super.restoreFromBundle( bundle ); - tier = bundle.getInt( TIER ); - attack = bundle.getInt( ATTACK ); - damage = bundle.getInt( DAMAGE ); + heroID = bundle.getInt( HEROID ); } public void duplicate( Hero hero ) { - tier = hero.tier(); - attack = hero.attackSkill( hero ); - damage = hero.damageRoll(); - } - - @Override - public int attackSkill( Char target ) { - return attack; + this.hero = hero; + Buff.affect(this, MirrorInvis.class, Short.MAX_VALUE); } @Override public int damageRoll() { - return damage; + int damage; + if (hero.belongings.weapon != null){ + damage = hero.belongings.weapon.damageRoll(this); + } else { + damage = hero.damageRoll(); //handles ring of force + } + return (damage+1)/2; //half hero damage, rounded up + } + + @Override + public int attackSkill( Char target ) { + return hero.attackSkill(target); + } + + @Override + public int defenseSkill(Char enemy) { + if (hero != null) { + int baseEvasion = 4 + hero.lvl; + int heroEvasion = hero.defenseSkill(enemy); + + //if the hero has more/less evasion, 50% of it is applied + return (baseEvasion + heroEvasion) / 2; + } else { + return 0; + } + } + + @Override + protected float attackDelay() { + return hero.attackDelay(); //handles ring of furor + } + + @Override + protected boolean canAttack(Char enemy) { + if (hero.belongings.weapon != null){ + return Dungeon.level.distance( pos, enemy.pos ) <= hero.belongings.weapon.reachFactor(this); + } else { + return super.canAttack(enemy); + } + } + + @Override + public int drRoll() { + if (hero != null && hero.belongings.weapon != null){ + return Random.NormalIntRange(0, hero.belongings.weapon.defenseFactor(this)/2); + } else { + return 0; + } } @Override public int attackProc( Char enemy, int damage ) { damage = super.attackProc( enemy, damage ); - - destroy(); - sprite.die(); - return damage; + MirrorInvis buff = buff(MirrorInvis.class); + if (buff != null){ + buff.detach(); + } + + if (enemy instanceof Mob) { + ((Mob)enemy).aggro( this ); + } + if (hero.belongings.weapon != null){ + return hero.belongings.weapon.proc( this, enemy, damage ); + } else { + return damage; + } } @Override public CharSprite sprite() { CharSprite s = super.sprite(); - ((MirrorSprite)s).updateArmor( tier ); + + //pre-0.7.0 saves + if (heroID == 0){ + heroID = Dungeon.hero.id(); + } + + hero = (Hero)Actor.findById(heroID); + if (hero != null) { + armTier = hero.tier(); + } + ((MirrorSprite)s).updateArmor( armTier ); return s; } @@ -120,4 +205,12 @@ public class MirrorImage extends NPC { immunities.add( CorrosiveGas.class ); immunities.add( Burning.class ); } + + public static class MirrorInvis extends Invisibility { + + @Override + public int icon() { + return BuffIndicator.NONE; + } + } } \ No newline at end of file diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/ScrollOfMirrorImage.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/ScrollOfMirrorImage.java index 8f42f9763..467e4f360 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/ScrollOfMirrorImage.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/ScrollOfMirrorImage.java @@ -43,7 +43,7 @@ public class ScrollOfMirrorImage extends Scroll { initials = 3; } - private static final int NIMAGES = 3; + private static final int NIMAGES = 2; @Override public void doRead() { @@ -61,8 +61,8 @@ public class ScrollOfMirrorImage extends Scroll { @Override public void empoweredRead() { - //spawns 2 images right away, delays 4 of them, 6 total. - new DelayedImageSpawner(6 - spawnImages(curUser, 2), 2, 3).attachTo(curUser); + //spawns 2 images right away, delays 3 of them, 5 total. + new DelayedImageSpawner(5 - spawnImages(curUser, 2), 1, 2).attachTo(curUser); setKnown(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/MirrorSprite.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/MirrorSprite.java index 7b9ed92ba..609cc338d 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/MirrorSprite.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/MirrorSprite.java @@ -42,7 +42,7 @@ public class MirrorSprite extends MobSprite { @Override public void link( Char ch ) { super.link( ch ); - updateArmor( ((MirrorImage)ch).tier ); + updateArmor( ((MirrorImage)ch).armTier ); } public void updateArmor( int tier ) { diff --git a/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/actors/actors.properties b/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/actors/actors.properties index 593685760..875e90922 100644 --- a/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/actors/actors.properties +++ b/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/actors/actors.properties @@ -341,7 +341,7 @@ actors.mobs.npcs.impshopkeeper.thief=I thought I could trust you! actors.mobs.npcs.impshopkeeper.desc=Imps are lesser demons. They are notable for neither their strength nor their magic talent. But they are quite smart and sociable, and many of imps prefer to live and do business among non-demons. actors.mobs.npcs.mirrorimage.name=mirror image -actors.mobs.npcs.mirrorimage.desc=This illusion bears a close resemblance to you, but it's paler and twitches a little. +actors.mobs.npcs.mirrorimage.desc=This illusion bears a close resemblance to you, even seeming to wield your current weapon and armor.\n\nMirror images will seek and attack enemies using their mimicked weapon, which behaves the same as yours, but deals less damage. They start out ethereal, but must take on a solid form in order to attack.\n\nWhile their offensive power can be potent, mirror images have no durability, and will fade the moment they take damage. actors.mobs.npcs.ratking.name=rat king actors.mobs.npcs.ratking.not_sleeping=I'm not sleeping! diff --git a/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/items/items.properties b/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/items/items.properties index ae9768ff3..577e4b7c0 100644 --- a/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/items/items.properties +++ b/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/items/items.properties @@ -632,7 +632,7 @@ items.scrolls.scrollofmagicmapping.layout=You are now aware of the level layout. items.scrolls.scrollofmagicmapping.desc=When this scroll is read, an image of crystal clarity will be etched into your memory, alerting you to the precise layout of the level and revealing all hidden secrets. The locations of items and creatures will remain unknown. items.scrolls.scrollofmirrorimage.name=scroll of mirror image -items.scrolls.scrollofmirrorimage.desc=The incantation on this scroll will create illusionary twins of the reader, which will chase their enemies. +items.scrolls.scrollofmirrorimage.desc=The incantation on this scroll will create two illusory twins of the reader. These mirror images act as weaker clones of the reader, and will chase down their enemies. They have no durability however, and will fade upon taking damage. items.scrolls.scrollofpsionicblast.name=scroll of psionic blast items.scrolls.scrollofpsionicblast.desc=This scroll contains destructive energy that can be channeled to assault the minds all visible creatures, blinding and damaging them. The power unleashed by the scroll is chaotic, so it will also blind and weaken the user.\n\nThe more injured the user is, the more powerful the scroll will be. At very low health psionic blast can kill most enemies instantly.