mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
Added new soldier flags: SOLDIER_BACK_ATTACK, SOLDIER_SNEAK_ATTACK (work for punch and stab attacks only).
ClosestKnownOpponent() now can return ID of closest opponent. CalcCoverValue: improved code to avoid friendly fire. EVENT_SoldierBeginPunchAttack: use supplied gridno as sTargetGridNo may not be set yet Boxing: - added possibility of counterattack after failed attack - added possibility of opportunity attack a passing enemy - bonus in CTH for boxers for attack from the back Boxing AI: - for boxers, always use high morale so that they attack - cautious boxer approach, reserve AP for two attacks (only if not attacking from the back) - try to avoid frontal attack - sometimes boxer may decide to restore breath instead of moving and attacking - boxer can step back to move away from opponent, if he is low on breath - improved main boxer AI git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8876 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
@@ -3012,6 +3012,96 @@ BOOLEAN HandleAtNewGridNo( SOLDIERTYPE *pSoldier, BOOLEAN *pfKeepMoving )
|
||||
}
|
||||
}
|
||||
|
||||
// sevenfm: check all nearby enemy boxers for opportunity attack
|
||||
if (IS_MERC_BODY_TYPE(pSoldier) &&
|
||||
(pSoldier->flags.uiStatusFlags & SOLDIER_BOXER) &&
|
||||
gTacticalStatus.bBoxingState == BOXING &&
|
||||
pSoldier->aiData.bAlertStatus >= STATUS_RED)
|
||||
{
|
||||
UINT32 uiLoop;
|
||||
UINT8 ubChance;
|
||||
SOLDIERTYPE *pOpponent;
|
||||
UINT8 ubDirection;
|
||||
|
||||
//loop through all the enemies
|
||||
for (uiLoop = 0; uiLoop < guiNumMercSlots; ++uiLoop)
|
||||
{
|
||||
pOpponent = MercSlots[uiLoop];
|
||||
|
||||
if (!pOpponent ||
|
||||
SpacesAway(pSoldier->sGridNo, pOpponent->sGridNo) > 1 ||
|
||||
pOpponent->stats.bLife < OKLIFE ||
|
||||
!ValidOpponent(pSoldier, pOpponent) ||
|
||||
pOpponent->bCollapsed ||
|
||||
pOpponent->bBreathCollapsed ||
|
||||
!IS_MERC_BODY_TYPE(pOpponent) ||
|
||||
!(pOpponent->flags.uiStatusFlags & SOLDIER_BOXER) ||
|
||||
gAnimControl[pOpponent->usAnimState].ubEndHeight < ANIM_STAND ||
|
||||
pOpponent->pathing.bLevel != pSoldier->pathing.bLevel ||
|
||||
!SoldierToSoldierLineOfSightTest(pOpponent, pSoldier, TRUE, CALC_FROM_WANTED_DIR) ||
|
||||
pOpponent->bActionPoints <= 0 ||
|
||||
pOpponent->inv[HANDPOS].exists() && pOpponent->inv[SECONDHANDPOS].exists() && !(Item[pOpponent->inv[HANDPOS].usItem].usItemClass & (IC_BLADE | IC_THROWING_KNIFE | IC_PUNCH)))
|
||||
{
|
||||
continue; // next merc
|
||||
}
|
||||
|
||||
ubChance = EffectiveAgility(pSoldier, FALSE) * (100 + pSoldier->bBreath) / 200;
|
||||
ubDirection = AIDirection(pOpponent->sGridNo, pSoldier->sGridNo);
|
||||
if (pOpponent->ubDirection == ubDirection)
|
||||
ubChance = ubChance * 3 / 4;
|
||||
else if (pOpponent->ubDirection == gOneCDirection[ubDirection] || pOpponent->ubDirection == gOneCCDirection[ubDirection])
|
||||
ubChance = ubChance / 2;
|
||||
else if (pOpponent->ubDirection == gTwoCDirection[ubDirection] || pOpponent->ubDirection == gTwoCCDirection[ubDirection])
|
||||
ubChance = ubChance / 4;
|
||||
else
|
||||
ubChance = 0;
|
||||
|
||||
if (!Chance(ubChance))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(Item[pOpponent->inv[HANDPOS].usItem].usItemClass & (IC_BLADE | IC_THROWING_KNIFE | IC_PUNCH)) &&
|
||||
!pOpponent->inv[SECONDHANDPOS].exists())
|
||||
{
|
||||
UINT16 usOldHandItem = pOpponent->inv[HANDPOS].usItem;
|
||||
SwapHandItems(pOpponent);
|
||||
pOpponent->ReLoadSoldierAnimationDueToHandItemChange(usOldHandItem, pOpponent->inv[HANDPOS].usItem);
|
||||
HandleSight(pOpponent, SIGHT_LOOK);
|
||||
|
||||
if (pOpponent->bTeam == gbPlayerNum)
|
||||
{
|
||||
fCharacterInfoPanelDirty = TRUE;
|
||||
fInterfacePanelDirty = DIRTYLEVEL2;
|
||||
}
|
||||
}
|
||||
|
||||
// stop soldier
|
||||
(*pfKeepMoving) = FALSE;
|
||||
pSoldier->EVENT_StopMerc(pSoldier->sGridNo, pSoldier->ubDirection);
|
||||
SetNewSituation(pSoldier);
|
||||
ActionDone(pSoldier);
|
||||
|
||||
// prepare attack
|
||||
pOpponent->aiData.bAimTime = 0;
|
||||
if (pOpponent->bActionPoints >= MinAPsToAttack(pOpponent, pSoldier->sGridNo, TRUE, 1, 0) && Chance(pOpponent->stats.bLife))
|
||||
pOpponent->aiData.bAimTime = 1;
|
||||
|
||||
pOpponent->bAimShotLocation = AIM_SHOT_RANDOM;
|
||||
if (gAnimControl[pSoldier->usAnimState].ubEndHeight > ANIM_PRONE)
|
||||
{
|
||||
if (Chance((6 + EffectiveDexterity(pOpponent, FALSE) / 10 + 5 * NUM_SKILL_TRAITS(pOpponent, MARTIAL_ARTS_NT)) * 100 / (100 + pSoldier->bBreath)))
|
||||
pOpponent->bAimShotLocation = AIM_SHOT_HEAD;
|
||||
else if (Chance(pSoldier->bBreath * EffectiveWisdom(pOpponent) / (100 + EffectiveDexterity(pOpponent, FALSE))))
|
||||
pOpponent->bAimShotLocation = AIM_SHOT_LEGS;
|
||||
else
|
||||
pOpponent->bAimShotLocation = AIM_SHOT_TORSO;
|
||||
}
|
||||
|
||||
HandleItem(pOpponent, pSoldier->sGridNo, pOpponent->pathing.bLevel, pOpponent->inv[HANDPOS].usItem, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
HandleSystemNewAISituation( pSoldier, FALSE );
|
||||
|
||||
// Flugente: tracker...
|
||||
|
||||
@@ -7891,6 +7891,10 @@ void SOLDIERTYPE::EVENT_BeginMercTurn( BOOLEAN fFromRealTime, INT32 iRealTimeCou
|
||||
this->usSoldierFlagMask2 &= ~SOLDIER_TAKEN_LARGE_HIT;
|
||||
}
|
||||
|
||||
// sevenfm: reset AI flags
|
||||
this->usSoldierFlagMask2 &= ~SOLDIER_BACK_ATTACK;
|
||||
this->usSoldierFlagMask2 &= ~SOLDIER_SNEAK_ATTACK;
|
||||
|
||||
// Flugente: reset extra stats. Currently they only depend on drug effects, and those are reset every turn
|
||||
this->ResetExtraStats( );
|
||||
|
||||
@@ -12780,13 +12784,32 @@ void SOLDIERTYPE::EVENT_SoldierBeginBladeAttack( INT32 sGridNo, UINT8 ubDirectio
|
||||
{
|
||||
GetSoldier( &pTSoldier, usSoldierIndex );
|
||||
|
||||
// sevenfm: set flag indicating back attack and sneak attack
|
||||
if (pTSoldier)
|
||||
{
|
||||
pTSoldier->usSoldierFlagMask2 &= ~SOLDIER_BACK_ATTACK;
|
||||
pTSoldier->usSoldierFlagMask2 &= ~SOLDIER_SNEAK_ATTACK;
|
||||
|
||||
UINT8 ubAttackDirection = AIDirection(this->sGridNo, pTSoldier->sGridNo);
|
||||
if (ubAttackDirection == pTSoldier->ubDirection ||
|
||||
ubAttackDirection == gOneCDirection[pTSoldier->ubDirection] ||
|
||||
ubAttackDirection == gOneCCDirection[pTSoldier->ubDirection])
|
||||
{
|
||||
pTSoldier->usSoldierFlagMask2 |= SOLDIER_BACK_ATTACK;
|
||||
}
|
||||
|
||||
if (pTSoldier->aiData.bOppList[this->ubID] != SEEN_CURRENTLY &&
|
||||
pTSoldier->aiData.bOppList[this->ubID] != SEEN_THIS_TURN &&
|
||||
pTSoldier->aiData.bOppList[this->ubID] != HEARD_THIS_TURN)
|
||||
{
|
||||
pTSoldier->usSoldierFlagMask2 |= SOLDIER_SNEAK_ATTACK;
|
||||
}
|
||||
}
|
||||
|
||||
// Flugente: if we attack with a bayonet, we don't need to change stance if even if we are standing and the target is prone...
|
||||
// so we simulate here that the target is still standing
|
||||
UINT8 targetheight = gAnimControl[pTSoldier->usAnimState].ubEndHeight;
|
||||
#if 0//dnl ch73 031013 several reasons why disabling this; 1. no animation for bayonet, 2. if target is prone it look ridicules to swing through air instead stub target, 3. incorrect APs calculation
|
||||
if ( this->bWeaponMode == WM_ATTACHED_BAYONET )
|
||||
targetheight = ANIM_STAND;
|
||||
#endif
|
||||
|
||||
// Look at stance of target
|
||||
switch ( targetheight )
|
||||
{
|
||||
@@ -12927,8 +12950,10 @@ void SOLDIERTYPE::EVENT_SoldierBeginPunchAttack( INT32 sGridNo, UINT8 ubDirectio
|
||||
|
||||
//}
|
||||
|
||||
// get target.....
|
||||
usSoldierIndex = WhoIsThere2( this->sTargetGridNo, this->pathing.bLevel );
|
||||
// sevenfm: use supplied gridno as sTargetGridNo may not be set yet
|
||||
//usSoldierIndex = WhoIsThere2( this->sTargetGridNo, this->pathing.bLevel );
|
||||
usSoldierIndex = WhoIsThere2(sGridNo, this->pathing.bLevel);
|
||||
|
||||
if ( usSoldierIndex != NOBODY )
|
||||
{
|
||||
GetSoldier( &pTSoldier, usSoldierIndex );
|
||||
@@ -12940,6 +12965,28 @@ void SOLDIERTYPE::EVENT_SoldierBeginPunchAttack( INT32 sGridNo, UINT8 ubDirectio
|
||||
return;
|
||||
}
|
||||
|
||||
// sevenfm: set flag indicating back attack and sneak attack
|
||||
if (pTSoldier)
|
||||
{
|
||||
pTSoldier->usSoldierFlagMask2 &= ~SOLDIER_BACK_ATTACK;
|
||||
pTSoldier->usSoldierFlagMask2 &= ~SOLDIER_SNEAK_ATTACK;
|
||||
|
||||
UINT8 ubAttackDirection = AIDirection(this->sGridNo, pTSoldier->sGridNo);
|
||||
if (ubAttackDirection == pTSoldier->ubDirection ||
|
||||
ubAttackDirection == gOneCDirection[pTSoldier->ubDirection] ||
|
||||
ubAttackDirection == gOneCCDirection[pTSoldier->ubDirection])
|
||||
{
|
||||
pTSoldier->usSoldierFlagMask2 |= SOLDIER_BACK_ATTACK;
|
||||
}
|
||||
|
||||
if (pTSoldier->aiData.bOppList[this->ubID] != SEEN_CURRENTLY &&
|
||||
pTSoldier->aiData.bOppList[this->ubID] != SEEN_THIS_TURN &&
|
||||
pTSoldier->aiData.bOppList[this->ubID] != HEARD_THIS_TURN)
|
||||
{
|
||||
pTSoldier->usSoldierFlagMask2 |= SOLDIER_SNEAK_ATTACK;
|
||||
}
|
||||
}
|
||||
|
||||
if ( fChangeDirection )
|
||||
{
|
||||
// CHANGE DIRECTION AND GOTO ANIMATION NOW
|
||||
|
||||
@@ -429,6 +429,8 @@ enum
|
||||
#define SOLDIER_DRAG_SOUND 0x00080000 // played sound when started dragging
|
||||
#define SOLDIER_SPENT_AP 0x00100000 // soldier has spent some AP this turn (including realtime)
|
||||
#define SOLDIER_TURNCOAT 0x00200000 // this enemy soldier will switch to the militia team if ordered to
|
||||
#define SOLDIER_BACK_ATTACK 0x00400000 // soldier was attacked from the back
|
||||
#define SOLDIER_SNEAK_ATTACK 0x00800000 // soldier was attacked by unseen enemy
|
||||
|
||||
#define SOLDIER_INTERROGATE_ALL 0x000001F8 // all interrogation flags
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
+69
-8
@@ -4091,7 +4091,9 @@ BOOLEAN UseHandToHand( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, BOOLEAN fStea
|
||||
{
|
||||
iHitChance = 0;
|
||||
}
|
||||
else if ( pTargetSoldier->aiData.bOppList[ pSoldier->ubID ] == NOT_HEARD_OR_SEEN )
|
||||
// sevenfm: use sneak attack code
|
||||
//else if ( pTargetSoldier->aiData.bOppList[ pSoldier->ubID ] == NOT_HEARD_OR_SEEN )
|
||||
else if (pTargetSoldier->usSoldierFlagMask2 & SOLDIER_SNEAK_ATTACK)
|
||||
{
|
||||
// give bonus for surprise, but not so much as struggle would still occur
|
||||
iHitChance = CalcChanceToSteal( pSoldier, pTargetSoldier, pSoldier->aiData.bAimTime ) + 20;
|
||||
@@ -4108,13 +4110,26 @@ BOOLEAN UseHandToHand( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, BOOLEAN fStea
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( pTargetSoldier->aiData.bOppList[ pSoldier->ubID ] == NOT_HEARD_OR_SEEN || pTargetSoldier->stats.bLife < OKLIFE || pTargetSoldier->bCollapsed )
|
||||
// sevenfm: use sneak attack code
|
||||
//if ( pTargetSoldier->aiData.bOppList[ pSoldier->ubID ] == NOT_HEARD_OR_SEEN || pTargetSoldier->stats.bLife < OKLIFE || pTargetSoldier->bCollapsed )
|
||||
if (pTargetSoldier->usSoldierFlagMask2 & SOLDIER_SNEAK_ATTACK || pTargetSoldier->stats.bLife < OKLIFE || pTargetSoldier->bCollapsed)
|
||||
{
|
||||
iHitChance = 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
iHitChance = CalcChanceToPunch( pSoldier, pTargetSoldier, pSoldier->aiData.bAimTime );
|
||||
|
||||
// sevenfm: bonus for boxers for attack from the back
|
||||
if (iHitChance < 100 &&
|
||||
(pSoldier->flags.uiStatusFlags & SOLDIER_BOXER) &&
|
||||
!pSoldier->bBlindedCounter &&
|
||||
gAnimControl[pTargetSoldier->usAnimState].ubEndHeight > ANIM_PRONE &&
|
||||
(pTargetSoldier->flags.uiStatusFlags & SOLDIER_BOXER) &&
|
||||
pTargetSoldier->usSoldierFlagMask2 & SOLDIER_BACK_ATTACK)
|
||||
{
|
||||
iHitChance += (100 - iHitChance) / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4714,13 +4729,59 @@ BOOLEAN UseHandToHand( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, BOOLEAN fStea
|
||||
PossiblyStartEnemyTaunt( pSoldier, TAUNT_MISS_HTH, pTargetSoldier->ubID );
|
||||
if( pTargetSoldier->aiData.bOppList[ pSoldier->ubID ] == SEEN_CURRENTLY )
|
||||
PossiblyStartEnemyTaunt( pTargetSoldier, TAUNT_GOT_MISSED_HTH, pSoldier->ubID );
|
||||
|
||||
//INT16 sMinAPCost = MinAPsToAttack(pTargetSoldier, pSoldier->sGridNo, TRUE, 0, 0);
|
||||
UINT8 ubCounterattackChance = EffectiveDexterity(pTargetSoldier, FALSE) * (100 + pTargetSoldier->bBreath) / 200;
|
||||
|
||||
// halve chance for counterattack if boxer was hit recently
|
||||
if (pTargetSoldier->usSoldierFlagMask2 & SOLDIER_TAKEN_LARGE_HIT)
|
||||
ubCounterattackChance /= 2;
|
||||
|
||||
// sevenfm: possibly counterattack when boxing
|
||||
if (pTargetSoldier->bActionPoints > 0 &&
|
||||
gGameOptions.fNewTraitSystem &&
|
||||
gTacticalStatus.bBoxingState == BOXING &&
|
||||
(pTargetSoldier->flags.uiStatusFlags & SOLDIER_BOXER) &&
|
||||
Chance(ubCounterattackChance) &&
|
||||
IS_MERC_BODY_TYPE(pSoldier) &&
|
||||
IS_MERC_BODY_TYPE(pTargetSoldier) &&
|
||||
gAnimControl[pTargetSoldier->usAnimState].ubEndHeight == ANIM_STAND &&
|
||||
!(pTargetSoldier->usSoldierFlagMask2 & SOLDIER_BACK_ATTACK) &&
|
||||
(!pTargetSoldier->inv[HANDPOS].exists() || Item[pTargetSoldier->inv[HANDPOS].usItem].usItemClass & (IC_BLADE | IC_THROWING_KNIFE | IC_PUNCH) || !pTargetSoldier->inv[SECONDHANDPOS].exists()))
|
||||
{
|
||||
if (!(Item[pTargetSoldier->inv[HANDPOS].usItem].usItemClass & (IC_BLADE | IC_THROWING_KNIFE | IC_PUNCH)) &&
|
||||
!pTargetSoldier->inv[SECONDHANDPOS].exists())
|
||||
{
|
||||
UINT16 usOldHandItem = pTargetSoldier->inv[HANDPOS].usItem;
|
||||
SwapHandItems(pTargetSoldier);
|
||||
pTargetSoldier->ReLoadSoldierAnimationDueToHandItemChange(usOldHandItem, pTargetSoldier->inv[HANDPOS].usItem);
|
||||
HandleSight(pTargetSoldier, SIGHT_LOOK);
|
||||
|
||||
if (pTargetSoldier->bTeam == gbPlayerNum)
|
||||
{
|
||||
fCharacterInfoPanelDirty = TRUE;
|
||||
fInterfacePanelDirty = DIRTYLEVEL2;
|
||||
}
|
||||
}
|
||||
|
||||
pTargetSoldier->aiData.bAimTime = 0;
|
||||
if (pTargetSoldier->bActionPoints >= MinAPsToAttack(pTargetSoldier, pSoldier->sGridNo, TRUE, 1, 0) && Chance(EffectiveStrength(pTargetSoldier, FALSE) / 4))
|
||||
pTargetSoldier->aiData.bAimTime = 1;
|
||||
|
||||
pTargetSoldier->bAimShotLocation = AIM_SHOT_RANDOM;
|
||||
if (gAnimControl[pSoldier->usAnimState].ubEndHeight > ANIM_PRONE)
|
||||
{
|
||||
if (Chance((6 + EffectiveDexterity(pTargetSoldier, FALSE) / 10 + 5 * NUM_SKILL_TRAITS(pTargetSoldier, MARTIAL_ARTS_NT)) * 100 / (100 + pSoldier->bBreath)))
|
||||
pTargetSoldier->bAimShotLocation = AIM_SHOT_HEAD;
|
||||
else if (Chance(pSoldier->bBreath * EffectiveWisdom(pTargetSoldier) / (100 + EffectiveDexterity(pTargetSoldier, FALSE))))
|
||||
pTargetSoldier->bAimShotLocation = AIM_SHOT_LEGS;
|
||||
else
|
||||
pTargetSoldier->bAimShotLocation = AIM_SHOT_TORSO;
|
||||
}
|
||||
|
||||
HandleItem(pTargetSoldier, pSoldier->sGridNo, pTargetSoldier->pathing.bLevel, pTargetSoldier->inv[HANDPOS].usItem, FALSE);
|
||||
}
|
||||
}
|
||||
// 0verhaul: And this too
|
||||
// else
|
||||
// {
|
||||
// DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - missed in HTH attack") );
|
||||
// FreeUpAttacker( (UINT8) pSoldier->ubID );
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-1
@@ -1385,7 +1385,7 @@ INT32 ClosestReachableDisturbance(SOLDIERTYPE *pSoldier, BOOLEAN * pfChangeLevel
|
||||
}
|
||||
|
||||
|
||||
INT32 ClosestKnownOpponent(SOLDIERTYPE *pSoldier, INT32 * psGridNo, INT8 * pbLevel)
|
||||
INT32 ClosestKnownOpponent(SOLDIERTYPE *pSoldier, INT32 * psGridNo, INT8 * pbLevel, UINT8 *pubOpponentID)
|
||||
{
|
||||
INT32 *psLastLoc,sGridNo, sClosestOpponent = NOWHERE;
|
||||
UINT32 uiLoop;
|
||||
@@ -1397,6 +1397,11 @@ INT32 ClosestKnownOpponent(SOLDIERTYPE *pSoldier, INT32 * psGridNo, INT8 * pbLev
|
||||
|
||||
bClosestLevel = -1;
|
||||
|
||||
if (pubOpponentID)
|
||||
{
|
||||
*pubOpponentID = NOBODY;
|
||||
}
|
||||
|
||||
// NOTE: THIS FUNCTION ALLOWS RETURN OF UNCONSCIOUS AND UNREACHABLE OPPONENTS
|
||||
psLastLoc = &(gsLastKnownOppLoc[pSoldier->ubID][0]);
|
||||
|
||||
@@ -1500,6 +1505,10 @@ INT32 ClosestKnownOpponent(SOLDIERTYPE *pSoldier, INT32 * psGridNo, INT8 * pbLev
|
||||
{
|
||||
*pbLevel = bClosestLevel;
|
||||
}
|
||||
if (pubOpponentID && pClosestOpponent)
|
||||
{
|
||||
*pubOpponentID = pClosestOpponent->ubID;
|
||||
}
|
||||
return( sClosestOpponent );
|
||||
}
|
||||
|
||||
|
||||
+226
-27
@@ -37,6 +37,7 @@
|
||||
#include "Text.h"
|
||||
#include "Exit Grids.h" // added by Flugente
|
||||
#include "Game Clock.h" // sevenfm
|
||||
#include "SkillCheck.h" // sevenfm
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// SANDRO - In this file, all APBPConstants[AP_CROUCH] and APBPConstants[AP_PRONE] were changed to GetAPsCrouch() and GetAPsProne()
|
||||
@@ -702,6 +703,11 @@ INT8 DecideActionGreen(SOLDIERTYPE *pSoldier)
|
||||
|
||||
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("DecideActionGreen, orders = %d",pSoldier->aiData.bOrders));
|
||||
|
||||
// sevenfm: disable stealth mode
|
||||
pSoldier->bStealthMode = FALSE;
|
||||
// disable reverse movement mode
|
||||
pSoldier->bReverse = FALSE;
|
||||
|
||||
BOOLEAN fCivilian = (PTR_CIVILIAN && (pSoldier->ubCivilianGroup == NON_CIV_GROUP || pSoldier->aiData.bNeutral || (pSoldier->ubBodyType >= FATCIV && pSoldier->ubBodyType <= CRIPPLECIV) ) );
|
||||
BOOLEAN fCivilianOrMilitia = PTR_CIV_OR_MILITIA;
|
||||
|
||||
@@ -1545,6 +1551,11 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier)
|
||||
STR16 tempstr;
|
||||
#endif
|
||||
|
||||
// sevenfm: disable stealth mode
|
||||
pSoldier->bStealthMode = FALSE;
|
||||
// disable reverse movement mode
|
||||
pSoldier->bReverse = FALSE;
|
||||
|
||||
if (fCivilian || (gGameExternalOptions.fAllNamedNpcsDecideAction && pSoldier->ubProfile != NO_PROFILE))
|
||||
{
|
||||
if (pSoldier->flags.uiStatusFlags & SOLDIER_COWERING)
|
||||
@@ -2457,6 +2468,11 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier)
|
||||
|
||||
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("DecideActionRed: soldier orders = %d",pSoldier->aiData.bOrders));
|
||||
|
||||
// sevenfm: disable stealth mode
|
||||
pSoldier->bStealthMode = FALSE;
|
||||
// disable reverse movement mode
|
||||
pSoldier->bReverse = FALSE;
|
||||
|
||||
// if we have absolutely no action points, we can't do a thing under RED!
|
||||
if ( pSoldier->bActionPoints <= 0 ) //Action points can be negative
|
||||
{
|
||||
@@ -2593,7 +2609,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier)
|
||||
//if (fCivilian && !(pSoldier->ubBodyType == COW || pSoldier->ubBodyType == CRIPPLECIV || pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE) && gTacticalStatus.bBoxingState == NOT_BOXING)
|
||||
if (fCivilian && !(pSoldier->ubBodyType == COW || pSoldier->ubBodyType == CRIPPLECIV || pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE))
|
||||
{
|
||||
if ( FindAIUsableObjClass( pSoldier, IC_WEAPON ) == ITEM_NOT_FOUND )
|
||||
if (FindAIUsableObjClass(pSoldier, IC_WEAPON) == NO_SLOT)
|
||||
{
|
||||
// cower in fear!!
|
||||
if ( pSoldier->flags.uiStatusFlags & SOLDIER_COWERING )
|
||||
@@ -4579,6 +4595,11 @@ INT16 ubMinAPCost;
|
||||
|
||||
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideActionBlack");
|
||||
|
||||
// sevenfm: disable stealth mode
|
||||
pSoldier->bStealthMode = FALSE;
|
||||
// disable reverse movement mode
|
||||
pSoldier->bReverse = FALSE;
|
||||
|
||||
// sevenfm: stop flanking when we see enemy
|
||||
if( AICheckIsFlanking(pSoldier) )
|
||||
{
|
||||
@@ -4674,7 +4695,9 @@ INT16 ubMinAPCost;
|
||||
bInGas = FALSE;
|
||||
|
||||
// calculate our morale
|
||||
pSoldier->aiData.bAIMorale = CalcMorale(pSoldier);
|
||||
// sevenfm: for boxer, always use high morale
|
||||
//pSoldier->aiData.bAIMorale = CalcMorale(pSoldier);
|
||||
pSoldier->aiData.bAIMorale = MORALE_FEARLESS;
|
||||
// and continue on...
|
||||
}
|
||||
else //????
|
||||
@@ -4835,7 +4858,6 @@ INT16 ubMinAPCost;
|
||||
// SOLDIER CAN ATTACK IF NOT IN WATER/GAS AND NOT DOING SOMETHING TOO FUNKY
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// NPCs in water/tear gas without masks are not permitted to shoot/stab/throw
|
||||
if ((pSoldier->bActionPoints < 2) || bInDeepWater || bInGas || pSoldier->aiData.bRTPCombat == RTP_COMBAT_REFRAIN)
|
||||
{
|
||||
@@ -4850,7 +4872,6 @@ INT16 ubMinAPCost;
|
||||
{
|
||||
do
|
||||
{
|
||||
|
||||
bCanAttack = CanNPCAttack(pSoldier);
|
||||
if (bCanAttack != TRUE)
|
||||
{
|
||||
@@ -5322,16 +5343,81 @@ INT16 ubMinAPCost;
|
||||
// CHOOSE THE BEST TYPE OF ATTACK OUT OF THOSE FOUND TO BE POSSIBLE
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"CHOOSE THE BEST TYPE OF ATTACK OUT OF THOSE FOUND TO BE POSSIBLE");
|
||||
BestAttack.iAttackValue = 0;
|
||||
|
||||
if (BestShot.ubPossible)
|
||||
{
|
||||
BestAttack.iAttackValue = BestShot.iAttackValue;
|
||||
ubBestAttackAction = AI_ACTION_FIRE_GUN;
|
||||
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"best action = fire gun");
|
||||
}
|
||||
else
|
||||
|
||||
// cautious boxer approach, reserve AP for two attacks (only if not attacking from the back)
|
||||
if (BestStab.ubPossible &&
|
||||
(pSoldier->flags.uiStatusFlags & SOLDIER_BOXER) &&
|
||||
SpacesAway(pSoldier->sGridNo, BestStab.sTarget) > 2 &&
|
||||
BestStab.ubOpponent != NOBODY &&
|
||||
MercPtrs[BestStab.ubOpponent] &&
|
||||
AIDirection(pSoldier->sGridNo, MercPtrs[BestStab.ubOpponent]->sGridNo) != MercPtrs[BestStab.ubOpponent]->ubDirection &&
|
||||
AIDirection(pSoldier->sGridNo, MercPtrs[BestStab.ubOpponent]->sGridNo) != gOneCDirection[MercPtrs[BestStab.ubOpponent]->ubDirection] &&
|
||||
AIDirection(pSoldier->sGridNo, MercPtrs[BestStab.ubOpponent]->sGridNo) != gOneCCDirection[MercPtrs[BestStab.ubOpponent]->ubDirection] &&
|
||||
pSoldier->bInitialActionPoints >= 2 * MinAPsToAttack(pSoldier, pSoldier->sLastTarget, FALSE, 0, 0) + APBPConstants[AP_MOVEMENT_FLAT] + APBPConstants[AP_MODIFIER_WALK] &&
|
||||
pSoldier->bActionPoints < BestStab.ubAPCost + MinAPsToAttack(pSoldier, pSoldier->sLastTarget, FALSE, 0, 0))
|
||||
{
|
||||
BestAttack.iAttackValue = 0;
|
||||
BestStab.ubPossible = FALSE;
|
||||
fTryPunching = FALSE;
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("boxer cannot reserve APs for second attack - disable stab attack"));
|
||||
}
|
||||
|
||||
// try to avoid frontal attack
|
||||
if (BestStab.ubPossible &&
|
||||
(pSoldier->flags.uiStatusFlags & SOLDIER_BOXER) &&
|
||||
SpacesAway(pSoldier->sGridNo, BestStab.sTarget) > 1 &&
|
||||
BestStab.ubOpponent != NOBODY &&
|
||||
MercPtrs[BestStab.ubOpponent] &&
|
||||
gAnimControl[MercPtrs[BestStab.ubOpponent]->usAnimState].ubEndHeight == ANIM_STAND &&
|
||||
MercPtrs[BestStab.ubOpponent]->bActionPoints > 0 &&
|
||||
Chance(EffectiveAgility(MercPtrs[BestStab.ubOpponent], FALSE) * (100 + MercPtrs[BestStab.ubOpponent]->bBreath) * EffectiveWisdom(pSoldier) / (100 * 200)))
|
||||
{
|
||||
// find closest spot around opponent, avoid front direction
|
||||
UINT8 ubMovementCost;
|
||||
INT32 sTempGridNo;
|
||||
UINT8 ubDirection;
|
||||
INT32 sPathCost;
|
||||
INT32 sBestSpot = NOWHERE;
|
||||
INT32 sBestPathCost = 0;
|
||||
|
||||
for (ubDirection = 0; ubDirection < NUM_WORLD_DIRECTIONS; ubDirection++)
|
||||
{
|
||||
sTempGridNo = NewGridNo(BestStab.sTarget, DirectionInc(ubDirection));
|
||||
|
||||
if (sTempGridNo != BestStab.sTarget)
|
||||
{
|
||||
ubMovementCost = gubWorldMovementCosts[sTempGridNo][ubDirection][pSoldier->pathing.bLevel];
|
||||
|
||||
if (ubMovementCost < TRAVELCOST_BLOCKED &&
|
||||
NewOKDestination(pSoldier, sTempGridNo, FALSE, pSoldier->pathing.bLevel) &&
|
||||
AIDirection(BestStab.sTarget, sTempGridNo) != MercPtrs[BestStab.ubOpponent]->ubDirection)
|
||||
{
|
||||
sPathCost = PlotPath(pSoldier, sTempGridNo, FALSE, FALSE, FALSE, DetermineMovementMode(pSoldier, AI_ACTION_GET_CLOSER), pSoldier->bStealthMode, pSoldier->bReverse, 0);
|
||||
if (TileIsOutOfBounds(sBestSpot) || sPathCost < sBestPathCost)
|
||||
{
|
||||
sBestSpot = sTempGridNo;
|
||||
sBestPathCost = sPathCost;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!TileIsOutOfBounds(sBestSpot) &&
|
||||
pSoldier->bActionPoints >= sPathCost + GetAPsToLook(pSoldier) + MinAPsToAttack(pSoldier, pSoldier->sLastTarget, FALSE, 0, 0))
|
||||
{
|
||||
pSoldier->aiData.usActionData = sBestSpot;
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("boxer: get closer to opponent, avoid front direction"));
|
||||
return(AI_ACTION_GET_CLOSER);
|
||||
}
|
||||
}
|
||||
|
||||
if (BestStab.ubPossible && ((BestStab.iAttackValue > BestAttack.iAttackValue) || (ubBestAttackAction == AI_ACTION_NONE)))
|
||||
{
|
||||
BestAttack.iAttackValue = BestStab.iAttackValue;
|
||||
@@ -6100,34 +6186,147 @@ L_NEWAIM:
|
||||
// try to make boxer close if possible
|
||||
if (pSoldier->flags.uiStatusFlags & SOLDIER_BOXER )
|
||||
{
|
||||
if ( ubCanMove )
|
||||
DebugAI(AI_MSG_TOPIC, pSoldier, String("[Make boxer close if possible]"));
|
||||
|
||||
UINT8 ubOpponentID;
|
||||
sClosestOpponent = ClosestKnownOpponent(pSoldier, NULL, NULL, &ubOpponentID);
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("boxer: found closest opponent [%d] at %d", ubOpponentID, sClosestOpponent));
|
||||
|
||||
if (!TileIsOutOfBounds(sClosestOpponent) &&
|
||||
ubOpponentID != NOBODY &&
|
||||
MercPtrs[ubOpponentID])
|
||||
{
|
||||
sClosestOpponent = ClosestSeenOpponent(pSoldier, NULL, NULL);
|
||||
|
||||
if (!TileIsOutOfBounds(sClosestOpponent))
|
||||
if (pSoldier->bActionPoints > 0)
|
||||
{
|
||||
// temporarily make boxer have orders of CLOSEPATROL rather than STATIONARY
|
||||
// And make him patrol the ring, not his usual place
|
||||
// so he has a good roaming range
|
||||
USHORT tgrd = pSoldier->aiData.sPatrolGrid[0];
|
||||
pSoldier->aiData.sPatrolGrid[0] = pSoldier->sGridNo;
|
||||
pSoldier->aiData.bOrders = CLOSEPATROL;
|
||||
pSoldier->aiData.usActionData = GoAsFarAsPossibleTowards( pSoldier, sClosestOpponent, AI_ACTION_GET_CLOSER );
|
||||
pSoldier->aiData.sPatrolGrid[0] = tgrd;
|
||||
pSoldier->aiData.bOrders = STATIONARY;
|
||||
|
||||
if (!TileIsOutOfBounds(pSoldier->aiData.usActionData))
|
||||
if (SpacesAway(pSoldier->sGridNo, sClosestOpponent) > 1)
|
||||
{
|
||||
// truncate path to 1 step
|
||||
pSoldier->aiData.usActionData = pSoldier->sGridNo + DirectionInc( (UINT8) pSoldier->pathing.usPathingData[0] );
|
||||
pSoldier->pathing.sFinalDestination = pSoldier->aiData.usActionData;
|
||||
pSoldier->aiData.bNextAction = AI_ACTION_END_TURN;
|
||||
return( AI_ACTION_GET_CLOSER );
|
||||
INT16 sReserveAP = GetAPsToLook(pSoldier) + 2 * MinAPsToAttack(pSoldier, pSoldier->sLastTarget, FALSE, 0, 0);
|
||||
BOOLEAN fLimitOneStep = FALSE;
|
||||
|
||||
if (pSoldier->bInitialActionPoints < sReserveAP + APBPConstants[AP_MOVEMENT_FLAT] + APBPConstants[AP_MODIFIER_WALK])
|
||||
{
|
||||
sReserveAP = GetAPsToLook(pSoldier) + MinAPsToAttack(pSoldier, pSoldier->sLastTarget, FALSE, 0, 0);
|
||||
}
|
||||
|
||||
if (pSoldier->bInitialActionPoints < sReserveAP + APBPConstants[AP_MOVEMENT_FLAT] + APBPConstants[AP_MODIFIER_WALK] &&
|
||||
pSoldier->bInitialActionPoints >= GetAPsToLook(pSoldier) + MinAPsToAttack(pSoldier, pSoldier->sLastTarget, FALSE, 0, 0) &&
|
||||
SpacesAway(pSoldier->sGridNo, sClosestOpponent) > 2)
|
||||
{
|
||||
sReserveAP = GetAPsToLook(pSoldier) + 1;
|
||||
fLimitOneStep = TRUE;
|
||||
}
|
||||
|
||||
// temporarily make boxer have orders of CLOSEPATROL rather than STATIONARY
|
||||
// And make him patrol the ring, not his usual place
|
||||
// so he has a good roaming range
|
||||
INT32 tgrd = pSoldier->aiData.sPatrolGrid[0];
|
||||
pSoldier->aiData.sPatrolGrid[0] = pSoldier->sGridNo;
|
||||
pSoldier->aiData.bOrders = CLOSEPATROL;
|
||||
//pSoldier->aiData.usActionData = GoAsFarAsPossibleTowards( pSoldier, sClosestOpponent, AI_ACTION_GET_CLOSER );
|
||||
pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier, sClosestOpponent, sReserveAP, AI_ACTION_GET_CLOSER, 0);
|
||||
pSoldier->aiData.sPatrolGrid[0] = tgrd;
|
||||
pSoldier->aiData.bOrders = STATIONARY;
|
||||
|
||||
// decide to restore breath
|
||||
if (!TileIsOutOfBounds(pSoldier->aiData.usActionData) &&
|
||||
(pSoldier->bBreath < OKBREATH ||
|
||||
pSoldier->bBreath < pSoldier->bBreathMax &&
|
||||
pSoldier->bBreath < MercPtrs[ubOpponentID]->bBreath &&
|
||||
Chance((100 - pSoldier->bBreath) * (100 - pSoldier->bBreath) / (2 * 100 * 100))))
|
||||
{
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("boxer: restore breath"));
|
||||
pSoldier->aiData.usActionData = NOWHERE;
|
||||
}
|
||||
|
||||
if (!TileIsOutOfBounds(pSoldier->aiData.usActionData))
|
||||
{
|
||||
// truncate path to 1 step
|
||||
if (fLimitOneStep)
|
||||
{
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("boxer: limit movement to one step"));
|
||||
pSoldier->aiData.usActionData = pSoldier->sGridNo + DirectionInc((UINT8)pSoldier->pathing.usPathingData[0]);
|
||||
pSoldier->pathing.sFinalDestination = pSoldier->aiData.usActionData;
|
||||
}
|
||||
|
||||
//pSoldier->aiData.bNextAction = AI_ACTION_END_TURN;
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("boxer: get closer to opponent"));
|
||||
return(AI_ACTION_GET_CLOSER);
|
||||
}
|
||||
}
|
||||
else if (pSoldier->bBreath < OKBREATH ||
|
||||
pSoldier->bBreath < pSoldier->bBreathMax &&
|
||||
(pSoldier->bBreath < MercPtrs[ubOpponentID]->bBreath || !pSoldier->aiData.bLastAttackHit && (pSoldier->usSoldierFlagMask2 & SOLDIER_TAKEN_LARGE_HIT)))
|
||||
{
|
||||
// maybe move away from opponent
|
||||
UINT8 ubOpponentDir = AIDirection(pSoldier->sGridNo, sClosestOpponent);
|
||||
INT32 sCheckGridNo = NewGridNo(pSoldier->sGridNo, DirectionInc(gOppositeDirection[ubOpponentDir]));
|
||||
|
||||
// only use reverse movement if we are facing opponent
|
||||
if (pSoldier->ubDirection == ubOpponentDir ||
|
||||
pSoldier->ubDirection == gOneCDirection[ubOpponentDir] ||
|
||||
pSoldier->ubDirection == gOneCCDirection[ubOpponentDir])
|
||||
{
|
||||
pSoldier->bReverse = TRUE;
|
||||
}
|
||||
|
||||
if (!NewOKDestination(pSoldier, sCheckGridNo, FALSE, pSoldier->pathing.bLevel) ||
|
||||
PlotPath(pSoldier, sCheckGridNo, FALSE, FALSE, FALSE, DetermineMovementMode(pSoldier, AI_ACTION_TAKE_COVER), pSoldier->bStealthMode, pSoldier->bReverse, 0) > pSoldier->bActionPoints - 1)
|
||||
{
|
||||
//if (sPathcost > pSoldier->bActionPoints - (GetAPsToLook(pSoldier) + 1))
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("boxer: bad destination or high path cost, cannot move away"));
|
||||
sCheckGridNo = NOWHERE;
|
||||
}
|
||||
|
||||
// maybe try diagonal movement
|
||||
if (TileIsOutOfBounds(sCheckGridNo) && Chance(50))
|
||||
{
|
||||
sCheckGridNo = NewGridNo(pSoldier->sGridNo, DirectionInc(gOneCDirection[gOppositeDirection[ubOpponentDir]]));
|
||||
if (!NewOKDestination(pSoldier, sCheckGridNo, FALSE, pSoldier->pathing.bLevel) ||
|
||||
PlotPath(pSoldier, sCheckGridNo, FALSE, FALSE, FALSE, DetermineMovementMode(pSoldier, AI_ACTION_TAKE_COVER), pSoldier->bStealthMode, pSoldier->bReverse, 0) > pSoldier->bActionPoints - 1)
|
||||
{
|
||||
//if (sPathcost > pSoldier->bActionPoints - (GetAPsToLook(pSoldier) + 1))
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("boxer: bad destination or high path cost, cannot move away"));
|
||||
sCheckGridNo = NOWHERE;
|
||||
}
|
||||
}
|
||||
if (TileIsOutOfBounds(sCheckGridNo) && Chance(50))
|
||||
{
|
||||
sCheckGridNo = NewGridNo(pSoldier->sGridNo, DirectionInc(gOneCCDirection[gOppositeDirection[ubOpponentDir]]));
|
||||
if (!NewOKDestination(pSoldier, sCheckGridNo, FALSE, pSoldier->pathing.bLevel) ||
|
||||
PlotPath(pSoldier, sCheckGridNo, FALSE, FALSE, FALSE, DetermineMovementMode(pSoldier, AI_ACTION_TAKE_COVER), pSoldier->bStealthMode, pSoldier->bReverse, 0) > pSoldier->bActionPoints - 1)
|
||||
{
|
||||
//if (sPathcost > pSoldier->bActionPoints - (GetAPsToLook(pSoldier) + 1))
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("boxer: bad destination or high path cost, cannot move away"));
|
||||
sCheckGridNo = NOWHERE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!TileIsOutOfBounds(sCheckGridNo))
|
||||
{
|
||||
pSoldier->aiData.usActionData = sCheckGridNo;
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("boxer: get away from opponent"));
|
||||
return(AI_ACTION_TAKE_COVER);
|
||||
}
|
||||
pSoldier->bReverse = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
UINT8 ubOpponentDir = AIDirection(pSoldier->sGridNo, sClosestOpponent);
|
||||
|
||||
// possibly turn to closest opponent
|
||||
if (pSoldier->ubDirection != ubOpponentDir &&
|
||||
pSoldier->InternalIsValidStance(ubOpponentDir, gAnimControl[pSoldier->usAnimState].ubEndHeight) &&
|
||||
pSoldier->bActionPoints >= GetAPsToLook(pSoldier))
|
||||
{
|
||||
pSoldier->aiData.usActionData = ubOpponentDir;
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("boxer: turn to closest opponent"));
|
||||
return(AI_ACTION_CHANGE_FACING);
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise do nothing
|
||||
return( AI_ACTION_NONE );
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("boxer: nothing to do"));
|
||||
return(AI_ACTION_NONE);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -403,19 +403,20 @@ INT32 CalcCoverValue(SOLDIERTYPE *pMe, INT32 sMyGridNo, INT32 iMyThreat, INT32 i
|
||||
bMyCTGT = CalcAverageCTGTForPosition( pMe, pHim->ubID, sHisGridNo, pHim->pathing.bLevel, iMyAPsLeft );
|
||||
gUnderFire.Disable();
|
||||
ubFriendlyFireChance = gUnderFire.Chance(pMe->bTeam, pMe->bSide, TRUE);
|
||||
|
||||
// sevenfm: penalize position if friendly fire chance is high
|
||||
if (gGameExternalOptions.fAIBetterCover && ubFriendlyFireChance > MIN_CHANCE_TO_ACCIDENTALLY_HIT_SOMEONE)
|
||||
|
||||
if (gGameExternalOptions.fAIBetterCover)
|
||||
{
|
||||
bMyCTGT = 1;
|
||||
}
|
||||
|
||||
// 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
|
||||
// cover is below the "see_thru" threshold, it's equivalent to perfect cover!
|
||||
if (bMyCTGT < SEE_THRU_COVER_THRESHOLD)
|
||||
// sevenfm: penalize position if friendly fire chance is high
|
||||
if (ubFriendlyFireChance > MIN_CHANCE_TO_ACCIDENTALLY_HIT_SOMEONE)
|
||||
bMyCTGT = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
bMyCTGT = 0;
|
||||
// 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
|
||||
// cover is below the "see_thru" threshold, it's equivalent to perfect cover!
|
||||
if (bMyCTGT < SEE_THRU_COVER_THRESHOLD)
|
||||
bMyCTGT = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -175,7 +175,7 @@ void CheckForChangingOrders(SOLDIERTYPE *pSoldier );
|
||||
|
||||
INT8 ClosestPanicTrigger( SOLDIERTYPE * pSoldier );
|
||||
|
||||
INT32 ClosestKnownOpponent(SOLDIERTYPE *pSoldier, INT32 * psGridNo, INT8 * pbLevel);
|
||||
INT32 ClosestKnownOpponent(SOLDIERTYPE *pSoldier, INT32 * psGridNo, INT8 * pbLevel, UINT8 *pubOpponentID = NULL);
|
||||
INT32 ClosestPC( SOLDIERTYPE *pSoldier, INT32 * psDistance );
|
||||
INT32 ClosestUnDisguisedPC( SOLDIERTYPE *pSoldier, INT32 * psDistance ); // Flugente: like ClosestPC(...), but does not account for covert or not visible mercs
|
||||
BOOLEAN CanAutoBandage( BOOLEAN fDoFullCheck );
|
||||
|
||||
Reference in New Issue
Block a user