mirror of
https://github.com/1dot13/source.git
synced 2026-08-05 14:00:23 +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...
|
||||
|
||||
Reference in New Issue
Block a user