Morale changes for AI soldiers:

- GetMoraleModifier: use bMorale for both player and AI.
- CalcSuppressionTolerance: use morale as a base for tolerance for AI soldiers.
- HandleSuppressionFire: morale loss for AI soldiers.
- EVENT_BeginMercTurn: increase morale for AI soldiers.
- TacticalCreateSoldier: Set morale = 60 + 2 * bExpLevel + Random(20) when creating AI soldier.

NEW_SUPPRESSION_CODE: UseGun, UseGunNCTH: reduce shock when firing gun.
AI_NEW_MORALE: limit AI morale depending on morale and shock level.

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@9181 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Sevenfm
2021-10-15 05:52:09 +00:00
parent 7a7f554908
commit 7978ad77f3
6 changed files with 98 additions and 32 deletions
+14 -2
View File
@@ -170,7 +170,19 @@ INT8 GetMoraleModifier( SOLDIERTYPE * pSoldier )
{ {
INT8 morale = 0; INT8 morale = 0;
if (pSoldier->flags.uiStatusFlags & SOLDIER_PC) // sevenfm: use bMorale for both player and AI
if (pSoldier->aiData.bMorale > 50)
{
// give +1 at 55, +3 at 65, up to +5 at 95 and above
morale = (pSoldier->aiData.bMorale - 45) / 10;
}
else
{
// give penalties down to -20 at 0 (-2 at 45, -4 by 40...)
morale = (pSoldier->aiData.bMorale - 50) * 2 / 5;
}
/*if (pSoldier->flags.uiStatusFlags & SOLDIER_PC)
{ {
if (pSoldier->aiData.bMorale > 50) if (pSoldier->aiData.bMorale > 50)
{ {
@@ -199,7 +211,7 @@ INT8 GetMoraleModifier( SOLDIERTYPE * pSoldier )
default: default:
morale = 0; morale = 0;
} }
} }*/
// Flugente: morale modifiers // Flugente: morale modifiers
morale = max( morale, morale * pSoldier->GetMoraleModifier( ) ); morale = max( morale, morale * pSoldier->GetMoraleModifier( ) );
+13 -28
View File
@@ -8755,13 +8755,8 @@ INT8 CalcSuppressionTolerance( SOLDIERTYPE * pSoldier )
INT8 bToleranceSkill; INT8 bToleranceSkill;
UINT8 ubMaxShock = gGameExternalOptions.ubMaxSuppressionShock; UINT8 ubMaxShock = gGameExternalOptions.ubMaxSuppressionShock;
if (pSoldier->flags.uiStatusFlags & SOLDIER_PC)
bToleranceMorale = pSoldier->aiData.bMorale;
else
bToleranceMorale = (20 + 80 * pSoldier->stats.bLife / max(OKLIFE, pSoldier->stats.bLifeMax) - 40 * min(ubMaxShock, pSoldier->aiData.bShock) / max(1, ubMaxShock));
// limit base tolerance to 75% when having max morale and experience level // limit base tolerance to 75% when having max morale and experience level
bToleranceSkill = (bToleranceMorale + 20 * pSoldier->stats.bExpLevel) / 4; bToleranceSkill = (pSoldier->aiData.bMorale + 20 * pSoldier->stats.bExpLevel) / 4;
// calculate tolerance as percent of max tolerance from INI // calculate tolerance as percent of max tolerance from INI
bTolerance = gGameExternalOptions.ubSuppressionToleranceMax * bToleranceSkill / 100; bTolerance = gGameExternalOptions.ubSuppressionToleranceMax * bToleranceSkill / 100;
} }
@@ -9020,27 +9015,6 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
else else
sFinalSuppressionEffectiveness = sFinalShooterDependentEffectiveness * gGameExternalOptions.usSuppressionEffectivenessAI / 100; sFinalSuppressionEffectiveness = sFinalShooterDependentEffectiveness * gGameExternalOptions.usSuppressionEffectivenessAI / 100;
// INI-Controlled intensity. SuppressionEffectiveness acts as a percentage applied to the number of lost APs.
// To turn off the entire Suppression system, simply set the INI value to 0. (0% AP Loss)
// The default is obviously 100%. You can increase or decrease it, at will.
// PLEASE NOTE that AP loss governs ALL OTHER SUPPRESSION EFFECTS.
// sevenfm: commented out duplicated code: we don't want to apply ubFinalSuppressionEffectivness twice
// ubPointsLost = ( ubPointsLost * sFinalSuppressionEffectiveness ) / 100;
// This is an upper cap for the number of APs we can lose per attack.
// sevenfm: commented out duplicated code:
/*
if (usLimitSuppressionAPsLostPerAttack > 0)
{
if (ubPointsLost > usLimitSuppressionAPsLostPerAttack)
{
// Flugente: eh.. wouldn't this _always_ be 255? I suspect this should be __min
//ubPointsLost = __max(255,(UINT8)usLimitSuppressionAPsLostPerAttack);
ubPointsLost = __min(255,(UINT8)usLimitSuppressionAPsLostPerAttack);
}
}
*/
// INI-Controlled intensity. SuppressionEffectiveness acts as a percentage applied to the number of lost APs. // INI-Controlled intensity. SuppressionEffectiveness acts as a percentage applied to the number of lost APs.
// To turn off the entire Suppression system, simply set the INI value to 0. (0% AP Loss) // To turn off the entire Suppression system, simply set the INI value to 0. (0% AP Loss)
// The default is obviously 100%. You can increase or decrease it, at will. // The default is obviously 100%. You can increase or decrease it, at will.
@@ -9134,7 +9108,18 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
{ {
for ( ubLoop2 = 0; ubLoop2 < (sPointsLost / APBPConstants[AP_LOST_PER_MORALE_DROP]); ubLoop2++ ) for ( ubLoop2 = 0; ubLoop2 < (sPointsLost / APBPConstants[AP_LOST_PER_MORALE_DROP]); ubLoop2++ )
{ {
HandleMoraleEvent( pSoldier, MORALE_SUPPRESSED, pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ); // sevenfm: morale loss for AI soldiers
if (pSoldier->ubProfile == NO_PROFILE)
{
if (IS_MERC_BODY_TYPE(pSoldier))
{
pSoldier->aiData.bMorale = max(20 + 2 * pSoldier->stats.bExpLevel, pSoldier->aiData.bMorale - 4);
}
}
else
{
HandleMoraleEvent(pSoldier, MORALE_SUPPRESSED, pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ);
}
// sevenfm: update ubLastMorale // sevenfm: update ubLastMorale
pSoldier->ubLastMorale++; pSoldier->ubLastMorale++;
} }
+12
View File
@@ -7967,6 +7967,18 @@ void SOLDIERTYPE::EVENT_BeginMercTurn( BOOLEAN fFromRealTime, INT32 iRealTimeCou
// reduce the effects of any residual shock from past injuries by half // reduce the effects of any residual shock from past injuries by half
this->aiData.bShock /= 2; this->aiData.bShock /= 2;
// sevenfm: increase morale for AI soldiers
if (this->ubProfile == NO_PROFILE &&
!(this->flags.uiStatusFlags & SOLDIER_VEHICLE) &&
!AM_A_ROBOT(this) &&
!ARMED_VEHICLE(this) &&
this->aiData.bShock == 0 &&
!this->aiData.bUnderFire &&
this->aiData.bMorale < 80 + 2 * this->stats.bExpLevel)
{
this->aiData.bMorale = __min(80 + 2 * this->stats.bExpLevel, this->aiData.bMorale + 2 + this->stats.bExpLevel / 5);
}
// if this person has heard a noise that hasn't been investigated // if this person has heard a noise that hasn't been investigated
if ( this->aiData.sNoiseGridno != NOWHERE ) if ( this->aiData.sNoiseGridno != NOWHERE )
{ {
+6
View File
@@ -966,6 +966,12 @@ SOLDIERTYPE* TacticalCreateSoldier( SOLDIERCREATE_STRUCT *pCreateStruct, UINT8 *
Soldier.uiAnimSubFlags |= SUB_ANIM_BIGGUYTHREATENSTANCE; Soldier.uiAnimSubFlags |= SUB_ANIM_BIGGUYTHREATENSTANCE;
} }
// sevenfm: max morale for AI soldiers
if (Soldier.ubProfile == NO_PROFILE)
{
Soldier.aiData.bMorale = 60 + 2 * Soldier.stats.bExpLevel + Random(20);
}
//For inventory, look for any face class items that may be located in the big pockets and if found, move //For inventory, look for any face class items that may be located in the big pockets and if found, move
//that item to a face slot and clear the pocket! //that item to a face slot and clear the pocket!
if( Soldier.bTeam != OUR_TEAM ) if( Soldier.bTeam != OUR_TEAM )
+48
View File
@@ -2460,6 +2460,30 @@ BOOLEAN UseGunNCTH( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo )
OBJECTTYPE* pObjAttHand = pSoldier->GetUsedWeapon( &pSoldier->inv[ pSoldier->ubAttackingHand ] ); OBJECTTYPE* pObjAttHand = pSoldier->GetUsedWeapon( &pSoldier->inv[ pSoldier->ubAttackingHand ] );
UINT16 usUBItem = pSoldier->GetUsedWeaponNumber( &pSoldier->inv[ pSoldier->ubAttackingHand ] ); UINT16 usUBItem = pSoldier->GetUsedWeaponNumber( &pSoldier->inv[ pSoldier->ubAttackingHand ] );
// sevenfm: reduce shock when firing gun, for autofire shots - apply once
SOLDIERTYPE* pTarget = SimpleFindSoldier(sTargetGridNo, pSoldier->bTargetLevel);
if (gGameExternalOptions.fNewSuppressionCode &&
Item[usUBItem].usItemClass == IC_GUN &&
pTarget &&
(pSoldier->bDoBurst == 1 || pSoldier->bDoBurst == 0))
{
UINT16 noisefactor = GetPercentNoiseVolume(pObjHand);
UINT8 ubDamage = Weapon[usUBItem].ubImpact;
INT8 bShotsToFire = 1;
if (pSoldier->bDoBurst)
{
bShotsToFire = pSoldier->bDoAutofire ? pSoldier->bDoAutofire : GetShotsPerBurst(pObjHand);
}
// calculate shock reduction value 0-50%
UINT8 ubShockReductPercent = (50 - 400 / (bShotsToFire + 8)) * noisefactor * Weapon[usUBItem].ubAttackVolume / (50 * 100);
if (pSoldier->IsValidSecondHandShot())
ubShockReductPercent = ubShockReductPercent * 3 / 2;
ubShockReductPercent = __min(50, ubShockReductPercent);
pSoldier->aiData.bShock -= pSoldier->aiData.bShock * ubShockReductPercent / 100;
}
// CALC MUZZLE SWAY // CALC MUZZLE SWAY
if ( Item[ usUBItem ].usItemClass == IC_THROWING_KNIFE ) if ( Item[ usUBItem ].usItemClass == IC_THROWING_KNIFE )
{ {
@@ -3201,6 +3225,30 @@ BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo )
usItemNum = pSoldier->usAttackingWeapon; usItemNum = pSoldier->usAttackingWeapon;
// sevenfm: reduce shock when firing gun, for autofire shots - apply once
SOLDIERTYPE* pTarget = SimpleFindSoldier(sTargetGridNo, pSoldier->bTargetLevel);
if (gGameExternalOptions.fNewSuppressionCode &&
Item[usUBItem].usItemClass == IC_GUN &&
pTarget &&
(pSoldier->bDoBurst == 1 || pSoldier->bDoBurst == 0))
{
UINT16 noisefactor = GetPercentNoiseVolume(pObjUsed);
UINT8 ubDamage = Weapon[usUBItem].ubImpact;
INT8 bShotsToFire = 1;
if (pSoldier->bDoBurst)
{
bShotsToFire = pSoldier->bDoAutofire ? pSoldier->bDoAutofire : GetShotsPerBurst(pObjUsed);
}
// calculate shock reduction value 0-50%
UINT8 ubShockReductPercent = (50 - 400 / (bShotsToFire + 8)) * noisefactor * Weapon[usUBItem].ubAttackVolume / (50 * 100);
if (pSoldier->IsValidSecondHandShot())
ubShockReductPercent = ubShockReductPercent * 3 / 2;
ubShockReductPercent = __min(50, ubShockReductPercent);
pSoldier->aiData.bShock -= pSoldier->aiData.bShock * ubShockReductPercent / 100;
}
// DEDUCT APs // DEDUCT APs
if (pSoldier->bDoBurst) if (pSoldier->bDoBurst)
{ {
+5 -2
View File
@@ -3925,10 +3925,13 @@ INT8 CalcMoraleNew(SOLDIERTYPE *pSoldier)
} }
// limit AI morale when soldier is under heavy fire // limit AI morale when soldier is under heavy fire
if (pSoldier->ShockLevelPercent() > 75) /*if (pSoldier->ShockLevelPercent() > 75)
bMoraleCategory = min(bMoraleCategory, MORALE_NORMAL); bMoraleCategory = min(bMoraleCategory, MORALE_NORMAL);
else if (pSoldier->ShockLevelPercent() > 50) else if (pSoldier->ShockLevelPercent() > 50)
bMoraleCategory = min(bMoraleCategory, MORALE_CONFIDENT); bMoraleCategory = min(bMoraleCategory, MORALE_CONFIDENT);*/
// limit AI morale depending on morale and shock level
bMoraleCategory = min(bMoraleCategory, max(MORALE_WORRIED, ((pSoldier->aiData.bOrders == SEEKENEMY ? pSoldier->aiData.bMorale + 20 : pSoldier->aiData.bMorale) * 100 / (100 + pSoldier->ShockLevelPercent())) / 20));
// prevent hopeless morale when not under attack // prevent hopeless morale when not under attack
if (bMoraleCategory == MORALE_HOPELESS && !pSoldier->aiData.bUnderFire) if (bMoraleCategory == MORALE_HOPELESS && !pSoldier->aiData.bUnderFire)