Skip to content

Reduce AI deadlocks #284

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 52 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
070867d
Check for closest known opponent in status black
Asdow Aug 16, 2023
d99b12c
Allow status black cover advance with full AP
Asdow Aug 16, 2023
e502727
Disable canceling AI actions for escorted mercs
Asdow Aug 17, 2023
bacad9b
Prevent AI deadlock when they try to shoot and player gets an interrupt
Asdow Aug 17, 2023
0e52907
Allow AI to shoot with lower aim if out of AP for current aim level
Asdow Aug 17, 2023
1c8d008
Move DebugAI() calls inside if blocks
Asdow Aug 17, 2023
664142c
Don't log AI info if pSoldier is null
Asdow Aug 17, 2023
1c4929c
Improve AI item handling log entry
Asdow Aug 17, 2023
613de1b
Remove useless code
Asdow Aug 18, 2023
0647826
Moved armed vehicle/robot in gas check into function
Asdow Aug 18, 2023
a0cbe42
Create function for decision to wear a gasmask
Asdow Aug 18, 2023
138ad06
Prevent AI deadlocks
Asdow Aug 19, 2023
c5d1615
Move decision if stuck in water or gas into its own function
Asdow Aug 19, 2023
96a7fa0
Add section comments to DecideActionBlack
Asdow Aug 19, 2023
d28ed97
Add section comments do DecideActionRed
Asdow Aug 19, 2023
1170f82
Move variable declarations to point of initialization
Asdow Aug 19, 2023
318e4a4
Improve AI logging
Asdow Aug 19, 2023
a45f3ae
Add more AI logging
Asdow Aug 20, 2023
ae709f2
Merge branch 'master' into decideaction
Asdow Oct 2, 2023
6131ebc
Comment out temp. fixes to flush out AI deadlocks
Asdow Oct 2, 2023
88af94e
Use Flugente's AI deadlock break & fix wstring for screenMsg
Asdow Oct 2, 2023
1586e8f
Allow possibly taking cover without full APs
Asdow Oct 2, 2023
d6c9cb2
Report soldier ID in DebugMsg when interrupt ends
Asdow Oct 2, 2023
a90e116
Merge branch 'master' into decideaction
Asdow Oct 10, 2023
22f2c9f
Correct AP check
Asdow Feb 1, 2024
ffb95a2
Remove unused variable from if checks
Asdow Feb 3, 2024
caf5828
Remove deadlock breaking from TurnBasedHandleNPCAI
Asdow Feb 4, 2024
7ee8165
Prevent AI deadlocking if NEW_SITUATION is encountered
Asdow Feb 4, 2024
f249406
Allow specific alert status AI logging
Asdow Feb 4, 2024
cd193c7
Call TurnBasedHandleNPCAI() if no action is in progress
Asdow Feb 4, 2024
0132726
Check if action should stay inprogress state
Asdow Feb 4, 2024
f646bc2
Set correct next action if npc has no AP
Asdow Feb 4, 2024
0ed68b6
Set functions to static
Asdow Feb 4, 2024
4faccb2
Fix indentation
Asdow Feb 4, 2024
79372d5
Try to find a cover spot when advancing to attack
Asdow Feb 4, 2024
5c86cf0
Attempt to continue moving towards enemy
Asdow Feb 10, 2024
0240729
Use correct string array
Asdow Feb 10, 2024
1aec54f
add another AI logging entry
Asdow Feb 10, 2024
3c2b048
Attempt to continue moving towards enemy
Asdow Feb 10, 2024
eaf7695
Use correct string array
Asdow Feb 10, 2024
f6052f0
add another AI logging entry
Asdow Feb 10, 2024
93acd19
Try to find a cover spot when advancing to attack
Asdow Feb 4, 2024
adf8638
Merge branch 'decideaction' of https://github.com/1dot13/source into …
Asdow Feb 10, 2024
b480a67
Reduce code duplication
Asdow Feb 10, 2024
877ec38
Whitespace changes
Asdow Feb 10, 2024
1a98420
Remove extraneous check
Asdow Feb 10, 2024
67a26e0
Add more AI logging
Asdow Feb 11, 2024
dfc17c6
Cancel action if new situation arises
Asdow Feb 11, 2024
57716e1
Revert back to original AI deadlock breaking
Asdow Feb 11, 2024
5fe730b
Merge branch 'master' into decideaction
Asdow Feb 11, 2024
ab2c5fc
Add BOXER() & ISVIP() macros
Asdow Feb 18, 2024
de91c7a
Render debug info in tactical
Asdow Feb 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions Tactical/Boxing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "Font Control.h"
#include "message.h"
#include "GameSettings.h" // added by SANDRO
#include "Soldier macros.h"

INT32 gsBoxerGridNo[ NUM_BOXERS ] = { 11393, 11233, 11073 };
UINT8 gubBoxerID[ NUM_BOXERS ] = { NOBODY, NOBODY, NOBODY };
Expand Down Expand Up @@ -55,7 +56,7 @@ void ExitBoxing( void )

if ( pSoldier != NULL )
{
if ( ( pSoldier->flags.uiStatusFlags & SOLDIER_BOXER ) && InARoom( pSoldier->sGridNo, &usRoom ) && usRoom == BOXING_RING )
if ( BOXER(pSoldier) && InARoom( pSoldier->sGridNo, &usRoom ) && usRoom == BOXING_RING )
{
if ( pSoldier->flags.uiStatusFlags & SOLDIER_PC )
{
Expand Down Expand Up @@ -239,7 +240,7 @@ void CountPeopleInBoxingRingAndDoActions( void )
{
++ubPlayersInRing;

if ( !pNonBoxingPlayer && !(pSoldier->flags.uiStatusFlags & SOLDIER_BOXER) )
if ( !pNonBoxingPlayer && !BOXER(pSoldier) )
{
pNonBoxingPlayer = pSoldier;
}
Expand Down Expand Up @@ -291,7 +292,7 @@ void CountPeopleInBoxingRingAndDoActions( void )
// ladieees and gennleman, we have a fight!
for (uiLoop = 0; uiLoop < 2; ++uiLoop)
{
if (!(pInRing[uiLoop]->flags.uiStatusFlags & SOLDIER_BOXER))
if (!BOXER(pInRing[uiLoop]))
{
// set as boxer!
pInRing[uiLoop]->flags.uiStatusFlags |= SOLDIER_BOXER;
Expand Down Expand Up @@ -515,7 +516,7 @@ void BoxingMovementCheck( SOLDIERTYPE * pSoldier )
// someone moving in/into the ring
CountPeopleInBoxingRingAndDoActions();
}
else if ( ( gTacticalStatus.bBoxingState == BOXING ) && ( pSoldier->flags.uiStatusFlags & SOLDIER_BOXER ) )
else if ( ( gTacticalStatus.bBoxingState == BOXING ) && BOXER(pSoldier) )
{
// boxer stepped out of the ring!
BoxingPlayerDisqualified( pSoldier, BOXER_OUT_OF_RING );
Expand Down Expand Up @@ -565,7 +566,7 @@ void ClearAllBoxerFlags( void )
{
for (UINT32 uiSlot = 0; uiSlot < guiNumMercSlots; ++uiSlot)
{
if ( MercSlots[ uiSlot ] && MercSlots[ uiSlot ]->flags.uiStatusFlags & SOLDIER_BOXER )
if ( MercSlots[ uiSlot ] && BOXER(MercSlots[ uiSlot ]) )
{
// Flugente: nuke the entire opponent count, remove boxing flag, reevaluate opponent list
DecayIndividualOpplist(MercSlots[uiSlot]);
Expand Down
53 changes: 51 additions & 2 deletions Tactical/Handle UI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
#include "SaveLoadScreen.h"
#include "Map Screen Interface.h" // added by Flugente for SquadNames
#include "Keys.h" // added by silversurfer for door handling from the side

#include "Cheats.h"
#include "AIInternals.h"
extern BOOLEAN gubWorldTileInLight[MAX_ALLOWED_WORLD_MAX];
extern BOOLEAN gubIsCorpseThere[MAX_ALLOWED_WORLD_MAX];
Expand Down Expand Up @@ -386,7 +386,7 @@ BOOLEAN gfDisplayTimerCursor = FALSE;
UINT32 guiTimerCursorID = 0;
UINT32 guiTimerLastUpdate = 0;
UINT32 guiTimerCursorDelay = 0;

UINT8 gRenderDebugInfoMode = DEBUG_OFF;

CHAR16 gzLocation[ 20 ];
BOOLEAN gfLocation = FALSE;
Expand Down Expand Up @@ -518,6 +518,54 @@ void GetMercOknoDirection( UINT8 ubSoldierID, BOOLEAN *pfGoDown, BOOLEAN *pfGoUp
}
//----------------------------------------------------------------------------------

void HandleRenderDebugInfoModes()
{
if (DEBUG_CHEAT_LEVEL())
{
switch (gRenderDebugInfoMode)
{
case DEBUG_PATHFINDING:
// Nothing to do here, pathfinding info is filled in the pathing functions.
break;
case DEBUG_THREATVALUE:
break;
case DEBUG_COVERVALUE:
// Calculate cover values for pSoldier under cursor, or for currently selected merc, if nobody is under the cursor.
if (gTacticalStatus.Team[OUR_TEAM].bTeamActive)
{
static SOLDIERTYPE* previousSoldier = nullptr;
static INT32 previousLocation = NOWHERE;
static UINT8 previousStance = 0;

UINT16 usSoldierIndex = NOBODY;
UINT32 uiMercFlags;
FindSoldierFromMouse(&usSoldierIndex, &uiMercFlags);
if (usSoldierIndex == NOBODY)
{
usSoldierIndex = gusSelectedSoldier;
}

if (usSoldierIndex != NOBODY)
{
// Get Soldier
INT32 iPercentBetter;
SOLDIERTYPE* pSoldier;
GetSoldier(&pSoldier, usSoldierIndex);
if (previousSoldier != pSoldier || previousLocation != pSoldier->sGridNo || previousStance != gAnimControl[pSoldier->usAnimState].ubEndHeight)
{
FindBestNearbyCover(pSoldier, pSoldier->aiData.bAIMorale, &iPercentBetter);
previousSoldier = pSoldier;
previousLocation = pSoldier->sGridNo;
previousStance = gAnimControl[pSoldier->usAnimState].ubEndHeight;
}
}
}
break;
default: // off
break;
}
}
}

void PreventFromTheFreezingBug(SOLDIERTYPE* pSoldier)
{
Expand Down Expand Up @@ -691,6 +739,7 @@ UINT32 HandleTacticalUI( void )
}
}

HandleRenderDebugInfoModes();
// Check if current event has changed and clear event if so, to prepare it for execution
// Clearing it does things like set first time flag, param variables, etc
if ( uiNewEvent != guiOldEvent )
Expand Down
4 changes: 3 additions & 1 deletion Tactical/Handle UI.h
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,8 @@ extern BOOLEAN gfUIForceReExamineCursorData;
extern INT16 guiCreateGuyIndex;
extern INT16 guiCreateBadGuyIndex;

extern UINT8 gRenderDebugInfoMode;

// WANNE: Calculate the APs to turn around
INT16 APsToTurnAround(SOLDIERTYPE *pSoldier, INT32 sAdjustedGridNo);

Expand Down Expand Up @@ -382,4 +384,4 @@ void GetGridNoScreenXY( INT32 sGridNo, INT16 *pScreenX, INT16 *pScreenY );
//Legion by Jazz
void GetMercOknoDirection( UINT8 ubSoldierID, BOOLEAN *pfGoDown, BOOLEAN *pfGoUp );

#endif
#endif
2 changes: 1 addition & 1 deletion Tactical/Interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6299,7 +6299,7 @@ BOOLEAN ShowSoldierRoleSymbol(SOLDIERTYPE* pSoldier)
if ( pSoldier->usSkillCounter[SOLDIER_COUNTER_ROLE_OBSERVED] >= gGameExternalOptions.usTurnsToUncover )
{
// are we a VIP? show that only when the player knows a VIP is in this sector. otherwise, don't even show our officer property
if ( pSoldier->usSoldierFlagMask & SOLDIER_VIP && !pSoldier->bSectorZ )
if (ISVIP(pSoldier) && !pSoldier->bSectorZ )
{
if ( PlayerKnowsAboutVIP( pSoldier->sSectorX, pSoldier->sSectorY ) )
{
Expand Down
18 changes: 9 additions & 9 deletions Tactical/Overhead.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3043,7 +3043,7 @@ BOOLEAN HandleAtNewGridNo( SOLDIERTYPE *pSoldier, BOOLEAN *pfKeepMoving )

// sevenfm: check all nearby enemy boxers for opportunity attack
if (IS_MERC_BODY_TYPE(pSoldier) &&
(pSoldier->flags.uiStatusFlags & SOLDIER_BOXER) &&
BOXER(pSoldier) &&
gTacticalStatus.bBoxingState == BOXING &&
pSoldier->aiData.bAlertStatus >= STATUS_RED)
{
Expand All @@ -3064,7 +3064,7 @@ BOOLEAN HandleAtNewGridNo( SOLDIERTYPE *pSoldier, BOOLEAN *pfKeepMoving )
pOpponent->bCollapsed ||
pOpponent->bBreathCollapsed ||
!IS_MERC_BODY_TYPE(pOpponent) ||
!(pOpponent->flags.uiStatusFlags & SOLDIER_BOXER) ||
!BOXER(pOpponent) ||
gAnimControl[pOpponent->usAnimState].ubEndHeight < ANIM_STAND ||
pOpponent->pathing.bLevel != pSoldier->pathing.bLevel ||
!SoldierToSoldierLineOfSightTest(pOpponent, pSoldier, TRUE, CALC_FROM_WANTED_DIR) ||
Expand Down Expand Up @@ -7233,7 +7233,7 @@ void RemoveCapturedEnemiesFromSectorInfo( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
//if ( pTeamSoldier->stats.bLife >= OKLIFE && pTeamSoldier->stats.bLife != 0 )
{
// officers and generals are 'special' prisoners...
if ( pTeamSoldier->usSoldierFlagMask & SOLDIER_VIP )
if (ISVIP(pTeamSoldier))
++sNumPrisoner[PRISONER_GENERAL];
// downed pilots count as officers too, even though they are civilians. This makes capturing them more rewarding
else if ( (pTeamSoldier->usSoldierFlagMask & SOLDIER_ENEMY_OFFICER) || pTeamSoldier->ubCivilianGroup == DOWNEDPILOT_CIV_GROUP )
Expand Down Expand Up @@ -7262,7 +7262,7 @@ void RemoveCapturedEnemiesFromSectorInfo( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
}

// Flugente: VIPs
if ( pTeamSoldier->usSoldierFlagMask & SOLDIER_VIP )
if (ISVIP(pTeamSoldier))
DeleteVIP( pTeamSoldier->sSectorX, pTeamSoldier->sSectorY );

// Flugente: turncoats
Expand Down Expand Up @@ -9320,10 +9320,10 @@ BOOLEAN ProcessImplicationsOfPCAttack( SOLDIERTYPE * pSoldier, SOLDIERTYPE ** pp
if ( gTacticalStatus.bBoxingState == BOXING )
{
// should have a check for "in boxing ring", no?
if ( ( pSoldier->usAttackingWeapon != NOTHING && !Item[pSoldier->usAttackingWeapon].brassknuckles ) || !( pSoldier->flags.uiStatusFlags & SOLDIER_BOXER ) || pSoldier->IsRiotShieldEquipped() )
if ( ( pSoldier->usAttackingWeapon != NOTHING && !Item[pSoldier->usAttackingWeapon].brassknuckles ) || !BOXER(pSoldier) || pSoldier->IsRiotShieldEquipped() )
{
// someone's cheating!
if ( (Item[ pSoldier->usAttackingWeapon ].usItemClass == IC_BLADE || Item[ pSoldier->usAttackingWeapon ].usItemClass == IC_PUNCH) && (pTarget->flags.uiStatusFlags & SOLDIER_BOXER) )
if ( (Item[ pSoldier->usAttackingWeapon ].usItemClass == IC_BLADE || Item[ pSoldier->usAttackingWeapon ].usItemClass == IC_PUNCH) && BOXER(pTarget) )
{
// knife or brass knuckles disqualify the player!
BoxingPlayerDisqualified( pSoldier, BAD_ATTACK );
Expand All @@ -9334,7 +9334,7 @@ BOOLEAN ProcessImplicationsOfPCAttack( SOLDIERTYPE * pSoldier, SOLDIERTYPE ** pp
//gTacticalStatus.bBoxingState = NOT_BOXING;
SetBoxingState( NOT_BOXING );
// if we are attacking a boxer we should set them to neutral (temporarily) so that the rest of the civgroup code works...
if ( (pTarget->bTeam == CIV_TEAM) && (pTarget->flags.uiStatusFlags & SOLDIER_BOXER) )
if ( (pTarget->bTeam == CIV_TEAM) && BOXER(pTarget) )
{
SetSoldierNeutral( pTarget );
}
Expand Down Expand Up @@ -9481,7 +9481,7 @@ BOOLEAN ProcessImplicationsOfPCAttack( SOLDIERTYPE * pSoldier, SOLDIERTYPE ** pp
//TriggerNPCWithIHateYouQuote( pTarget->ubProfile );
}
}
else if ( pTarget->ubCivilianGroup != NON_CIV_GROUP && !( pTarget->flags.uiStatusFlags & SOLDIER_BOXER ) )
else if ( pTarget->ubCivilianGroup != NON_CIV_GROUP && !BOXER(pTarget) )
{
// Firing at a civ in a civ group who isn't hostile... if anyone in that civ group can see this
// going on they should become hostile.
Expand Down Expand Up @@ -10927,7 +10927,7 @@ void TurnCoatAttemptMessageBoxCallBack( UINT8 ubExitValue )
UINT8 approachchance = MercPtrs[gusSelectedSoldier]->GetTurncoatConvinctionChance( prisonerdialoguetargetID, approachselected );

// you can never turn a VIP (though we don't tell the player if someone is a VIP, lest they have an exploit to find out)
if ( pSoldier->usSoldierFlagMask & SOLDIER_VIP )
if (ISVIP(pSoldier))
approachchance = 0;

// as using random numbers to pass the check would result in players savescumming, use a number based on the soldier's stats
Expand Down
Loading