@@ -526,16 +526,15 @@ boolean freeCaptivesEmbeddedAt(short x, short y) {
526
526
return false;
527
527
}
528
528
529
- // Do we need confirmation so we don't accidently hit an acid mound?
529
+ /// @brief Ask the player for confirmation before attacking an acidic monster
530
+ /// @param hitList the creature(s) getting attacked
531
+ /// @return true to abort the attack
530
532
boolean abortAttackAgainstAcidicTarget (creature * hitList [8 ]) {
531
533
short i ;
532
534
char monstName [COLS ], weaponName [COLS ];
533
535
char buf [COLS * 3 ];
534
536
535
- if (rogue .weapon
536
- && !(rogue .weapon -> flags & ITEM_PROTECTED )
537
- && !player .status [STATUS_HALLUCINATING ]
538
- && !player .status [STATUS_CONFUSED ]) {
537
+ if (rogue .weapon && !(rogue .weapon -> flags & ITEM_PROTECTED )) {
539
538
540
539
for (i = 0 ; i < 8 ; i ++ ) {
541
540
if (hitList [i ]
@@ -560,9 +559,54 @@ boolean abortAttackAgainstAcidicTarget(creature *hitList[8]) {
560
559
return false;
561
560
}
562
561
562
+ /// @brief Ask the player for confirmation before attacking a discordant ally
563
+ /// @param hitList the creature(s) getting attacked
564
+ /// @return true to abort the attack
565
+ static boolean abortAttackAgainstDiscordantAlly (const creature * hitList [8 ]) {
566
+
567
+ for (int i = 0 ; i < 8 ; i ++ ) {
568
+ if (hitList [i ]
569
+ && hitList [i ]-> creatureState == MONSTER_ALLY
570
+ && hitList [i ]-> status [STATUS_DISCORDANT ]
571
+ && canSeeMonster (hitList [i ])) {
572
+
573
+ char monstName [COLS ], buf [COLS * 3 ];
574
+ monsterName (monstName , hitList [i ], true);
575
+ sprintf (buf , "Are you sure you want to attack %s?" , monstName );
576
+ if (confirm (buf , false)) {
577
+ return false; // Don't abort. Attack the ally.
578
+ } else {
579
+ return true; // Abort!
580
+ }
581
+ }
582
+ }
583
+ return false; // the confirmation dialog was not shown
584
+ }
585
+
586
+ /// @brief Determines if a player attack against the given creature(s) should be aborted. A confirmation
587
+ /// dialog is shown when attempting to attack an acidic monster or discordant ally, unless confused or
588
+ /// hallucinating (but not telepathic).
589
+ /// @param hitList the creature(s) getting attacked
590
+ /// @return true to abort the attack
591
+ static boolean abortAttack (const creature * hitList [8 ]) {
592
+
593
+ // too bad so sad if you're confused or hallucinating (but not telepathic)
594
+ if (player .status [STATUS_CONFUSED ]
595
+ || (player .status [STATUS_HALLUCINATING ] && !player .status [STATUS_TELEPATHIC ])) {
596
+ return false;
597
+ }
598
+
599
+ if (abortAttackAgainstAcidicTarget (hitList )
600
+ || abortAttackAgainstDiscordantAlly (hitList )) {
601
+ return true;
602
+ }
603
+
604
+ return false; // either the player confirmed the attack or the confirmation dialog was not shown
605
+ }
606
+
563
607
// Returns true if a whip attack was launched.
564
608
// If "aborted" pointer is provided, sets it to true if it was aborted because
565
- // the player opted not to attack an acid mound (in which case the whole turn
609
+ // the player opted not to attack (in which case the whole turn
566
610
// should be aborted), as opposed to there being no valid whip attack available
567
611
// (in which case the player/monster should move instead).
568
612
boolean handleWhipAttacks (creature * attacker , enum directions dir , boolean * aborted ) {
@@ -600,7 +644,7 @@ boolean handleWhipAttacks(creature *attacker, enum directions dir, boolean *abor
600
644
601
645
if (attacker == & player ) {
602
646
hitList [0 ] = defender ;
603
- if (abortAttackAgainstAcidicTarget (hitList )) {
647
+ if (abortAttack (hitList )) {
604
648
if (aborted ) {
605
649
* aborted = true;
606
650
}
@@ -618,7 +662,7 @@ boolean handleWhipAttacks(creature *attacker, enum directions dir, boolean *abor
618
662
619
663
// Returns true if a spear attack was launched.
620
664
// If "aborted" pointer is provided, sets it to true if it was aborted because
621
- // the player opted not to attack an acid mound (in which case the whole turn
665
+ // the player opted not to attack (in which case the whole turn
622
666
// should be aborted), as opposed to there being no valid spear attack available
623
667
// (in which case the player/monster should move instead).
624
668
boolean handleSpearAttacks (creature * attacker , enum directions dir , boolean * aborted ) {
@@ -682,7 +726,7 @@ boolean handleSpearAttacks(creature *attacker, enum directions dir, boolean *abo
682
726
range = i ;
683
727
if (proceed ) {
684
728
if (attacker == & player ) {
685
- if (abortAttackAgainstAcidicTarget (hitList )) {
729
+ if (abortAttack (hitList )) {
686
730
if (aborted ) {
687
731
* aborted = true;
688
732
}
@@ -869,7 +913,7 @@ boolean playerMoves(short direction) {
869
913
moveEntrancedMonsters (direction );
870
914
playerTurnEnded ();
871
915
return true;
872
- } else if (specialAttackAborted ) { // Canceled an attack against an acid mound.
916
+ } else if (specialAttackAborted ) { // Canceled an attack against an acidic monster or discordant ally
873
917
brogueAssert (!committed );
874
918
cancelKeystroke ();
875
919
rogue .disturbed = true;
@@ -897,15 +941,15 @@ boolean playerMoves(short direction) {
897
941
}
898
942
}
899
943
900
- if (defender -> creatureState != MONSTER_ALLY ) {
944
+ if (defender -> creatureState != MONSTER_ALLY || defender -> status [ STATUS_DISCORDANT ] ) {
901
945
// Make a hit list of monsters the player is attacking this turn.
902
946
// We separate this tallying phase from the actual attacking phase because sometimes the attacks themselves
903
947
// create more monsters, and those shouldn't be attacked in the same turn.
904
948
905
949
buildHitList (hitList , & player , defender ,
906
950
rogue .weapon && (rogue .weapon -> flags & ITEM_ATTACKS_ALL_ADJACENT ));
907
951
908
- if (abortAttackAgainstAcidicTarget (hitList )) { // Acid mound attack confirmation.
952
+ if (abortAttack (hitList )) {
909
953
brogueAssert (!committed );
910
954
cancelKeystroke ();
911
955
rogue .disturbed = true;
@@ -1049,7 +1093,7 @@ boolean playerMoves(short direction) {
1049
1093
&& (!cellHasTerrainFlag (tempMonst -> loc .x , tempMonst -> loc .y , T_OBSTRUCTS_PASSABILITY ) || (tempMonst -> info .flags & MONST_ATTACKABLE_THRU_WALLS ))) {
1050
1094
1051
1095
hitList [0 ] = tempMonst ;
1052
- if (abortAttackAgainstAcidicTarget (hitList )) { // Acid mound attack confirmation.
1096
+ if (abortAttack (hitList )) {
1053
1097
brogueAssert (!committed );
1054
1098
cancelKeystroke ();
1055
1099
rogue .disturbed = true;
@@ -1060,7 +1104,7 @@ boolean playerMoves(short direction) {
1060
1104
}
1061
1105
if (rogue .weapon && (rogue .weapon -> flags & ITEM_PASS_ATTACKS )) {
1062
1106
buildFlailHitList (x , y , newX , newY , hitList );
1063
- if (abortAttackAgainstAcidicTarget (hitList )) { // Acid mound attack confirmation.
1107
+ if (abortAttack (hitList )) {
1064
1108
brogueAssert (!committed );
1065
1109
cancelKeystroke ();
1066
1110
rogue .disturbed = true;
0 commit comments