Red, Black AI: try to use sidearm if not enough AP to shoot with main weapon.

Black AI: improved check to avoid friendly fire.
FindAIUsableObjClass: by default search for weapon with longest range, if fSidearm = TRUE search for fastest weapon.
AICalcChanceToHitGun: if AI_EXTRA_SUPPRESSION = TRUE, always return min 1% for AI.
RangeChangeDesire:
- civilians only want to run away
- added small bonus to range change desire if soldier has no gun or short range weapon
CalcBestShot, CheckIfShotPossible: always check if can shoot at target seen by another soldier.
CalcBestShot, CalcBestThrow, CalcBestStab: initialize attack data.
Removed obsolete code.

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8782 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Sevenfm
2020-04-08 21:24:56 +00:00
parent 5350258334
commit 4e34605f86
8 changed files with 209 additions and 607 deletions
+76 -237
View File
@@ -161,7 +161,7 @@ void ResetWeaponMode( SOLDIERTYPE * pSoldier )
}
//</SB>
void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUnseen)
void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot)
{
UINT32 uiLoop;
INT32 iAttackValue, iThreatValue, iHitRate, iBestHitRate, iPercentBetter, iEstDamage, iTrueLastTarget;
@@ -176,23 +176,25 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUns
ubBestChanceToHit = ubBestAimTime = ubChanceToHit = ubChanceToReallyHit = 0;
// sevenfm: initialize
pBestShot->ubPossible = FALSE;
pBestShot->ubChanceToReallyHit = 0;
pBestShot->iAttackValue = 0;
pBestShot->ubOpponent = NOBODY;
pBestShot->ubFriendlyFireChance = 0;
// sevenfm: set attacking hand and target
pSoldier->ubAttackingHand = HANDPOS;
pSoldier->ubTargetID = NOBODY;
pSoldier->usAttackingWeapon = pSoldier->inv[HANDPOS].usItem;
pSoldier->bWeaponMode = WM_NORMAL;
#ifdef dnlCALCBESTSHOT//dnl ch69 130913 rather setup available scopes here then in later inside loop
std::map<INT8, OBJECTTYPE*> ObjList;
GetScopeLists(pSoldier, &pSoldier->inv[HANDPOS], ObjList);
pSoldier->bScopeMode = USE_BEST_SCOPE;
pSoldier->bDoBurst = 0;
pSoldier->bDoAutofire = 0;
#else
INT16 ubBurstAPs, ubChanceToHit2;
#endif
//ubBurstAPs = CalcAPsToBurst( pSoldier->CalcActionPoints( ), &(pSoldier->inv[HANDPOS]), pSoldier );//dnl ch64 270813
//InitAttackType(pBestShot); // set all structure fields to defaults//dnl ch69 150913 already initialize from class constructor
// hang a pointer into active soldier's personal opponent list
//pbPersOL = &(pSoldier->aiData.bOppList[0]);
// determine which attack against which target has the greatest attack value
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
@@ -208,14 +210,14 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUns
continue; // next merc
// if this opponent is not currently in sight (ignore known but unseen!)
if ((pSoldier->aiData.bOppList[pOpponent->ubID] != SEEN_CURRENTLY && !shootUnseen)) //guys we can't see
/*if ((pSoldier->aiData.bOppList[pOpponent->ubID] != SEEN_CURRENTLY && !shootUnseen)) //guys we can't see
{
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("CalcBestShot: soldier = %d, target = %d, skip guys we can't see, shootUnseen = %d, personal opplist = %d",pSoldier->ubID, pOpponent->ubID, shootUnseen, pSoldier->aiData.bOppList[pOpponent->ubID]));
continue; // next opponent
}
}*/
if ((pSoldier->aiData.bOppList[pOpponent->ubID] != SEEN_CURRENTLY && gbPublicOpplist[pSoldier->bTeam][pOpponent->ubID] != SEEN_CURRENTLY)) // guys nobody sees
{
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("CalcBestShot: soldier = %d, target = %d, skip guys nobody sees, shootUnseen = %d, public opplist = %d",pSoldier->ubID, pOpponent->ubID, shootUnseen,gbPublicOpplist[pSoldier->bTeam][pOpponent->ubID]));
DebugMsg(TOPIC_JA2, DBG_LEVEL_3, String("CalcBestShot: soldier = %d, target = %d, skip guys nobody sees, public opplist = %d", pSoldier->ubID, pOpponent->ubID, gbPublicOpplist[pSoldier->bTeam][pOpponent->ubID]));
continue; // next opponent
}
@@ -231,26 +233,8 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUns
#ifdef DEBUGATTACKS
DebugAI( String( "%s sees %s at gridno %d\n",pSoldier->GetName(),ExtMen[pOpponent->ubID].GetName(),pOpponent->sGridNo ) );
#endif
#ifndef dnlCALCBESTSHOT//dnl ch69 140913
// calculate minimum action points required to shoot at this opponent
// if ( !Weapon[pSoldier->usAttackingWeapon].NoSemiAuto )
// SANDRO - calculate this with the alternative mode, as it is faster, decide the actual bScopeMode later
if ( gGameExternalOptions.ubAllowAlternativeWeaponHolding )
{
if (!WeaponReady( pSoldier )) // but only if we are not already in raised weapon stance
pSoldier->bScopeMode = USE_ALT_WEAPON_HOLD;
else
pSoldier->bScopeMode = USE_BEST_SCOPE;
}
ubMinAPcost = MinAPsToAttack(pSoldier,pOpponent->sGridNo,ADDTURNCOST,0);
// What the.... The APs to attack on the HandleItem side does not make a test like this. It always uses the MinAPs as a base.
// else
// ubMinAPcost = CalcAPsToAutofire( pSoldier->CalcActionPoints( ), &(pSoldier->inv[HANDPOS]), 3 );
//NumMessage("MinAPcost to shoot this opponent = ",ubMinAPcost);
#else
ubMinAPcost = MinAPsToAttack(pSoldier, pOpponent->sGridNo, DONTADDTURNCOST, 0);// later will be decide if shoot is possible this here is just best guess so ignore turnover
#endif
// if we don't have enough APs left to shoot even a snap-shot at this guy
if (ubMinAPcost > pSoldier->bActionPoints)
continue; // next opponent
@@ -313,150 +297,7 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUns
//}
iBestHitRate = 0; // reset best hit rate to minimum
#ifndef dnlCALCBESTSHOT//dnl ch69 130913 although there is nothing wrong with code unfortunately below and later in DecideAction is not use properly with missing conditions so AI get invalid action handling due to improper APs calculation, also try to optimize a bit to get less AICalcChanceToHitGun calls and to use with different stance decisions
// SANDRO: decide here, whether to use the alternative holding or normal holding
bScopeMode = USE_BEST_SCOPE;
if ( gGameExternalOptions.ubAllowAlternativeWeaponHolding )
{
pSoldier->bScopeMode = USE_ALT_WEAPON_HOLD;
ubChanceToHit = (INT16) AICalcChanceToHitGun(pSoldier, pOpponent->sGridNo, 0, AIM_SHOT_TORSO, pOpponent->pathing.bLevel, STANDING);//dnl ch59 130813 get CtH from alternative hold, without aiming
pSoldier->bScopeMode = USE_BEST_SCOPE;
// CASE #1 - Enemy very close, or we have very good chance to hit from hip with no aiming
if (( PythSpacesAway( pSoldier->sGridNo, pOpponent->sGridNo ) < 5 || ubChanceToHit > 80 ) && !WeaponReady(pSoldier) )
bScopeMode = USE_ALT_WEAPON_HOLD;
// CASE #2 - HeavyGun tag, or heavy LMG in hand
if (Weapon[pSoldier->usAttackingWeapon].HeavyGun || (Weapon[pSoldier->usAttackingWeapon].ubWeaponType == GUN_LMG && GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) > 50))
bScopeMode = USE_ALT_WEAPON_HOLD;
// reset the mode back
// CASE #3 - We don't have enough APs for shot from regular stance, and there is at least some reasonable chance we hit target from alternative mode
if ( (MinAPsToAttack(pSoldier,pOpponent->sGridNo,ADDTURNCOST,0) > pSoldier->bActionPoints) && (ubChanceToHit > 30) )
bScopeMode = USE_ALT_WEAPON_HOLD;
// CASE #4 - CtH with alternative hold is simply better than with normal hold (probably due to scope giving penalty on short range)
else if ( !WeaponReady(pSoldier) ) // ... and we are not in ready weapon stance yet
{
pSoldier->bScopeMode = USE_ALT_WEAPON_HOLD;
ubChanceToHit = (INT16) AICalcChanceToHitGun(pSoldier, pOpponent->sGridNo, AllowedAimingLevels( pSoldier, pOpponent->sGridNo ), AIM_SHOT_TORSO, pOpponent->pathing.bLevel, STANDING);//dnl ch59 130813
pSoldier->bScopeMode = USE_BEST_SCOPE;
ubChanceToHit2 = (INT16) AICalcChanceToHitGun(pSoldier, pOpponent->sGridNo, AllowedAimingLevels( pSoldier, pOpponent->sGridNo ), AIM_SHOT_TORSO, pOpponent->pathing.bLevel, STANDING);//dnl ch59 130813
if ( ubChanceToHit > ubChanceToHit2 && ubChanceToHit > 30 && (ubChanceToHit-ubChanceToHit2) >= 15 )
bScopeMode = USE_ALT_WEAPON_HOLD;
}
}
if ( gGameExternalOptions.fScopeModes )
{
// Now try to decide which scope mode is better
// we simply compare the chance to hit with various scopes at full aiming, sometimes, we get penalty for using a scope at close range
// in case the best scope is not actually the "best" (at this distance), we will use the other one
if ( bScopeMode == USE_BEST_SCOPE )
{
ubChanceToHit = (INT16) AICalcChanceToHitGun(pSoldier, pOpponent->sGridNo, AllowedAimingLevels( pSoldier, pOpponent->sGridNo ), AIM_SHOT_TORSO, pOpponent->pathing.bLevel, STANDING);//dnl ch59 130813
std::map<INT8, OBJECTTYPE*> ObjList;
GetScopeLists(pSoldier, &pSoldier->inv[HANDPOS], ObjList);
do
{
pSoldier->bScopeMode++;
if ( ObjList[pSoldier->bScopeMode] != NULL )
{
ubChanceToHit2 = (INT16) AICalcChanceToHitGun(pSoldier, pOpponent->sGridNo, AllowedAimingLevels( pSoldier, pOpponent->sGridNo ), AIM_SHOT_TORSO, pOpponent->pathing.bLevel, STANDING);//dnl ch59 130813
if ( ubChanceToHit2 > ubChanceToHit )
{
bScopeMode = pSoldier->bScopeMode;
ubChanceToHit = ubChanceToHit2;
}
}
}
while( ObjList[pSoldier->bScopeMode] == NULL && pSoldier->bScopeMode != NUM_SCOPE_MODES);
}
}
pSoldier->bScopeMode = bScopeMode; // just for later calculations
// recalculate MinAPsToAttack with our selected scope mode
ubMinAPcost = MinAPsToAttack(pSoldier,pOpponent->sGridNo,ADDTURNCOST,0);
// calc next attack's minimum shooting cost (excludes readying & turning)
ubRawAPCost = MinAPsToShootOrStab(pSoldier,pOpponent->sGridNo,0,FALSE);
// calculate the maximum possible aiming time
#if 0//dnl ch64 270813 maybe I'm wrong but don't see purpose of this
if ( ARMED_VEHICLE( pSoldier ) )
{
ubMaxPossibleAimTime = pSoldier->bActionPoints - ubMinAPcost;
// always burst
if ( ubMaxPossibleAimTime < ubBurstAPs )
{
// should this be a return instead?
continue;
}
// bursts aren't aimed
ubMaxPossibleAimTime = 0;
}
else
#endif
{
// HEADROCK HAM 3.6: Calculation must take into account APBP constants and other aiming modifications!
INT8 bAPsLeft = pSoldier->bActionPoints - ubMinAPcost;
ubMaxPossibleAimTime = CalcAimingLevelsAvailableWithAP( pSoldier, pOpponent->sGridNo, bAPsLeft );
}
// consider the various aiming times
if ( !Weapon[pSoldier->usAttackingWeapon].NoSemiAuto )
{
for (ubAimTime = APBPConstants[AP_MIN_AIM_ATTACK]; ubAimTime <= ubMaxPossibleAimTime; ubAimTime++)
{
//HandleMyMouseCursor(KEYBOARDALSO);
//NumMessage("ubAimTime = ",ubAimTime);
//dnl ch59 180813 Find true best chance to hit depending of stance so AI would be more eager to attack
ubChanceToHit = AICalcChanceToHitGun(pSoldier, pOpponent->sGridNo,ubAimTime, AIM_SHOT_TORSO, pOpponent->pathing.bLevel, STANDING);
if(!ARMED_VEHICLE(pSoldier))//dnl ch64 270813
{
if((ubChanceToHit2=AICalcChanceToHitGun(pSoldier, pOpponent->sGridNo, ubAimTime, AIM_SHOT_TORSO, pOpponent->pathing.bLevel, CROUCHING)) > ubChanceToHit)
ubChanceToHit = ubChanceToHit2;
if((ubChanceToHit2=AICalcChanceToHitGun(pSoldier, pOpponent->sGridNo, ubAimTime, AIM_SHOT_TORSO, pOpponent->pathing.bLevel, PRONE)) > ubChanceToHit)
ubChanceToHit = ubChanceToHit2;
}
// ExtMen[pOpponent->ubID].haveStats = TRUE;
//NumMessage("chance to Hit = ",ubChanceToHit);
//sprintf(tempstr,"Vs. %s, at AimTime %d, ubChanceToHit = %d",ExtMen[pOpponent->ubID].GetName(),ubAimTime,ubChanceToHit);
//PopMessage(tempstr);
// sevenfm: 100 AP system
iHitRate = (pSoldier->bActionPoints * ubChanceToHit) / (ubRawAPCost + ubAimTime * APBPConstants[AP_CLICK_AIM]);
//iHitRate = (pSoldier->bActionPoints * ubChanceToHit) / (ubRawAPCost + ubAimTime);
//NumMessage("hitRate = ",iHitRate);
// if aiming for this amount of time produces a better hit rate
if (iHitRate > iBestHitRate)
{
iBestHitRate = iHitRate;
ubBestAimTime = ubAimTime;
ubBestChanceToHit = ubChanceToHit;
}
}
}
else
{
ubAimTime = APBPConstants[AP_MIN_AIM_ATTACK];
//dnl ch59 180813 Find true best chance to hit depending of stance for autofire
ubChanceToHit = AICalcChanceToHitGun(pSoldier, pOpponent->sGridNo, ubAimTime, AIM_SHOT_TORSO, pOpponent->pathing.bLevel, STANDING);
if(!ARMED_VEHICLE(pSoldier))//dnl ch64 270813
{
if((ubChanceToHit2=AICalcChanceToHitGun(pSoldier, pOpponent->sGridNo, ubAimTime, AIM_SHOT_TORSO, pOpponent->pathing.bLevel, CROUCHING)) > ubChanceToHit)
ubChanceToHit = ubChanceToHit2;
if((ubChanceToHit2=AICalcChanceToHitGun(pSoldier, pOpponent->sGridNo, ubAimTime, AIM_SHOT_TORSO, pOpponent->pathing.bLevel, PRONE)) > ubChanceToHit)
ubChanceToHit = ubChanceToHit2;
}
Assert( ubRawAPCost > 0);
// sevenfm: 100AP system
iHitRate = (pSoldier->bActionPoints * ubChanceToHit) / (ubRawAPCost + ubAimTime * APBPConstants[AP_CLICK_AIM]);
//iHitRate = (pSoldier->bActionPoints * ubChanceToHit) / (ubRawAPCost + ubAimTime);
iBestHitRate = iHitRate;
ubBestAimTime = ubAimTime;
ubBestChanceToHit = ubChanceToHit;
}
#else
//dnl ch69 130913 Hoping to optimize
// consider alternate holding mode and different scopes
for(pSoldier->bScopeMode=(gGameExternalOptions.ubAllowAlternativeWeaponHolding?USE_ALT_WEAPON_HOLD:USE_BEST_SCOPE); pSoldier->bScopeMode<=(gGameExternalOptions.fScopeModes?NUM_SCOPE_MODES-1:USE_BEST_SCOPE); pSoldier->bScopeMode++)
@@ -505,7 +346,6 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUns
{
ubChanceToHit = AICalcChanceToHitGun(pSoldier, pOpponent->sGridNo, ubAimTime, AIM_SHOT_TORSO, pOpponent->pathing.bLevel, STANDING);
iHitRate = ((pSoldier->bActionPoints - (ubMinAPcost - ubRawAPCost)) * ubChanceToHit) / (ubRawAPCost + ubAimTime * APBPConstants[AP_CLICK_AIM]);
//SendFmtMsg("CalcBestShot_S=%d hr=%d at=%d sm=%d op=%d/%d aps=%d,%d,%d,%d,%d", ubChanceToHit, iHitRate, ubAimTime, pSoldier->bScopeMode, pOpponent->ubID, pOpponent->sGridNo, ubMinAPcost, ubRawAPCost, sStanceAPcost, usTurningCost, usRaiseGunCost);
if(iHitRate > iBestHitRate || (Item[pSoldier->usAttackingWeapon].usItemClass & IC_THROWING_KNIFE) && ubChanceToHit > ubBestChanceToHit)// rather take best chance for throwing knives
{
iBestHitRate = iHitRate;
@@ -560,7 +400,6 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUns
{
ubChanceToHit = AICalcChanceToHitGun(pSoldier, pOpponent->sGridNo, ubAimTime, AIM_SHOT_TORSO, pOpponent->pathing.bLevel, CROUCHING);
iHitRate = ((pSoldier->bActionPoints - (ubMinAPcost - ubRawAPCost)) * ubChanceToHit) / (ubRawAPCost + ubAimTime * APBPConstants[AP_CLICK_AIM]);
//SendFmtMsg("CalcBestShot_C=%d hr=%d at=%d sm=%d op=%d/%d aps=%d,%d,%d,%d,%d", ubChanceToHit, iHitRate, ubAimTime, pSoldier->bScopeMode, pOpponent->ubID, pOpponent->sGridNo, ubMinAPcost, ubRawAPCost, sStanceAPcost, usTurningCost, usRaiseGunCost);
if(iHitRate > iBestHitRate)
{
iBestHitRate = iHitRate;
@@ -597,7 +436,6 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUns
{
ubChanceToHit = AICalcChanceToHitGun(pSoldier, pOpponent->sGridNo, ubAimTime, AIM_SHOT_TORSO, pOpponent->pathing.bLevel, PRONE);
iHitRate = ((pSoldier->bActionPoints - (ubMinAPcost - ubRawAPCost)) * ubChanceToHit) / (ubRawAPCost + ubAimTime * APBPConstants[AP_CLICK_AIM]);
//SendFmtMsg("CalcBestShot_P=%d hr=%d at=%d sm=%d op=%d/%d aps=%d,%d,%d,%d,%d", ubChanceToHit, iHitRate, ubAimTime, pSoldier->bScopeMode, pOpponent->ubID, pOpponent->sGridNo, ubMinAPcost, ubRawAPCost, sStanceAPcost, usTurningCost, usRaiseGunCost);
if(iHitRate > iBestHitRate)
{
iBestHitRate = iHitRate;
@@ -614,7 +452,7 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUns
}
}
}
#endif
// if we can't get any kind of hit rate at all
if (iBestHitRate == 0)
continue; // next opponent
@@ -730,12 +568,8 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUns
pBestShot->sTarget = pOpponent->sGridNo;
pBestShot->bTargetLevel = pOpponent->pathing.bLevel;
pBestShot->iAttackValue = iAttackValue;
#ifndef dnlCALCBESTSHOT//dnl ch69 140913
pBestShot->ubAPCost = ubMinAPcost;
#else
pBestShot->ubAPCost = sBestAPcost;
pBestShot->ubStance = ubBestStance;
#endif
pBestShot->bScopeMode = bScopeMode;
if(gUnderFire.Count(pSoldier->bTeam))//dnl ch61 180813
pBestShot->ubFriendlyFireChance = gUnderFire.Chance(pSoldier->bTeam);
@@ -743,7 +577,7 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUns
pBestShot->ubFriendlyFireChance = 0;
}
}
//if(pBestShot->ubPossible)SendFmtMsg("CalcBestShot;\r\n ID=%d Loc=%d APs=%d Ac=%d AcData=%d Al=%d, SM=%d, LAc=%d, NAc=%d AT=%d\r\n AP?=%d,%d,%d/%d BS=%d", pSoldier->ubID, pSoldier->sGridNo, pSoldier->bActionPoints, pSoldier->aiData.bAction, pSoldier->aiData.usActionData, pSoldier->aiData.bAlertStatus, pBestShot->bScopeMode, pSoldier->aiData.bLastAction, pSoldier->aiData.bNextAction, pBestShot->ubAimTime, pBestShot->ubAPCost, CalcAPCostForAiming(pSoldier, pBestShot->sTarget, (INT8)pBestShot->ubAimTime), CalcTotalAPsToAttack(pSoldier, pBestShot->sTarget, TRUE, pBestShot->ubAimTime), CalcTotalAPsToAttack(pSoldier, pBestShot->sTarget, FALSE, pBestShot->ubAimTime), pBestShot->ubStance);
pSoldier->bScopeMode = USE_BEST_SCOPE; // better reset this back
}
@@ -847,8 +681,15 @@ void CalcBestThrow(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestThrow)
usInHand = pSoldier->inv[HANDPOS].usItem;
usGrenade = NOTHING;
if ( IsGrenadeLauncherAttached(&pSoldier->inv[HANDPOS]) )
// sevenfm: initialize
pBestThrow->ubPossible = FALSE;
pBestThrow->ubChanceToReallyHit = 0;
pBestThrow->iAttackValue = 0;
if (IsGrenadeLauncherAttached(&pSoldier->inv[HANDPOS]))
{
usInHand = GetAttachedGrenadeLauncher(&pSoldier->inv[HANDPOS]);
}
if ( EXPLOSIVE_GUN( usInHand ) )
{
@@ -1652,6 +1493,12 @@ void CalcBestStab(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestStab, BOOLEAN fBladeAt
pSoldier->usAttackingWeapon = pSoldier->inv[HANDPOS].usItem;
// sevenfm: initialize
pBestStab->ubPossible = FALSE;
pBestStab->iAttackValue = 0;
pBestStab->ubChanceToReallyHit = 0;
pBestStab->ubOpponent = NOBODY;
// temporarily make this guy run so we get a proper AP cost value
// from CalcTotalAPsToAttack
usTrueMovementMode = pSoldier->usUIMovementMode;
@@ -2515,9 +2362,9 @@ INT8 TryToReload( SOLDIERTYPE * pSoldier )
// modify by ini values
if ( Item[ pObj->usItem ].usItemClass == IC_GUN )
sModifiedReloadAP *= gItemSettings.fAPtoReloadManuallyModifierGun[ Weapon[ pObj->usItem ].ubWeaponType ];
sModifiedReloadAP = (INT16)(sModifiedReloadAP * gItemSettings.fAPtoReloadManuallyModifierGun[Weapon[pObj->usItem].ubWeaponType]);
else if ( Item[ pObj->usItem ].usItemClass == IC_LAUNCHER )
sModifiedReloadAP *= gItemSettings.fAPtoReloadManuallyModifierLauncher;
sModifiedReloadAP = (INT16)(sModifiedReloadAP * gItemSettings.fAPtoReloadManuallyModifierLauncher);
////////////////////////////////////////////////////////////////////////////////////////////////////////
// STOMP traits - SANDRO
@@ -2568,9 +2415,9 @@ INT8 TryToReload( SOLDIERTYPE * pSoldier )
// modify by ini values
if ( Item[ pObj2->usItem ].usItemClass == IC_GUN )
sModifiedReloadAP *= gItemSettings.fAPtoReloadManuallyModifierGun[ Weapon[ pObj2->usItem ].ubWeaponType ];
sModifiedReloadAP = (INT16)(sModifiedReloadAP * gItemSettings.fAPtoReloadManuallyModifierGun[Weapon[pObj2->usItem].ubWeaponType]);
else if ( Item[ pObj2->usItem ].usItemClass == IC_LAUNCHER )
sModifiedReloadAP *= gItemSettings.fAPtoReloadManuallyModifierLauncher;
sModifiedReloadAP = (INT16)(sModifiedReloadAP * gItemSettings.fAPtoReloadManuallyModifierLauncher);
////////////////////////////////////////////////////////////////////////////////////////////////////////
// STOMP traits - SANDRO (well, I don't know any one-handed sniper rifle, but what the hell...)
@@ -3109,76 +2956,68 @@ INT16 AdvanceToFiringRange( SOLDIERTYPE * pSoldier, INT16 sClosestOpponent )
}
void CheckIfShotPossible(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN suppressionFire)
void CheckIfShotPossible(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot)
{
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"CheckIfShotPossible");
INT16 ubMinAPcost;
pBestShot->ubPossible = FALSE;
pBestShot->bWeaponIn = NO_SLOT;
if ( !ARMED_VEHICLE( pSoldier ) )
{
// AIs never have more than one gun anyway
pBestShot->bWeaponIn = FindAIUsableObjClass( pSoldier, IC_GUN );
}
pBestShot->bWeaponIn = FindAIUsableObjClass(pSoldier, IC_GUN);
// if the soldier does have a long range rifle
// if the soldier does have a gun
if (pBestShot->bWeaponIn != NO_SLOT)
{
OBJECTTYPE * pObj = &pSoldier->inv[pBestShot->bWeaponIn];
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("CheckIfShotPossible: found a gun item # %d",pObj->usItem ));
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("CheckIfShotPossible: weapon type %d",Weapon [pObj->usItem ].ubWeaponType ));
// if it's in his holster, swap it into his hand temporarily
if (pBestShot->bWeaponIn != HANDPOS)
{
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"CheckIfShotPossible: Rearranging pocket");
RearrangePocket(pSoldier, HANDPOS, pBestShot->bWeaponIn, TEMPORARILY);
}
BOOLEAN fEnableAISuppression = FALSE;
// get the minimum cost to attack with this item
ubMinAPcost = MinAPsToAttack(pSoldier, pSoldier->sLastTarget, ADDTURNCOST, 0);
// CHRISL: Changed from a simple flag to two externalized values for more modder control over AI suppression
if( suppressionFire &&
IsGunAutofireCapable(&pSoldier->inv[pBestShot->bWeaponIn]) &&
GetMagSize(pObj) >= gGameExternalOptions.ubAISuppressionMinimumMagSize &&
(*pObj)[0]->data.gun.ubGunShotsLeft >= gGameExternalOptions.ubAISuppressionMinimumAmmo )
// if we can afford the minimum AP cost
if (pSoldier->bActionPoints >= ubMinAPcost)
{
fEnableAISuppression = TRUE;
// then look around for a worthy target (which sets bestThrow.ubPossible)
CalcBestShot(pSoldier, pBestShot);
}
// sevenfm: allow any soldier with long range weapon to shoot in RED state (if he can hit)
if( !suppressionFire &&
GunRange(pObj, pSoldier) > DAY_VISION_RANGE )
{
fEnableAISuppression = TRUE;
}
if (fEnableAISuppression)
{
// get the minimum cost to attack with this item
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"CheckIfShotPossible: getting min aps");
ubMinAPcost = MinAPsToAttack( pSoldier, pSoldier->sLastTarget, ADDTURNCOST,pBestShot->ubAimTime);
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("CheckIfShotPossible: min AP cost: %d", ubMinAPcost));
// if we can afford the minimum AP cost
if (pSoldier->bActionPoints >= ubMinAPcost)
{
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("CheckIfShotPossible: CalcBestShot"));
// then look around for a worthy target (which sets bestThrow.ubPossible)
CalcBestShot( pSoldier, pBestShot,TRUE);
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("CheckIfShotPossible: CalcBestShot done"));
}
}
// if it was in his holster, swap it back into his holster for now
if (pBestShot->bWeaponIn != HANDPOS)
{
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"CheckIfShotPossible: Rearranging pocket");
RearrangePocket( pSoldier, HANDPOS, pBestShot->bWeaponIn, TEMPORARILY );
}
// try to use sidearm
if (pSoldier->bActionPoints < ubMinAPcost && IS_MERC_BODY_TYPE(pSoldier))
{
pBestShot->bWeaponIn = FindAIUsableObjClass(pSoldier, IC_GUN, TRUE);
if (pBestShot->bWeaponIn != NO_SLOT)
{
// if it's in his holster, swap it into his hand temporarily
if (pBestShot->bWeaponIn != HANDPOS)
{
RearrangePocket(pSoldier, HANDPOS, pBestShot->bWeaponIn, TEMPORARILY);
}
// get the minimum cost to attack with this item
ubMinAPcost = MinAPsToAttack(pSoldier, pSoldier->sLastTarget, ADDTURNCOST, 0);
if (pSoldier->bActionPoints >= ubMinAPcost)
{
// then look around for a worthy target (which sets bestThrow.ubPossible)
CalcBestShot(pSoldier, pBestShot);
}
// if it was in his holster, swap it back into his holster for now
if (pBestShot->bWeaponIn != HANDPOS)
{
RearrangePocket(pSoldier, HANDPOS, pBestShot->bWeaponIn, TEMPORARILY);
}
}
}
}
}