v0.8.0: improved enemy AI:

- Ripper demons now cannot leap to an enemy they can't see
- fixed characters being able to target invisible enemies
This commit is contained in:
Evan Debenham 2020-03-30 19:23:24 -04:00
parent 22a6c3e8a6
commit 35d639f973
2 changed files with 16 additions and 19 deletions

View File

@ -37,7 +37,6 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Preparation;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Sleep; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Sleep;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.SoulMark; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.SoulMark;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Terror; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Terror;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Weakness;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.effects.Flare; import com.shatteredpixel.shatteredpixeldungeon.effects.Flare;
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck; import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
@ -239,18 +238,22 @@ public abstract class Mob extends Char {
if ( buff(Amok.class) != null) { if ( buff(Amok.class) != null) {
//try to find an enemy mob to attack first. //try to find an enemy mob to attack first.
for (Mob mob : Dungeon.level.mobs) for (Mob mob : Dungeon.level.mobs)
if (mob.alignment == Alignment.ENEMY && mob != this && fieldOfView[mob.pos]) if (mob.alignment == Alignment.ENEMY && mob != this
&& fieldOfView[mob.pos] && mob.invisible <= 0) {
enemies.add(mob); enemies.add(mob);
}
if (enemies.isEmpty()) { if (enemies.isEmpty()) {
//try to find ally mobs to attack second. //try to find ally mobs to attack second.
for (Mob mob : Dungeon.level.mobs) for (Mob mob : Dungeon.level.mobs)
if (mob.alignment == Alignment.ALLY && mob != this && fieldOfView[mob.pos]) if (mob.alignment == Alignment.ALLY && mob != this
&& fieldOfView[mob.pos] && mob.invisible <= 0) {
enemies.add(mob); enemies.add(mob);
}
if (enemies.isEmpty()) { if (enemies.isEmpty()) {
//try to find the hero third //try to find the hero third
if (fieldOfView[Dungeon.hero.pos]) { if (fieldOfView[Dungeon.hero.pos] && Dungeon.hero.invisible <= 0) {
enemies.add(Dungeon.hero); enemies.add(Dungeon.hero);
} }
} }
@ -260,7 +263,8 @@ public abstract class Mob extends Char {
} else if ( alignment == Alignment.ALLY ) { } else if ( alignment == Alignment.ALLY ) {
//look for hostile mobs to attack //look for hostile mobs to attack
for (Mob mob : Dungeon.level.mobs) for (Mob mob : Dungeon.level.mobs)
if (mob.alignment == Alignment.ENEMY && fieldOfView[mob.pos]) if (mob.alignment == Alignment.ENEMY && fieldOfView[mob.pos]
&& mob.invisible <= 0 && !mob.isInvulnerable(getClass()))
//intelligent allies do not target mobs which are passive, wandering, or asleep //intelligent allies do not target mobs which are passive, wandering, or asleep
if (!intelligentAlly || if (!intelligentAlly ||
(mob.state != mob.SLEEPING && mob.state != mob.PASSIVE && mob.state != mob.WANDERING)) { (mob.state != mob.SLEEPING && mob.state != mob.PASSIVE && mob.state != mob.WANDERING)) {
@ -271,11 +275,11 @@ public abstract class Mob extends Char {
} else if (alignment == Alignment.ENEMY) { } else if (alignment == Alignment.ENEMY) {
//look for ally mobs to attack //look for ally mobs to attack
for (Mob mob : Dungeon.level.mobs) for (Mob mob : Dungeon.level.mobs)
if (mob.alignment == Alignment.ALLY && fieldOfView[mob.pos]) if (mob.alignment == Alignment.ALLY && fieldOfView[mob.pos] && mob.invisible <= 0 && !mob.isInvulnerable(getClass()))
enemies.add(mob); enemies.add(mob);
//and look for the hero //and look for the hero
if (fieldOfView[Dungeon.hero.pos]) { if (fieldOfView[Dungeon.hero.pos] && Dungeon.hero.invisible <= 0 && !Dungeon.hero.isInvulnerable(getClass())) {
enemies.add(Dungeon.hero); enemies.add(Dungeon.hero);
} }
@ -289,15 +293,6 @@ public abstract class Mob extends Char {
} }
} }
//if we are not amoked, remove any enemies which are invulnerable to us.
if (buff(Amok.class) == null) {
for (Char enemy : enemies.toArray(new Char[0])) {
if (enemy.isInvulnerable(getClass())){
enemies.remove(enemy);
}
}
}
//neutral characters in particular do not choose enemies. //neutral characters in particular do not choose enemies.
if (enemies.isEmpty()){ if (enemies.isEmpty()){
return null; return null;
@ -437,6 +432,7 @@ public abstract class Mob extends Char {
// of a temporary blockage, and therefore waiting for it to clear is the best option. // of a temporary blockage, and therefore waiting for it to clear is the best option.
if (path == null || if (path == null ||
(state == HUNTING && path.size() > Math.max(9, 2*Dungeon.level.distance(pos, target)))) { (state == HUNTING && path.size() > Math.max(9, 2*Dungeon.level.distance(pos, target)))) {
//
return false; return false;
} }
@ -739,7 +735,7 @@ public abstract class Mob extends Char {
@Override @Override
public boolean act( boolean enemyInFOV, boolean justAlerted ) { public boolean act( boolean enemyInFOV, boolean justAlerted ) {
if (enemyInFOV && Random.Float( distance( enemy ) + enemy.stealth() + (enemy.flying ? 2 : 0) ) < 1) { if (enemyInFOV && Random.Float( distance( enemy ) + enemy.stealth() ) < 1) {
enemySeen = true; enemySeen = true;
@ -861,6 +857,7 @@ public abstract class Mob extends Char {
} }
} }
//FIXME this works fairly well but is coded poorly. Should refactor
protected class Fleeing implements AiState { protected class Fleeing implements AiState {
public static final String TAG = "FLEEING"; public static final String TAG = "FLEEING";

View File

@ -187,7 +187,7 @@ public class RipperDemon extends Mob {
return true; return true;
} }
if (Dungeon.level.distance(pos, enemy.pos) >= 3) { if (enemyInFOV && Dungeon.level.distance(pos, enemy.pos) >= 3) {
int targetPos = enemy.pos; int targetPos = enemy.pos;
if (lastEnemyPos != enemy.pos){ if (lastEnemyPos != enemy.pos){