Black AI:

- fixed bug when AI soldier was ordered to move to his current spot when trying to get closer
- check if soldier can find cover before disabling the attack

Added more AI log info.

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8933 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Sevenfm
2021-02-12 07:15:03 +00:00
parent 39776dc569
commit f0693d4aad
+98 -43
View File
@@ -703,6 +703,9 @@ INT8 DecideActionGreen(SOLDIERTYPE *pSoldier)
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("DecideActionGreen, orders = %d",pSoldier->aiData.bOrders)); DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("DecideActionGreen, orders = %d",pSoldier->aiData.bOrders));
DebugAI(AI_MSG_START, pSoldier, String("[Green]"));
LogDecideInfo(pSoldier);
// sevenfm: disable stealth mode // sevenfm: disable stealth mode
pSoldier->bStealthMode = FALSE; pSoldier->bStealthMode = FALSE;
// disable reverse movement mode // disable reverse movement mode
@@ -1553,6 +1556,9 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier)
STR16 tempstr; STR16 tempstr;
#endif #endif
DebugAI(AI_MSG_START, pSoldier, String("[Yellow]"));
LogDecideInfo(pSoldier);
// sevenfm: disable stealth mode // sevenfm: disable stealth mode
pSoldier->bStealthMode = FALSE; pSoldier->bStealthMode = FALSE;
// disable reverse movement mode // disable reverse movement mode
@@ -2478,6 +2484,9 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier)
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("DecideActionRed: soldier orders = %d",pSoldier->aiData.bOrders)); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("DecideActionRed: soldier orders = %d",pSoldier->aiData.bOrders));
DebugAI(AI_MSG_START, pSoldier, String("[Red]"));
LogDecideInfo(pSoldier);
// sevenfm: disable stealth mode // sevenfm: disable stealth mode
pSoldier->bStealthMode = FALSE; pSoldier->bStealthMode = FALSE;
// disable reverse movement mode // disable reverse movement mode
@@ -3597,7 +3606,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier)
} }
} }
DebugAI(AI_MSG_TOPIC, pSoldier, String("[self smoke when under fire]")); DebugAI(AI_MSG_TOPIC, pSoldier, String("[Self smoke when under fire]"));
if (gfTurnBasedAI && if (gfTurnBasedAI &&
pSoldier->bActionPoints == pSoldier->bInitialActionPoints && pSoldier->bActionPoints == pSoldier->bInitialActionPoints &&
pSoldier->aiData.bUnderFire && pSoldier->aiData.bUnderFire &&
@@ -4888,6 +4897,9 @@ INT16 ubMinAPCost;
#endif #endif
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("DecideActionBlack: soldier = %d, orders = %d, attitude = %d",pSoldier->ubID,pSoldier->aiData.bOrders,pSoldier->aiData.bAttitude)); DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("DecideActionBlack: soldier = %d, orders = %d, attitude = %d",pSoldier->ubID,pSoldier->aiData.bOrders,pSoldier->aiData.bAttitude));
DebugAI(AI_MSG_START, pSoldier, String("[Black]"));
LogDecideInfo(pSoldier);
ATTACKTYPE BestShot, BestThrow, BestStab ,BestAttack;//dnl ch69 150913 ATTACKTYPE BestShot, BestThrow, BestStab ,BestAttack;//dnl ch69 150913
BOOLEAN fCivilian = (PTR_CIVILIAN && (pSoldier->ubCivilianGroup == NON_CIV_GROUP || pSoldier->aiData.bNeutral || (pSoldier->ubBodyType >= FATCIV && pSoldier->ubBodyType <= CRIPPLECIV) ) ); BOOLEAN fCivilian = (PTR_CIVILIAN && (pSoldier->ubCivilianGroup == NON_CIV_GROUP || pSoldier->aiData.bNeutral || (pSoldier->ubBodyType >= FATCIV && pSoldier->ubBodyType <= CRIPPLECIV) ) );
BOOLEAN fClimb; BOOLEAN fClimb;
@@ -5277,7 +5289,7 @@ INT16 ubMinAPCost;
} }
} }
DebugAI(AI_MSG_TOPIC, pSoldier, String("[self smoke when under fire]")); DebugAI(AI_MSG_TOPIC, pSoldier, String("[Self smoke when under fire]"));
if (SoldierAI(pSoldier) && if (SoldierAI(pSoldier) &&
gfTurnBasedAI && gfTurnBasedAI &&
pSoldier->bActionPoints == pSoldier->bInitialActionPoints && pSoldier->bActionPoints == pSoldier->bInitialActionPoints &&
@@ -5744,7 +5756,7 @@ INT16 ubMinAPCost;
{ {
BestAttack.iAttackValue = BestShot.iAttackValue; BestAttack.iAttackValue = BestShot.iAttackValue;
ubBestAttackAction = AI_ACTION_FIRE_GUN; ubBestAttackAction = AI_ACTION_FIRE_GUN;
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"best action = fire gun"); DebugAI(AI_MSG_INFO, pSoldier, String("best action = fire gun, iAttackValue = %d", BestAttack.iAttackValue));
} }
// cautious boxer approach, reserve AP for two attacks (only if not attacking from the back) // cautious boxer approach, reserve AP for two attacks (only if not attacking from the back)
@@ -5819,12 +5831,12 @@ INT16 ubMinAPCost;
if ( Item[ pSoldier->inv[BestStab.bWeaponIn].usItem ].usItemClass & IC_THROWING_KNIFE ) if ( Item[ pSoldier->inv[BestStab.bWeaponIn].usItem ].usItemClass & IC_THROWING_KNIFE )
{ {
ubBestAttackAction = AI_ACTION_THROW_KNIFE; ubBestAttackAction = AI_ACTION_THROW_KNIFE;
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"best action = throw knife"); DebugAI(AI_MSG_INFO, pSoldier, String("best action = throw knife, iAttackValue = %d", BestAttack.iAttackValue));
} }
else if ( Item[ pSoldier->inv[BestStab.bWeaponIn].usItem ].usItemClass & IC_BLADE ) // SANDRO - check specifically for blade attack else if ( Item[ pSoldier->inv[BestStab.bWeaponIn].usItem ].usItemClass & IC_BLADE ) // SANDRO - check specifically for blade attack
{ {
ubBestAttackAction = AI_ACTION_KNIFE_MOVE; ubBestAttackAction = AI_ACTION_KNIFE_MOVE;
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"best action = move to stab"); DebugAI(AI_MSG_INFO, pSoldier, String("best action = move to stab, iAttackValue = %d", BestAttack.iAttackValue));
} }
//////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////
// SANDRO - added a chance to try to steal merc's gun from hands // SANDRO - added a chance to try to steal merc's gun from hands
@@ -5833,12 +5845,12 @@ INT16 ubMinAPCost;
if (AIDetermineStealingWeaponAttempt( pSoldier, MercPtrs[BestStab.ubOpponent] ) == TRUE) if (AIDetermineStealingWeaponAttempt( pSoldier, MercPtrs[BestStab.ubOpponent] ) == TRUE)
{ {
ubBestAttackAction = AI_ACTION_STEAL_MOVE; ubBestAttackAction = AI_ACTION_STEAL_MOVE;
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"best action = move to steal weapon"); DebugAI(AI_MSG_INFO, pSoldier, String("best action = move to steal weapon, iAttackValue = %d", BestStab.iAttackValue));
} }
else else
{ {
ubBestAttackAction = AI_ACTION_KNIFE_MOVE; ubBestAttackAction = AI_ACTION_KNIFE_MOVE;
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"best action = move to punch"); DebugAI(AI_MSG_INFO, pSoldier, String("best action = knife move, iAttackValue = %d", BestStab.iAttackValue));
} }
} }
//////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////
@@ -5846,7 +5858,7 @@ INT16 ubMinAPCost;
if ( BestThrow.ubPossible && ((BestThrow.iAttackValue > BestAttack.iAttackValue) || (ubBestAttackAction == AI_ACTION_NONE)) && !(ARMED_VEHICLE( pSoldier ) && ubBestAttackAction == AI_ACTION_FIRE_GUN && BestShot.ubChanceToReallyHit > 20 && Random( 2 )) )//dnl ch64 290813 tank always had better chance to fire from cannon so this will increase probabilty to use machinegun too if ( BestThrow.ubPossible && ((BestThrow.iAttackValue > BestAttack.iAttackValue) || (ubBestAttackAction == AI_ACTION_NONE)) && !(ARMED_VEHICLE( pSoldier ) && ubBestAttackAction == AI_ACTION_FIRE_GUN && BestShot.ubChanceToReallyHit > 20 && Random( 2 )) )//dnl ch64 290813 tank always had better chance to fire from cannon so this will increase probabilty to use machinegun too
{ {
ubBestAttackAction = AI_ACTION_TOSS_PROJECTILE; ubBestAttackAction = AI_ACTION_TOSS_PROJECTILE;
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"best action = throw something"); DebugAI(AI_MSG_INFO, pSoldier, String("best action = throw something, iAttackValue = %d", BestThrow.iAttackValue));
} }
if ( ( ubBestAttackAction == AI_ACTION_NONE ) && fTryPunching ) if ( ( ubBestAttackAction == AI_ACTION_NONE ) && fTryPunching )
@@ -5860,7 +5872,7 @@ INT16 ubMinAPCost;
// if it's in his holster, swap it into his hand temporarily // if it's in his holster, swap it into his hand temporarily
if (bWeaponIn != HANDPOS) if (bWeaponIn != HANDPOS)
{ {
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionblack: swap knife into hand"); DebugAI(AI_MSG_INFO, pSoldier, String("swap knife into hand"));
RearrangePocket(pSoldier,HANDPOS,bWeaponIn,TEMPORARILY); RearrangePocket(pSoldier,HANDPOS,bWeaponIn,TEMPORARILY);
} }
@@ -5878,46 +5890,46 @@ INT16 ubMinAPCost;
// now we KNOW FOR SURE that we will do something (stab, at least) // now we KNOW FOR SURE that we will do something (stab, at least)
NPCDoesAct(pSoldier); NPCDoesAct(pSoldier);
ubBestAttackAction = AI_ACTION_KNIFE_MOVE; ubBestAttackAction = AI_ACTION_KNIFE_MOVE;
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"NPC decided to move to stab"); DebugAI(AI_MSG_INFO, pSoldier, String("best action = move to stab, iAttackValue = %d", BestStab.iAttackValue));
} }
} }
// if it was in his holster, swap it back into his holster for now // if it was in his holster, swap it back into his holster for now
if (bWeaponIn != HANDPOS) if (bWeaponIn != HANDPOS)
{ {
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionblack: about to put knife away"); DebugAI(AI_MSG_INFO, pSoldier, String("put knife away"));
RearrangePocket(pSoldier,HANDPOS,bWeaponIn,TEMPORARILY); RearrangePocket(pSoldier,HANDPOS,bWeaponIn,TEMPORARILY);
} }
} }
} }
// copy the information on the best action selected into BestAttack struct // copy the information on the best action selected into BestAttack struct
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"copy the information on the best action selected into BestAttack struct"); DebugAI(AI_MSG_INFO, pSoldier, String("copy the information on the best action selected into BestAttack struct"));
switch (ubBestAttackAction) switch (ubBestAttackAction)
{ {
case AI_ACTION_FIRE_GUN: case AI_ACTION_FIRE_GUN:
memcpy(&BestAttack,&BestShot,sizeof(BestAttack)); memcpy(&BestAttack,&BestShot,sizeof(BestAttack));
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideActionBlack: best attack = firing a gun"); DebugAI(AI_MSG_INFO, pSoldier, String("Best attack - shooting"));
break; break;
case AI_ACTION_TOSS_PROJECTILE: case AI_ACTION_TOSS_PROJECTILE:
memcpy(&BestAttack,&BestThrow,sizeof(BestAttack)); memcpy(&BestAttack,&BestThrow,sizeof(BestAttack));
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideActionBlack: best attack = tossing a grenade"); DebugAI(AI_MSG_INFO, pSoldier, String("Best attack - throwing grenade"));
break; break;
case AI_ACTION_THROW_KNIFE: case AI_ACTION_THROW_KNIFE:
case AI_ACTION_KNIFE_MOVE: case AI_ACTION_KNIFE_MOVE:
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideActionBlack: best attack = stab with a knife"); DebugAI(AI_MSG_INFO, pSoldier, String("Best attack - stab"));
memcpy(&BestAttack,&BestStab,sizeof(BestAttack)); memcpy(&BestAttack,&BestStab,sizeof(BestAttack));
break; break;
case AI_ACTION_STEAL_MOVE: // added by SANDRO case AI_ACTION_STEAL_MOVE: // added by SANDRO
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideActionBlack: best attack = try to steal weapon"); DebugAI(AI_MSG_INFO, pSoldier, String("Best attack - steal weapon"));
memcpy(&BestAttack,&BestStab,sizeof(BestAttack)); memcpy(&BestAttack,&BestStab,sizeof(BestAttack));
break; break;
default: default:
// set to empty // set to empty
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideActionBlack: best attack = no good attack"); DebugAI(AI_MSG_INFO, pSoldier, String("Best attack - no good attack"));
memset( &BestAttack, 0, sizeof( BestAttack ) ); memset( &BestAttack, 0, sizeof( BestAttack ) );
break; break;
} }
@@ -6110,6 +6122,7 @@ INT16 ubMinAPCost;
} }
} }
DebugAI(AI_MSG_TOPIC, pSoldier, String("[Allow taking cover]"));
if ( (pSoldier->bActionPoints == pSoldier->bInitialActionPoints) && if ( (pSoldier->bActionPoints == pSoldier->bInitialActionPoints) &&
(ubBestAttackAction == AI_ACTION_FIRE_GUN) && (ubBestAttackAction == AI_ACTION_FIRE_GUN) &&
(pSoldier->aiData.bShock == 0) && (pSoldier->aiData.bShock == 0) &&
@@ -6124,15 +6137,20 @@ INT16 ubMinAPCost;
{ {
// make militia a bit more cautious // make militia a bit more cautious
// 3 (UINT16) CONVERSIONS HERE TO AVOID ERRORS. GOTTHARD 7/15/08 // 3 (UINT16) CONVERSIONS HERE TO AVOID ERRORS. GOTTHARD 7/15/08
if ( ( (pSoldier->bTeam == MILITIA_TEAM) && ((INT16)(PreRandom( 20 )) > BestAttack.ubChanceToReallyHit) ) if (pSoldier->bTeam == MILITIA_TEAM && (INT16)(PreRandom(20)) > BestAttack.ubChanceToReallyHit ||
|| ( (pSoldier->bTeam != MILITIA_TEAM) && ((INT16)(PreRandom( 40 )) > BestAttack.ubChanceToReallyHit) ) ) pSoldier->bTeam != MILITIA_TEAM && (INT16)(PreRandom(40)) > BestAttack.ubChanceToReallyHit)
{ {
//ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_TESTVERSION, L"AI %d allowing cover check, chance to hit is only %d, at range %d", BestAttack.ubChanceToReallyHit, PythSpacesAway( pSoldier->sGridNo, BestAttack.sTarget ) ); DebugAI(AI_MSG_INFO, pSoldier, String("Allow cover check"));
// maybe taking cover would be better! // maybe taking cover would be better!
fAllowCoverCheck = TRUE; fAllowCoverCheck = TRUE;
if ( (INT16)(PreRandom( 10 )) > BestAttack.ubChanceToReallyHit )
sBestCover = FindBestNearbyCover(pSoldier, pSoldier->aiData.bAIMorale, &iCoverPercentBetter);
if ( (INT16)(PreRandom( 10 )) > BestAttack.ubChanceToReallyHit &&
!TileIsOutOfBounds(sBestCover) &&
(iCoverPercentBetter > 10 || !AnyCoverAtSpot(pSoldier, pSoldier->sGridNo)))
{ {
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideActionBlack: can't hit so screw the attack"); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideActionBlack: can't hit so screw the attack");
DebugAI(AI_MSG_INFO, pSoldier, String("can't hit, screw the attack"));
// screw the attack! // screw the attack!
ubBestAttackAction = AI_ACTION_NONE; ubBestAttackAction = AI_ACTION_NONE;
} }
@@ -6142,6 +6160,7 @@ INT16 ubMinAPCost;
} }
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"LOOK FOR SOME KIND OF COVER BETTER THAN WHAT WE HAVE NOW"); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"LOOK FOR SOME KIND OF COVER BETTER THAN WHAT WE HAVE NOW");
DebugAI(AI_MSG_TOPIC, pSoldier, String("[Find cover]"));
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// LOOK FOR SOME KIND OF COVER BETTER THAN WHAT WE HAVE NOW // LOOK FOR SOME KIND OF COVER BETTER THAN WHAT WE HAVE NOW
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@@ -6149,14 +6168,19 @@ INT16 ubMinAPCost;
// if soldier has enough APs left to move at least 1 square's worth, // if soldier has enough APs left to move at least 1 square's worth,
// and either he can't attack any more, or his attack did wound someone // and either he can't attack any more, or his attack did wound someone
iCoverPercentBetter = 0; iCoverPercentBetter = 0;
if ( (ubCanMove && !SkipCoverCheck && !gfHiddenInterrupt && if ( (ubCanMove && !SkipCoverCheck && !gfHiddenInterrupt &&
((ubBestAttackAction == AI_ACTION_NONE) || pSoldier->aiData.bLastAttackHit) && ((ubBestAttackAction == AI_ACTION_NONE) || pSoldier->aiData.bLastAttackHit) &&
(pSoldier->bTeam != gbPlayerNum || pSoldier->aiData.fAIFlags & AI_RTP_OPTION_CAN_SEEK_COVER) && (pSoldier->bTeam != gbPlayerNum || pSoldier->aiData.fAIFlags & AI_RTP_OPTION_CAN_SEEK_COVER) &&
!(pSoldier->flags.uiStatusFlags & SOLDIER_BOXER) ) !(pSoldier->flags.uiStatusFlags & SOLDIER_BOXER) )
|| fAllowCoverCheck ) || fAllowCoverCheck )
{ {
sBestCover = FindBestNearbyCover(pSoldier,pSoldier->aiData.bAIMorale,&iCoverPercentBetter); // sevenfm: if not found yet
if(TileIsOutOfBounds(sBestCover))
{
sBestCover = FindBestNearbyCover(pSoldier, pSoldier->aiData.bAIMorale, &iCoverPercentBetter);
}
DebugAI(AI_MSG_INFO, pSoldier, String("Found cover spot %d percent better %d movement mode %d", sBestCover, iCoverPercentBetter, DetermineMovementMode(pSoldier, AI_ACTION_TAKE_COVER)));
} }
@@ -6165,6 +6189,7 @@ INT16 ubMinAPCost;
#endif #endif
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideActionBlack: DECIDE BETWEEN ATTACKING AND DEFENDING (TAKING COVER)"); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideActionBlack: DECIDE BETWEEN ATTACKING AND DEFENDING (TAKING COVER)");
DebugAI(AI_MSG_TOPIC, pSoldier, String("[Decide attack/cover]"));
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// IF NECESSARY, DECIDE BETWEEN ATTACKING AND DEFENDING (TAKING COVER) // IF NECESSARY, DECIDE BETWEEN ATTACKING AND DEFENDING (TAKING COVER)
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@@ -6230,19 +6255,23 @@ INT16 ubMinAPCost;
DebugAI( tempstr ); DebugAI( tempstr );
#endif #endif
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideActionBlack: if his defensive instincts win out, forget all about the attack"); DebugAI(AI_MSG_INFO, pSoldier, String("iOffense %d iDefense %d", iOffense, iDefense));
// if his defensive instincts win out, forget all about the attack // if his defensive instincts win out, forget all about the attack
if (iDefense > iOffense) if (iDefense > iOffense)
{
DebugAI(AI_MSG_INFO, pSoldier, String("[decided taking cover, disable attack]"));
ubBestAttackAction = AI_ACTION_NONE; ubBestAttackAction = AI_ACTION_NONE;
}
} }
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("DecideActionBlack: is attack still desirable? ubBestAttackAction = %d",ubBestAttackAction)); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("DecideActionBlack: is attack still desirable? ubBestAttackAction = %d",ubBestAttackAction));
DebugAI(AI_MSG_TOPIC, pSoldier, String("[Attack]"));
// if attack is still desirable (meaning it's also preferred to taking cover) // if attack is still desirable (meaning it's also preferred to taking cover)
if (ubBestAttackAction != AI_ACTION_NONE) if (ubBestAttackAction != AI_ACTION_NONE)
{ {
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideActionBlack: attack is still desirable (meaning it's also preferred to taking cover)"); DebugAI(AI_MSG_TOPIC, pSoldier, String("[Prepare attack]"));
// if we wanted to be REALLY mean, we could look at chance to hit and decide whether // if we wanted to be REALLY mean, we could look at chance to hit and decide whether
// to shoot at the head... // to shoot at the head...
@@ -6257,10 +6286,7 @@ INT16 ubMinAPCost;
if (ubBestAttackAction == AI_ACTION_FIRE_GUN) if (ubBestAttackAction == AI_ACTION_FIRE_GUN)
{ {
if ( gGameExternalOptions.fEnemyTanksCanMoveInTactical || !ARMED_VEHICLE( pSoldier ) ) DebugAI(AI_MSG_TOPIC, pSoldier, String("[Prepare shooting]"));
{
// add reserve AP code here
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// IF ENOUGH APs TO BURST, RANDOM CHANCE OF DOING SO // IF ENOUGH APs TO BURST, RANDOM CHANCE OF DOING SO
@@ -6271,7 +6297,7 @@ INT16 ubMinAPCost;
pSoldier->inv[BestAttack.bWeaponIn][0]->data.gun.ubGunShotsLeft > 1 && pSoldier->inv[BestAttack.bWeaponIn][0]->data.gun.ubGunShotsLeft > 1 &&
(pSoldier->bTeam != gbPlayerNum || pSoldier->aiData.bRTPCombat == RTP_COMBAT_AGGRESSIVE) ) (pSoldier->bTeam != gbPlayerNum || pSoldier->aiData.bRTPCombat == RTP_COMBAT_AGGRESSIVE) )
{ {
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideActionBlack: ENOUGH APs TO BURST, RANDOM CHANCE OF DOING SO"); DebugAI(AI_MSG_INFO, pSoldier, String("enough APs to burst, random chance of doing so"));
ubBurstAPs = CalcAPsToBurst( pSoldier->CalcActionPoints(), &(pSoldier->inv[BestAttack.bWeaponIn]), pSoldier ); ubBurstAPs = CalcAPsToBurst( pSoldier->CalcActionPoints(), &(pSoldier->inv[BestAttack.bWeaponIn]), pSoldier );
@@ -6346,11 +6372,12 @@ INT16 ubMinAPCost;
(( pSoldier->inv[BestAttack.bWeaponIn][0]->data.gun.ubGunShotsLeft > 1 && (( pSoldier->inv[BestAttack.bWeaponIn][0]->data.gun.ubGunShotsLeft > 1 &&
!pSoldier->bDoBurst ) || Weapon[pSoldier->inv[BestAttack.bWeaponIn].usItem].NoSemiAuto) ) !pSoldier->bDoBurst ) || Weapon[pSoldier->inv[BestAttack.bWeaponIn].usItem].NoSemiAuto) )
{ {
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideActionBlack: ENOUGH APs TO AUTOFIRE, RANDOM CHANCE OF DOING SO"); DebugAI(AI_MSG_INFO, pSoldier, String("enough APs to autofire, random chance of doing so"));
L_NEWAIM: L_NEWAIM:
FLOAT dTotalRecoil = 0.0f; FLOAT dTotalRecoil = 0.0f;
pSoldier->bDoAutofire = 0; pSoldier->bDoAutofire = 0;
if(UsingNewCTHSystem() == true){ if(UsingNewCTHSystem() == true)
{
do do
{ {
pSoldier->bDoAutofire++; pSoldier->bDoAutofire++;
@@ -6358,7 +6385,9 @@ L_NEWAIM:
ubBurstAPs = CalcAPsToAutofire( pSoldier->CalcActionPoints(), &(pSoldier->inv[BestShot.bWeaponIn]), pSoldier->bDoAutofire, pSoldier ); ubBurstAPs = CalcAPsToAutofire( pSoldier->CalcActionPoints(), &(pSoldier->inv[BestShot.bWeaponIn]), pSoldier->bDoAutofire, pSoldier );
} }
while( pSoldier->bActionPoints >= BestShot.ubAPCost + ubBurstAPs + sActualAimAP && pSoldier->inv[ BestAttack.bWeaponIn ][0]->data.gun.ubGunShotsLeft >= pSoldier->bDoAutofire && dTotalRecoil <= 10.0f );//dnl ch64 260813 pSoldier->ubAttackingHand is wrong because decision is to use BestAttack.bWeaponIn while( pSoldier->bActionPoints >= BestShot.ubAPCost + ubBurstAPs + sActualAimAP && pSoldier->inv[ BestAttack.bWeaponIn ][0]->data.gun.ubGunShotsLeft >= pSoldier->bDoAutofire && dTotalRecoil <= 10.0f );//dnl ch64 260813 pSoldier->ubAttackingHand is wrong because decision is to use BestAttack.bWeaponIn
} else { }
else
{
do do
{ {
pSoldier->bDoAutofire++; pSoldier->bDoAutofire++;
@@ -6369,6 +6398,8 @@ L_NEWAIM:
pSoldier->bDoAutofire--; pSoldier->bDoAutofire--;
DebugAI(AI_MSG_INFO, pSoldier, String("autofire %d", pSoldier->bDoAutofire));
//dnl ch69 130913 let try increase autofire rate for aim cost //dnl ch69 130913 let try increase autofire rate for aim cost
// sevenfm: LIMIT_MAX_DEVIATION option increases effectiveness of suppression // sevenfm: LIMIT_MAX_DEVIATION option increases effectiveness of suppression
if ((!UsingNewCTHSystem() || gGameCTHConstants.LIMIT_MAX_DEVIATION) && if ((!UsingNewCTHSystem() || gGameCTHConstants.LIMIT_MAX_DEVIATION) &&
@@ -6380,6 +6411,7 @@ L_NEWAIM:
{ {
pSoldier->aiData.bAimTime--; pSoldier->aiData.bAimTime--;
sActualAimAP = CalcAPCostForAiming(pSoldier, BestAttack.sTarget, (INT8)pSoldier->aiData.bAimTime); sActualAimAP = CalcAPCostForAiming(pSoldier, BestAttack.sTarget, (INT8)pSoldier->aiData.bAimTime);
DebugAI(AI_MSG_INFO, pSoldier, String("reduce aim to %d, recalc autofire, aim AP %d", pSoldier->aiData.bAimTime, sActualAimAP));
goto L_NEWAIM; goto L_NEWAIM;
} }
@@ -6438,6 +6470,8 @@ L_NEWAIM:
} }
} }
DebugAI(AI_MSG_INFO, pSoldier, String("chance for autofire %d", iChance));
if ((INT32) PreRandom( 100 ) < iChance || Weapon[pSoldier->inv[BestAttack.bWeaponIn].usItem].NoSemiAuto) if ((INT32) PreRandom( 100 ) < iChance || Weapon[pSoldier->inv[BestAttack.bWeaponIn].usItem].NoSemiAuto)
{ {
//dnl ch69 140913 return aiming for autofire with halfautofire fix //dnl ch69 140913 return aiming for autofire with halfautofire fix
@@ -6496,6 +6530,9 @@ L_NEWAIM:
(RangeChangeDesire( pSoldier ) >= 3) ) // Cunning and above (RangeChangeDesire( pSoldier ) >= 3) ) // Cunning and above
{ {
sClosestOpponent = Menptr[BestShot.ubOpponent].sGridNo; sClosestOpponent = Menptr[BestShot.ubOpponent].sGridNo;
DebugAI(AI_MSG_INFO, pSoldier, String("check if can advance to closest opponent %d", sClosestOpponent));
if (!TileIsOutOfBounds(sClosestOpponent)) if (!TileIsOutOfBounds(sClosestOpponent))
{ {
// temporarily make merc get closer reserving enough for expected cost of shot // temporarily make merc get closer reserving enough for expected cost of shot
@@ -6509,12 +6546,15 @@ L_NEWAIM:
if (!TileIsOutOfBounds(pSoldier->aiData.usActionData)) if (!TileIsOutOfBounds(pSoldier->aiData.usActionData))
{ {
pSoldier->aiData.usActionData = pSoldier->sGridNo ; //pSoldier->aiData.usActionData = pSoldier->sGridNo ;
pSoldier->aiData.usActionData = pSoldier->aiData.usActionData;
pSoldier->pathing.sFinalDestination = pSoldier->aiData.usActionData; pSoldier->pathing.sFinalDestination = pSoldier->aiData.usActionData;
pSoldier->aiData.bNextAction = AI_ACTION_FIRE_GUN; pSoldier->aiData.bNextAction = AI_ACTION_FIRE_GUN;
pSoldier->aiData.usNextActionData = BestAttack.sTarget; pSoldier->aiData.usNextActionData = BestAttack.sTarget;
pSoldier->aiData.bNextTargetLevel = BestAttack.bTargetLevel; pSoldier->aiData.bNextTargetLevel = BestAttack.bTargetLevel;
DebugAI(AI_MSG_INFO, pSoldier, String("try to get closer, move to %d", pSoldier->aiData.usActionData));
return( AI_ACTION_GET_CLOSER ); return( AI_ACTION_GET_CLOSER );
} }
} }
@@ -6557,6 +6597,8 @@ L_NEWAIM:
} }
else if (ubBestAttackAction == AI_ACTION_THROW_KNIFE) else if (ubBestAttackAction == AI_ACTION_THROW_KNIFE)
{ {
DebugAI(AI_MSG_TOPIC, pSoldier, String("[Prepare throwing knife]"));
if (BestAttack.bWeaponIn != HANDPOS && gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND ) if (BestAttack.bWeaponIn != HANDPOS && gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND )
{ {
// we had better make sure we lower our gun first! // we had better make sure we lower our gun first!
@@ -6574,6 +6616,8 @@ L_NEWAIM:
// SANDRO - chance to make aimed punch/stab for martial arts/melee // SANDRO - chance to make aimed punch/stab for martial arts/melee
else if (ubBestAttackAction == AI_ACTION_KNIFE_MOVE && gGameOptions.fNewTraitSystem) else if (ubBestAttackAction == AI_ACTION_KNIFE_MOVE && gGameOptions.fNewTraitSystem)
{ {
DebugAI(AI_MSG_TOPIC, pSoldier, String("[Prepare knife attack]"));
pSoldier->aiData.bAimTime = 0; pSoldier->aiData.bAimTime = 0;
iChance = 0; iChance = 0;
@@ -6606,7 +6650,7 @@ L_NEWAIM:
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// OTHERWISE, JUST GO AHEAD & ATTACK! // OTHERWISE, JUST GO AHEAD & ATTACK!
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"OTHERWISE, JUST GO AHEAD & ATTACK!"); DebugAI(AI_MSG_TOPIC, pSoldier, String("Attack!"));
//dnl ch64 270813 must be as below RearrangePocket with FOREVER will screw already decided BURST or AUTOFIRE //dnl ch64 270813 must be as below RearrangePocket with FOREVER will screw already decided BURST or AUTOFIRE
INT8 bDoBurst = pSoldier->bDoBurst; INT8 bDoBurst = pSoldier->bDoBurst;
@@ -6614,11 +6658,14 @@ L_NEWAIM:
// swap weapon to hand if necessary // swap weapon to hand if necessary
if (BestAttack.bWeaponIn != HANDPOS) if (BestAttack.bWeaponIn != HANDPOS)
{ {
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionblack: swap weapon into hand"); DebugAI(AI_MSG_INFO, pSoldier, String("swap weapon into hand from %d", BestAttack.bWeaponIn));
RearrangePocket(pSoldier,HANDPOS,BestAttack.bWeaponIn,FOREVER); RearrangePocket(pSoldier,HANDPOS,BestAttack.bWeaponIn,FOREVER);
} }
if(ubBestAttackAction == AI_ACTION_FIRE_GUN && bDoBurst == 1)//dnl ch64 270813 if(ubBestAttackAction == AI_ACTION_FIRE_GUN && bDoBurst == 1)//dnl ch64 270813
{ {
DebugAI(AI_MSG_INFO, pSoldier, String("using burst/autofire"));
pSoldier->bDoAutofire = bDoAutofire; pSoldier->bDoAutofire = bDoAutofire;
pSoldier->bDoBurst = bDoBurst; pSoldier->bDoBurst = bDoBurst;
if(bDoAutofire > 1) if(bDoAutofire > 1)
@@ -6627,6 +6674,8 @@ L_NEWAIM:
pSoldier->bWeaponMode = WM_BURST; pSoldier->bWeaponMode = WM_BURST;
} }
DebugAI(AI_MSG_INFO, pSoldier, String("prepare attack at target %d level %d aim %d ap %d cth %d opponent %d", BestAttack.sTarget, BestAttack.bTargetLevel, BestAttack.ubAimTime, BestAttack.ubAPCost, BestAttack.ubChanceToReallyHit, BestAttack.ubOpponent));
if (ubBestAttackAction == AI_ACTION_FIRE_GUN) if (ubBestAttackAction == AI_ACTION_FIRE_GUN)
{ {
if (gAnimControl[pSoldier->usAnimState].ubEndHeight != BestAttack.ubStance && if (gAnimControl[pSoldier->usAnimState].ubEndHeight != BestAttack.ubStance &&
@@ -6685,12 +6734,14 @@ L_NEWAIM:
} }
} }
DebugAI(AI_MSG_TOPIC, pSoldier, String("[End of Tank AI]"));
// end of tank AI // end of tank AI
if ( !gGameExternalOptions.fEnemyTanksCanMoveInTactical && ARMED_VEHICLE( pSoldier ) ) if ( !gGameExternalOptions.fEnemyTanksCanMoveInTactical && ARMED_VEHICLE( pSoldier ) )
{ {
return( AI_ACTION_NONE ); return( AI_ACTION_NONE );
} }
DebugAI(AI_MSG_TOPIC, pSoldier, String("[Window jump]"));
// get the location of the closest reachable opponent // get the location of the closest reachable opponent
/* Flugente 22.02.2012 - A few clarifications: I changed ClosestSeenOpponent so that for zombies, this function also returns an opponent if he is on the /* Flugente 22.02.2012 - A few clarifications: I changed ClosestSeenOpponent so that for zombies, this function also returns an opponent if he is on the
* roof of a building, we are not, but our GridNo belongs to that same building. * roof of a building, we are not, but our GridNo belongs to that same building.
@@ -6779,6 +6830,7 @@ L_NEWAIM:
} }
} }
DebugAI(AI_MSG_TOPIC, pSoldier, String("[Make boxer close if possible]"));
// try to make boxer close if possible // try to make boxer close if possible
if (pSoldier->flags.uiStatusFlags & SOLDIER_BOXER ) if (pSoldier->flags.uiStatusFlags & SOLDIER_BOXER )
{ {
@@ -6928,7 +6980,8 @@ L_NEWAIM:
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// IF A LOCATION WITH BETTER COVER IS AVAILABLE & REACHABLE, GO FOR IT! // IF A LOCATION WITH BETTER COVER IS AVAILABLE & REACHABLE, GO FOR IT!
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
DebugAI(AI_MSG_TOPIC, pSoldier, String("[Take cover]"));
if (!TileIsOutOfBounds(sBestCover)) if (!TileIsOutOfBounds(sBestCover))
{ {
#ifdef DEBUGDECISIONS #ifdef DEBUGDECISIONS
@@ -6948,12 +7001,12 @@ L_NEWAIM:
} }
return(AI_ACTION_TAKE_COVER); return(AI_ACTION_TAKE_COVER);
} }
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// IF THINGS ARE REALLY HOPELESS, OR UNARMED, TRY TO RUN AWAY // IF THINGS ARE REALLY HOPELESS, OR UNARMED, TRY TO RUN AWAY
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
DebugAI(AI_MSG_TOPIC, pSoldier, String("[Run away]"));
// if soldier has enough APs left to move at least 1 square's worth // if soldier has enough APs left to move at least 1 square's worth
if ( ubCanMove && (pSoldier->bTeam != gbPlayerNum || pSoldier->aiData.fAIFlags & AI_RTP_OPTION_CAN_RETREAT) ) if ( ubCanMove && (pSoldier->bTeam != gbPlayerNum || pSoldier->aiData.fAIFlags & AI_RTP_OPTION_CAN_RETREAT) )
{ {
@@ -6979,6 +7032,7 @@ L_NEWAIM:
// IF SPOTTERS HAVE BEEN CALLED FOR, AND WE HAVE SOME NEW SIGHTINGS, RADIO! // IF SPOTTERS HAVE BEEN CALLED FOR, AND WE HAVE SOME NEW SIGHTINGS, RADIO!
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
DebugAI(AI_MSG_TOPIC, pSoldier, String("[Radio sightings]"));
// if we're a computer merc, and we have the action points remaining to RADIO // if we're a computer merc, and we have the action points remaining to RADIO
// (we never want NPCs to choose to radio if they would have to wait a turn) // (we never want NPCs to choose to radio if they would have to wait a turn)
// and we're not swimming in deep water, and somebody has called for spotters // and we're not swimming in deep water, and somebody has called for spotters
@@ -7012,7 +7066,7 @@ L_NEWAIM:
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// CROUCH IF NOT CROUCHING ALREADY // CROUCH IF NOT CROUCHING ALREADY
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
DebugAI(AI_MSG_TOPIC, pSoldier, String("[Crouch if not crouching already]"));
// if not in water and not already crouched, try to crouch down first // if not in water and not already crouched, try to crouch down first
if (!gfTurnBasedAI || GetAPsToChangeStance( pSoldier, ANIM_CROUCH ) <= pSoldier->bActionPoints) if (!gfTurnBasedAI || GetAPsToChangeStance( pSoldier, ANIM_CROUCH ) <= pSoldier->bActionPoints)
{ {
@@ -7080,7 +7134,7 @@ L_NEWAIM:
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// TURN TO FACE CLOSEST KNOWN OPPONENT (IF NOT FACING THERE ALREADY) // TURN TO FACE CLOSEST KNOWN OPPONENT (IF NOT FACING THERE ALREADY)
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
DebugAI(AI_MSG_TOPIC, pSoldier, String("[Turn to closest known opponent]"));
if (!gfTurnBasedAI || GetAPsToLook( pSoldier ) <= pSoldier->bActionPoints) if (!gfTurnBasedAI || GetAPsToLook( pSoldier ) <= pSoldier->bActionPoints)
{ {
// hopeless guys shouldn't waste their time this way, UNLESS they CAN move // hopeless guys shouldn't waste their time this way, UNLESS they CAN move
@@ -7121,7 +7175,7 @@ L_NEWAIM:
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// RADIO RED ALERT: determine %chance to call others and report contact // RADIO RED ALERT: determine %chance to call others and report contact
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
DebugAI(AI_MSG_TOPIC, pSoldier, String("[Report contacts]"));
if ( !(pSoldier->usSoldierFlagMask & SOLDIER_RAISED_REDALERT) && pSoldier->bTeam == MILITIA_TEAM && (pSoldier->bActionPoints >= APBPConstants[AP_RADIO]) && (gTacticalStatus.Team[pSoldier->bTeam].bMenInSector > 1) ) if ( !(pSoldier->usSoldierFlagMask & SOLDIER_RAISED_REDALERT) && pSoldier->bTeam == MILITIA_TEAM && (pSoldier->bActionPoints >= APBPConstants[AP_RADIO]) && (gTacticalStatus.Team[pSoldier->bTeam].bMenInSector > 1) )
{ {
@@ -7212,6 +7266,7 @@ L_NEWAIM:
#ifdef DEBUGDECISIONS #ifdef DEBUGDECISIONS
AINameMessage(pSoldier,"- DOES NOTHING (BLACK)",1000); AINameMessage(pSoldier,"- DOES NOTHING (BLACK)",1000);
#endif #endif
DebugAI(AI_MSG_TOPIC, pSoldier, String("[Nothing to do]"));
// by default, if everything else fails, just stand in place and wait // by default, if everything else fails, just stand in place and wait
pSoldier->aiData.usActionData = NOWHERE; pSoldier->aiData.usActionData = NOWHERE;