From 49af7826ef2c98201a7033774bb7902a989f8471 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Tue, 3 Sep 2024 11:40:49 -0400 Subject: [PATCH] v2.5.0: further fixes to sleeping AI, and compensation balance tweaks: - shadow clone now benefits from silent steps - flying characters are now stealthy, do not wake distant sleepers --- .../assets/messages/actors/actors.properties | 2 +- .../actors/mobs/Mob.java | 31 +++++++++++++------ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/core/src/main/assets/messages/actors/actors.properties b/core/src/main/assets/messages/actors/actors.properties index 8ff9ccff9..7d4dfba3a 100644 --- a/core/src/main/assets/messages/actors/actors.properties +++ b/core/src/main/assets/messages/actors/actors.properties @@ -254,7 +254,7 @@ actors.buffs.invulnerability.name=invulnerable actors.buffs.invulnerability.desc=You are suffuse with great protective power, granting you a brief period of invulnerability!\n\nTurns remaining: %s. actors.buffs.levitation.name=levitating -actors.buffs.levitation.desc=A magical force is levitating you over the ground, making you feel weightless.\n\nLevitating characters ignore all ground-based effects. Traps won't trigger, water won't put out fire, plants won't be trampled, roots will miss, and pits will be hovered over. Be careful, as all these things can come into effect the second the levitation ends!\n\nTurns of levitation remaining: %s. +actors.buffs.levitation.desc=A magical force is levitating you over the ground, making you feel weightless.\n\nLevitating characters move silently and ignore all ground-based effects. Traps won't trigger, water won't put out fire, plants won't be trampled, roots will miss, and pits will be hovered over. Be careful, as all these things can come into effect the second the levitation ends!\n\nTurns of levitation remaining: %s. actors.buffs.lifelink.name=life link actors.buffs.lifelink.desc=This character's life force is linked to another character nearby. Any damage taken is shared between them.\n\nWhenever this character takes damage, half of it will be dealt to the life link target instead.\n\nTurns of life link remaining: %s, or until the linked character dies. 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 a472d696a..d8c50459e 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 @@ -51,6 +51,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroClass; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.duelist.Feint; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.rogue.ShadowClone; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.DirectableAlly; import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter; import com.shatteredpixel.shatteredpixeldungeon.effects.FloatingText; @@ -293,9 +294,6 @@ public abstract class Mob extends Char { //We are charmed and current enemy is what charmed us } else if (buff(Charm.class) != null && buff(Charm.class).object == enemy.id()) { newEnemy = true; - //We are sleeping (rather than preferring existing target, we want to see if anything is closer - } else if (state == SLEEPING){ - newEnemy = true; } //additionally, if we are an ally, find a new enemy if... @@ -1031,17 +1029,32 @@ public abstract class Mob extends Char { } } - if (enemyInFOV) { + //can be awoken by the least stealthy hostile present, not necessarily just our target + if (enemyInFOV || (enemy != null && enemy.invisible > 0)) { - float enemyStealth = enemy.stealth(); + float closestHostileDist = Float.POSITIVE_INFINITY; - if (enemy instanceof Hero && ((Hero) enemy).hasTalent(Talent.SILENT_STEPS)){ - if (Dungeon.level.distance(pos, enemy.pos) >= 4 - ((Hero) enemy).pointsInTalent(Talent.SILENT_STEPS)) { - enemyStealth = Float.POSITIVE_INFINITY; + for (Char ch : Actor.chars()){ + if (fieldOfView[ch.pos] && ch.invisible == 0 && ch.alignment != alignment && ch.alignment != Alignment.NEUTRAL){ + float chDist = ch.stealth() + distance(ch); + //silent steps rogue talent, which also applies to rogue's shadow clone + if ((ch instanceof Hero || ch instanceof ShadowClone.ShadowAlly) + && Dungeon.hero.hasTalent(Talent.SILENT_STEPS)){ + if (distance(ch) >= 4 - Dungeon.hero.pointsInTalent(Talent.SILENT_STEPS)) { + chDist = Float.POSITIVE_INFINITY; + } + } + //flying characters are naturally stealthy + if (ch.flying && distance(ch) >= 2){ + chDist = Float.POSITIVE_INFINITY; + } + if (chDist < closestHostileDist){ + closestHostileDist = chDist; + } } } - if (Random.Float( distance( enemy ) + enemyStealth ) < 1) { + if (Random.Float( closestHostileDist ) < 1) { awaken(enemyInFOV); if (state == SLEEPING){ spend(TICK); //wait if we can't wake up for some reason