mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
Brief: //dnl ch69
- Add alternative fix for CalcBestShot which should remove existing APs problems maybe even create AI deadlier then ever ;-) Details: - Existing CalcBestShot simply became inadequate and buggier for so many add ons to game, so compiling with dnlCALCBESTSHOT is alternative option which calculate all turning, stance and raising gun cost for different stances and all available scopes, and after all hoping fix incorrect APs calculation as well, hitrate formula is adapt to 100AP system, also try to optimize a bit to get less AICalcChanceToHitGun calls and to use with different stance decisions. - From ch58 aiming for burst and autofire was disabled as was causing invalid action handle due to incorrect APs calculation so from now aiming AI also use aiming before bursting. git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@6403 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
+24
-19
@@ -126,25 +126,32 @@ typedef struct
|
||||
} THREATTYPE;
|
||||
|
||||
// define for bAimTime for bursting
|
||||
#define BURSTING 20
|
||||
#define AUTOFIRING 21
|
||||
//#define BURSTING 20
|
||||
//#define AUTOFIRING 21
|
||||
|
||||
typedef struct
|
||||
//dnl ch69 140913
|
||||
#define dnlCALCBESTSHOT// old CalcBestShot simply became inadequate and buggier for so many add ons to game, so this one is alternative option which calculate all turning, stance and raising gun cost for different stances and all available scopes
|
||||
class ATTACKTYPE
|
||||
{
|
||||
UINT8 ubPossible; // is this attack form possible? T/F
|
||||
UINT8 ubOpponent; // which soldier is the victim?
|
||||
//CHANGED STRUCTURE VALUE BY GOTTHARD 7/14/07
|
||||
INT16 ubAimTime; // how many extra APs to spend on aiming
|
||||
INT16 ubChanceToReallyHit; // chance to hit * chance to get through cover
|
||||
//END STRUCTURE CHANGE BY GOTTHARD 7/14/07
|
||||
INT32 iAttackValue; // relative worthiness of this type of attack
|
||||
INT32 sTarget; // target gridno of this attack
|
||||
INT8 bTargetLevel; // target level of this attack
|
||||
UINT8 ubFriendlyFireChance; // highest chance to hit someone of our guys //dnl ch61 180813
|
||||
INT16 ubAPCost; // how many APs the attack will use up
|
||||
INT8 bWeaponIn; // the inv slot of the weapon in question
|
||||
INT8 bScopeMode; // SANDRO: added for scope mode and alternative weapon holding
|
||||
} ATTACKTYPE;
|
||||
public:
|
||||
UINT8 ubPossible; // is this attack form possible
|
||||
UINT8 ubOpponent; // which soldier is the victim
|
||||
//CHANGED STRUCTURE VALUE BY GOTTHARD 7/14/07
|
||||
INT16 ubAimTime; // how many extra APs to spend on aiming
|
||||
INT16 ubChanceToReallyHit; // chance to hit * chance to get through cover
|
||||
//END STRUCTURE CHANGE BY GOTTHARD 7/14/07
|
||||
INT16 ubAPCost; // how many APs the attack will use up
|
||||
INT32 iAttackValue; // relative worthiness of this type of attack
|
||||
INT32 sTarget; // target gridno of this attack
|
||||
INT8 bTargetLevel; // target level of this attack
|
||||
INT8 bWeaponIn; // the inv slot of the weapon in question
|
||||
INT8 bScopeMode; // SANDRO: added for scope mode and alternative weapon holding
|
||||
UINT8 ubStance; // recommended stance for attack
|
||||
UINT8 ubFriendlyFireChance; // highest chance to hit someone of our guys //dnl ch61 180813
|
||||
|
||||
ATTACKTYPE(void){ InitAttackType(this); }
|
||||
void InitAttackType(ATTACKTYPE *pAttack);
|
||||
};
|
||||
|
||||
//dnl ch61 180813
|
||||
#define MAXUNDERFIRE 100
|
||||
@@ -239,8 +246,6 @@ BOOLEAN InGas( SOLDIERTYPE *pSoldier, INT32 sGridNo );
|
||||
BOOLEAN InGasOrSmoke( SOLDIERTYPE *pSoldier, INT32 sGridNo );
|
||||
BOOLEAN InWaterGasOrSmoke( SOLDIERTYPE *pSoldier, INT32 sGridNo );
|
||||
|
||||
void InitAttackType(ATTACKTYPE *pAttack);
|
||||
|
||||
INT32 InternalGoAsFarAsPossibleTowards(SOLDIERTYPE *pSoldier, INT32 sDesGrid, INT16 bReserveAPs, INT8 bAction, INT8 fFlags );
|
||||
|
||||
int LegalNPCDestination(SOLDIERTYPE *pSoldier, INT32 sGridno, UINT8 ubPathMode, UINT8 ubWaterOK, UINT8 fFlags);
|
||||
|
||||
@@ -2353,16 +2353,14 @@ void CheckForChangingOrders(SOLDIERTYPE *pSoldier)
|
||||
}
|
||||
}
|
||||
|
||||
void InitAttackType(ATTACKTYPE *pAttack)
|
||||
void ATTACKTYPE::InitAttackType(ATTACKTYPE *pAttack)//dnl ch69 140913
|
||||
{
|
||||
// initialize the given bestAttack structure fields to their default values
|
||||
pAttack->ubPossible = FALSE;
|
||||
pAttack->ubOpponent = NOBODY;
|
||||
pAttack->ubAimTime = 0;
|
||||
pAttack->ubChanceToReallyHit = 0;
|
||||
pAttack->sTarget = NOWHERE;
|
||||
pAttack->iAttackValue = 0;
|
||||
pAttack->ubAPCost = 0;
|
||||
memset(pAttack, 0, sizeof(ATTACKTYPE));
|
||||
pAttack->ubOpponent = NOBODY;
|
||||
pAttack->sTarget = NOWHERE;
|
||||
pAttack->bWeaponIn = NO_SLOT;
|
||||
pAttack->ubStance = STANDING;
|
||||
}
|
||||
|
||||
void HandleInitialRedAlert( INT8 bTeam, UINT8 ubCommunicate)
|
||||
|
||||
+179
-27
@@ -23,6 +23,7 @@
|
||||
#include "Sound Control.h"
|
||||
#include "message.h"
|
||||
#include "Vehicles.h"
|
||||
#include "Soldier Functions.h"//dnl ch69 140913
|
||||
#endif
|
||||
|
||||
extern INT16 DirIncrementer[8];
|
||||
@@ -156,28 +157,32 @@ void ResetWeaponMode( SOLDIERTYPE * pSoldier )
|
||||
void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUnseen)
|
||||
{
|
||||
UINT32 uiLoop;
|
||||
INT32 iAttackValue;
|
||||
INT32 iThreatValue;
|
||||
INT32 iHitRate,iBestHitRate,iPercentBetter;
|
||||
INT32 iEstDamage;
|
||||
UINT8 ubMaxPossibleAimTime;
|
||||
INT16 ubAimTime,ubMinAPcost,ubRawAPCost;
|
||||
UINT8 ubChanceToReallyHit = 0;
|
||||
INT16 ubChanceToHit,ubChanceToHit2,ubBestAimTime,ubChanceToGetThrough,ubBestChanceToHit;
|
||||
SOLDIERTYPE *pOpponent;
|
||||
//INT16 ubBurstAPs;//dnl ch64 270813
|
||||
INT32 iAttackValue, iThreatValue, iHitRate, iBestHitRate, iPercentBetter, iEstDamage, iTrueLastTarget;
|
||||
UINT16 usTrueState, usTurningCost, usRaiseGunCost;
|
||||
INT16 ubAimTime, ubMinAPcost, ubRawAPCost, sBestAPcost, ubChanceToHit, ubBestAimTime, ubChanceToGetThrough, ubBestChanceToHit, sStanceAPcost;
|
||||
BOOLEAN fAddingTurningCost, fAddingRaiseGunCost;
|
||||
UINT8 ubMaxPossibleAimTime, ubStance, ubBestStance, ubChanceToReallyHit;
|
||||
INT8 bScopeMode;
|
||||
SOLDIERTYPE *pOpponent;
|
||||
|
||||
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"CalcBestShot");
|
||||
|
||||
ubBestChanceToHit = ubBestAimTime = ubChanceToHit = 0;
|
||||
ubBestChanceToHit = ubBestAimTime = ubChanceToHit = ubChanceToReallyHit = 0;
|
||||
|
||||
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->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
|
||||
//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]);
|
||||
@@ -218,7 +223,7 @@ 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
|
||||
@@ -235,7 +240,9 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUns
|
||||
// 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
|
||||
@@ -298,7 +305,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 )
|
||||
@@ -437,7 +444,144 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUns
|
||||
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++)
|
||||
{
|
||||
if(pSoldier->bScopeMode == USE_ALT_WEAPON_HOLD || (pSoldier->bScopeMode >= USE_BEST_SCOPE && ObjList[pSoldier->bScopeMode] != NULL))
|
||||
{
|
||||
usTrueState = pSoldier->usAnimState;// because is used in CalculateRaiseGunCost, CalcAimingLevelsAvailableWithAP, CalculateTurningCost
|
||||
iTrueLastTarget = pSoldier->sLastTarget;// because is used in MinAPsToShootOrStab
|
||||
ubStance = ANIM_STAND;
|
||||
if(IsValidStance(pSoldier, ubStance))
|
||||
{
|
||||
sStanceAPcost = GetAPsToChangeStance(pSoldier, ubStance);
|
||||
if(sStanceAPcost)// Going up so first is stance change then turnover, do animation change before APs calculation
|
||||
{
|
||||
pSoldier->usAnimState = STANDING;
|
||||
pSoldier->sLastTarget = NOWHERE;
|
||||
}
|
||||
GetAPChargeForShootOrStabWRTGunRaises(pSoldier, pOpponent->sGridNo, TRUE, &fAddingTurningCost, &fAddingRaiseGunCost, 0);
|
||||
usTurningCost = CalculateTurningCost(pSoldier, pSoldier->usAttackingWeapon, fAddingTurningCost);
|
||||
usRaiseGunCost = CalculateRaiseGunCost(pSoldier, fAddingRaiseGunCost, pOpponent->sGridNo, 0);
|
||||
ubRawAPCost = MinAPsToShootOrStab(pSoldier, pOpponent->sGridNo, 0, FALSE, 2);
|
||||
ubMinAPcost = ubRawAPCost + usTurningCost + sStanceAPcost + usRaiseGunCost;
|
||||
//ubMinAPcost = MinAPsToAttack(pSoldier, pOpponent->sGridNo, ADDTURNCOST, 0) + sStanceAPcost;
|
||||
if(pSoldier->bActionPoints-ubMinAPcost >= 0)
|
||||
{
|
||||
// calc next attack's minimum shooting cost (excludes readying & turning & raise gun)
|
||||
//ubRawAPCost = MinAPsToShootOrStab(pSoldier, pOpponent->sGridNo, 0, FALSE, 2);
|
||||
ubMaxPossibleAimTime = CalcAimingLevelsAvailableWithAP(pSoldier, pOpponent->sGridNo, pSoldier->bActionPoints-ubMinAPcost);
|
||||
for(ubAimTime=APBPConstants[AP_MIN_AIM_ATTACK]; ubAimTime<=ubMaxPossibleAimTime; ubAimTime++)
|
||||
{
|
||||
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)
|
||||
{
|
||||
iBestHitRate = iHitRate;
|
||||
ubBestAimTime = ubAimTime;
|
||||
ubBestChanceToHit = ubChanceToHit;
|
||||
bScopeMode = pSoldier->bScopeMode;
|
||||
sBestAPcost = ubMinAPcost;
|
||||
ubBestStance = ubStance;
|
||||
}
|
||||
}
|
||||
}
|
||||
pSoldier->usAnimState = usTrueState;
|
||||
pSoldier->sLastTarget = iTrueLastTarget;
|
||||
}
|
||||
ubStance = ANIM_CROUCH;
|
||||
if(IsValidStance(pSoldier, ubStance) && pSoldier->bScopeMode != USE_ALT_WEAPON_HOLD)
|
||||
{
|
||||
usTurningCost = 32767;
|
||||
if(gAnimControl[pSoldier->usAnimState].ubEndHeight > ubStance)// Going down
|
||||
{
|
||||
GetAPChargeForShootOrStabWRTGunRaises(pSoldier, pOpponent->sGridNo, TRUE, &fAddingTurningCost, &fAddingRaiseGunCost, 0);
|
||||
usTurningCost = CalculateTurningCost(pSoldier, pSoldier->usAttackingWeapon, fAddingTurningCost);
|
||||
}
|
||||
sStanceAPcost = GetAPsToChangeStance(pSoldier, ubStance);
|
||||
if(sStanceAPcost)
|
||||
{
|
||||
pSoldier->usAnimState = CROUCHING;
|
||||
pSoldier->sLastTarget = NOWHERE;
|
||||
fAddingRaiseGunCost = TRUE;
|
||||
}
|
||||
if(usTurningCost == 32767)// Going up or same
|
||||
{
|
||||
GetAPChargeForShootOrStabWRTGunRaises(pSoldier, pOpponent->sGridNo, TRUE, &fAddingTurningCost, &fAddingRaiseGunCost, 0);
|
||||
usTurningCost = CalculateTurningCost(pSoldier, pSoldier->usAttackingWeapon, fAddingTurningCost);
|
||||
}
|
||||
usRaiseGunCost = CalculateRaiseGunCost(pSoldier, fAddingRaiseGunCost, pOpponent->sGridNo, 0);
|
||||
ubRawAPCost = MinAPsToShootOrStab(pSoldier, pOpponent->sGridNo, 0, FALSE, 2);
|
||||
ubMinAPcost = ubRawAPCost + usTurningCost + sStanceAPcost + usRaiseGunCost;
|
||||
//ubMinAPcost = MinAPsToAttack(pSoldier, pOpponent->sGridNo, ADDTURNCOST, 0) + sStanceAPcost;
|
||||
if(pSoldier->bActionPoints-ubMinAPcost >= 0)
|
||||
{
|
||||
//ubRawAPCost = MinAPsToShootOrStab(pSoldier, pOpponent->sGridNo, 0, FALSE, 2);
|
||||
ubMaxPossibleAimTime = CalcAimingLevelsAvailableWithAP(pSoldier, pOpponent->sGridNo, pSoldier->bActionPoints-ubMinAPcost);
|
||||
for(ubAimTime=APBPConstants[AP_MIN_AIM_ATTACK]; ubAimTime<=ubMaxPossibleAimTime; ubAimTime++)
|
||||
{
|
||||
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;
|
||||
ubBestAimTime = ubAimTime;
|
||||
ubBestChanceToHit = ubChanceToHit;
|
||||
bScopeMode = pSoldier->bScopeMode;
|
||||
sBestAPcost = ubMinAPcost;
|
||||
ubBestStance = ubStance;
|
||||
}
|
||||
}
|
||||
}
|
||||
pSoldier->usAnimState = usTrueState;
|
||||
pSoldier->sLastTarget = iTrueLastTarget;
|
||||
}
|
||||
ubStance = ANIM_PRONE;
|
||||
if(IsValidStance(pSoldier, ubStance) && pSoldier->bScopeMode != USE_ALT_WEAPON_HOLD)
|
||||
{
|
||||
GetAPChargeForShootOrStabWRTGunRaises(pSoldier, pOpponent->sGridNo, TRUE, &fAddingTurningCost, &fAddingRaiseGunCost, 0);
|
||||
usTurningCost = CalculateTurningCost(pSoldier, pSoldier->usAttackingWeapon, fAddingTurningCost);
|
||||
sStanceAPcost = GetAPsToChangeStance(pSoldier, ubStance);
|
||||
if(sStanceAPcost)// Going down so first is turnover then change stance, do APs calculation before animation change
|
||||
{
|
||||
pSoldier->usAnimState = PRONE;
|
||||
pSoldier->sLastTarget = NOWHERE;
|
||||
fAddingRaiseGunCost = TRUE;
|
||||
}
|
||||
usRaiseGunCost = CalculateRaiseGunCost(pSoldier, fAddingRaiseGunCost, pOpponent->sGridNo, 0);
|
||||
ubRawAPCost = MinAPsToShootOrStab(pSoldier, pOpponent->sGridNo, 0, FALSE, 2);
|
||||
ubMinAPcost = ubRawAPCost + usTurningCost + sStanceAPcost + usRaiseGunCost;
|
||||
//ubMinAPcost = MinAPsToAttack(pSoldier, pOpponent->sGridNo, ADDTURNCOST, 0) + sStanceAPcost;
|
||||
if(pSoldier->bActionPoints-ubMinAPcost >= 0)
|
||||
{
|
||||
//ubRawAPCost = MinAPsToShootOrStab(pSoldier, pOpponent->sGridNo, 0, FALSE, 2);
|
||||
ubMaxPossibleAimTime = CalcAimingLevelsAvailableWithAP(pSoldier, pOpponent->sGridNo, pSoldier->bActionPoints-ubMinAPcost);
|
||||
for(ubAimTime=APBPConstants[AP_MIN_AIM_ATTACK]; ubAimTime<=ubMaxPossibleAimTime; ubAimTime++)
|
||||
{
|
||||
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;
|
||||
ubBestAimTime = ubAimTime;
|
||||
ubBestChanceToHit = ubChanceToHit;
|
||||
bScopeMode = pSoldier->bScopeMode;
|
||||
sBestAPcost = ubMinAPcost;
|
||||
ubBestStance = ubStance;
|
||||
}
|
||||
}
|
||||
}
|
||||
pSoldier->usAnimState = usTrueState;
|
||||
pSoldier->sLastTarget = iTrueLastTarget;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// if we can't get any kind of hit rate at all
|
||||
if (iBestHitRate == 0)
|
||||
continue; // next opponent
|
||||
@@ -513,18 +657,24 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUns
|
||||
pBestShot->ubPossible = TRUE;
|
||||
pBestShot->ubOpponent = pOpponent->ubID;
|
||||
pBestShot->ubAimTime = ubBestAimTime;
|
||||
pBestShot->ubChanceToReallyHit = ubChanceToReallyHit;
|
||||
pBestShot->sTarget = pOpponent->sGridNo;
|
||||
pBestShot->bTargetLevel = pOpponent->pathing.bLevel;
|
||||
pBestShot->iAttackValue = iAttackValue;
|
||||
pBestShot->ubAPCost = ubMinAPcost;
|
||||
pBestShot->bScopeMode = bScopeMode;
|
||||
pBestShot->ubChanceToReallyHit = ubChanceToReallyHit;
|
||||
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);
|
||||
else
|
||||
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
|
||||
}
|
||||
|
||||
@@ -942,7 +1092,7 @@ void CalcBestThrow(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestThrow)
|
||||
}
|
||||
|
||||
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"calcbestthrow: about to initattacktype");
|
||||
InitAttackType(pBestThrow); // set all structure fields to defaults
|
||||
//InitAttackType(pBestThrow); // set all structure fields to defaults//dnl ch69 150913
|
||||
|
||||
// look at the squares near each known opponent and try to find the one
|
||||
// place where a tossed projectile would do the most harm to the opponents
|
||||
@@ -1230,6 +1380,7 @@ void CalcBestThrow(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestThrow)
|
||||
{
|
||||
ubRawAPCost = MinAPsToShootOrStab( pSoldier, sGridNo,ubMaxPossibleAimTime,FALSE);
|
||||
ubChanceToHit = (UINT8) AICalcChanceToHitGun(pSoldier, sGridNo, ubMaxPossibleAimTime, AIM_SHOT_TORSO, pOpponent->pathing.bLevel, STANDING);//dnl ch59 130813
|
||||
//SendFmtMsg("CalcBestThrow=%d APs=%d mat=%d gno=%d EXPGUN!!!", ubChanceToHit, ubRawAPCost, ubMaxPossibleAimTime, sGridNo);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1239,6 +1390,7 @@ void CalcBestThrow(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestThrow)
|
||||
DebugMsg(TOPIC_JA2 , DBG_LEVEL_3 , String("Raw AP Cost = %d",ubRawAPCost ));
|
||||
ubChanceToHit = (UINT8) CalcThrownChanceToHit( pSoldier, sGridNo, ubMaxPossibleAimTime, AIM_SHOT_TORSO );
|
||||
DebugMsg(TOPIC_JA2 , DBG_LEVEL_3 , String("Chance to hit = %d",ubChanceToHit ));
|
||||
//SendFmtMsg("CalcBestThrow=%d APs=%d mat=%d gno=%d", ubChanceToHit, ubRawAPCost, ubMaxPossibleAimTime, sGridNo);
|
||||
}
|
||||
|
||||
// mortars are inherently quite inaccurate, don't get proximity bonus
|
||||
@@ -1292,7 +1444,7 @@ void CalcBestThrow(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestThrow)
|
||||
pBestThrow->ubChanceToReallyHit = ubChanceToReallyHit;
|
||||
pBestThrow->sTarget = sGridNo;
|
||||
pBestThrow->iAttackValue = iAttackValue;
|
||||
pBestThrow->ubAPCost = ubMinAPcost + CalcAPCostForAiming(pSoldier, sGridNo, ubMaxPossibleAimTime, FALSE);//dnl ch64 310813
|
||||
pBestThrow->ubAPCost = ubMinAPcost + CalcAPCostForAiming(pSoldier, sGridNo, ubMaxPossibleAimTime);//dnl ch64 310813
|
||||
pBestThrow->bTargetLevel = bOpponentLevel[ubLoop];
|
||||
|
||||
//sprintf(tempstr,"new best THROW AttackValue = %d at grid #%d",iAttackValue/100000,gridno);
|
||||
@@ -1341,7 +1493,7 @@ void CalcBestStab(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestStab, BOOLEAN fBladeAt
|
||||
SOLDIERTYPE *pOpponent;
|
||||
UINT16 usTrueMovementMode;
|
||||
INT16 ubBestChanceToHit;
|
||||
InitAttackType(pBestStab); // set all structure fields to defaults
|
||||
//InitAttackType(pBestStab); // set all structure fields to defaults//dnl ch69 150913
|
||||
|
||||
pSoldier->usAttackingWeapon = pSoldier->inv[HANDPOS].usItem;
|
||||
|
||||
@@ -1562,7 +1714,7 @@ void CalcTentacleAttack(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestStab )
|
||||
SOLDIERTYPE *pOpponent;
|
||||
|
||||
|
||||
InitAttackType(pBestStab); // set all structure fields to defaults
|
||||
//InitAttackType(pBestStab); // set all structure fields to defaults//dnl ch69 150913
|
||||
|
||||
pSoldier->usAttackingWeapon = pSoldier->inv[HANDPOS].usItem;
|
||||
|
||||
|
||||
@@ -916,7 +916,7 @@ INT8 CreatureDecideActionBlack( SOLDIERTYPE * pSoldier )
|
||||
INT8 bCanAttack;
|
||||
INT8 bSpitIn, bWeaponIn;
|
||||
UINT32 uiChance;
|
||||
ATTACKTYPE BestShot = {}, BestStab = {}, BestAttack = {}, CurrStab = {};
|
||||
ATTACKTYPE BestShot, BestStab, BestAttack, CurrStab;//dnl ch69 150913
|
||||
BOOLEAN fRunAway = FALSE;
|
||||
BOOLEAN fChangeLevel;
|
||||
|
||||
|
||||
+71
-22
@@ -4014,7 +4014,7 @@ INT16 ubMinAPCost;
|
||||
return( ZombieDecideActionBlack(pSoldier) );
|
||||
#endif
|
||||
|
||||
ATTACKTYPE BestShot = {},BestThrow = {},BestStab = {},BestAttack = {};
|
||||
ATTACKTYPE BestShot, BestThrow, BestStab ,BestAttack;//dnl ch69 150913
|
||||
BOOLEAN fCivilian = (PTR_CIVILIAN && (pSoldier->ubCivilianGroup == NON_CIV_GROUP || pSoldier->aiData.bNeutral || (pSoldier->ubBodyType >= FATCIV && pSoldier->ubBodyType <= CRIPPLECIV) ) );
|
||||
UINT8 ubBestStance = 1, ubStanceCost;
|
||||
BOOLEAN fChangeStanceFirst; // before firing
|
||||
@@ -4849,7 +4849,7 @@ INT16 ubMinAPCost;
|
||||
}
|
||||
|
||||
// NB a desire of 4 or more is only achievable by brave/aggressive guys with high morale
|
||||
UINT16 usRange = GetModifiedGunRange(pSoldier->inv[ BestAttack.bWeaponIn ].usItem);
|
||||
UINT16 usRange = BestAttack.bWeaponIn==NO_SLOT ? 0 : GetModifiedGunRange(pSoldier->inv[BestAttack.bWeaponIn].usItem);//dnl ch69 150913
|
||||
|
||||
if ( (pSoldier->bActionPoints == pSoldier->bInitialActionPoints) &&
|
||||
(ubBestAttackAction == AI_ACTION_FIRE_GUN) &&
|
||||
@@ -5001,6 +5001,7 @@ 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 ( !TANK( pSoldier ) && ( pSoldier->bActionPoints >= BestAttack.ubAPCost + GetAPsCrouch( pSoldier, TRUE) + MinAPsToAttack( pSoldier, BestAttack.sTarget, ADDTURNCOST,0, 1 ) ) )
|
||||
{
|
||||
@@ -5076,6 +5077,44 @@ INT16 ubMinAPCost;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
if(!TANK(pSoldier))
|
||||
{
|
||||
// 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));
|
||||
if(gAnimControl[pSoldier->usAnimState].ubEndHeight > BestAttack.ubStance)// Going down
|
||||
{
|
||||
// First change direction
|
||||
if(pSoldier->ubDirection != bDirection && pSoldier->InternalIsValidStance(bDirection, gAnimControl[pSoldier->usAnimState].ubEndHeight))
|
||||
{
|
||||
// we're not facing towards him, so turn first!
|
||||
pSoldier->aiData.usActionData = bDirection;
|
||||
return(AI_ACTION_CHANGE_FACING);
|
||||
}
|
||||
else
|
||||
{
|
||||
ubBestStance = BestAttack.ubStance;
|
||||
fChangeStanceFirst = TRUE;
|
||||
}
|
||||
}
|
||||
else if(gAnimControl[pSoldier->usAnimState].ubEndHeight < BestAttack.ubStance)// Going up
|
||||
{
|
||||
// First change stance
|
||||
ubBestStance = BestAttack.ubStance;
|
||||
fChangeStanceFirst = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Change facing
|
||||
if(pSoldier->ubDirection != bDirection && pSoldier->InternalIsValidStance(bDirection, gAnimControl[pSoldier->usAnimState].ubEndHeight))
|
||||
{
|
||||
// we're not facing towards him, so turn first!
|
||||
pSoldier->aiData.usActionData = bDirection;
|
||||
return(AI_ACTION_CHANGE_FACING);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// IF ENOUGH APs TO BURST, RANDOM CHANCE OF DOING SO
|
||||
@@ -5143,14 +5182,13 @@ INT16 ubMinAPCost;
|
||||
|
||||
if ( (INT32) PreRandom( 100 ) < iChance)
|
||||
{
|
||||
BestAttack.ubAPCost = BestAttack.ubAPCost + ubBurstAPs;
|
||||
BestAttack.ubAPCost += ubBurstAPs + sActualAimTime;//dnl??? ch58 130913
|
||||
// check for spread burst possibilities
|
||||
if (pSoldier->aiData.bAttitude != ATTACKSLAYONLY)
|
||||
{
|
||||
CalcSpreadBurst( pSoldier, BestAttack.sTarget, BestAttack.bTargetLevel );
|
||||
}
|
||||
//dnl ch58 180813 After HAM 4 BURSTING is not in use any more, for burst bAimTime and bDoAutofire must be set to 0
|
||||
pSoldier->aiData.bAimTime = 0;
|
||||
//dnl ch58 130913 return aiming for burst
|
||||
pSoldier->bDoBurst = 1;
|
||||
pSoldier->bDoAutofire = 0;
|
||||
}
|
||||
@@ -5163,7 +5201,7 @@ INT16 ubMinAPCost;
|
||||
!pSoldier->bDoBurst ) || Weapon[pSoldier->inv[BestAttack.bWeaponIn].usItem].NoSemiAuto) )
|
||||
{
|
||||
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideActionBlack: ENOUGH APs TO AUTOFIRE, RANDOM CHANCE OF DOING SO");
|
||||
|
||||
L_NEWAIM:
|
||||
FLOAT dTotalRecoil = 0.0f;
|
||||
pSoldier->bDoAutofire = 0;
|
||||
if(UsingNewCTHSystem() == true){
|
||||
@@ -5182,15 +5220,21 @@ INT16 ubMinAPCost;
|
||||
pSoldier->bDoAutofire++;
|
||||
ubBurstAPs = CalcAPsToAutofire( pSoldier->CalcActionPoints(), &(pSoldier->inv[BestAttack.bWeaponIn]), pSoldier->bDoAutofire, pSoldier );
|
||||
}
|
||||
while( pSoldier->bActionPoints >= BestAttack.ubAPCost + ubBurstAPs && pSoldier->inv[ BestAttack.bWeaponIn ][0]->data.gun.ubGunShotsLeft >= pSoldier->bDoAutofire && GetAutoPenalty(&pSoldier->inv[ BestAttack.bWeaponIn ], gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE)*pSoldier->bDoAutofire <= 80);//dnl ch64 260813 pSoldier->ubAttackingHand is wrong because decision is to use BestAttack.bWeaponIn
|
||||
while( pSoldier->bActionPoints >= BestAttack.ubAPCost + ubBurstAPs + sActualAimTime && pSoldier->inv[ BestAttack.bWeaponIn ][0]->data.gun.ubGunShotsLeft >= pSoldier->bDoAutofire && GetAutoPenalty(&pSoldier->inv[ BestAttack.bWeaponIn ], gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE)*pSoldier->bDoAutofire <= 80);//dnl ch64 130913 pSoldier->ubAttackingHand is wrong because decision is to use BestAttack.bWeaponIn, also missing sActualAimTime
|
||||
}
|
||||
|
||||
pSoldier->bDoAutofire--;
|
||||
if(!UsingNewCTHSystem() && pSoldier->bDoAutofire < 3 && pSoldier->aiData.bAimTime > 0 && pSoldier->inv[BestAttack.bWeaponIn][0]->data.gun.ubGunShotsLeft >= 3)//dnl ch69 130913 let try increase autofire rate for aim cost
|
||||
{
|
||||
pSoldier->aiData.bAimTime--;
|
||||
sActualAimTime = CalcAPCostForAiming(pSoldier, BestAttack.sTarget, (INT8)pSoldier->aiData.bAimTime);
|
||||
goto L_NEWAIM;
|
||||
}
|
||||
if (pSoldier->bDoAutofire > 0)
|
||||
{
|
||||
ubBurstAPs = CalcAPsToAutofire( pSoldier->CalcActionPoints(), &(pSoldier->inv[BestAttack.bWeaponIn]), pSoldier->bDoAutofire, pSoldier );
|
||||
|
||||
if (pSoldier->bActionPoints >= BestAttack.ubAPCost + ubBurstAPs )
|
||||
if (pSoldier->bActionPoints >= BestAttack.ubAPCost + sActualAimTime + ubBurstAPs )
|
||||
{
|
||||
// Base chance of bursting is 25% if best shot was +0 aim, down to 8% at +4
|
||||
if ( TANK( pSoldier ) )
|
||||
@@ -5243,21 +5287,28 @@ INT16 ubMinAPCost;
|
||||
|
||||
if ((INT32) PreRandom( 100 ) < iChance || Weapon[pSoldier->inv[BestAttack.bWeaponIn].usItem].NoSemiAuto)
|
||||
{
|
||||
//dnl ch58 180813 After HAM 4 AUTOFIRING and sActualAimTime is not used in burst or autofire mode calculations and pSoldier->aiData.bAimTime must be 0
|
||||
pSoldier->aiData.bAimTime = 0;
|
||||
//dnl ch69 140913 return aiming for autofire with halfautofire fix
|
||||
pSoldier->bDoBurst = 1;
|
||||
INT16 ubHalfBurstAPs = CalcAPsToAutofire(pSoldier->CalcActionPoints(), &pSoldier->inv[BestAttack.bWeaponIn], 4, pSoldier);
|
||||
if(Weapon[pSoldier->inv[BestAttack.bWeaponIn].usItem].NoSemiAuto)
|
||||
iChance = 35;
|
||||
if(pSoldier->bActionPoints > (2 * BestAttack.ubAPCost + ubHalfBurstAPs) && PreRandom(100) < iChance)
|
||||
INT16 ubHalfBurstAPs = 256;
|
||||
if(pSoldier->inv[BestAttack.bWeaponIn][0]->data.gun.ubGunShotsLeft < 4)
|
||||
iChance = 0;
|
||||
else
|
||||
{
|
||||
ubHalfBurstAPs = CalcAPsToAutofire(pSoldier->CalcActionPoints(), &pSoldier->inv[BestAttack.bWeaponIn], 4, pSoldier);
|
||||
if(Weapon[pSoldier->inv[BestAttack.bWeaponIn].usItem].NoSemiAuto)
|
||||
iChance = 35;
|
||||
}
|
||||
if((INT32)PreRandom(100) < iChance && pSoldier->bActionPoints > (2 * BestAttack.ubAPCost + ubHalfBurstAPs + sActualAimTime))
|
||||
{
|
||||
// Try short autofire to enhance chance of hitting
|
||||
pSoldier->bDoAutofire = 4;
|
||||
BestAttack.ubAPCost += ubHalfBurstAPs;
|
||||
BestAttack.ubAPCost += ubHalfBurstAPs + sActualAimTime;
|
||||
//SendFmtMsg("HALF-Auto=%d ubAPCost=%d iChance=%d ubBurstAPs=%d,%d", pSoldier->bDoAutofire, BestAttack.ubAPCost, iChance, ubHalfBurstAPs, sActualAimTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
BestAttack.ubAPCost += ubBurstAPs;
|
||||
BestAttack.ubAPCost += ubBurstAPs + sActualAimTime;
|
||||
//SendFmtMsg("FULL-Auto=%d ubAPCost=%d iChance=%d ubBurstAPs=%d,%d", pSoldier->bDoAutofire, BestAttack.ubAPCost, iChance, ubBurstAPs, sActualAimTime);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -5485,8 +5536,7 @@ INT16 ubMinAPCost;
|
||||
{
|
||||
CalcSpreadBurst( pSoldier, BestAttack.sTarget, BestAttack.bTargetLevel );
|
||||
}
|
||||
//dnl ch58 200813 After HAM 4 BURSTING is not in use any more, for burst bAimTime and bDoAutofire must be set to 0
|
||||
pSoldier->aiData.bAimTime = 0;
|
||||
//dnl ch58 140913 After HAM 4 BURSTING is not in use any more, for burst bDoAutofire must be set to 0
|
||||
pSoldier->bDoBurst = 1;
|
||||
pSoldier->bDoAutofire = 0;
|
||||
}
|
||||
@@ -7449,7 +7499,7 @@ void DecideAlertStatus( SOLDIERTYPE *pSoldier )
|
||||
#endif
|
||||
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("DecideActionBlack: soldier = %d, orders = %d, attitude = %d",pSoldier->ubID,pSoldier->aiData.bOrders,pSoldier->aiData.bAttitude));
|
||||
|
||||
ATTACKTYPE BestStab = {},BestAttack = {};
|
||||
ATTACKTYPE BestStab, BestAttack;//dnl ch69 150913
|
||||
UINT8 ubBestStance = 1;
|
||||
BOOLEAN fChangeStanceFirst; // before firing
|
||||
INT16 ubBurstAPs;
|
||||
@@ -7765,7 +7815,7 @@ void DecideAlertStatus( SOLDIERTYPE *pSoldier )
|
||||
}
|
||||
|
||||
// NB a desire of 4 or more is only achievable by brave/aggressive guys with high morale
|
||||
UINT16 usRange = GetModifiedGunRange(pSoldier->inv[ BestAttack.bWeaponIn ].usItem);
|
||||
//UINT16 usRange = GetModifiedGunRange(pSoldier->inv[ BestAttack.bWeaponIn ].usItem);//dnl ch69 150913 not in use
|
||||
|
||||
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideActionBlack: DECIDE BETWEEN ATTACKING AND DEFENDING (TAKING COVER)");
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -7965,8 +8015,7 @@ void DecideAlertStatus( SOLDIERTYPE *pSoldier )
|
||||
{
|
||||
CalcSpreadBurst( pSoldier, BestAttack.sTarget, BestAttack.bTargetLevel );
|
||||
}
|
||||
//dnl ch58 200813 After HAM 4 BURSTING is not in use any more, for burst bAimTime and bDoAutofire must be set to 0
|
||||
pSoldier->aiData.bAimTime = 0;
|
||||
//dnl ch58 140913 After HAM 4 BURSTING is not in use any more, for burst bDoAutofire must be set to 0
|
||||
pSoldier->bDoBurst = 1;
|
||||
pSoldier->bDoAutofire = 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user