-
Notifications
You must be signed in to change notification settings - Fork 141
Description
Reported by Bentwing on Discord
Allies will often die to invulnerable monsters (Revnants, Warden) in otherwise avoidable ways. Two specific cases include stepping too near an invulnerable monster, and blinking next to an invulnerable monster.
ANALYSIS
CASE 1: Ally too close to invulnerable monster
Allies will flee from monsters in some cases, as defined by allyFlees():
BrogueCE/src/brogue/Monsters.c
Line 2988 in 1ba4240
| static boolean allyFlees(creature *ally, creature *closestEnemy) { |
In particular, an ally will flee from any monster if monsterFleesFrom() returns true:
BrogueCE/src/brogue/Monsters.c
Line 3011 in 1ba4240
| if (monsterFleesFrom(ally, closestEnemy)) { |
Invulnerable monsters are one of the cases in which monsters will flee, but only if they are within 3 spaces of the enemy:
BrogueCE/src/brogue/Monsters.c
Lines 2955 to 2964 in 1ba4240
| if (distanceBetween((pos){x, y}, defender->loc) >= 4) { | |
| return false; | |
| } | |
| if ((defender->info.flags & (MONST_IMMUNE_TO_WEAPONS | MONST_INVULNERABLE)) | |
| && !(defender->info.flags & MONST_IMMOBILE)) { | |
| // Don't charge if the monster is damage-immune and is NOT immobile; | |
| // i.e., keep distance from revenants and stone guardians but not mirror totems. | |
| return true; | |
| } |
This is not enough distance to avoid being hit by the invulnerable monster when maneuvering in close quarters.
CASE 2: Ally blinks next to invulnerable monster
If there is an enemy nearby, an ally will move toward it. This occurs in moveAlly(), and correctly checks that the enemy is not invulnerable:
BrogueCE/src/brogue/Monsters.c
Lines 3153 to 3156 in 1ba4240
| if (closestMonster | |
| && (distanceBetween((pos){x, y}, player.loc) < leashLength || (monst->bookkeepingFlags & MB_DOES_NOT_TRACK_LEADER)) | |
| && !(monst->info.flags & MONST_MAINTAINS_DISTANCE) | |
| && !attackWouldBeFutile(monst, closestMonster)) { |
But if the ally has the ability to blink, a new map of potential destinations is built, ignoring the invulnerable status of all monsters (including the closest one), and that map is used to decide where to blink.
BrogueCE/src/brogue/Monsters.c
Lines 3182 to 3188 in 1ba4240
| if (target != monst | |
| && (!(target->bookkeepingFlags & MB_SUBMERGED) || (monst->bookkeepingFlags & MB_SUBMERGED)) | |
| && monsterWillAttackTarget(monst, target) | |
| && distanceBetween((pos){x, y}, target->loc) < shortestDistance | |
| && traversiblePathBetween(monst, target->loc.x, target->loc.y) | |
| && (!monsterAvoids(monst, target->loc) || (target->info.flags & MONST_ATTACKABLE_THRU_WALLS)) | |
| && (!target->status[STATUS_INVISIBLE] || ((monst->info.flags & MONST_ALWAYS_USE_ABILITY) || rand_percent(33)))) { |
This means that blink-enabled allies will not take invulnerability into consideration when choosing a blink target.
RECOMMENDED FIX:
CASE 1 - swap the order of the distance check and invulnerable check. Add an arbitrary distance, greater than 4, to the invulnerable check. I recommend at least 6 spaces.
CASE 2 - Insert a check for attackWouldBeFutile() when building the blink map.