From a803c142d8dc668dc4eed4b6eaa4e848415d4eb3 Mon Sep 17 00:00:00 2001 From: Bryan Turner Date: Thu, 9 Mar 2023 23:22:11 -0500 Subject: [PATCH 1/5] Fix for whip/pike attack invisible but revealed enemies --- src/brogue/Items.c | 5 +++-- src/brogue/Movement.c | 11 +++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/brogue/Items.c b/src/brogue/Items.c index 07fc63a1..3567daa8 100644 --- a/src/brogue/Items.c +++ b/src/brogue/Items.c @@ -639,7 +639,7 @@ void populateItems(pos upstairs) { } else if (rogue.depthLevel > gameConst->amuletLevel) { theCategory = GEM; } else { - + for (int j = 0; j < gameConst->numberMeteredItems; j++) { // Create any metered items that reach generation thresholds if (meteredItemsGenerationTable[j].levelScaling != 0 && @@ -3497,7 +3497,8 @@ void getImpactLoc(pos *returnLoc, const pos originLoc, const pos targetLoc, for (i=0; ibookkeepingFlags & MB_SUBMERGED)) { // Imaginary bolt hit the player or a monster. break; diff --git a/src/brogue/Movement.c b/src/brogue/Movement.c index f0033568..7bb10cac 100644 --- a/src/brogue/Movement.c +++ b/src/brogue/Movement.c @@ -587,8 +587,9 @@ boolean handleWhipAttacks(creature *attacker, enum directions dir, boolean *abor defender = monsterAtLoc(strikeLoc); if (defender - && (attacker != &player || canSeeMonster(defender)) - && !monsterIsHidden(defender, attacker) + && (attacker != &player + || canSeeMonster(defender) + || monsterRevealed(defender)) && monsterWillAttackTarget(attacker, defender)) { if (attacker == &player) { @@ -654,8 +655,10 @@ boolean handleSpearAttacks(creature *attacker, enum directions dir, boolean *abo /* We check if i=0, i.e. the defender is right next to us, because we have to do "normal" attacking here. We can't just return false and leave to playerMoves/moveMonster due to the collateral hitlist. */ - if (i == 0 || !monsterIsHidden(defender, attacker) - && (attacker != &player || canSeeMonster(defender))) { + if (i == 0 + || attacker != &player + || canSeeMonster(defender) + || monsterRevealed(defender)) { // We'll attack. proceed = true; } From b52efd6667c964f5652151992e82f96f09c7d853 Mon Sep 17 00:00:00 2001 From: Bryan Turner Date: Thu, 9 Mar 2023 23:44:30 -0500 Subject: [PATCH 2/5] ChangeLog --- changes/issue-516.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 changes/issue-516.md diff --git a/changes/issue-516.md b/changes/issue-516.md new file mode 100644 index 00000000..ba8915fd --- /dev/null +++ b/changes/issue-516.md @@ -0,0 +1,2 @@ +- + The whip, spear, and rapier now work against invisible enemies when you are telepathic. From 6b5e9e4f187fff579940f4d31c1449fed48e9219 Mon Sep 17 00:00:00 2001 From: Bryan Turner Date: Sat, 11 Mar 2023 22:46:18 -0500 Subject: [PATCH 3/5] Centralizing hit check logic --- src/brogue/Items.c | 6 ++---- src/brogue/Monsters.c | 24 ++++++++++++++++++++++++ src/brogue/Movement.c | 17 ++++------------- src/brogue/Rogue.h | 1 + 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/brogue/Items.c b/src/brogue/Items.c index 3567daa8..e8f28db1 100644 --- a/src/brogue/Items.c +++ b/src/brogue/Items.c @@ -3491,15 +3491,13 @@ void getImpactLoc(pos *returnLoc, const pos originLoc, const pos targetLoc, pos coords[DCOLS + 1]; short i, n; creature *monst; + creature *orig = monsterAtLoc(originLoc); n = getLineCoordinates(coords, originLoc, targetLoc, theBolt); n = min(n, maxDistance); for (i=0; ibookkeepingFlags & MB_SUBMERGED)) { + if (canAttack(orig, monst)) { // Imaginary bolt hit the player or a monster. break; } diff --git a/src/brogue/Monsters.c b/src/brogue/Monsters.c index ed9d35e6..ec9aa3be 100644 --- a/src/brogue/Monsters.c +++ b/src/brogue/Monsters.c @@ -231,6 +231,30 @@ boolean canDirectlySeeMonster(creature *monst) { return false; } +// Centralize the logic of whether an attacker can/will attack the defender +boolean canAttack( creature *attacker, creature *defender ) { + if (attacker == NULL || defender == NULL) return false; + + // Must be enemies + boolean areEnemies = monsterWillAttackTarget(attacker, defender); + + // Must be able to attack the cell where the defender is located + boolean canAttackCell = !cellHasTerrainFlag(defender->loc.x, defender->loc.y, T_OBSTRUCTS_PASSABILITY) + || (defender->info.flags & MONST_ATTACKABLE_THRU_WALLS); + + // Must be able to detect the defender + boolean locationKnown = !monsterIsHidden(defender, attacker); + + // If the player is the attacker, also check vision and telepathy + if (attacker == &player) { + locationKnown = (locationKnown && playerCanSee(defender->loc.x, defender->loc.y)) + || monsterRevealed(defender); + } + + // All three requirements must be met + return (areEnemies && canAttackCell && locationKnown); +} + void monsterName(char *buf, creature *monst, boolean includeArticle) { short oldRNG; diff --git a/src/brogue/Movement.c b/src/brogue/Movement.c index 7bb10cac..3aa89049 100644 --- a/src/brogue/Movement.c +++ b/src/brogue/Movement.c @@ -586,12 +586,7 @@ boolean handleWhipAttacks(creature *attacker, enum directions dir, boolean *abor getImpactLoc(&strikeLoc, originLoc, targetLoc, 5, false, &boltCatalog[BOLT_WHIP]); defender = monsterAtLoc(strikeLoc); - if (defender - && (attacker != &player - || canSeeMonster(defender) - || monsterRevealed(defender)) - && monsterWillAttackTarget(attacker, defender)) { - + if (canAttack(attacker, defender)) { if (attacker == &player) { hitList[0] = defender; if (abortAttackAgainstAcidicTarget(hitList)) { @@ -655,10 +650,7 @@ boolean handleSpearAttacks(creature *attacker, enum directions dir, boolean *abo /* We check if i=0, i.e. the defender is right next to us, because we have to do "normal" attacking here. We can't just return false and leave to playerMoves/moveMonster due to the collateral hitlist. */ - if (i == 0 - || attacker != &player - || canSeeMonster(defender) - || monsterRevealed(defender)) { + if (i == 0 || canAttack(attacker, defender)) { // We'll attack. proceed = true; } @@ -725,11 +717,10 @@ void buildFlailHitList(const short x, const short y, const short newX, const sho my = monst->loc.y; if (distanceBetween((pos){x, y}, (pos){mx, my}) == 1 && distanceBetween((pos){newX, newY}, (pos){mx, my}) == 1 - && canSeeMonster(monst) - && monstersAreEnemies(&player, monst) + && canAttack(&player, monst) && monst->creatureState != MONSTER_ALLY && !(monst->bookkeepingFlags & MB_IS_DYING) - && (!cellHasTerrainFlag(monst->loc.x, monst->loc.y, T_OBSTRUCTS_PASSABILITY) || (monst->info.flags & MONST_ATTACKABLE_THRU_WALLS))) { + && canAttack(&player, monst)) { while (hitList[i]) { i++; diff --git a/src/brogue/Rogue.h b/src/brogue/Rogue.h index de02c8fe..24f4cb9b 100644 --- a/src/brogue/Rogue.h +++ b/src/brogue/Rogue.h @@ -3170,6 +3170,7 @@ extern "C" { boolean monsterIsHidden(const creature *monst, const creature *observer); boolean canSeeMonster(creature *monst); boolean canDirectlySeeMonster(creature *monst); + boolean canAttack( creature *attacker, creature *defender ); void monsterName(char *buf, creature *monst, boolean includeArticle); boolean monsterIsInClass(const creature *monst, const short monsterClass); boolean chooseTarget(pos *returnLoc, short maxDistance, boolean stopAtTarget, boolean autoTarget, From b17dfe1eac8ce684c76b8901ea06026aa5242e00 Mon Sep 17 00:00:00 2001 From: Bryan Turner Date: Sat, 29 Apr 2023 17:44:57 -0400 Subject: [PATCH 4/5] Whip cannot strike submerged enemies --- src/brogue/Items.c | 3 ++- src/brogue/Movement.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/brogue/Items.c b/src/brogue/Items.c index e8f28db1..e657ebc9 100644 --- a/src/brogue/Items.c +++ b/src/brogue/Items.c @@ -3497,7 +3497,8 @@ void getImpactLoc(pos *returnLoc, const pos originLoc, const pos targetLoc, n = min(n, maxDistance); for (i=0; ibookkeepingFlags & MB_SUBMERGED)) { // Imaginary bolt hit the player or a monster. break; } diff --git a/src/brogue/Movement.c b/src/brogue/Movement.c index 3aa89049..e3e54db1 100644 --- a/src/brogue/Movement.c +++ b/src/brogue/Movement.c @@ -586,7 +586,8 @@ boolean handleWhipAttacks(creature *attacker, enum directions dir, boolean *abor getImpactLoc(&strikeLoc, originLoc, targetLoc, 5, false, &boltCatalog[BOLT_WHIP]); defender = monsterAtLoc(strikeLoc); - if (canAttack(attacker, defender)) { + if (canAttack(attacker, defender) + && !(defender->bookkeepingFlags & MB_SUBMERGED)) { if (attacker == &player) { hitList[0] = defender; if (abortAttackAgainstAcidicTarget(hitList)) { From 100f0bc086cdf50dc5a42f5275eb48156eb99a9b Mon Sep 17 00:00:00 2001 From: Tom M Date: Tue, 26 Sep 2023 16:59:34 +0100 Subject: [PATCH 5/5] Refactor canAttack's locationKnown The player case was equivalent to `canSee || revealed` because the inner `|| revealed` in `canSee` is made redundant by the outer one. --- src/brogue/Monsters.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/brogue/Monsters.c b/src/brogue/Monsters.c index ec9aa3be..fe6f6027 100644 --- a/src/brogue/Monsters.c +++ b/src/brogue/Monsters.c @@ -243,12 +243,12 @@ boolean canAttack( creature *attacker, creature *defender ) { || (defender->info.flags & MONST_ATTACKABLE_THRU_WALLS); // Must be able to detect the defender - boolean locationKnown = !monsterIsHidden(defender, attacker); - - // If the player is the attacker, also check vision and telepathy + boolean locationKnown; if (attacker == &player) { - locationKnown = (locationKnown && playerCanSee(defender->loc.x, defender->loc.y)) - || monsterRevealed(defender); + locationKnown = canSeeMonster(defender) || monsterRevealed(defender); + } else { + // Monsters don't understand revealing. + locationKnown = !monsterIsHidden(defender, attacker); } // All three requirements must be met