From 367a364eb36c2fdc7457cfe71a27c0773dea74e3 Mon Sep 17 00:00:00 2001 From: Evan Debenham <Evan@ShatteredPixel.com> Date: Thu, 20 May 2021 01:23:10 -0400 Subject: [PATCH] v0.9.3: externalize some ghost hero properties to new class --- .../actors/mobs/Mob.java | 7 +- .../actors/mobs/npcs/DirectableAlly.java | 148 +++++++++++++++++ .../items/artifacts/DriedRose.java | 157 ++++-------------- 3 files changed, 181 insertions(+), 131 deletions(-) create mode 100644 core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/DirectableAlly.java 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 71ff8bd1b..89ae0c8ce 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 @@ -41,6 +41,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.SoulMark; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Terror; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.DirectableAlly; import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter; import com.shatteredpixel.shatteredpixeldungeon.effects.Speck; import com.shatteredpixel.shatteredpixeldungeon.effects.Surprise; @@ -1062,9 +1063,9 @@ public abstract class Mob extends Char { public static void holdAllies( Level level, int holdFromPos ){ heldAllies.clear(); for (Mob mob : level.mobs.toArray( new Mob[0] )) { - //preserve the ghost no matter where they are - if (mob instanceof DriedRose.GhostHero) { - ((DriedRose.GhostHero) mob).clearDefensingPos(); + //preserve directable allies no matter where they are + if (mob instanceof DirectableAlly) { + ((DirectableAlly) mob).clearDefensingPos(); level.mobs.remove( mob ); heldAllies.add(mob); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/DirectableAlly.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/DirectableAlly.java new file mode 100644 index 000000000..5bc488699 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/DirectableAlly.java @@ -0,0 +1,148 @@ +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.mobs.Mob; +import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.DriedRose; +import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; +import com.watabou.utils.Bundle; +import com.watabou.utils.Random; + +public class DirectableAlly extends NPC { + + { + alignment = Char.Alignment.ALLY; + intelligentAlly = true; + WANDERING = new Wandering(); + + //before other mobs + actPriority = MOB_PRIO + 1; + + } + + protected int defendingPos = -1; + protected boolean movingToDefendPos = false; + + public void defendPos( int cell ){ + aggro(null); + state = WANDERING; + defendingPos = cell; + movingToDefendPos = true; + } + + public void clearDefensingPos(){ + defendingPos = -1; + movingToDefendPos = false; + } + + public void followHero(){ + aggro(null); + state = WANDERING; + defendingPos = -1; + movingToDefendPos = false; + } + + public void targetChar( Char ch ){ + aggro(ch); + target = ch.pos; + movingToDefendPos = false; + } + + public void directTocell( int cell ){ + if (!Dungeon.level.heroFOV[cell] + || Actor.findChar(cell) == null + || (Actor.findChar(cell) != Dungeon.hero && Actor.findChar(cell).alignment != Char.Alignment.ENEMY)){ + defendPos( cell ); + return; + } + + //TODO commenting this out for now, it should be pointless?? + /*if (fieldOfView == null || fieldOfView.length != Dungeon.level.length()){ + fieldOfView = new boolean[Dungeon.level.length()]; + } + Dungeon.level.updateFieldOfView( this, fieldOfView );*/ + + if (Actor.findChar(cell) == Dungeon.hero){ + followHero(); + + } else if (Actor.findChar(cell).alignment == Char.Alignment.ENEMY){ + targetChar(Actor.findChar(cell)); + + } + } + + + @Override + protected Char chooseEnemy() { + Char enemy = super.chooseEnemy(); + + int targetPos = defendingPos != -1 ? defendingPos : Dungeon.hero.pos; + + //will never attack something far from their target + if (enemy != null + && Dungeon.level.mobs.contains(enemy) + && (Dungeon.level.distance(enemy.pos, targetPos) <= 8)){ + return enemy; + } + + return null; + } + + private static final String DEFEND_POS = "defend_pos"; + private static final String MOVING_TO_DEFEND = "moving_to_defend"; + + @Override + public void storeInBundle(Bundle bundle) { + super.storeInBundle(bundle); + bundle.put(DEFEND_POS, defendingPos); + bundle.put(MOVING_TO_DEFEND, movingToDefendPos); + } + + @Override + public void restoreFromBundle(Bundle bundle) { + super.restoreFromBundle(bundle); + if (bundle.contains(DEFEND_POS)) defendingPos = bundle.getInt(DEFEND_POS); + movingToDefendPos = bundle.getBoolean(MOVING_TO_DEFEND); + } + + private class Wandering extends Mob.Wandering { + + @Override + public boolean act( boolean enemyInFOV, boolean justAlerted ) { + if ( enemyInFOV && !movingToDefendPos ) { + + enemySeen = true; + + notice(); + alerted = true; + state = HUNTING; + target = enemy.pos; + + } else { + + enemySeen = false; + + int oldPos = pos; + target = defendingPos != -1 ? defendingPos : Dungeon.hero.pos; + //always move towards the hero when wandering + if (getCloser( target )) { + spend( 1 / speed() ); + if (pos == defendingPos) movingToDefendPos = false; + return moveSprite( oldPos, pos ); + } else { + //if it can't move closer to defending pos, then give up and defend current position + if (movingToDefendPos){ + defendingPos = pos; + movingToDefendPos = false; + } + spend( TICK ); + } + + } + return true; + } + + } + +} 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 3af696dcd..e55c85b5d 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 @@ -35,6 +35,7 @@ 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.Wraith; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.DirectableAlly; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Ghost; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.NPC; import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter; @@ -434,37 +435,9 @@ public class DriedRose extends Artifact { if (cell == null) return; Sample.INSTANCE.play( Assets.Sounds.GHOST ); - - if (!Dungeon.level.heroFOV[cell] - || Actor.findChar(cell) == null - || (Actor.findChar(cell) != Dungeon.hero && Actor.findChar(cell).alignment != Char.Alignment.ENEMY)){ - ghost.yell(Messages.get(ghost, "directed_position_" + Random.IntRange(1, 5))); - ghost.aggro(null); - ghost.state = ghost.WANDERING; - ghost.defendingPos = cell; - ghost.movingToDefendPos = true; - return; - } - - if (ghost.fieldOfView == null || ghost.fieldOfView.length != Dungeon.level.length()){ - ghost.fieldOfView = new boolean[Dungeon.level.length()]; - } - Dungeon.level.updateFieldOfView( ghost, ghost.fieldOfView ); - - if (Actor.findChar(cell) == Dungeon.hero){ - ghost.yell(Messages.get(ghost, "directed_follow_" + Random.IntRange(1, 5))); - ghost.aggro(null); - ghost.state = ghost.WANDERING; - ghost.defendingPos = -1; - ghost.movingToDefendPos = false; - - } else if (Actor.findChar(cell).alignment == Char.Alignment.ENEMY){ - ghost.yell(Messages.get(ghost, "directed_attack_" + Random.IntRange(1, 5))); - ghost.aggro(Actor.findChar(cell)); - ghost.setTarget(cell); - ghost.movingToDefendPos = false; - - } + + ghost.directTocell(cell); + } @Override @@ -510,22 +483,15 @@ public class DriedRose extends Artifact { } - public static class GhostHero extends NPC { + public static class GhostHero extends DirectableAlly { { spriteClass = GhostSprite.class; flying = true; - - alignment = Alignment.ALLY; - intelligentAlly = true; - WANDERING = new Wandering(); state = HUNTING; - //before other mobs - actPriority = MOB_PRIO + 1; - properties.add(Property.UNDEAD); } @@ -541,7 +507,25 @@ public class DriedRose extends Artifact { updateRose(); HP = HT; } - + + @Override + public void defendPos(int cell) { + yell(Messages.get(this, "directed_position_" + Random.IntRange(1, 5))); + super.defendPos(cell); + } + + @Override + public void followHero() { + yell(Messages.get(this, "directed_follow_" + Random.IntRange(1, 5))); + super.followHero(); + } + + @Override + public void targetChar(Char ch) { + yell(Messages.get(this, "directed_attack_" + Random.IntRange(1, 5))); + super.targetChar(ch); + } + private void updateRose(){ if (rose == null) { rose = Dungeon.hero.belongings.getItem(DriedRose.class); @@ -552,14 +536,6 @@ public class DriedRose extends Artifact { if (rose == null) return; HT = 20 + 8*rose.level(); } - - private int defendingPos = -1; - private boolean movingToDefendPos = false; - - public void clearDefensingPos(){ - defendingPos = -1; - movingToDefendPos = false; - } @Override protected boolean act() { @@ -573,22 +549,6 @@ public class DriedRose extends Artifact { } return super.act(); } - - @Override - protected Char chooseEnemy() { - Char enemy = super.chooseEnemy(); - - int targetPos = defendingPos != -1 ? defendingPos : Dungeon.hero.pos; - - //will never attack something far from their target - if (enemy != null - && Dungeon.level.mobs.contains(enemy) - && (Dungeon.level.distance(enemy.pos, targetPos) <= 8)){ - return enemy; - } - - return null; - } @Override public int attackSkill(Char target) { @@ -672,6 +632,11 @@ public class DriedRose extends Artifact { if (rose != null && rose.armor != null){ speed = rose.armor.speedFactor(this, speed); } + + //moves 2 tiles at a time when returning to the hero + if (state == WANDERING && defendingPos == -1){ + speed *= 2; + } return speed; } @@ -709,10 +674,6 @@ public class DriedRose extends Artifact { } return block; } - - private void setTarget(int cell) { - target = cell; - } @Override public boolean isImmune(Class effect) { @@ -832,23 +793,6 @@ public class DriedRose extends Artifact { Sample.INSTANCE.play( Assets.Sounds.GHOST ); } - private static final String DEFEND_POS = "defend_pos"; - private static final String MOVING_TO_DEFEND = "moving_to_defend"; - - @Override - public void storeInBundle(Bundle bundle) { - super.storeInBundle(bundle); - bundle.put(DEFEND_POS, defendingPos); - bundle.put(MOVING_TO_DEFEND, movingToDefendPos); - } - - @Override - public void restoreFromBundle(Bundle bundle) { - super.restoreFromBundle(bundle); - if (bundle.contains(DEFEND_POS)) defendingPos = bundle.getInt(DEFEND_POS); - movingToDefendPos = bundle.getBoolean(MOVING_TO_DEFEND); - } - { immunities.add( ToxicGas.class ); immunities.add( CorrosiveGas.class ); @@ -857,49 +801,6 @@ public class DriedRose extends Artifact { immunities.add( ScrollOfPsionicBlast.class ); immunities.add( Corruption.class ); } - - private class Wandering extends Mob.Wandering { - - @Override - public boolean act( boolean enemyInFOV, boolean justAlerted ) { - if ( enemyInFOV && !movingToDefendPos ) { - - enemySeen = true; - - notice(); - alerted = true; - state = HUNTING; - target = enemy.pos; - - } else { - - enemySeen = false; - - int oldPos = pos; - target = defendingPos != -1 ? defendingPos : Dungeon.hero.pos; - //always move towards the hero when wandering - if (getCloser( target )) { - //moves 2 tiles at a time when returning to the hero - if (defendingPos == -1 && !Dungeon.level.adjacent(target, pos)){ - getCloser( target ); - } - spend( 1 / speed() ); - if (pos == defendingPos) movingToDefendPos = false; - return moveSprite( oldPos, pos ); - } else { - //if ghost can't move closer to defending pos, then give up an defend current position - if (movingToDefendPos){ - defendingPos = pos; - movingToDefendPos = false; - } - spend( TICK ); - } - - } - return true; - } - - } }