v0.9.3: externalize some ghost hero properties to new class
This commit is contained in:
parent
886bd3d0a8
commit
367a364eb3
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user