v0.9.3: externalize some ghost hero properties to new class

This commit is contained in:
Evan Debenham 2021-05-20 01:23:10 -04:00
parent 886bd3d0a8
commit 367a364eb3
3 changed files with 181 additions and 131 deletions

View File

@ -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);

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}