mirror of
https://github.com/1dot13/source.git
synced 2026-09-16 14:47:17 +02:00
Increased max possible soldiers stored for friendly fire check to 256.
Friendly fire chance code also checks for soldiers of the same side and optionally neutral civilians. CalcCoverValue: check friendly fire chance for each position, penalize position if friendly fire chance is high (needs AI_BETTER_COVER = TRUE) UnderFire::Add: - store friendly fire CTH for new added person - use max value when replacing friendly fire CTH for existing person CalcBestShot: - check CTGT and friendly fire chance for every stance - ignore possible shot if can hit friends in this stance CalcMoraleNew: improved code to make enemy slightly more aggressive. git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8873 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
@@ -285,7 +285,6 @@ static UINT32 guiStructureHitChance[ MAX_DIST_FOR_LESS_THAN_MAX_CHANCE_TO_HIT_ST
|
|||||||
|
|
||||||
#define MIN_DIST_FOR_HIT_FRIENDS 30
|
#define MIN_DIST_FOR_HIT_FRIENDS 30
|
||||||
#define MIN_DIST_FOR_HIT_FRIENDS_UNAIMED 15
|
#define MIN_DIST_FOR_HIT_FRIENDS_UNAIMED 15
|
||||||
#define MIN_CHANCE_TO_ACCIDENTALLY_HIT_SOMEONE 3
|
|
||||||
|
|
||||||
#define RADIANS_IN_CIRCLE 6.283
|
#define RADIANS_IN_CIRCLE 6.283
|
||||||
#define DEGREES_22_5 (RADIANS_IN_CIRCLE * 22.5 / 360)
|
#define DEGREES_22_5 (RADIANS_IN_CIRCLE * 22.5 / 360)
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ typedef INT64 FIXEDPT;
|
|||||||
// fixed-point arithmetic definitions end here
|
// fixed-point arithmetic definitions end here
|
||||||
|
|
||||||
#define OK_CHANCE_TO_GET_THROUGH 10
|
#define OK_CHANCE_TO_GET_THROUGH 10
|
||||||
|
#define MIN_CHANCE_TO_ACCIDENTALLY_HIT_SOMEONE 3
|
||||||
|
|
||||||
enum CollisionEnums
|
enum CollisionEnums
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -122,12 +122,12 @@
|
|||||||
#include "InterfaceItemImages.h" // added by Sevenfm
|
#include "InterfaceItemImages.h" // added by Sevenfm
|
||||||
#include "DynamicDialogueWidget.h" // added by Flugente for DelayBoxDestructionBy(...)
|
#include "DynamicDialogueWidget.h" // added by Flugente for DelayBoxDestructionBy(...)
|
||||||
#include "Utilities.h" // added by Flugente
|
#include "Utilities.h" // added by Flugente
|
||||||
|
#include "AIInternals.h" // sevenfm
|
||||||
|
|
||||||
//forward declarations of common classes to eliminate includes
|
//forward declarations of common classes to eliminate includes
|
||||||
class OBJECTTYPE;
|
class OBJECTTYPE;
|
||||||
class SOLDIERTYPE;
|
class SOLDIERTYPE;
|
||||||
|
|
||||||
|
|
||||||
extern UIKEYBOARD_HOOK gUIKeyboardHook;
|
extern UIKEYBOARD_HOOK gUIKeyboardHook;
|
||||||
extern BOOLEAN fRightButtonDown;
|
extern BOOLEAN fRightButtonDown;
|
||||||
extern BOOLEAN fLeftButtonDown;
|
extern BOOLEAN fLeftButtonDown;
|
||||||
@@ -3373,6 +3373,25 @@ void GetKeyboardInput( UINT32 *puiNewEvent )
|
|||||||
//Get the gridno the cursor is at
|
//Get the gridno the cursor is at
|
||||||
GetMouseMapPos( &usGridNo );
|
GetMouseMapPos( &usGridNo );
|
||||||
|
|
||||||
|
// code to test friendly fire detection
|
||||||
|
//if there is a selected soldier, and the cursor location is valid
|
||||||
|
/*if (gusSelectedSoldier != NOBODY && !TileIsOutOfBounds(usGridNo) && gfUIFullTargetFound)
|
||||||
|
{
|
||||||
|
SOLDIERTYPE *pSoldier = MercPtrs[gusSelectedSoldier];
|
||||||
|
SOLDIERTYPE *pOpponent = MercPtrs[gusUIFullTargetID];
|
||||||
|
UINT8 ubChanceToGetThrough;
|
||||||
|
|
||||||
|
if (pSoldier && pOpponent)
|
||||||
|
{
|
||||||
|
gUnderFire.Clear();
|
||||||
|
gUnderFire.Enable();
|
||||||
|
ubChanceToGetThrough = AISoldierToSoldierChanceToGetThrough(pSoldier, pOpponent);
|
||||||
|
gUnderFire.Disable();
|
||||||
|
|
||||||
|
ScreenMsg(FONT_ORANGE, MSG_INTERFACE, L"friendly fire chance %d count %d", gUnderFire.Chance(pSoldier->bTeam, pSoldier->bSide, TRUE), gUnderFire.Count(pSoldier->bTeam));
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
// if the cursor location is valid
|
// if the cursor location is valid
|
||||||
if ( !TileIsOutOfBounds(usGridNo) )
|
if ( !TileIsOutOfBounds(usGridNo) )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
//dnl ch61 180813
|
//dnl ch61 180813
|
||||||
#define MAXUNDERFIRE 100
|
#define MAXUNDERFIRE 256
|
||||||
class UnderFire
|
class UnderFire
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@@ -155,14 +155,14 @@ private:
|
|||||||
UINT16 usUnderFireID[MAXUNDERFIRE];
|
UINT16 usUnderFireID[MAXUNDERFIRE];
|
||||||
UINT8 ubUnderFireCTH[MAXUNDERFIRE];
|
UINT8 ubUnderFireCTH[MAXUNDERFIRE];
|
||||||
public:
|
public:
|
||||||
UnderFire(void){ Clear(); }
|
UnderFire(void){ Clear(); fEnable = FALSE; }
|
||||||
void Clear(void);
|
void Clear(void);
|
||||||
void Add(UINT16 usID, UINT8 ubCTH);
|
void Add(UINT16 usID, UINT8 ubCTH);
|
||||||
void Enable(void){ fEnable=TRUE; }
|
void Enable(void){ fEnable=TRUE; }
|
||||||
void Disable(void){ fEnable=FALSE; }
|
void Disable(void){ fEnable=FALSE; }
|
||||||
UINT16 GetUnderFireCnt(void){ return(usUnderFireCnt); }
|
UINT16 GetUnderFireCnt(void){ return(usUnderFireCnt); }
|
||||||
UINT16 Count(INT8 bTeam);
|
UINT16 Count(INT8 bTeam);
|
||||||
UINT8 Chance(INT8 bTeam);
|
UINT8 Chance(INT8 bTeam, INT8 bSide, BOOLEAN fCheckNeutral);
|
||||||
};
|
};
|
||||||
extern UnderFire gUnderFire;
|
extern UnderFire gUnderFire;
|
||||||
|
|
||||||
|
|||||||
@@ -3874,9 +3874,9 @@ INT8 CalcMoraleNew(SOLDIERTYPE *pSoldier)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// count friends that flank around the same spot
|
// count friends that flank around the same spot
|
||||||
if( CountFriendsFlankSameSpot( pSoldier ) > 0 )
|
if( CountFriendsFlankSameSpot( pSoldier ) == 0 )
|
||||||
{
|
{
|
||||||
bMoraleCategory --;
|
bMoraleCategory ++;
|
||||||
}
|
}
|
||||||
|
|
||||||
INT32 sClosestOpponent = ClosestKnownOpponent(pSoldier, NULL, NULL);
|
INT32 sClosestOpponent = ClosestKnownOpponent(pSoldier, NULL, NULL);
|
||||||
|
|||||||
+109
-57
@@ -170,7 +170,7 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot)
|
|||||||
UINT32 uiLoop;
|
UINT32 uiLoop;
|
||||||
INT32 iAttackValue, iThreatValue, iHitRate, iBestHitRate, iPercentBetter, iEstDamage, iTrueLastTarget;
|
INT32 iAttackValue, iThreatValue, iHitRate, iBestHitRate, iPercentBetter, iEstDamage, iTrueLastTarget;
|
||||||
UINT16 usTrueState, usTurningCost, usRaiseGunCost;
|
UINT16 usTrueState, usTurningCost, usRaiseGunCost;
|
||||||
INT16 ubAimTime, ubMinAPcost, ubRawAPCost, sBestAPcost, ubChanceToHit, ubBestAimTime, ubChanceToGetThrough, ubBestChanceToHit, sStanceAPcost;
|
INT16 ubAimTime, ubMinAPcost, ubRawAPCost, sBestAPcost, ubChanceToHit, ubBestAimTime, ubChanceToGetThrough, ubBestChanceToGetThrough, ubFriendlyFireChance, ubBestFriendlyFireChance, ubBestChanceToHit, sStanceAPcost;
|
||||||
BOOLEAN fAddingTurningCost, fAddingRaiseGunCost;
|
BOOLEAN fAddingTurningCost, fAddingRaiseGunCost;
|
||||||
UINT8 ubMaxPossibleAimTime, ubStance, ubBestStance, ubChanceToReallyHit;
|
UINT8 ubMaxPossibleAimTime, ubStance, ubBestStance, ubChanceToReallyHit;
|
||||||
INT8 bScopeMode;
|
INT8 bScopeMode;
|
||||||
@@ -178,7 +178,7 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot)
|
|||||||
|
|
||||||
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"CalcBestShot");
|
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"CalcBestShot");
|
||||||
|
|
||||||
ubBestChanceToHit = ubBestAimTime = ubChanceToHit = ubChanceToReallyHit = 0;
|
ubBestChanceToHit = ubBestAimTime = ubChanceToHit = ubBestChanceToGetThrough = ubBestFriendlyFireChance = ubChanceToReallyHit = 0;
|
||||||
|
|
||||||
// sevenfm: initialize
|
// sevenfm: initialize
|
||||||
pBestShot->ubPossible = FALSE;
|
pBestShot->ubPossible = FALSE;
|
||||||
@@ -243,22 +243,23 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot)
|
|||||||
if (ubMinAPcost > pSoldier->bActionPoints)
|
if (ubMinAPcost > pSoldier->bActionPoints)
|
||||||
continue; // next opponent
|
continue; // next opponent
|
||||||
|
|
||||||
//KeepInterfaceGoing();
|
// sevenfm: check CTGT and friendly fire for each stance instead since they can be different
|
||||||
|
|
||||||
// calculate chance to get through the opponent's cover (if any)
|
// calculate chance to get through the opponent's cover (if any)
|
||||||
//dnl ch61 180813
|
//dnl ch61 180813
|
||||||
gUnderFire.Clear();
|
/*gUnderFire.Clear();
|
||||||
gUnderFire.Enable();
|
gUnderFire.Enable();
|
||||||
ubChanceToGetThrough = AISoldierToSoldierChanceToGetThrough( pSoldier, pOpponent );
|
ubChanceToGetThrough = AISoldierToSoldierChanceToGetThrough( pSoldier, pOpponent );
|
||||||
|
ubFriendlyFireChance = gUnderFire.Chance(pSoldier->bTeam, pSoldier->bSide, TRUE);
|
||||||
gUnderFire.Disable();
|
gUnderFire.Disable();
|
||||||
// ubChanceToGetThrough = ChanceToGetThrough(pSoldier,pOpponent->sGridNo,NOTFAKE,ACTUAL,TESTWALLS,9999,M9PISTOL,NOT_FOR_LOS);
|
|
||||||
|
|
||||||
//NumMessage("Chance to get through = ",ubChanceToGetThrough);
|
|
||||||
|
|
||||||
// if we can't possibly get through all the cover
|
// if we can't possibly get through all the cover
|
||||||
if (ubChanceToGetThrough == 0)
|
if (ubChanceToGetThrough == 0)
|
||||||
continue; // next opponent
|
continue; // next opponent
|
||||||
|
|
||||||
|
// sevenfm: ignore opponent if we can hit friend
|
||||||
|
if (ubFriendlyFireChance > MIN_CHANCE_TO_ACCIDENTALLY_HIT_SOMEONE)
|
||||||
|
continue;*/
|
||||||
|
|
||||||
if ( (pSoldier->flags.uiStatusFlags & SOLDIER_MONSTER) && (pSoldier->ubBodyType != QUEENMONSTER ) )
|
if ( (pSoldier->flags.uiStatusFlags & SOLDIER_MONSTER) && (pSoldier->ubBodyType != QUEENMONSTER ) )
|
||||||
{
|
{
|
||||||
STRUCTURE_FILE_REF * pStructureFileRef;
|
STRUCTURE_FILE_REF * pStructureFileRef;
|
||||||
@@ -345,22 +346,38 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot)
|
|||||||
}
|
}
|
||||||
ubRawAPCost = MinAPsToShootOrStab(pSoldier, pOpponent->sGridNo, 0, FALSE, 2);
|
ubRawAPCost = MinAPsToShootOrStab(pSoldier, pOpponent->sGridNo, 0, FALSE, 2);
|
||||||
ubMinAPcost = ubRawAPCost + usTurningCost + sStanceAPcost + usRaiseGunCost;
|
ubMinAPcost = ubRawAPCost + usTurningCost + sStanceAPcost + usRaiseGunCost;
|
||||||
if(pSoldier->bActionPoints-ubMinAPcost >= 0)
|
if(pSoldier->bActionPoints - ubMinAPcost >= 0)
|
||||||
{
|
{
|
||||||
// calc next attack's minimum shooting cost (excludes readying & turning & raise gun)
|
// calc next attack's minimum shooting cost (excludes readying & turning & raise gun)
|
||||||
ubMaxPossibleAimTime = CalcAimingLevelsAvailableWithAP(pSoldier, pOpponent->sGridNo, pSoldier->bActionPoints-ubMinAPcost);
|
ubMaxPossibleAimTime = CalcAimingLevelsAvailableWithAP(pSoldier, pOpponent->sGridNo, pSoldier->bActionPoints-ubMinAPcost);
|
||||||
for(ubAimTime=APBPConstants[AP_MIN_AIM_ATTACK]; ubAimTime<=ubMaxPossibleAimTime; ubAimTime++)
|
|
||||||
|
// sevenfm: check CTGT and friendly fire chance for every stance
|
||||||
|
gUnderFire.Clear();
|
||||||
|
gUnderFire.Enable();
|
||||||
|
ubChanceToGetThrough = AISoldierToSoldierChanceToGetThrough(pSoldier, pOpponent);
|
||||||
|
ubFriendlyFireChance = gUnderFire.Chance(pSoldier->bTeam, pSoldier->bSide, TRUE);
|
||||||
|
gUnderFire.Disable();
|
||||||
|
|
||||||
|
// sevenfm: only use this stance if we can hit target and cannot hit friends
|
||||||
|
if (ubChanceToGetThrough > 0 && ubFriendlyFireChance <= MIN_CHANCE_TO_ACCIDENTALLY_HIT_SOMEONE)
|
||||||
{
|
{
|
||||||
ubChanceToHit = AICalcChanceToHitGun(pSoldier, pOpponent->sGridNo, ubAimTime, AIM_SHOT_TORSO, pOpponent->pathing.bLevel, STANDING);
|
for (ubAimTime = APBPConstants[AP_MIN_AIM_ATTACK]; ubAimTime <= ubMaxPossibleAimTime; ubAimTime++)
|
||||||
iHitRate = ((pSoldier->bActionPoints - (ubMinAPcost - ubRawAPCost)) * ubChanceToHit) / (ubRawAPCost + ubAimTime * APBPConstants[AP_CLICK_AIM]);
|
|
||||||
if(iHitRate > iBestHitRate || (Item[pSoldier->usAttackingWeapon].usItemClass & IC_THROWING_KNIFE) && ubChanceToHit > ubBestChanceToHit)// rather take best chance for throwing knives
|
|
||||||
{
|
{
|
||||||
iBestHitRate = iHitRate;
|
ubChanceToHit = AICalcChanceToHitGun(pSoldier, pOpponent->sGridNo, ubAimTime, AIM_SHOT_TORSO, pOpponent->pathing.bLevel, STANDING);
|
||||||
ubBestAimTime = ubAimTime;
|
iHitRate = ((pSoldier->bActionPoints - (ubMinAPcost - ubRawAPCost)) * ubChanceToHit) / (ubRawAPCost + ubAimTime * APBPConstants[AP_CLICK_AIM]);
|
||||||
ubBestChanceToHit = ubChanceToHit;
|
// sevenfm: take into account CTGT for every stance
|
||||||
bScopeMode = pSoldier->bScopeMode;
|
if (iHitRate * ubChanceToGetThrough > iBestHitRate * ubBestChanceToGetThrough ||
|
||||||
sBestAPcost = ubMinAPcost;
|
(Item[pSoldier->usAttackingWeapon].usItemClass & IC_THROWING_KNIFE) && ubChanceToHit > ubBestChanceToHit)// rather take best chance for throwing knives
|
||||||
ubBestStance = ubStance;
|
{
|
||||||
|
iBestHitRate = iHitRate;
|
||||||
|
ubBestAimTime = ubAimTime;
|
||||||
|
ubBestChanceToHit = ubChanceToHit;
|
||||||
|
ubBestChanceToGetThrough = ubChanceToGetThrough;
|
||||||
|
ubBestFriendlyFireChance = ubFriendlyFireChance;
|
||||||
|
bScopeMode = pSoldier->bScopeMode;
|
||||||
|
sBestAPcost = ubMinAPcost;
|
||||||
|
ubBestStance = ubStance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -395,21 +412,36 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot)
|
|||||||
ubRawAPCost = MinAPsToShootOrStab(pSoldier, pOpponent->sGridNo, 0, FALSE, 2);
|
ubRawAPCost = MinAPsToShootOrStab(pSoldier, pOpponent->sGridNo, 0, FALSE, 2);
|
||||||
ubMinAPcost = ubRawAPCost + usTurningCost + sStanceAPcost + usRaiseGunCost;
|
ubMinAPcost = ubRawAPCost + usTurningCost + sStanceAPcost + usRaiseGunCost;
|
||||||
|
|
||||||
if(pSoldier->bActionPoints-ubMinAPcost >= 0)
|
if(pSoldier->bActionPoints - ubMinAPcost >= 0)
|
||||||
{
|
{
|
||||||
ubMaxPossibleAimTime = CalcAimingLevelsAvailableWithAP(pSoldier, pOpponent->sGridNo, pSoldier->bActionPoints-ubMinAPcost);
|
ubMaxPossibleAimTime = CalcAimingLevelsAvailableWithAP(pSoldier, pOpponent->sGridNo, pSoldier->bActionPoints-ubMinAPcost);
|
||||||
for(ubAimTime=APBPConstants[AP_MIN_AIM_ATTACK]; ubAimTime<=ubMaxPossibleAimTime; ubAimTime++)
|
|
||||||
|
// sevenfm: check CTGT and friendly fire chance for every stance
|
||||||
|
gUnderFire.Clear();
|
||||||
|
gUnderFire.Enable();
|
||||||
|
ubChanceToGetThrough = AISoldierToSoldierChanceToGetThrough(pSoldier, pOpponent);
|
||||||
|
ubFriendlyFireChance = gUnderFire.Chance(pSoldier->bTeam, pSoldier->bSide, TRUE);
|
||||||
|
gUnderFire.Disable();
|
||||||
|
|
||||||
|
// sevenfm: only use this stance if we can hit target and cannot hit friends
|
||||||
|
if (ubChanceToGetThrough > 0 && ubFriendlyFireChance <= MIN_CHANCE_TO_ACCIDENTALLY_HIT_SOMEONE)
|
||||||
{
|
{
|
||||||
ubChanceToHit = AICalcChanceToHitGun(pSoldier, pOpponent->sGridNo, ubAimTime, AIM_SHOT_TORSO, pOpponent->pathing.bLevel, CROUCHING);
|
for (ubAimTime = APBPConstants[AP_MIN_AIM_ATTACK]; ubAimTime <= ubMaxPossibleAimTime; ubAimTime++)
|
||||||
iHitRate = ((pSoldier->bActionPoints - (ubMinAPcost - ubRawAPCost)) * ubChanceToHit) / (ubRawAPCost + ubAimTime * APBPConstants[AP_CLICK_AIM]);
|
|
||||||
if(iHitRate > iBestHitRate)
|
|
||||||
{
|
{
|
||||||
iBestHitRate = iHitRate;
|
ubChanceToHit = AICalcChanceToHitGun(pSoldier, pOpponent->sGridNo, ubAimTime, AIM_SHOT_TORSO, pOpponent->pathing.bLevel, CROUCHING);
|
||||||
ubBestAimTime = ubAimTime;
|
iHitRate = ((pSoldier->bActionPoints - (ubMinAPcost - ubRawAPCost)) * ubChanceToHit) / (ubRawAPCost + ubAimTime * APBPConstants[AP_CLICK_AIM]);
|
||||||
ubBestChanceToHit = ubChanceToHit;
|
// sevenfm: take into account CTGT for every stance
|
||||||
bScopeMode = pSoldier->bScopeMode;
|
if (iHitRate * ubChanceToGetThrough > iBestHitRate * ubBestChanceToGetThrough)
|
||||||
sBestAPcost = ubMinAPcost;
|
{
|
||||||
ubBestStance = ubStance;
|
iBestHitRate = iHitRate;
|
||||||
|
ubBestAimTime = ubAimTime;
|
||||||
|
ubBestChanceToHit = ubChanceToHit;
|
||||||
|
ubBestChanceToGetThrough = ubChanceToGetThrough;
|
||||||
|
ubBestFriendlyFireChance = ubFriendlyFireChance;
|
||||||
|
bScopeMode = pSoldier->bScopeMode;
|
||||||
|
sBestAPcost = ubMinAPcost;
|
||||||
|
ubBestStance = ubStance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -441,21 +473,36 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot)
|
|||||||
ubRawAPCost = MinAPsToShootOrStab(pSoldier, pOpponent->sGridNo, 0, FALSE, 2);
|
ubRawAPCost = MinAPsToShootOrStab(pSoldier, pOpponent->sGridNo, 0, FALSE, 2);
|
||||||
ubMinAPcost = ubRawAPCost + usTurningCost + sStanceAPcost + usRaiseGunCost;
|
ubMinAPcost = ubRawAPCost + usTurningCost + sStanceAPcost + usRaiseGunCost;
|
||||||
|
|
||||||
if(pSoldier->bActionPoints-ubMinAPcost >= 0)
|
if(pSoldier->bActionPoints - ubMinAPcost >= 0)
|
||||||
{
|
{
|
||||||
ubMaxPossibleAimTime = CalcAimingLevelsAvailableWithAP(pSoldier, pOpponent->sGridNo, pSoldier->bActionPoints-ubMinAPcost);
|
ubMaxPossibleAimTime = CalcAimingLevelsAvailableWithAP(pSoldier, pOpponent->sGridNo, pSoldier->bActionPoints-ubMinAPcost);
|
||||||
for(ubAimTime=APBPConstants[AP_MIN_AIM_ATTACK]; ubAimTime<=ubMaxPossibleAimTime; ubAimTime++)
|
|
||||||
|
// sevenfm: check CTGT and friendly fire chance for every stance
|
||||||
|
gUnderFire.Clear();
|
||||||
|
gUnderFire.Enable();
|
||||||
|
ubChanceToGetThrough = AISoldierToSoldierChanceToGetThrough(pSoldier, pOpponent);
|
||||||
|
ubFriendlyFireChance = gUnderFire.Chance(pSoldier->bTeam, pSoldier->bSide, TRUE);
|
||||||
|
gUnderFire.Disable();
|
||||||
|
|
||||||
|
// sevenfm: only use this stance if we can hit target and cannot hit friends
|
||||||
|
if (ubChanceToGetThrough > 0 && ubFriendlyFireChance <= MIN_CHANCE_TO_ACCIDENTALLY_HIT_SOMEONE)
|
||||||
{
|
{
|
||||||
ubChanceToHit = AICalcChanceToHitGun(pSoldier, pOpponent->sGridNo, ubAimTime, AIM_SHOT_TORSO, pOpponent->pathing.bLevel, PRONE);
|
for (ubAimTime = APBPConstants[AP_MIN_AIM_ATTACK]; ubAimTime <= ubMaxPossibleAimTime; ubAimTime++)
|
||||||
iHitRate = ((pSoldier->bActionPoints - (ubMinAPcost - ubRawAPCost)) * ubChanceToHit) / (ubRawAPCost + ubAimTime * APBPConstants[AP_CLICK_AIM]);
|
|
||||||
if(iHitRate > iBestHitRate)
|
|
||||||
{
|
{
|
||||||
iBestHitRate = iHitRate;
|
ubChanceToHit = AICalcChanceToHitGun(pSoldier, pOpponent->sGridNo, ubAimTime, AIM_SHOT_TORSO, pOpponent->pathing.bLevel, PRONE);
|
||||||
ubBestAimTime = ubAimTime;
|
iHitRate = ((pSoldier->bActionPoints - (ubMinAPcost - ubRawAPCost)) * ubChanceToHit) / (ubRawAPCost + ubAimTime * APBPConstants[AP_CLICK_AIM]);
|
||||||
ubBestChanceToHit = ubChanceToHit;
|
// sevenfm: take into account CTGT for every stance
|
||||||
bScopeMode = pSoldier->bScopeMode;
|
if (iHitRate * ubChanceToGetThrough > iBestHitRate * ubBestChanceToGetThrough)
|
||||||
sBestAPcost = ubMinAPcost;
|
{
|
||||||
ubBestStance = ubStance;
|
iBestHitRate = iHitRate;
|
||||||
|
ubBestAimTime = ubAimTime;
|
||||||
|
ubBestChanceToHit = ubChanceToHit;
|
||||||
|
ubBestChanceToGetThrough = ubChanceToGetThrough;
|
||||||
|
ubBestFriendlyFireChance = ubFriendlyFireChance;
|
||||||
|
bScopeMode = pSoldier->bScopeMode;
|
||||||
|
sBestAPcost = ubMinAPcost;
|
||||||
|
ubBestStance = ubStance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -470,7 +517,7 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot)
|
|||||||
continue; // next opponent
|
continue; // next opponent
|
||||||
|
|
||||||
// calculate chance to REALLY hit: shoot accurately AND get past cover
|
// calculate chance to REALLY hit: shoot accurately AND get past cover
|
||||||
ubChanceToReallyHit = (UINT8)ceil((ubBestChanceToHit * ubChanceToGetThrough) / 100.0f);
|
ubChanceToReallyHit = (UINT8)ceil((ubBestChanceToHit * ubBestChanceToGetThrough) / 100.0f);
|
||||||
|
|
||||||
// if we can't REALLY hit at all
|
// if we can't REALLY hit at all
|
||||||
if (ubChanceToReallyHit == 0)
|
if (ubChanceToReallyHit == 0)
|
||||||
@@ -583,10 +630,7 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot)
|
|||||||
pBestShot->ubAPCost = sBestAPcost;
|
pBestShot->ubAPCost = sBestAPcost;
|
||||||
pBestShot->ubStance = ubBestStance;
|
pBestShot->ubStance = ubBestStance;
|
||||||
pBestShot->bScopeMode = bScopeMode;
|
pBestShot->bScopeMode = bScopeMode;
|
||||||
if(gUnderFire.Count(pSoldier->bTeam))//dnl ch61 180813
|
pBestShot->ubFriendlyFireChance = ubBestFriendlyFireChance;
|
||||||
pBestShot->ubFriendlyFireChance = gUnderFire.Chance(pSoldier->bTeam);
|
|
||||||
else
|
|
||||||
pBestShot->ubFriendlyFireChance = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3199,39 +3243,47 @@ void UnderFire::Clear(void)
|
|||||||
|
|
||||||
void UnderFire::Add(UINT16 usID, UINT8 ubCTH)
|
void UnderFire::Add(UINT16 usID, UINT8 ubCTH)
|
||||||
{
|
{
|
||||||
if(!fEnable)
|
if (!fEnable)
|
||||||
return;
|
return;
|
||||||
if(usUnderFireCnt < MAXUNDERFIRE)
|
|
||||||
|
if (usUnderFireCnt < MAXUNDERFIRE)
|
||||||
{
|
{
|
||||||
for(int i=0; i<usUnderFireCnt; i++)
|
for (int i = 0; i < usUnderFireCnt; i++)
|
||||||
if(usUnderFireID[i] == usID)
|
{
|
||||||
|
if (usUnderFireID[i] == usID)
|
||||||
{
|
{
|
||||||
if(ubUnderFireCTH[i] != ubCTH)
|
if (ubUnderFireCTH[i] < ubCTH) // sevenfm: use max value
|
||||||
ubUnderFireCTH[i] = ubCTH;
|
ubUnderFireCTH[i] = ubCTH;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
usUnderFireID[usUnderFireCnt++] = usID;
|
}
|
||||||
|
ubUnderFireCTH[usUnderFireCnt] = ubCTH; // sevenfm: store CTH too!
|
||||||
|
usUnderFireID[usUnderFireCnt] = usID;
|
||||||
|
usUnderFireCnt++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT16 UnderFire::Count(INT8 bTeam)
|
UINT16 UnderFire::Count(INT8 bTeam)
|
||||||
{
|
{
|
||||||
UINT16 cnt = 0;
|
UINT16 cnt = 0;
|
||||||
for(int i=0; i<usUnderFireCnt; i++)
|
for (UINT16 i = 0; i < usUnderFireCnt; i++)
|
||||||
{
|
{
|
||||||
if(MercPtrs[usUnderFireID[i]]->bTeam == bTeam)
|
if (MercPtrs[usUnderFireID[i]]->bTeam == bTeam)
|
||||||
++cnt;
|
++cnt;
|
||||||
}
|
}
|
||||||
return(cnt);
|
return(cnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT8 UnderFire::Chance(INT8 bTeam)
|
UINT8 UnderFire::Chance(INT8 bTeam, INT8 bSide, BOOLEAN fCheckNeutral)
|
||||||
{
|
{
|
||||||
UINT8 cth = 0;
|
UINT8 cth = 0;
|
||||||
for(int i=0; i<usUnderFireCnt; i++)
|
for (UINT16 i = 0; i < usUnderFireCnt; i++)
|
||||||
{
|
{
|
||||||
if(MercPtrs[usUnderFireID[i]]->bTeam == bTeam && ubUnderFireCTH[i] > cth)
|
if ((MercPtrs[usUnderFireID[i]]->bTeam == bTeam || MercPtrs[usUnderFireID[i]]->bSide == bSide || fCheckNeutral && MercPtrs[usUnderFireID[i]]->aiData.bNeutral) &&
|
||||||
|
ubUnderFireCTH[i] > cth)
|
||||||
|
{
|
||||||
cth = ubUnderFireCTH[i];
|
cth = ubUnderFireCTH[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return(cth);
|
return(cth);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -306,6 +306,7 @@ INT32 CalcCoverValue(SOLDIERTYPE *pMe, INT32 sMyGridNo, INT32 iMyThreat, INT32 i
|
|||||||
// sevenfm
|
// sevenfm
|
||||||
bHisLevel = pHim->pathing.bLevel;
|
bHisLevel = pHim->pathing.bLevel;
|
||||||
bMyLevel = pMe->pathing.bLevel;
|
bMyLevel = pMe->pathing.bLevel;
|
||||||
|
UINT8 ubFriendlyFireChance = 0;
|
||||||
|
|
||||||
// THE FOLLOWING STUFF IS *VEERRRY SCAARRRY*, BUT SHOULD WORK. IF YOU REALLY
|
// THE FOLLOWING STUFF IS *VEERRRY SCAARRRY*, BUT SHOULD WORK. IF YOU REALLY
|
||||||
// HATE IT, THEN CHANGE ChanceToGetThrough() TO WORK FROM A GRIDNO TO GRIDNO
|
// HATE IT, THEN CHANGE ChanceToGetThrough() TO WORK FROM A GRIDNO TO GRIDNO
|
||||||
@@ -394,9 +395,20 @@ INT32 CalcCoverValue(SOLDIERTYPE *pMe, INT32 sMyGridNo, INT32 iMyThreat, INT32 i
|
|||||||
pHim->dYPos = (FLOAT) sTempY;
|
pHim->dYPos = (FLOAT) sTempY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sevenfm: also check friendly fire chance for each position
|
||||||
|
gUnderFire.Clear();
|
||||||
|
gUnderFire.Enable();
|
||||||
// let's not assume anything about the stance the enemy might take, so take an average
|
// let's not assume anything about the stance the enemy might take, so take an average
|
||||||
// value... no cover give a higher value than partial cover
|
// value... no cover give a higher value than partial cover
|
||||||
bMyCTGT = CalcAverageCTGTForPosition( pMe, pHim->ubID, sHisGridNo, pHim->pathing.bLevel, iMyAPsLeft );
|
bMyCTGT = CalcAverageCTGTForPosition( pMe, pHim->ubID, sHisGridNo, pHim->pathing.bLevel, iMyAPsLeft );
|
||||||
|
gUnderFire.Disable();
|
||||||
|
|
||||||
|
// sevenfm: penalize position if friendly fire chance is high
|
||||||
|
if (gGameExternalOptions.fAIBetterCover && ubFriendlyFireChance > MIN_CHANCE_TO_ACCIDENTALLY_HIT_SOMEONE)
|
||||||
|
{
|
||||||
|
ubFriendlyFireChance = gUnderFire.Chance(pMe->bTeam, pMe->bSide, TRUE);
|
||||||
|
bMyCTGT = 1;
|
||||||
|
}
|
||||||
|
|
||||||
// since NPCs are too dumb to shoot "blind", ie. at opponents that they
|
// since NPCs are too dumb to shoot "blind", ie. at opponents that they
|
||||||
// themselves can't see (mercs can, using another as a spotter!), if the
|
// themselves can't see (mercs can, using another as a spotter!), if the
|
||||||
|
|||||||
Reference in New Issue
Block a user