EstimateStabDamage: updated code.

Black AI: 
- reduce stab attack attractiveness if target is not very close
- reduce stab attack attractiveness if soldier sees more than one opponent
- for HTH attacks, skills don't have effect on choosing attack type for boxers
- reduce HTH attack attractiveness if soldier sees more than one opponent
- allow to increase autofire bullets by reducing aim in NCTH if LIMIT_MAX_DEVIATION option is enabled

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8902 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Sevenfm
2020-10-16 19:52:57 +00:00
parent 47c58e79d5
commit b5cbc32261
2 changed files with 178 additions and 134 deletions
+103 -90
View File
@@ -33,6 +33,7 @@
#include "Structure Wrap.h" // IsRoofPresentAtGridNo
#include "Render Fun.h"
#include "worldman.h"
#include "WCheck.h"
#endif
// anv: for enemy taunts
@@ -1710,6 +1711,7 @@ void CalcBestStab(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestStab, BOOLEAN fBladeAt
//InitAttackType(pBestStab); // set all structure fields to defaults//dnl ch69 150913
pSoldier->usAttackingWeapon = pSoldier->inv[HANDPOS].usItem;
pSoldier->bWeaponMode = WM_NORMAL;
// sevenfm: initialize
pBestStab->ubPossible = FALSE;
@@ -1872,7 +1874,6 @@ void CalcBestStab(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestStab, BOOLEAN fBladeAt
// NOTE: ignore my cover! By the time I run beside him I won't have any!
iThreatValue = CalcManThreatValue(pOpponent,pSoldier->sGridNo,FALSE,pSoldier);
// estimate the damage this stab would do to this opponent
iEstDamage = EstimateStabDamage(pSoldier,pOpponent,ubBestChanceToHit, fBladeAttack );
//NumMessage("STAB EstDamage = ", iEstDamage);
@@ -2399,155 +2400,167 @@ INT32 EstimateThrowDamage( SOLDIERTYPE *pSoldier, UINT8 ubItemPos, SOLDIERTYPE *
return( iDamage);
}
INT32 EstimateStabDamage( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent,
INT16 ubChanceToHit, BOOLEAN fBladeAttack )
INT32 EstimateStabDamage( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, INT16 ubChanceToHit, BOOLEAN fBladeAttack )
{
INT32 iImpact, iFluke, iBonus;
INT32 iImpact, iBonus;
UINT16 usItem;
UINT16 usItem;
CHECKF(pSoldier);
CHECKF(pOpponent);
usItem = pSoldier->inv[HANDPOS].usItem;
if (fBladeAttack)
{
iImpact = GetDamage(&pSoldier->inv[HANDPOS]);
iImpact += EffectiveStrength( pSoldier, FALSE ) / 20; // 0 to 5 for strength, adjusted by damage taken
iImpact = GetDamage(&(pSoldier->inv[HANDPOS]));
iImpact += EffectiveStrength(pSoldier, FALSE) / 20; // 0 to 5 for strength, adjusted by damage taken
if (AM_A_ROBOT(pOpponent))
{
iImpact /= 4;
}
}
else
{
// this all was a little changed for enhanced close combat system - SANDRO
if ( gGameExternalOptions.fEnhancedCloseCombatSystem )
{
iImpact = EffectiveStrength( pSoldier, FALSE ) / 5; // 0 to 20 for strength, adjusted by damage taken
iImpact = EffectiveStrength(pSoldier, FALSE) / 5; // 0 to 20 for strength, adjusted by damage taken
if ( pSoldier->usAttackingWeapon )
// NB martial artists don't get a bonus for using brass knuckles! - oh, they do in STOMP - SANDRO
if (pSoldier->usAttackingWeapon)
{
if (gGameOptions.fNewTraitSystem)
{
iImpact += GetDamage(&pSoldier->inv[HANDPOS]);
iImpact += GetDamage(&(pSoldier->inv[HANDPOS]));
if (AM_A_ROBOT(pOpponent))
{
iImpact /= 2;
}
}
else
{
// base HTH damage
iImpact += 4; // Slightly reduced for we can now attack to head for bigger damage - SANDRO
// Add melee damage multiplier to bare HtH attacks as well - SANDRO
// actually I make the influence a little lesser, because to the blades and so,
// only the item impact is multiplied, not the level and strength bonus, but here it does
iImpact += iImpact * gGameExternalOptions.iMeleeDamageModifier / 120;
if (!HAS_SKILL_TRAIT(pSoldier, MARTIALARTS_OT))
{
iImpact += GetDamage(&(pSoldier->inv[HANDPOS]));
}
if (AM_A_ROBOT(pOpponent))
{
iImpact /= 2;
}
}
}
else
{
// NB martial artists don't get a bonus for using brass knuckles!
if (pSoldier->usAttackingWeapon && !( HAS_SKILL_TRAIT( pSoldier, MARTIALARTS_OT ) ) )
// base HTH damage
// Enhanced Close Combat System - Slightly reduced for we can now attack to head for bigger damage
if (gGameExternalOptions.fEnhancedCloseCombatSystem)
{
iImpact = GetDamage(&pSoldier->inv[HANDPOS]);
iImpact += 4;
}
else
{
// base HTH damage
iImpact = 5;
iImpact += 5;
}
// Add melee damage multiplier to HtH attacks as well - SANDRO
iImpact = (INT32)(iImpact * gGameExternalOptions.iMeleeDamageModifier / 100);
if (AM_A_ROBOT(pOpponent))
{
iImpact = 0;
}
iImpact += EffectiveStrength( pSoldier, FALSE ) / 5; // 0 to 20 for strength, adjusted by damage taken
}
}
iImpact += EffectiveExpLevel(pSoldier) / 2;
iImpact += (EffectiveExpLevel( pSoldier ) / 2); // 0 to 4 for level // SANDRO - added effective level calc
// up to 25% extra impact for accurate attacks
iImpact = iImpact * (100 + ubChanceToHit / 4) / 100;
iFluke = 0;
iBonus = ubChanceToHit / 4; // up to 50% extra impact for accurate attacks
iImpact = iImpact * (100 + iFluke + iBonus) / 100;
iBonus = 0;
if (!fBladeAttack)
{
// add bonuses for hand-to-hand and martial arts
// Check for new traits - SANDRO
if ( gGameOptions.fNewTraitSystem )
if (gGameOptions.fNewTraitSystem)
{
if (!pSoldier->usAttackingWeapon || Item[pSoldier->inv[HANDPOS].usItem].brassknuckles)
if (!pSoldier->usAttackingWeapon || Item[usItem].brassknuckles)
{
// add bonuses for martial arts
if ( HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) )
// add bonus for martial arts
if (HAS_SKILL_TRAIT(pSoldier, MARTIAL_ARTS_NT))
{
// also add breath damage bonus into consideration
iImpact = (INT32)(iImpact * ( 100 + (gSkillTraitValues.ubMABonusDamageHandToHand + gSkillTraitValues.ubMABonusBreathDamageHandToHand) * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) ) / 100.0f + 0.5f);
// The Spinning kicks or aimed punch bonus - SANDRO
//if (pSoldier->usAnimState == NINJA_SPINKICK || (pSoldier->aiData.bAimTime > 0))
//{
// iImpact += (iImpact * gSkillTraitValues.usMAAimedPunchDamageBonus * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) ) / 100; // +75% damage per trait
//}
iBonus += (gSkillTraitValues.ubMABonusDamageHandToHand * NUM_SKILL_TRAITS(pSoldier, MARTIAL_ARTS_NT));
}
}
else
{
// +30% damage of blunt weapons for melee character
if (HAS_SKILL_TRAIT( pSoldier, MELEE_NT ))
// bonus damage of blunt weapons for melee character
if (HAS_SKILL_TRAIT(pSoldier, MELEE_NT))
{
iImpact = (INT32)(iImpact * (100 + gSkillTraitValues.ubMEDamageBonusBlunt) / 100.0f + 0.5f);
//if (pSoldier->aiData.bAimTime > 0)
//{
// iImpact += (iImpact * (100 + gSkillTraitValues.usMEAimedMeleeAttackDamageBonus) / 100); // 50% incresed damage if focused melee attack
//}
iBonus += gSkillTraitValues.ubMEDamageBonusBlunt;
}
}
}
else
else // original code
{
if ( HAS_SKILL_TRAIT( pSoldier, MARTIALARTS_OT ) )
// add bonuses for hand-to-hand and martial arts
if (HAS_SKILL_TRAIT(pSoldier, MARTIALARTS_OT))
{
iImpact = (INT32)(iImpact * (100 + gbSkillTraitBonus[MARTIALARTS_OT] * NUM_SKILL_TRAITS( pSoldier, MARTIALARTS_OT ) ) / 100.0f + 0.5f);
iBonus += gbSkillTraitBonus[MARTIALARTS_OT] * NUM_SKILL_TRAITS(pSoldier, MARTIALARTS_OT);
if (pSoldier->usAnimState == NINJA_SPINKICK)
{
iBonus += 100;
}
}
if ( HAS_SKILL_TRAIT( pSoldier, HANDTOHAND_OT ) )
if (HAS_SKILL_TRAIT(pSoldier, HANDTOHAND_OT))
{
iImpact = (INT32)(iImpact * (100 + gbSkillTraitBonus[HANDTOHAND_OT] * NUM_SKILL_TRAITS( pSoldier, HANDTOHAND_OT ) ) / 100.0f + 0.5f);
// SPECIAL - give TRIPLE bonus for damage for hand-to-hand trait
// because the HTH bonus is half that of martial arts, and gets only 1x for to-hit bonus
iBonus += 3 * gbSkillTraitBonus[HANDTOHAND_OT] * NUM_SKILL_TRAITS(pSoldier, HANDTOHAND_OT);
}
}
// SANDRO - Enhanced Close Combat System - aiming at body parts makes difference
if (gGameExternalOptions.fEnhancedCloseCombatSystem && (gAnimControl[ pOpponent->usAnimState ].ubEndHeight == ANIM_PRONE))
{
iImpact = (INT32)(iImpact * 150 / 100); // 50% incresed damage to lying characters
}
// Here, if we're doing a bare-fisted attack,
// we want to pay attention just to wounds inflicted
// SANDRO - No, we may consider the breath damage as asort of "real" damage too, so only reduce it by half
iImpact = iImpact / 2;
//iImpact = iImpact / PUNCH_REAL_DAMAGE_PORTION;
}
// SANDRO - damage bonus to melee trait
else
{
if ( HAS_SKILL_TRAIT( pSoldier, MELEE_NT ) && (gGameOptions.fNewTraitSystem) )
{
iImpact += (iImpact * (100 + gSkillTraitValues.ubMEDamageBonusBlades ) / 100); // +30% damage
//if (pSoldier->aiData.bAimTime > 0)
//{
// iImpact += (iImpact * ( 100 + gSkillTraitValues.usMEAimedMeleeAttackDamageBonus ) / 100); // 50% incresed damage if focused melee attack
//}
}
// SANDRO - Enhanced Close Combat System
if (gGameExternalOptions.fEnhancedCloseCombatSystem)
{
if (gAnimControl[ pOpponent->usAnimState ].ubEndHeight == ANIM_PRONE)
if (gAnimControl[pOpponent->usAnimState].ubEndHeight == ANIM_PRONE)
{
iImpact = (INT32)(iImpact * 140 / 100); // 40% incresed damage to lying characters
iBonus += 30; // 30% increased damage to lying characters
}
}
}
// DAMAGE BONUS TO KNIFE ATTACK WITH MELEE SKILL
else
{
if (gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT(pSoldier, MELEE_NT))
{
iBonus += gSkillTraitValues.ubMEDamageBonusBlades; // +30% damage
}
// Enhanced Close Combat System
if (gGameExternalOptions.fEnhancedCloseCombatSystem)
{
if (gAnimControl[pOpponent->usAnimState].ubEndHeight == ANIM_PRONE)
{
iBonus += 30; // increased damage to lying characters
}
}
}
// Flugente: Add personal damage bonus
iImpact = (iImpact * (100 + pSoldier->GetMeleeDamageBonus() ) / 100);
// apply all bonuses
iImpact = (iImpact * (100 + iBonus) + 50) / 100; // round it properly
if (iImpact < 1)
// Flugente: moved the damage calculation into a separate function
iImpact = max(1, (INT32)(iImpact * (100 - pOpponent->GetDamageResistance(FALSE, FALSE)) / 100));
// Flugente: Add personal damage bonus
if (fBladeAttack)
{
iImpact = 1;
iImpact = (iImpact * (100 + pSoldier->GetMeleeDamageBonus()) / 100);
}
return( iImpact );
iImpact = max(1, iImpact);
return iImpact;
}
INT8 TryToReload( SOLDIERTYPE * pSoldier )
+75 -44
View File
@@ -5559,6 +5559,26 @@ INT16 ubMinAPCost;
if (BestStab.ubPossible)
{
INT32 sAttackDist = PythSpacesAway(pSoldier->sGridNo, BestStab.sTarget);
INT32 sMaxStabAttackDist = TACTICAL_RANGE / 8;
// sevenfm: limit stab attacks when target is not very close
if (sAttackDist > sMaxStabAttackDist)
{
BestStab.iAttackValue = BestStab.iAttackValue * sMaxStabAttackDist / sAttackDist;
}
if (!(gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT(pSoldier, MELEE_NT)) &&
!(!gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT(pSoldier, KNIFING_OT)))
{
BestStab.iAttackValue /= 4;
}
// sevenfm: reduce stab attack attractiveness depending on number of seen opponents
if (pSoldier->aiData.bOppCnt > 1)
{
BestStab.iAttackValue /= pSoldier->aiData.bOppCnt;
}
// now we KNOW FOR SURE that we will do something (stab, at least)
NPCDoesAct(pSoldier);
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"NPC decided to stab");
@@ -5604,62 +5624,72 @@ INT16 ubMinAPCost;
if (BestStab.ubPossible)
{
// if we have not enough APs to deal at least two or three punches,
// reduce the attack value as one punch ain't much
if( gGameOptions.fNewTraitSystem )
if (!(pSoldier->flags.uiStatusFlags & SOLDIER_BOXER))
{
// if we are not specialized, reduce the attack attractiveness generaly
if ( !HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) )
// if we have not enough APs to deal at least two or three punches,
// reduce the attack value as one punch ain't much
if (gGameOptions.fNewTraitSystem)
{
BestStab.iAttackValue /= 4;
// if too far and not having APs for at least 3 hits no way to attack
if (((CalcTotalAPsToAttack( pSoldier,BestStab.sTarget,ADDTURNCOST, 0 ) + (2 * (ApsToPunch( pSoldier )))) > pSoldier->bActionPoints) && !(PythSpacesAway(pSoldier->sGridNo, BestStab.sTarget) <= 1) )
// if we are not specialized, reduce the attack attractiveness generally
if (!HAS_SKILL_TRAIT(pSoldier, MARTIAL_ARTS_NT))
{
BestStab.ubPossible = 0;
BestStab.iAttackValue = 0;
BestStab.iAttackValue /= 4;
// if too far and not having APs for at least 3 hits no way to attack
if (((CalcTotalAPsToAttack(pSoldier, BestStab.sTarget, ADDTURNCOST, 0) + (2 * (ApsToPunch(pSoldier)))) > pSoldier->bActionPoints) && !(PythSpacesAway(pSoldier->sGridNo, BestStab.sTarget) <= 1))
{
BestStab.ubPossible = 0;
BestStab.iAttackValue = 0;
}
}
else
{
if (PythSpacesAway(pSoldier->sGridNo, BestStab.sTarget) <= 1)
{
BestStab.iAttackValue = (BestStab.iAttackValue * 2);
}
// if too far and not having APs for at least 2 hits
else if (((CalcTotalAPsToAttack(pSoldier, BestStab.sTarget, ADDTURNCOST, 0) + ApsToPunch(pSoldier)) > pSoldier->bActionPoints) && !(PythSpacesAway(pSoldier->sGridNo, BestStab.sTarget) <= 1))
{
BestStab.iAttackValue /= 3;
}
}
}
else
{
if (PythSpacesAway(pSoldier->sGridNo, BestStab.sTarget) <= 1)
if (!HAS_SKILL_TRAIT(pSoldier, MARTIALARTS_OT) && !HAS_SKILL_TRAIT(pSoldier, HANDTOHAND_OT))
{
BestStab.iAttackValue = (BestStab.iAttackValue * 2);
// if we are not specialized, reduce the attack attractiveness generally
BestStab.iAttackValue /= 4;
// if too far and not having APs for at least 3 hits
if (((CalcTotalAPsToAttack(pSoldier, BestStab.sTarget, ADDTURNCOST, 0) + (2 * (ApsToPunch(pSoldier)))) > pSoldier->bActionPoints) && !(PythSpacesAway(pSoldier->sGridNo, BestStab.sTarget <= 1)))
{
BestStab.ubPossible = 0;
BestStab.iAttackValue = 0;
}
}
// if too far and not having APs for at least 2 hits
else if (((CalcTotalAPsToAttack( pSoldier,BestStab.sTarget,ADDTURNCOST, 0 ) + ApsToPunch( pSoldier )) > pSoldier->bActionPoints) && !(PythSpacesAway(pSoldier->sGridNo, BestStab.sTarget) <= 1))
else
{
BestStab.iAttackValue /= 3;
}
}
}
else
{
if ( !HAS_SKILL_TRAIT( pSoldier, MARTIALARTS_OT ) && !HAS_SKILL_TRAIT( pSoldier, HANDTOHAND_OT ) )
{
// if we are not specialized, reduce the attack attractiveness generaly
BestStab.iAttackValue /= 4;
// if too far and not having APs for at least 3 hits
if (((CalcTotalAPsToAttack( pSoldier,BestStab.sTarget,ADDTURNCOST, 0 ) + (2 * (ApsToPunch( pSoldier )))) > pSoldier->bActionPoints) && !(PythSpacesAway(pSoldier->sGridNo, BestStab.sTarget <= 1)) )
{
BestStab.ubPossible = 0;
BestStab.iAttackValue = 0;
}
}
else
{
BestStab.iAttackValue = ((BestStab.iAttackValue * 3)/2);
BestStab.iAttackValue = ((BestStab.iAttackValue * 3) / 2);
if (PythSpacesAway(pSoldier->sGridNo, BestStab.sTarget) <= 1)
{
BestStab.iAttackValue = ((BestStab.iAttackValue * 3)/2);
}
// if too far and not having APs for at least 2 hits
else if (((CalcTotalAPsToAttack( pSoldier,BestStab.sTarget,ADDTURNCOST, 0 ) + ApsToPunch( pSoldier )) > pSoldier->bActionPoints) && !(PythSpacesAway(pSoldier->sGridNo, BestStab.sTarget <= 1)) )
{
BestStab.iAttackValue /= 3;
if (PythSpacesAway(pSoldier->sGridNo, BestStab.sTarget) <= 1)
{
BestStab.iAttackValue = ((BestStab.iAttackValue * 3) / 2);
}
// if too far and not having APs for at least 2 hits
else if (((CalcTotalAPsToAttack(pSoldier, BestStab.sTarget, ADDTURNCOST, 0) + ApsToPunch(pSoldier)) > pSoldier->bActionPoints) && !(PythSpacesAway(pSoldier->sGridNo, BestStab.sTarget <= 1)))
{
BestStab.iAttackValue /= 3;
}
}
}
}
// sevenfm: reduce HTH attack attractiveness depending on number of seen opponents
if (pSoldier->aiData.bOppCnt > 1)
{
BestStab.iAttackValue /= pSoldier->aiData.bOppCnt;
}
}
// now we KNOW FOR SURE that we will do something (stab, at least)
NPCDoesAct(pSoldier);
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"NPC decided to punch");
@@ -6156,7 +6186,8 @@ L_NEWAIM:
pSoldier->bDoAutofire--;
//dnl ch69 130913 let try increase autofire rate for aim cost
if(!UsingNewCTHSystem() &&
// sevenfm: LIMIT_MAX_DEVIATION option increases effectiveness of suppression
if ((!UsingNewCTHSystem() || gGameCTHConstants.LIMIT_MAX_DEVIATION) &&
pSoldier->bDoAutofire < 3 &&
pSoldier->aiData.bAimTime > 0 &&
pSoldier->inv[BestAttack.bWeaponIn][0]->data.gun.ubGunShotsLeft >= 3 &&