mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
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:
+28
-12
@@ -1744,32 +1744,48 @@ INT8 FindObjClass( SOLDIERTYPE * pSoldier, UINT32 usItemClass )
|
||||
return( NO_SLOT );
|
||||
}
|
||||
|
||||
INT8 FindAIUsableObjClass( SOLDIERTYPE * pSoldier, UINT32 usItemClass )
|
||||
INT8 FindAIUsableObjClass(SOLDIERTYPE * pSoldier, UINT32 usItemClass, BOOLEAN fSidearm)
|
||||
{
|
||||
// finds the first object of the specified class which does NOT have
|
||||
// the "unusable by AI" flag set.
|
||||
|
||||
// uses & rather than == so that this function can search for any weapon
|
||||
|
||||
// This is for the AI only so:
|
||||
INT8 bBestSlot = NO_SLOT;
|
||||
INT8 bInvSize = (INT8)pSoldier->inv.size();
|
||||
|
||||
// Do not consider tank cannons or rocket launchers to be "guns"
|
||||
|
||||
INT8 invsize = (INT8)pSoldier->inv.size();
|
||||
for (INT8 bLoop = 0; bLoop < invsize; ++bLoop)
|
||||
for (INT8 bLoop = 0; bLoop < bInvSize; ++bLoop)
|
||||
{
|
||||
if (pSoldier->inv[bLoop].exists() == true) {
|
||||
if ( (Item[pSoldier->inv[bLoop].usItem].usItemClass & usItemClass) && !(pSoldier->inv[bLoop].fFlags & OBJECT_AI_UNUSABLE) && (pSoldier->inv[bLoop][0]->data.objectStatus >= USABLE ) )
|
||||
if (pSoldier->inv[bLoop].exists())
|
||||
{
|
||||
if ((Item[pSoldier->inv[bLoop].usItem].usItemClass & usItemClass) &&
|
||||
!(pSoldier->inv[bLoop].fFlags & OBJECT_AI_UNUSABLE) &&
|
||||
(pSoldier->inv[bLoop][0]->data.objectStatus >= USABLE))
|
||||
{
|
||||
if ( usItemClass == IC_GUN && EXPLOSIVE_GUN( pSoldier->inv[bLoop].usItem ) )
|
||||
// Do not consider tank cannons or rocket launchers to be "guns" for AI
|
||||
if (usItemClass == IC_GUN && EXPLOSIVE_GUN(pSoldier->inv[bLoop].usItem))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return( bLoop );
|
||||
// if not searching for gun, return first usable of required type
|
||||
if (usItemClass != IC_GUN)
|
||||
{
|
||||
bBestSlot = bLoop;
|
||||
break;
|
||||
}
|
||||
// we are searching for gun
|
||||
if (bBestSlot == NO_SLOT || // haven't found any gun yet
|
||||
// by default, search for weapon with longest range
|
||||
!fSidearm && Weapon[pSoldier->inv[bLoop].usItem].usRange > Weapon[pSoldier->inv[bBestSlot].usItem].usRange ||
|
||||
// when searching for sidearm, find fastest weapon
|
||||
fSidearm && Weapon[Item[pSoldier->inv[bLoop].usItem].ubClassIndex].ubReadyTime + BaseAPsToShootOrStab(APBPConstants[DEFAULT_APS], APBPConstants[DEFAULT_AIMSKILL], &pSoldier->inv[bLoop], pSoldier) <
|
||||
Weapon[Item[pSoldier->inv[bBestSlot].usItem].ubClassIndex].ubReadyTime + BaseAPsToShootOrStab(APBPConstants[DEFAULT_APS], APBPConstants[DEFAULT_AIMSKILL], &pSoldier->inv[bBestSlot], pSoldier))
|
||||
{
|
||||
bBestSlot = bLoop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return( NO_SLOT );
|
||||
return bBestSlot;
|
||||
}
|
||||
|
||||
INT8 FindAIUsableObjClassWithin( SOLDIERTYPE * pSoldier, UINT32 usItemClass, INT8 bLower, INT8 bUpper )
|
||||
|
||||
+11
-17
@@ -16,29 +16,23 @@ class SOLDIERTYPE;
|
||||
#define NIGHTSIGHTGOGGLES_BONUS 2 * STRAIGHT_RATIO
|
||||
#define UVGOGGLES_BONUS 4 * STRAIGHT_RATIO
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
extern UINT8 SlotToPocket[7];
|
||||
|
||||
extern BOOLEAN WeaponInHand( SOLDIERTYPE * pSoldier );
|
||||
|
||||
INT8 FindAmmo( SOLDIERTYPE * pSoldier, UINT8 ubCalibre, UINT16 ubMagSize, UINT8 ubAmmoType, INT8 bExcludeSlot );
|
||||
|
||||
INT8 FindBestWeaponIfCurrentIsOutOfRange(SOLDIERTYPE * pSoldier, INT8 bCurrentWeaponIndex, UINT16 bWantedRange);
|
||||
|
||||
INT16 FindAttachmentSlot( OBJECTTYPE* pObj, UINT16 usItem, UINT8 subObject = 0);
|
||||
OBJECTTYPE* FindAttachment( OBJECTTYPE * pObj, UINT16 usItem, UINT8 subObject = 0 );
|
||||
extern INT8 FindObjClass( SOLDIERTYPE * pSoldier, UINT32 usItemClass );
|
||||
extern INT8 FindAIUsableObjClass( SOLDIERTYPE * pSoldier, UINT32 usItemClass );
|
||||
extern INT8 FindAIUsableObjClassWithin( SOLDIERTYPE * pSoldier, UINT32 usItemClass, INT8 bLower, INT8 bUpper );
|
||||
extern INT8 FindEmptySlotWithin( SOLDIERTYPE * pSoldier, INT8 bLower, INT8 bUpper );
|
||||
extern INT8 FindObjInObjRange( SOLDIERTYPE * pSoldier, UINT16 usItem1, UINT16 usItem2 );
|
||||
extern INT8 FindLaunchable( SOLDIERTYPE * pSoldier, UINT16 usWeapon );
|
||||
extern INT8 FindGLGrenade( SOLDIERTYPE * pSoldier );
|
||||
extern INT8 FindThrowableGrenade( SOLDIERTYPE * pSoldier );
|
||||
extern INT8 FindUsableObj( SOLDIERTYPE * pSoldier, UINT16 usItem );
|
||||
INT16 FindAttachmentSlot(OBJECTTYPE* pObj, UINT16 usItem, UINT8 subObject = 0);
|
||||
OBJECTTYPE* FindAttachment(OBJECTTYPE * pObj, UINT16 usItem, UINT8 subObject = 0);
|
||||
extern INT8 FindObjClass(SOLDIERTYPE * pSoldier, UINT32 usItemClass);
|
||||
extern INT8 FindAIUsableObjClass(SOLDIERTYPE * pSoldier, UINT32 usItemClass, BOOLEAN fSidearm = FALSE);
|
||||
extern INT8 FindAIUsableObjClassWithin(SOLDIERTYPE * pSoldier, UINT32 usItemClass, INT8 bLower, INT8 bUpper);
|
||||
extern INT8 FindEmptySlotWithin(SOLDIERTYPE * pSoldier, INT8 bLower, INT8 bUpper);
|
||||
extern INT8 FindObjInObjRange(SOLDIERTYPE * pSoldier, UINT16 usItem1, UINT16 usItem2);
|
||||
extern INT8 FindLaunchable(SOLDIERTYPE * pSoldier, UINT16 usWeapon);
|
||||
extern INT8 FindGLGrenade(SOLDIERTYPE * pSoldier);
|
||||
extern INT8 FindThrowableGrenade(SOLDIERTYPE * pSoldier);
|
||||
extern INT8 FindUsableObj(SOLDIERTYPE * pSoldier, UINT16 usItem);
|
||||
|
||||
void DeleteObj(OBJECTTYPE * pObj );
|
||||
void SwapObjs( OBJECTTYPE * pObj1, OBJECTTYPE * pObj2 );
|
||||
|
||||
+22
-22
@@ -7364,6 +7364,7 @@ UINT32 AICalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTim
|
||||
// same as CCTHG but fakes the attacker always standing
|
||||
usTrueState = pSoldier->usAnimState;
|
||||
bTrueLevel = pSoldier->bTargetLevel;
|
||||
|
||||
pSoldier->bTargetLevel = bTargetLevel;
|
||||
pSoldier->usAnimState = usAnimState;
|
||||
if(Item[pSoldier->usAttackingWeapon].usItemClass & IC_THROWING_KNIFE)//dnl ch70 160913
|
||||
@@ -7373,18 +7374,11 @@ UINT32 AICalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTim
|
||||
else
|
||||
{
|
||||
uiChance = CalcChanceToHitGun(pSoldier, sGridNo, ubAimTime, ubAimPos);
|
||||
|
||||
// sevenfm: allow small CTH for AI for suppression fire
|
||||
if( gGameExternalOptions.fAIExtraSuppression &&
|
||||
pSoldier->aiData.bAlertStatus == STATUS_RED &&
|
||||
Weapon[ pSoldier->usAttackingWeapon ].bAutofireShotsPerFiveAP > 0 )
|
||||
{
|
||||
uiChance = __max(1, uiChance);
|
||||
}
|
||||
}
|
||||
pSoldier->usAnimState = usTrueState;
|
||||
pSoldier->bTargetLevel = bTrueLevel;
|
||||
if(UsingNewCTHSystem() == true && !(Item[pSoldier->usAttackingWeapon].usItemClass & IC_THROWING_KNIFE))//dnl ch70 160913
|
||||
|
||||
if(UsingNewCTHSystem() && !(Item[pSoldier->usAttackingWeapon].usItemClass & IC_THROWING_KNIFE))//dnl ch70 160913
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
// HEADROCK HAM 4: NCTH calculation
|
||||
@@ -7468,11 +7462,7 @@ UINT32 AICalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTim
|
||||
// real aperture for shooter based on CTH calculation
|
||||
dAperture = dAperture * ( 100 - uiChance ) / 100.0f;
|
||||
|
||||
if (dAperture == 0)
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
else
|
||||
if(dAperture > 0)
|
||||
{
|
||||
// silversurfer: This cannot be correct. An aperture of 10 already gives a very good chance to hit. If we take this value and
|
||||
// calculate the target area it's PI * 10 * 10 which results in ~300 (rounded down) and not 28.26. This low number was the reason why AI
|
||||
@@ -7488,18 +7478,19 @@ UINT32 AICalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTim
|
||||
|
||||
uiChance = (UINT32)__min(100, (dTargetArea / dApertureArea) * 100);
|
||||
}
|
||||
FLOAT dGunRange;
|
||||
else
|
||||
{
|
||||
uiChance = 100;
|
||||
}
|
||||
|
||||
// Flugente: check for underbarrel weapons and use that object if necessary
|
||||
OBJECTTYPE* pObjAttHand = pSoldier->GetUsedWeapon( &(pSoldier->inv[pSoldier->ubAttackingHand]) );
|
||||
|
||||
dGunRange = (FLOAT)(GunRange( pObjAttHand, pSoldier ) );
|
||||
FLOAT dGunRange = (FLOAT)(GunRange(pObjAttHand, pSoldier));
|
||||
|
||||
FLOAT dMaxGunRange = dGunRange * gGameCTHConstants.MAX_EFFECTIVE_RANGE_MULTIPLIER;
|
||||
if ( dMaxGunRange < d2DDistance)
|
||||
{
|
||||
// Weapon out of conceivable hit range. Reduce chance to hit to 0!
|
||||
return (0);
|
||||
uiChance = 1; // sevenfm: set min CTH to 1% for AI
|
||||
}
|
||||
else if ( dGunRange < d2DDistance)
|
||||
{
|
||||
@@ -7508,15 +7499,24 @@ UINT32 AICalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTim
|
||||
if (gGameCTHConstants.MAX_EFFECTIVE_USE_GRADIENT)
|
||||
{
|
||||
// Just outside range. Reduce considerably!
|
||||
return min(uiChance, (UINT)(dChance - (dMaxChanceReduction * ((d2DDistance - dGunRange) / (dMaxGunRange - dGunRange)))));
|
||||
uiChance = min(uiChance, (UINT32)(dChance - (dMaxChanceReduction * ((d2DDistance - dGunRange) / (dMaxGunRange - dGunRange)))));
|
||||
}
|
||||
else
|
||||
{
|
||||
return (UINT)(dChance - dMaxChanceReduction);
|
||||
uiChance = (UINT32)(dChance - dMaxChanceReduction);
|
||||
}
|
||||
}
|
||||
}
|
||||
return( uiChance );
|
||||
|
||||
if (gGameExternalOptions.fAIExtraSuppression)
|
||||
{
|
||||
// sevenfm: always min 1% for AI to shoot
|
||||
return max(1, uiChance);
|
||||
}
|
||||
else
|
||||
{
|
||||
return uiChance;
|
||||
}
|
||||
}
|
||||
|
||||
INT32 CalcBodyImpactReduction( UINT8 ubAmmoType, UINT8 ubHitLocation )
|
||||
|
||||
@@ -187,7 +187,7 @@ typedef enum
|
||||
INT16 AdvanceToFiringRange( SOLDIERTYPE * pSoldier, INT16 sClosestOpponent );
|
||||
|
||||
BOOLEAN AimingGun(SOLDIERTYPE *pSoldier);
|
||||
void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUnseen);
|
||||
void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot);
|
||||
void CalcBestStab(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestStab, BOOLEAN fBladeAttack);
|
||||
void CalcBestThrow(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestThrow);
|
||||
void CalcTentacleAttack(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestStab );
|
||||
@@ -266,7 +266,7 @@ INT32 FindNearbyDarkerSpot( SOLDIERTYPE *pSoldier );
|
||||
|
||||
BOOLEAN ArmySeesOpponents( void );
|
||||
|
||||
void CheckIfShotPossible(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN suppressionFire);
|
||||
void CheckIfShotPossible(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot);
|
||||
|
||||
INT32 FindBestCoverNearTheGridNo(SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubSearchRadius );
|
||||
|
||||
|
||||
+25
-8
@@ -3104,21 +3104,38 @@ INT32 RangeChangeDesire( SOLDIERTYPE * pSoldier )
|
||||
INT32 iRangeFactorMultiplier;
|
||||
|
||||
iRangeFactorMultiplier = pSoldier->aiData.bAIMorale - 1;
|
||||
|
||||
// civilians only run away
|
||||
if (pSoldier->aiData.bNeutral)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (pSoldier->aiData.bAttitude)
|
||||
{
|
||||
case DEFENSIVE: iRangeFactorMultiplier += -1; break;
|
||||
case BRAVESOLO: iRangeFactorMultiplier += 2; break;
|
||||
case BRAVEAID: iRangeFactorMultiplier += 2; break;
|
||||
case CUNNINGSOLO: iRangeFactorMultiplier += 0; break;
|
||||
case CUNNINGAID: iRangeFactorMultiplier += 0; break;
|
||||
case ATTACKSLAYONLY:
|
||||
case AGGRESSIVE: iRangeFactorMultiplier += 1; break;
|
||||
case DEFENSIVE: iRangeFactorMultiplier += -1; break;
|
||||
case BRAVESOLO: iRangeFactorMultiplier += 2; break;
|
||||
case BRAVEAID: iRangeFactorMultiplier += 2; break;
|
||||
case CUNNINGSOLO: iRangeFactorMultiplier += 0; break;
|
||||
case CUNNINGAID: iRangeFactorMultiplier += 0; break;
|
||||
case ATTACKSLAYONLY:
|
||||
case AGGRESSIVE: iRangeFactorMultiplier += 1; break;
|
||||
}
|
||||
|
||||
if(IS_MERC_BODY_TYPE(pSoldier))
|
||||
{
|
||||
if (!AICheckHasGun(pSoldier))
|
||||
iRangeFactorMultiplier += 2; // if we have no weapons, try to get closer to enemy
|
||||
else if (GuySawEnemy(pSoldier, SEEN_LAST_TURN) && AICheckShortWeaponRange(pSoldier))
|
||||
iRangeFactorMultiplier += 1; // bonus if weapon range is short
|
||||
}
|
||||
|
||||
if ( gTacticalStatus.bConsNumTurnsWeHaventSeenButEnemyDoes > 0 )
|
||||
{
|
||||
iRangeFactorMultiplier += gTacticalStatus.bConsNumTurnsWeHaventSeenButEnemyDoes;
|
||||
}
|
||||
return( iRangeFactorMultiplier );
|
||||
|
||||
return iRangeFactorMultiplier;
|
||||
}
|
||||
|
||||
BOOLEAN ArmySeesOpponents( void )
|
||||
|
||||
+76
-237
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1149,7 +1149,7 @@ INT8 CreatureDecideActionBlack( SOLDIERTYPE * pSoldier )
|
||||
if (pSoldier->bActionPoints >= ubMinAPCost)
|
||||
{
|
||||
// look around for a worthy target (which sets BestShot.ubPossible)
|
||||
CalcBestShot(pSoldier,&BestShot,FALSE);
|
||||
CalcBestShot(pSoldier,&BestShot);
|
||||
|
||||
if (BestShot.ubPossible)
|
||||
{
|
||||
|
||||
+44
-308
@@ -1621,14 +1621,9 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier)
|
||||
if (TileIsOutOfBounds(sNoiseGridNo))
|
||||
{
|
||||
// then we have no business being under YELLOW status any more!
|
||||
#ifdef RECORDNET
|
||||
fprintf(NetDebugFile,"\nDecideActionYellow: ERROR - No important noise known by guynum %d\n\n",pSoldier->ubID);
|
||||
#endif
|
||||
|
||||
#ifdef BETAVERSION
|
||||
NumMessage("DecideActionYellow: ERROR - No important noise known by guynum ",pSoldier->ubID);
|
||||
#endif
|
||||
|
||||
return(AI_ACTION_NONE);
|
||||
}
|
||||
|
||||
@@ -2349,14 +2344,9 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier)
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
if ((INT16)PreRandom(100) < 50 )
|
||||
{
|
||||
#ifdef RECORDNET
|
||||
fprintf(NetDebugFile,"\tDecideActionYellow: guynum %d ignores noise, switching to GREEN AI...\n",pSoldier->ubID);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUGDECISIONS
|
||||
AINameMessage(pSoldier,"ignores noise completely and BYPASSES to GREEN!",1000);
|
||||
#endif
|
||||
|
||||
// Skip YELLOW until new situation, 15% extra chance to do GREEN actions
|
||||
pSoldier->aiData.bBypassToGreen = 15;
|
||||
return(DecideActionGreen(pSoldier));
|
||||
@@ -2757,13 +2747,8 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier)
|
||||
}
|
||||
}
|
||||
|
||||
//}//hayden
|
||||
|
||||
|
||||
|
||||
|
||||
// SNIPER!
|
||||
CheckIfShotPossible(pSoldier,&BestShot,FALSE);
|
||||
CheckIfShotPossible(pSoldier, &BestShot);
|
||||
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("decideactionred: is sniper shot possible? = %d, CTH = %d",BestShot.ubPossible,BestShot.ubChanceToReallyHit));
|
||||
|
||||
if (BestShot.ubPossible && BestShot.ubChanceToReallyHit > 50 )
|
||||
@@ -2875,7 +2860,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier)
|
||||
}
|
||||
|
||||
//SUPPRESSION FIRE
|
||||
CheckIfShotPossible(pSoldier,&BestShot,TRUE); //WarmSteel - No longer returns 0 when there IS actually a chance to hit.
|
||||
CheckIfShotPossible(pSoldier,&BestShot); //WarmSteel - No longer returns 0 when there IS actually a chance to hit.
|
||||
|
||||
// sevenfm: check that we have a clip to reload
|
||||
BOOLEAN fExtraClip = FALSE;
|
||||
@@ -4352,14 +4337,9 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier)
|
||||
pSoldier->bBleeding = __max( 0, pSoldier->bBleeding - (pSoldier->bActionPoints/2) );
|
||||
return( AI_ACTION_NONE ); // will end-turn/wait depending on whether we're in TB or realtime
|
||||
}
|
||||
#ifdef RECORDNET
|
||||
fprintf(NetDebugFile,"\tDecideActionRed: guynum %d switching to GREEN AI...\n",pSoldier->ubID);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUGDECISIONS
|
||||
AINameMessage(pSoldier,"- chose to SKIP all RED actions, BYPASSES to GREEN!",1000);
|
||||
#endif
|
||||
|
||||
// Skip RED until new situation/next turn, 30% extra chance to do GREEN actions
|
||||
pSoldier->aiData.bBypassToGreen = 30;
|
||||
return(DecideActionGreen(pSoldier));
|
||||
@@ -5004,7 +4984,6 @@ INT16 ubMinAPCost;
|
||||
|
||||
BestAttack.ubChanceToReallyHit = 0;
|
||||
|
||||
|
||||
// if we are able attack
|
||||
if (bCanAttack)
|
||||
{
|
||||
@@ -5015,111 +4994,49 @@ INT16 ubMinAPCost;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"FIRE A GUN AT AN OPPONENT");
|
||||
|
||||
bWeaponIn = FindAIUsableObjClass( pSoldier, IC_GUN );
|
||||
CheckIfShotPossible(pSoldier, &BestShot);
|
||||
|
||||
if (bWeaponIn != NO_SLOT)
|
||||
if (BestShot.ubFriendlyFireChance) //dnl ch61 180813
|
||||
{
|
||||
BestShot.bWeaponIn = bWeaponIn;
|
||||
// if it's in another pocket, swap it into his hand temporarily
|
||||
if (bWeaponIn != HANDPOS)
|
||||
// determine chance to shoot
|
||||
INT32 iChanceToShoot;
|
||||
|
||||
iChanceToShoot = 100 - BestShot.ubFriendlyFireChance;
|
||||
iChanceToShoot = iChanceToShoot * iChanceToShoot / 100;
|
||||
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("Friendly fire chance %d, chance to shoot %d", BestShot.ubFriendlyFireChance, iChanceToShoot));
|
||||
|
||||
if (Chance(100 - iChanceToShoot))
|
||||
{
|
||||
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionblack: swap gun into hand");
|
||||
RearrangePocket(pSoldier,HANDPOS,bWeaponIn,TEMPORARILY);
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("Friendly fire check failed, skip shooting!"));
|
||||
BestShot.ubPossible = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (BestShot.ubPossible)
|
||||
{
|
||||
// if the selected opponent is not a threat (unconscious & !serviced)
|
||||
// (usually, this means all the guys we see are unconscious, but, on
|
||||
// rare occasions, we may not be able to shoot a healthy guy, too)
|
||||
if ((Menptr[BestShot.ubOpponent].stats.bLife < OKLIFE) &&
|
||||
!Menptr[BestShot.ubOpponent].bService &&
|
||||
(pSoldier->aiData.bAttitude != AGGRESSIVE || Chance((100 - BestShot.ubChanceToReallyHit) / 2)))
|
||||
{
|
||||
// get the location of the closest CONSCIOUS reachable opponent
|
||||
sClosestDisturbance = ClosestReachableDisturbance(pSoldier, &fClimb);
|
||||
|
||||
// if we found one
|
||||
if (!TileIsOutOfBounds(sClosestDisturbance))
|
||||
{
|
||||
// then make decision as if at alert status RED
|
||||
return DecideActionRed(pSoldier);
|
||||
}
|
||||
// else kill the guy, he could be the last opponent alive in this sector
|
||||
}
|
||||
|
||||
// now it better be a gun, or the guy can't shoot (but has other attack(s))
|
||||
if (Item[pSoldier->inv[HANDPOS].usItem].usItemClass == IC_GUN && pSoldier->inv[HANDPOS][0]->data.gun.bGunStatus >= USABLE)
|
||||
{
|
||||
// get the minimum cost to attack the same target with this gun
|
||||
ubMinAPCost = MinAPsToAttack(pSoldier,pSoldier->sLastTarget,ADDTURNCOST,0);
|
||||
|
||||
// if we have enough action points to shoot with this gun
|
||||
if (pSoldier->bActionPoints >= ubMinAPCost)
|
||||
{
|
||||
// look around for a worthy target (which sets BestShot.ubPossible)
|
||||
BOOLEAN shootUnseen = FALSE;
|
||||
///ddd
|
||||
//if (gGameOptions.ubDifficultyLevel > DIF_LEVEL_MEDIUM ) //comm by ddd
|
||||
if (gGameOptions.ubDifficultyLevel > DIF_LEVEL_MEDIUM || gGameExternalOptions.bNewTacticalAIBehavior)
|
||||
shootUnseen = TRUE;
|
||||
|
||||
CalcBestShot(pSoldier,&BestShot,shootUnseen);
|
||||
|
||||
if (pSoldier->bTeam == gbPlayerNum && pSoldier->aiData.bRTPCombat == RTP_COMBAT_CONSERVE)
|
||||
{
|
||||
if (BestShot.ubChanceToReallyHit < 30)
|
||||
{
|
||||
// skip firing, our chance isn't good enough
|
||||
BestShot.ubPossible = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if(BestShot.ubFriendlyFireChance)//dnl ch61 180813
|
||||
{
|
||||
iChance = 0;
|
||||
if(BestShot.ubFriendlyFireChance == 100)
|
||||
{
|
||||
if(pSoldier->aiData.bAttitude == AGGRESSIVE)
|
||||
iChance = 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(pSoldier->aiData.bAttitude)
|
||||
{
|
||||
case DEFENSIVE:iChance = 15;break;
|
||||
case BRAVESOLO:iChance = 25;break;
|
||||
case BRAVEAID:iChance = 20;break;
|
||||
case CUNNINGSOLO:iChance = 35;break;
|
||||
case CUNNINGAID:iChance = 30;break;
|
||||
case AGGRESSIVE:iChance = 45;break;
|
||||
case ATTACKSLAYONLY:iChance = 40;break;
|
||||
default:iChance = 10;break;
|
||||
}
|
||||
}
|
||||
if(!((INT32)Random(100) < iChance))
|
||||
BestShot.ubPossible = FALSE;
|
||||
}
|
||||
|
||||
if (BestShot.ubPossible)
|
||||
{
|
||||
// if the selected opponent is not a threat (unconscious & !serviced)
|
||||
// (usually, this means all the guys we see are unconscious, but, on
|
||||
// rare occasions, we may not be able to shoot a healthy guy, too)
|
||||
if ((Menptr[BestShot.ubOpponent].stats.bLife < OKLIFE) &&
|
||||
!Menptr[BestShot.ubOpponent].bService &&
|
||||
(pSoldier->aiData.bAttitude != AGGRESSIVE || Chance((100 - BestShot.ubChanceToReallyHit) / 2)))
|
||||
{
|
||||
// get the location of the closest CONSCIOUS reachable opponent
|
||||
sClosestDisturbance = ClosestReachableDisturbance(pSoldier, &fClimb);
|
||||
|
||||
// if we found one
|
||||
if (!TileIsOutOfBounds(sClosestDisturbance))
|
||||
{
|
||||
// don't bother checking GRENADES/KNIVES, he can't have conscious targets
|
||||
#ifdef RECORDNET
|
||||
fprintf(NetDebugFile,"\tDecideActionBlack: all visible opponents unconscious, switching to RED AI...\n");
|
||||
#endif
|
||||
// then make decision as if at alert status RED
|
||||
return DecideActionRed(pSoldier);
|
||||
}
|
||||
// else kill the guy, he could be the last opponent alive in this sector
|
||||
}
|
||||
|
||||
// now we KNOW FOR SURE that we will do something (shoot, at least)
|
||||
NPCDoesAct(pSoldier);
|
||||
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"NPC decided to shoot (or something)");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// if it was in his holster, swap it back into his holster for now
|
||||
if (bWeaponIn != HANDPOS)
|
||||
{
|
||||
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionblack: swap gun into holster");
|
||||
RearrangePocket(pSoldier,HANDPOS,bWeaponIn,TEMPORARILY);
|
||||
}
|
||||
|
||||
}
|
||||
// now we KNOW FOR SURE that we will do something (shoot, at least)
|
||||
NPCDoesAct(pSoldier);
|
||||
DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "NPC decided to shoot (or something)");
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -5207,7 +5124,7 @@ INT16 ubMinAPCost;
|
||||
// throwing knife code works like shooting
|
||||
|
||||
// look around for a worthy target (which sets BestStab.ubPossible)
|
||||
CalcBestShot(pSoldier,&BestStab,FALSE);
|
||||
CalcBestShot(pSoldier,&BestStab);
|
||||
|
||||
if (BestStab.ubPossible)
|
||||
{
|
||||
@@ -5631,83 +5548,6 @@ INT16 ubMinAPCost;
|
||||
|
||||
if (ubBestAttackAction == AI_ACTION_FIRE_GUN)
|
||||
{
|
||||
#ifndef dnlCALCBESTSHOT//dnl ch69 140913
|
||||
// Do we need to change stance? NB We'll have to ready our gun again
|
||||
if ( !ARMED_VEHICLE( pSoldier ) && ( pSoldier->bActionPoints >= BestAttack.ubAPCost + GetAPsCrouch( pSoldier, TRUE) + MinAPsToAttack( pSoldier, BestAttack.sTarget, ADDTURNCOST,0, 1 ) ) )
|
||||
{
|
||||
// since the AI considers shooting chance from standing primarily, if we are not
|
||||
// standing we should always consider a stance change
|
||||
if ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_STAND )
|
||||
{
|
||||
iChance = 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
iChance = 50;
|
||||
switch (pSoldier->aiData.bAttitude)
|
||||
{
|
||||
case DEFENSIVE: iChance += 20; break;
|
||||
case BRAVESOLO: iChance -= 10; break;
|
||||
case BRAVEAID: iChance -= 10; break;
|
||||
case CUNNINGSOLO: iChance += 10; break;
|
||||
case CUNNINGAID: iChance += 10; break;
|
||||
case AGGRESSIVE: iChance -= 20; break;
|
||||
case ATTACKSLAYONLY: iChance -= 30; break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( (INT32)PreRandom( 100 ) < iChance || GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, BestAttack.sTarget ) <= MIN_PRONE_RANGE )
|
||||
{
|
||||
|
||||
// first get the direction, as we will need to pass that in to ShootingStanceChange
|
||||
bDirection = atan8(CenterX(pSoldier->sGridNo),CenterY(pSoldier->sGridNo),CenterX(BestAttack.sTarget),CenterY(BestAttack.sTarget));
|
||||
|
||||
ubBestStance = ShootingStanceChange( pSoldier, &BestAttack, bDirection );
|
||||
if (ubBestStance != 0)
|
||||
{
|
||||
// change stance first!
|
||||
if ( pSoldier->ubDirection != bDirection && pSoldier->InternalIsValidStance( bDirection, gAnimControl[ pSoldier->usAnimState ].ubEndHeight ) )
|
||||
{
|
||||
// we're not facing towards him, so turn first!
|
||||
pSoldier->aiData.usActionData = bDirection;
|
||||
|
||||
#ifdef DEBUGDECISIONS
|
||||
sprintf(tempstr,"%s - TURNS to face CLOSEST OPPONENT in direction %d",pSoldier->name,pSoldier->aiData.usActionData);
|
||||
AIPopMessage(tempstr);
|
||||
#endif
|
||||
|
||||
return(AI_ACTION_CHANGE_FACING);
|
||||
}
|
||||
|
||||
// pSoldier->aiData.usActionData = ubBestStance;
|
||||
|
||||
// attack after we change stance
|
||||
// we don't just return here because we want to check whether to
|
||||
// burst first
|
||||
fChangeStanceFirst = TRUE;
|
||||
|
||||
// account for increased AP cost and having to re-ready weapon
|
||||
ubStanceCost = (UINT8) GetAPsToChangeStance( pSoldier, ubBestStance );
|
||||
BestAttack.ubAPCost = MinAPsToAttack( pSoldier, BestAttack.sTarget, ADDTURNCOST, 0, 1) + ubStanceCost;
|
||||
|
||||
// Clip the aim time if necessary
|
||||
// HEADROCK HAM 3.6: Use Actual Aiming Costs, without assuming that each aim level = 1 AP.
|
||||
if ( BestAttack.ubAPCost + sActualAimTime > pSoldier->bActionPoints )
|
||||
{
|
||||
// AP cost would balance (plus X, minus X) but aim time is reduced
|
||||
// HEADROCK HAM 3.6: Use actual Aiming Costs.
|
||||
BestAttack.ubAimTime = CalcAimingLevelsAvailableWithAP( pSoldier, BestAttack.sTarget, (pSoldier->bActionPoints - BestAttack.ubAPCost - ubStanceCost) );
|
||||
if (BestAttack.ubAimTime < 0 )
|
||||
{
|
||||
// This is actually a logic error situation. The ChangeStance section is supposed
|
||||
// to not make a shot impossible after changing stance.
|
||||
BestAttack.ubPossible = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
if ( gGameExternalOptions.fEnemyTanksCanMoveInTactical || !ARMED_VEHICLE( pSoldier ) )
|
||||
{
|
||||
// first get the direction, as we will need to pass that in to ShootingStanceChange
|
||||
@@ -5744,7 +5584,6 @@ INT16 ubMinAPCost;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// IF ENOUGH APs TO BURST, RANDOM CHANCE OF DOING SO
|
||||
@@ -7191,14 +7030,9 @@ INT8 ArmedVehicleDecideActionYellow( SOLDIERTYPE *pSoldier )
|
||||
if ( TileIsOutOfBounds( sNoiseGridNo ) )
|
||||
{
|
||||
// then we have no business being under YELLOW status any more!
|
||||
#ifdef RECORDNET
|
||||
fprintf( NetDebugFile, "\ArmedVehicleDecideActionYellow: ERROR - No important noise known by guynum %d\n\n", pSoldier->ubID );
|
||||
#endif
|
||||
|
||||
#ifdef BETAVERSION
|
||||
NumMessage( "ArmedVehicleDecideActionYellow: ERROR - No important noise known by guynum ", pSoldier->ubID );
|
||||
#endif
|
||||
|
||||
return(AI_ACTION_NONE);
|
||||
}
|
||||
|
||||
@@ -7644,14 +7478,9 @@ INT8 ArmedVehicleDecideActionYellow( SOLDIERTYPE *pSoldier )
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
if ( (INT16)PreRandom( 100 ) < 50 )
|
||||
{
|
||||
#ifdef RECORDNET
|
||||
fprintf( NetDebugFile, "\tDecideActionYellow: guynum %d ignores noise, switching to GREEN AI...\n", pSoldier->ubID );
|
||||
#endif
|
||||
|
||||
#ifdef DEBUGDECISIONS
|
||||
AINameMessage( pSoldier, "ignores noise completely and BYPASSES to GREEN!", 1000 );
|
||||
#endif
|
||||
|
||||
// Skip YELLOW until new situation, 15% extra chance to do GREEN actions
|
||||
pSoldier->aiData.bBypassToGreen = 15;
|
||||
return(ArmedVehicleDecideActionGreen( pSoldier ));
|
||||
@@ -7808,7 +7637,7 @@ INT8 ArmedVehicleDecideActionRed( SOLDIERTYPE *pSoldier)
|
||||
//}//hayden
|
||||
|
||||
// SNIPER!
|
||||
CheckIfShotPossible( pSoldier, &BestShot, FALSE );
|
||||
CheckIfShotPossible(pSoldier, &BestShot);
|
||||
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "ArmedVehicleDecideActionRed: is sniper shot possible? = %d, CTH = %d", BestShot.ubPossible, BestShot.ubChanceToReallyHit ) );
|
||||
|
||||
if ( BestShot.ubPossible && BestShot.ubChanceToReallyHit > 50 )
|
||||
@@ -7882,7 +7711,7 @@ INT8 ArmedVehicleDecideActionRed( SOLDIERTYPE *pSoldier)
|
||||
}
|
||||
|
||||
//SUPPRESSION FIRE
|
||||
CheckIfShotPossible( pSoldier, &BestShot, TRUE ); //WarmSteel - No longer returns 0 when there IS actually a chance to hit.
|
||||
CheckIfShotPossible(pSoldier, &BestShot); //WarmSteel - No longer returns 0 when there IS actually a chance to hit.
|
||||
|
||||
// sevenfm: check that we have a clip to reload
|
||||
BOOLEAN fExtraClip = FALSE;
|
||||
@@ -8795,14 +8624,9 @@ INT8 ArmedVehicleDecideActionRed( SOLDIERTYPE *pSoldier)
|
||||
// if not in combat or under fire, and we COULD have moved, just chose not to
|
||||
if ( (pSoldier->aiData.bAlertStatus != STATUS_BLACK) && !pSoldier->aiData.bUnderFire && ubCanMove && (!gfTurnBasedAI || pSoldier->bActionPoints >= pSoldier->bInitialActionPoints) && (TileIsOutOfBounds( ClosestReachableDisturbance( pSoldier, &fClimb ) )) )
|
||||
{
|
||||
#ifdef RECORDNET
|
||||
fprintf( NetDebugFile, "\tArmedVehicleDecideActionRed: guynum %d switching to GREEN AI...\n", pSoldier->ubID );
|
||||
#endif
|
||||
|
||||
#ifdef DEBUGDECISIONS
|
||||
AINameMessage( pSoldier, "- chose to SKIP all RED actions, BYPASSES to GREEN!", 1000 );
|
||||
#endif
|
||||
|
||||
// Skip RED until new situation/next turn, 30% extra chance to do GREEN actions
|
||||
pSoldier->aiData.bBypassToGreen = 30;
|
||||
return(ArmedVehicleDecideActionGreen( pSoldier ));
|
||||
@@ -9045,13 +8869,7 @@ INT8 ArmedVehicleDecideActionBlack( SOLDIERTYPE *pSoldier )
|
||||
if ( pSoldier->bActionPoints >= ubMinAPCost )
|
||||
{
|
||||
// look around for a worthy target (which sets BestShot.ubPossible)
|
||||
BOOLEAN shootUnseen = FALSE;
|
||||
///ddd
|
||||
//if (gGameOptions.ubDifficultyLevel > DIF_LEVEL_MEDIUM ) //comm by ddd
|
||||
if ( gGameOptions.ubDifficultyLevel > DIF_LEVEL_MEDIUM || gGameExternalOptions.bNewTacticalAIBehavior )
|
||||
shootUnseen = TRUE;
|
||||
|
||||
CalcBestShot( pSoldier, &BestShot, shootUnseen );
|
||||
CalcBestShot(pSoldier, &BestShot);
|
||||
|
||||
if ( pSoldier->bTeam == gbPlayerNum && pSoldier->aiData.bRTPCombat == RTP_COMBAT_CONSERVE )
|
||||
{
|
||||
@@ -9105,10 +8923,6 @@ INT8 ArmedVehicleDecideActionBlack( SOLDIERTYPE *pSoldier )
|
||||
// if we found one
|
||||
if ( !TileIsOutOfBounds( sClosestDisturbance ) )
|
||||
{
|
||||
// don't bother checking GRENADES/KNIVES, he can't have conscious targets
|
||||
#ifdef RECORDNET
|
||||
fprintf( NetDebugFile, "\ArmedVehicleDecideActionBlack: all visible opponents unconscious, switching to RED AI...\n" );
|
||||
#endif
|
||||
// then make decision as if at alert status RED, but make sure
|
||||
// we don't try to SEEK OPPONENT the unconscious guy!
|
||||
return DecideActionRed(pSoldier);
|
||||
@@ -9363,83 +9177,6 @@ INT8 ArmedVehicleDecideActionBlack( SOLDIERTYPE *pSoldier )
|
||||
|
||||
if ( ubBestAttackAction == AI_ACTION_FIRE_GUN )
|
||||
{
|
||||
#ifndef dnlCALCBESTSHOT//dnl ch69 140913
|
||||
// Do we need to change stance? NB We'll have to ready our gun again
|
||||
if ( !ARMED_VEHICLE( pSoldier ) && (pSoldier->bActionPoints >= BestAttack.ubAPCost + GetAPsCrouch( pSoldier, TRUE ) + MinAPsToAttack( pSoldier, BestAttack.sTarget, ADDTURNCOST, 0, 1 )) )
|
||||
{
|
||||
// since the AI considers shooting chance from standing primarily, if we are not
|
||||
// standing we should always consider a stance change
|
||||
if ( gAnimControl[pSoldier->usAnimState].ubEndHeight != ANIM_STAND )
|
||||
{
|
||||
iChance = 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
iChance = 50;
|
||||
switch ( pSoldier->aiData.bAttitude )
|
||||
{
|
||||
case DEFENSIVE: iChance += 20; break;
|
||||
case BRAVESOLO: iChance -= 10; break;
|
||||
case BRAVEAID: iChance -= 10; break;
|
||||
case CUNNINGSOLO: iChance += 10; break;
|
||||
case CUNNINGAID: iChance += 10; break;
|
||||
case AGGRESSIVE: iChance -= 20; break;
|
||||
case ATTACKSLAYONLY: iChance -= 30; break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( (INT32)PreRandom( 100 ) < iChance || GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, BestAttack.sTarget ) <= MIN_PRONE_RANGE )
|
||||
{
|
||||
|
||||
// first get the direction, as we will need to pass that in to ShootingStanceChange
|
||||
bDirection = atan8( CenterX( pSoldier->sGridNo ), CenterY( pSoldier->sGridNo ), CenterX( BestAttack.sTarget ), CenterY( BestAttack.sTarget ) );
|
||||
|
||||
ubBestStance = ShootingStanceChange( pSoldier, &BestAttack, bDirection );
|
||||
if ( ubBestStance != 0 )
|
||||
{
|
||||
// change stance first!
|
||||
if ( pSoldier->ubDirection != bDirection && pSoldier->InternalIsValidStance( bDirection, gAnimControl[pSoldier->usAnimState].ubEndHeight ) )
|
||||
{
|
||||
// we're not facing towards him, so turn first!
|
||||
pSoldier->aiData.usActionData = bDirection;
|
||||
|
||||
#ifdef DEBUGDECISIONS
|
||||
sprintf( tempstr, "%s - TURNS to face CLOSEST OPPONENT in direction %d", pSoldier->name, pSoldier->aiData.usActionData );
|
||||
AIPopMessage( tempstr );
|
||||
#endif
|
||||
|
||||
return(AI_ACTION_CHANGE_FACING);
|
||||
}
|
||||
|
||||
// pSoldier->aiData.usActionData = ubBestStance;
|
||||
|
||||
// attack after we change stance
|
||||
// we don't just return here because we want to check whether to
|
||||
// burst first
|
||||
fChangeStanceFirst = TRUE;
|
||||
|
||||
// account for increased AP cost and having to re-ready weapon
|
||||
ubStanceCost = (UINT8)GetAPsToChangeStance( pSoldier, ubBestStance );
|
||||
BestAttack.ubAPCost = MinAPsToAttack( pSoldier, BestAttack.sTarget, ADDTURNCOST, 0, 1 ) + ubStanceCost;
|
||||
|
||||
// Clip the aim time if necessary
|
||||
// HEADROCK HAM 3.6: Use Actual Aiming Costs, without assuming that each aim level = 1 AP.
|
||||
if ( BestAttack.ubAPCost + sActualAimTime > pSoldier->bActionPoints )
|
||||
{
|
||||
// AP cost would balance (plus X, minus X) but aim time is reduced
|
||||
// HEADROCK HAM 3.6: Use actual Aiming Costs.
|
||||
BestAttack.ubAimTime = CalcAimingLevelsAvailableWithAP( pSoldier, BestAttack.sTarget, (pSoldier->bActionPoints - BestAttack.ubAPCost - ubStanceCost) );
|
||||
if ( BestAttack.ubAimTime < 0 )
|
||||
{
|
||||
// This is actually a logic error situation. The ChangeStance section is supposed
|
||||
// to not make a shot impossible after changing stance.
|
||||
BestAttack.ubPossible = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
if ( gGameExternalOptions.fEnemyTanksCanMoveInTactical )
|
||||
{
|
||||
// first get the direction, as we will need to pass that in to ShootingStanceChange
|
||||
@@ -9453,7 +9190,6 @@ INT8 ArmedVehicleDecideActionBlack( SOLDIERTYPE *pSoldier )
|
||||
return(AI_ACTION_CHANGE_FACING);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// IF ENOUGH APs TO BURST, RANDOM CHANCE OF DOING SO
|
||||
|
||||
Reference in New Issue
Block a user