*************************

* HAM 3.6 (by Headrock) *
*************************
- Info: Needed GameDir files for HAM 3.6 are not committed yet to the SVN GameDir. Will do that in the next few days
- For more infos on HAM 3.6 check out: http://www.ja-galaxy-forum.com/board/ubbthreads.php?ubb=showflat&Number=244808&page=0&fpart=1


git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@3323 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Wanne
2010-02-20 15:49:46 +00:00
parent 53821fcf49
commit f010769397
120 changed files with 16937 additions and 2200 deletions
+309 -168
View File
@@ -180,6 +180,8 @@ void HandleEndDemoInCreatureLevel( );
void DeathTimerCallback( void );
void CaptureTimerCallback( void );
// HEADROCK HAM 3.6: Define now.
void MilitiaChangesSides( void );
extern void CheckForAlertWhenEnemyDies( SOLDIERTYPE * pDyingSoldier );
extern void PlaySoldierFootstepSound( SOLDIERTYPE *pSoldier );
@@ -2224,6 +2226,22 @@ BOOLEAN HandleGotoNewGridNo( SOLDIERTYPE *pSoldier, BOOLEAN *pfKeepMoving, BOOLE
// better stop and reconsider what to do...
SetNewSituation( pSoldier );
ActionDone( pSoldier );
// HEADROCK HAM 3.6: Militia can now place flags when they spot landmines.
if (gGameExternalOptions.fMilitiaPlaceBlueFlags &&
pSoldier->bTeam == MILITIA_TEAM)
{
// This line causes the screen to focus on the gridno if it is not currently visible.
// Is it desirable when militia spot mines? Probably not. Turned off for now.
//LocateGridNo( sMineGridNo );
// Flash gridno
ITEM_POOL *pItemPool = NULL;
GetItemPool( sMineGridNo, &pItemPool, 0 );
SetItemPoolLocator( pItemPool );
// Add flag
AddBlueFlag(sMineGridNo,1);
}
}
}
}
@@ -3593,7 +3611,17 @@ void HandleNPCTeamMemberDeath( SOLDIERTYPE *pSoldierOld )
if ( pSoldierOld->ubAttackerID != NOBODY )
{
// also treat this as murder - but player will never be blamed for militia death he didn't cause
HandleMurderOfCivilian( pSoldierOld, pSoldierOld->flags.fIntendedTarget );
// HEADROCK HAM 3.6: Actually this function never runs for militia (see function for details)
//HandleMurderOfCivilian( pSoldierOld, pSoldierOld->flags.fIntendedTarget );
// HEADROCK HAM 3.6: INI setting can cause militia to turn ONLY of they are killed intentionally
if (pSoldierOld->flags.fIntendedTarget // Must be intentional
&& gGameExternalOptions.ubCanMilitiaBecomeHostile > 0 // INI setting
&& pSoldierOld->bSide == gbPlayerNum // Must not be hostile by now
)
{
MilitiaChangesSides(); // Militia turn on you.
}
}
HandleGlobalLoyaltyEvent( GLOBAL_LOYALTY_NATIVE_KILLED, gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
@@ -3854,7 +3882,12 @@ void MakeCivHostile( SOLDIERTYPE *pSoldier, INT8 bNewSide )
}
if ( pSoldier->aiData.bNeutral )
{
SetSoldierNonNeutral( pSoldier );
// HEADROCK HAM 3.6: INI Setting decides whether non-combat civs can become hostile
if (gGameExternalOptions.fCanTrueCiviliansBecomeHostile ||
!IS_CIV_BODY_TYPE(pSoldier))
{
SetSoldierNonNeutral( pSoldier );
}
RecalculateOppCntsDueToNoLongerNeutral( pSoldier );
}
}
@@ -3979,6 +4012,13 @@ SOLDIERTYPE * CivilianGroupMemberChangesSides( SOLDIERTYPE * pAttacked )
gTacticalStatus.fCivGroupHostile[ pNewAttacked->ubCivilianGroup ] = CIV_GROUP_WILL_EVENTUALLY_BECOME_HOSTILE;
}
// HEADROCK HAM 3.6: If this sector has affiliated bloodcats, make them all hostile.
if ( gBloodcatPlacements[SECTOR(pNewAttacked->sSectorX,pNewAttacked->sSectorY)][0].PlacementType == BLOODCAT_PLACEMENT_STATIC &&
gBloodcatPlacements[SECTOR(pNewAttacked->sSectorX,pNewAttacked->sSectorY)][ gGameOptions.ubDifficultyLevel-1 ].ubFactionAffiliation == pNewAttacked->ubCivilianGroup )
{
MakeBloodcatsHostile();
}
return( pNewAttacked );
}
@@ -6203,26 +6243,27 @@ void DeathNoMessageTimerCallback( void )
}
}
// HEADROCK HAM 3.5: This function needs a Z-Level argument!!! It is screwing up garrisons, when a battle is won underneath
// a sector.
void RemoveStaticEnemiesFromSectorInfo( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
{
if (!bMapZ) // Battle ended Above-ground
{
SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR( sMapX, sMapY ) ] );
if (!bMapZ) // Battle ended Above-ground
{
SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR( sMapX, sMapY ) ] );
pSectorInfo->ubNumAdmins = pSectorInfo->ubNumTroops = pSectorInfo->ubNumElites = 0;
pSectorInfo->ubAdminsInBattle = pSectorInfo->ubTroopsInBattle = pSectorInfo->ubElitesInBattle = 0;
}
else
{
UNDERGROUND_SECTORINFO *pSectorInfo;
pSectorInfo = FindUnderGroundSector( sMapX, sMapY, bMapZ );
pSectorInfo->ubNumAdmins = pSectorInfo->ubNumTroops = pSectorInfo->ubNumElites = 0;
pSectorInfo->ubAdminsInBattle = pSectorInfo->ubTroopsInBattle = pSectorInfo->ubElitesInBattle = 0;
}
pSectorInfo->ubNumAdmins = pSectorInfo->ubNumTroops = pSectorInfo->ubNumElites = 0;
pSectorInfo->ubAdminsInBattle = pSectorInfo->ubTroopsInBattle = pSectorInfo->ubElitesInBattle = 0;
}
else
{
UNDERGROUND_SECTORINFO *pSectorInfo;
pSectorInfo = FindUnderGroundSector( sMapX, sMapY, bMapZ );
pSectorInfo->ubNumAdmins = pSectorInfo->ubNumTroops = pSectorInfo->ubNumElites = 0;
pSectorInfo->ubAdminsInBattle = pSectorInfo->ubTroopsInBattle = pSectorInfo->ubElitesInBattle = 0;
}
}
//!!!!
//IMPORTANT NEW NOTE:
//Whenever returning TRUE, make sure you clear gfBlitBattleSectorLocator;
@@ -6383,6 +6424,9 @@ BOOLEAN CheckForEndOfBattle( BOOLEAN fAnEnemyRetreated )
}
// Kill all enemies. Sometime even after killing all the enemies, there appeares "in battle" enemies in sector info
// HEADROCK HAM 3.5: This has to take Z-Level into account, otherwise winning a battle underground will kill all
// enemies in the sector above! We still need to run the function though, to prevent confusions with the
// strategic screen, which is what it was doing only for aboveground. UNTIL NOW, muahaha.
RemoveStaticEnemiesFromSectorInfo( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
@@ -7221,15 +7265,20 @@ INT8 CalcSuppressionTolerance( SOLDIERTYPE * pSoldier )
}
}
if (bTolerance < gGameExternalOptions.iSuppressionToleranceMin)
// HEADROCK HAM 3.2: This is actually a feature from HAM 2.9. It adds bonuses/penalties for nearby friends.
if (gGameExternalOptions.fFriendliesAffectTolerance)
{
bTolerance = gGameExternalOptions.iSuppressionToleranceMin;
bTolerance += CheckStatusNearbyFriendlies( pSoldier );
}
if (bTolerance > gGameExternalOptions.iSuppressionToleranceMax)
// HEADROCK HAM 3.3: Moving rapidly makes one less prone to suppression.
if (gGameExternalOptions.ubTilesMovedPerBonusTolerancePoint > 0)
{
bTolerance = gGameExternalOptions.iSuppressionToleranceMax;
bTolerance += pSoldier->bTilesMoved / gGameExternalOptions.ubTilesMovedPerBonusTolerancePoint;
}
bTolerance = __max(bTolerance, gGameExternalOptions.ubSuppressionToleranceMin);
bTolerance = __min(bTolerance, gGameExternalOptions.ubSuppressionToleranceMax);
return( bTolerance );
}
@@ -7239,163 +7288,154 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
///////////////////////////////////////////////////////////////////////////////
//
// HEADROCK HAM B2: This entire function has been completely revamped.
// HEADROCK HAM 3.5: Revamped again.
//
///////////////////////////////////////////////////////////////////////////////
// External options.
BOOLEAN APS_SUPPRESSED = gGameExternalOptions.fSuppressionAPLossPerAttack;
BOOLEAN APS_SUPPRESSED_TOTAL = gGameExternalOptions.fSuppressionAPLossPerTurn;
//INT8 SUPPRESSION_AP_LIMIT = gGameExternalOptions.iMinAPLimitFromSuppression;
INT8 MAXIMUM_SUPPRESSION_SHOCK = gGameExternalOptions.iMaxSuppressionShock;
INT8 bTolerance;
INT16 sClosestOpponent, sClosestOppLoc;
UINT8 ubPointsLost, ubTotalPointsLost, ubNewStance;
UINT32 uiLoop;
// This function runs after very attack is completed. It calculates the number
// of "Suppression Points" any character has received during the attack, and
// inflicts various penalties accordingly.
// The most important result of this function is AP loss.
SOLDIERTYPE * pSoldier;
INT8 bTolerance;
INT16 sClosestOpponent, sClosestOppLoc;
UINT8 ubPointsLost, ubNewStance;
UINT32 uiLoop;
UINT8 ubLoop2;
// Flag to determine if the target is cowering (if allowed)
BOOLEAN fCower;
SOLDIERTYPE * pSoldier;
BOOLEAN fCower;
// External options
// JA2_OPTIONS.INI
INT8 MAXIMUM_SUPPRESSION_SHOCK = gGameExternalOptions.ubMaxSuppressionShock;
// APBPConstants.INI
UINT16 usLimitSuppressionAPsLostPerAttack = APBPConstants[AP_MAX_SUPPRESSED];
UINT16 usLimitSuppressionAPsLostPerTurn = APBPConstants[AP_MAX_TURN_SUPPRESSED];
//HEADROCK HAM 3.5: Ratio between AP Loss and Suppression Shock
UINT16 uiShockPerAPLossDivisor = APBPConstants[AP_SUPPRESSION_SHOCK_DIVISOR];
// Loop through every character.
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
{
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: loop = %d, numslots = %d ",uiLoop, guiNumMercSlots));
pSoldier = MercSlots[uiLoop];
// Has this character received any Suppression Points since the last attack?
// HEADROCK: Suppression Points accumulate by bullets flying near the character. It includes
// friendly fire at a certain distance. As of HAM 3.2, it also happens with nearby explosions.
// The number of points accumulated resets to 0 at the end of this function.
if (pSoldier && IS_MERC_BODY_TYPE( pSoldier) && pSoldier->stats.bLife >= OKLIFE && pSoldier->ubSuppressionPoints > 0)
{
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: soldier id = %d, life = %d, suppression points = %d",pSoldier->ubID,pSoldier->stats.bLife, pSoldier->ubSuppressionPoints));
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: calc suppression tolerance"));
// Calculate the character's tolerance to suppression. Helps reduce the severity of the penalties inflicted
// during this function.
bTolerance = CalcSuppressionTolerance( pSoldier );
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: figure out aps lost"));
// multiply by 2, add 1 and divide by 2 to round off to nearest whole number
// HEADROCK: Note that suppression points accumulate by bullets flying near the character. It includes
// friendly fire at a certain distance. Also note that it may be reset either each attack or each turn
// (based on new INI settings), which has a small effect on how suppression builds up (but nothing
// major).
// This formula gives a linear increase in AP loss relative to Suppression Points. The most Suppression
// Points we have, the most APs we're going to lose. Tolerance mitigates this by making the graph angle
// more shallow.
// The relation between AP Loss and Suppression Points is LINEAR.
ubPointsLost = ( ( (pSoldier->ubSuppressionPoints * APBPConstants[AP_SUPPRESSION_MOD]) / (bTolerance + 6) ) * 2 + 1 ) / 2;
// HEADROCK HAM Beta 2.2: SuppressionEffectiveness acts as a percentage for the number of lost APs.
ubPointsLost = ( ubPointsLost * gGameExternalOptions.iSuppressionEffectiveness ) / 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.
ubPointsLost = ( ubPointsLost * gGameExternalOptions.sSuppressionEffectiveness ) / 100;
// reduce loss of APs based on stance
// ATE: Taken out because we can possibly supress ourselves...
//switch (gAnimControl[ pSoldier->usAnimState ].ubEndHeight)
//{
// case ANIM_PRONE:
// ubPointsLost = ubPointsLost * 2 / 4;
// break;
// case ANIM_CROUCH:
// ubPointsLost = ubPointsLost * 3 / 4;
// break;
// default:
// break;
//}
// cap the # of APs we can lose
// HEADROCK HAM B2: This now reads an external value. 0 means no limit.
if (APS_SUPPRESSED == TRUE)
// This is an upper cap for the number of APs we can lose per attack.
if (usLimitSuppressionAPsLostPerAttack > 0)
{
if (ubPointsLost > APBPConstants[AP_MAX_SUPPRESSED])
if (ubPointsLost > usLimitSuppressionAPsLostPerAttack)
{
ubPointsLost = (UINT8)APBPConstants[AP_MAX_SUPPRESSED];
ubPointsLost = __max(255,(UINT8)usLimitSuppressionAPsLostPerAttack);
}
}
// HEADROCK HAM B2: This makes sure that we never lose more APs than we're allowed per turn,
if (APS_SUPPRESSED_TOTAL = TRUE)
// This makes sure that we never lose more APs than we're allowed per turn.
if (usLimitSuppressionAPsLostPerTurn > 0)
{
if (pSoldier->ubAPsLostToSuppression + ubPointsLost > APBPConstants[AP_MAX_TURN_SUPPRESSED])
{
ubPointsLost = APBPConstants[AP_MAX_TURN_SUPPRESSED] - pSoldier->ubAPsLostToSuppression;
ubPointsLost = usLimitSuppressionAPsLostPerTurn - pSoldier->ubAPsLostToSuppression;
}
}
// Keeps a number for later reference
ubTotalPointsLost = ubPointsLost;
// Make sure we're suffering extra AP loss at all. If the number of APs we're supposed to lose now
// is equal/higher to the number of APs we've already lost, it means we haven't actually gained any
// suppression. This is very important, as this function runs EVERY TIME an attack, ANY attack, ends.
// If the soldier hasn't suffered suppression since the last time this check ran, we'll hit the
// "continue" command. Note that with a certain INI setting, this value is reset after each attack
// or after each turn, but overall the function acts the same in both cases.
if (pSoldier->ubAPsLostToSuppression >= ubPointsLost)
{
continue;
}
// APs actually lost will be the difference between the potential loss and the APs we've already lost
// so far. Would theoretically equal 0 if we haven't suffered sufficient extra suppression this turn to
// cause any AP loss, but then we would've already hit the "continue" command, above.
ubPointsLost -= pSoldier->ubAPsLostToSuppression;
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: check for morale effects"));
// HEADROCK HAM B2: This nifty little bit gives suppression an "extra kick". Soldiers affected by
// suppression (I.E. lost APs) will also suffer from SHOCK. This is similar to getting shot but
// without the health/stamina loss - the soldier will lose 5% CTH for every point of shock they suffer.
// Shock is sliced in half at the start of every turn. Also note that shock may cause "cowering", and
// may also reduce any attacker's aim as well!
if (gGameExternalOptions.fSuppressionShock)
// This nifty little bit gives suppression an "extra kick". Soldiers affected by suppression (I.E. lost APs)
// will also suffer from SHOCK. As shock accumulates, the soldier becomes less accurate and may find it
// difficult to perform certain manual tasks. Additionally, he also becomes harder to hit, because the fear
// causes him to hide as best as he can from incoming fire.
// Shock is sliced in half at the start of every turn. Also note that shock may cause "cowering" (see below).
if (gGameExternalOptions.usSuppressionShockEffect > 0)
{
// Can't get shock if we haven't lost APs.
if (ubPointsLost > 0)
{
// Experienced and/or high-morale soldiers suffer less shock than others.
INT8 bShockValue, bShockLimit;
bShockLimit = MAXIMUM_SUPPRESSION_SHOCK - bTolerance;
// the amount of shock received depends mainly on how many APs we've lost. 8 here is arbitrary,
// as the shock loss can later be adjusted by the external modifier below.
bShockValue = (bShockLimit * ubPointsLost) / 8;
// Limit defined by INI.
bShockLimit = MAXIMUM_SUPPRESSION_SHOCK;
// The amount of shock received depends on how many APs we've lost - Every AP lost will cause one
// point of shock. This is then divided by 4 if using the 100AP system.
bShockValue = ubPointsLost / uiShockPerAPLossDivisor;
if (bShockValue < 0)
bShockValue = 0;
if (bShockLimit < 0)
bShockLimit = 0;
bShockValue = __max(0,bShockValue);
bShockLimit = __max(0,bShockLimit);
// use external value to determine how effective SHOCK really is.
bShockValue = (bShockValue * gGameExternalOptions.iSuppressionShockEffectiveness) / 100;
bShockValue = (bShockValue * gGameExternalOptions.usSuppressionShockEffect) / 100;
// Make sure total shock doesn't go TOO high. Maximum is around 30 (for a CTH effect of -150!),
// including previous shock from suppression and/or wounds. The Maximum is mitigated by
// the character's experience and morale. The shock value can bump above that level
// momentarily, for particularily lousy characters, rendering them practically incapable of firing
// back effectively... But of course, it is halved once the character starts his next turn, so
// shock at turnstart will usually be no higher than 15.
// Make sure total shock doesn't go TOO high. Maximum is around 30, including previous shock
// from suppression and/or wounds. It is possible to breach the maximum after a good suppressive
// attack.
if ( pSoldier->aiData.bShock + bShockValue <= bShockLimit )
{
// Shock limit not yet breached. Add shock to character.
pSoldier->aiData.bShock += bShockValue;
pSoldier->aiData.bShock = __min(127, pSoldier->aiData.bShock + bShockValue);
}
else if ( pSoldier->aiData.bShock < bShockLimit ) // Shock limit will be breached.
{
// Original shock was lower than the limit, so add extra shock and breach the limit.
pSoldier->aiData.bShock += bShockValue;
pSoldier->aiData.bShock = __min(127, pSoldier->aiData.bShock + bShockValue);
}
// Else, original shock was already over the limit. No more shock is added.
}
}
// HEADROCK: Untrained characters won't react well to being fired at (they'll keep standing), but if
// Suppression Shock is activated, they may dive and "COWER" anyway. For this to happen, they must first
// make a check to see if they are in enough shock to cower.
// HEADROCK: Cowering is the panic that grips a character due to suffering too much suppression shock. If
// enough shock has been accumulated, the soldier goes into this panic. Generally, cowering will cause
// the character to drop a stance if he can, overriding other conditions for a stance-change (see below).
// Cowering characters may become considerably easier to suppress with additional firepower. In other
// words, if you're cowering, you've effectively turned from a bad-ass to a wimp.
fCower = false;
if ( gGameExternalOptions.fSuppressionShock && gGameExternalOptions.iAimPenaltyPerTargetShock > 0 )
if ( gGameExternalOptions.usSuppressionShockEffect > 0 )
{
if (pSoldier->aiData.bShock >= bTolerance)
{ fCower = true; }
{
fCower = true;
// If cowering, increase suppression effectiveness by external percentage. If the setting is
// over 100%, then the condition of cowering makes the character even MORE susceptible to suppression.
if (gGameExternalOptions.usCowerEffectOnSuppression > 0)
ubPointsLost = (ubPointsLost * gGameExternalOptions.usCowerEffectOnSuppression) / 100;
// If soldier is visible on-screen, report to player that they are cowering.
if ( pSoldier->bVisible != -1 )
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113HAMMessage[0], pSoldier->name );
}
}
// HEADROCK HAM B2: If enemy cowers in fear, let the player know.
if (fCower)
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113HAMMessage[0], pSoldier->name );
// If cowering, increase suppression effectiveness by external percentage
if (gGameExternalOptions.iCowerEffectOnSuppression > 0)
ubPointsLost = (ubPointsLost * gGameExternalOptions.iCowerEffectOnSuppression) / 100;
}
// morale modifier
// For every 2 APs lost, subtract morale by a certain value.
// HEADROCK: Modified - now externalized to INI.
// Suppression reduces morale. For every X APs lost, morale goes down by a point. X is defined by INI.
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: check for morale effects"));
if (APBPConstants[AP_LOST_PER_MORALE_DROP] > 0 && ubPointsLost > 0)
{
for ( ubLoop2 = 0; ubLoop2 < (ubPointsLost / APBPConstants[AP_LOST_PER_MORALE_DROP]); ubLoop2++ )
@@ -7408,34 +7448,24 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
ubNewStance = 0;
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: check for reaction"));
// merc may get to react
// Headrock: apply suppression effectiveness percentage to this value.
if ( (pSoldier->ubSuppressionPoints * gGameExternalOptions.iSuppressionEffectiveness) / 100 >= ( 130 / (6 + bTolerance) ) || fCower )
// HEADROCK HAM 3.5: Characters who have enough APs to drop WILL DROP. This is strictly for survival reasons,
// because upright characters can easily get themselves killed. Soldiers drop stance for "free", using up
// the APs that they've just lost to do so.
switch (gAnimControl[ pSoldier->usAnimState ].ubEndHeight)
{
// merc gets to use APs to react!
switch (gAnimControl[ pSoldier->usAnimState ].ubEndHeight)
{
case ANIM_PRONE:
// can't change stance below prone!
break;
case ANIM_CROUCH:
if (ubTotalPointsLost >= APBPConstants[AP_PRONE] && IsValidStance( pSoldier, ANIM_PRONE ) )
if (ubPointsLost >= APBPConstants[AP_PRONE] && IsValidStance( pSoldier, ANIM_PRONE ) && gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_PRONE )
{
sClosestOpponent = ClosestKnownOpponent( pSoldier, &sClosestOppLoc, NULL );
// HEADROCK: Added cowering.
if (sClosestOpponent == NOWHERE || SpacesAway( pSoldier->sGridNo, sClosestOppLoc ) > 8 || fCower)
{
if (ubPointsLost < APBPConstants[AP_PRONE])
{
// Have to give APs back so that we can change stance without
// losing more APs
pSoldier->bActionPoints += (APBPConstants[AP_PRONE] - ubPointsLost);
ubPointsLost = 0;
}
else
{
ubPointsLost -= APBPConstants[AP_PRONE];
}
ubPointsLost -= APBPConstants[AP_PRONE];
ubNewStance = ANIM_PRONE;
}
}
@@ -7446,7 +7476,7 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
// can't change stance here!
break;
}
else if (ubTotalPointsLost >= (APBPConstants[AP_CROUCH] + APBPConstants[AP_PRONE]) && ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_PRONE ) && IsValidStance( pSoldier, ANIM_PRONE ) )
else if (ubPointsLost >= (APBPConstants[AP_CROUCH] + APBPConstants[AP_PRONE]) && ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_PRONE ) && IsValidStance( pSoldier, ANIM_PRONE ) )
{
sClosestOpponent = ClosestKnownOpponent( pSoldier, &sClosestOppLoc, NULL );
// HEADROCK: Added cowering.
@@ -7469,19 +7499,40 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
ubNewStance = ANIM_CROUCH;
}
}
else if ( ubTotalPointsLost >= APBPConstants[AP_CROUCH] && ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_CROUCH ) && IsValidStance( pSoldier, ANIM_CROUCH ) )
else if ( ubPointsLost >= APBPConstants[AP_CROUCH] && ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_CROUCH ) && IsValidStance( pSoldier, ANIM_CROUCH ) )
{
// crouch!
ubNewStance = ANIM_CROUCH;
}
break;
}
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: reduce action points"));
// HEADROCK HAM 3.1: If this setting is enabled, it will show an on-screen message that tells us the
// character has lost his entire next turn. This only fires once per turn, the moment a character drops
// to the minimum AP limit.
if (gGameExternalOptions.fShowSuppressionShutdown)
{
// If we're about the hit the lower limit
if (pSoldier->bActionPoints > APBPConstants[AP_MIN_LIMIT] && pSoldier->bActionPoints - ubPointsLost <= APBPConstants[AP_MIN_LIMIT])
{
// And soldier is visible
if ( pSoldier->bVisible != -1 )
{
// "Soldier is pinned down!"
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113HAMMessage[1], pSoldier->name );
// HEADROCK HAM 3.2: Added a radio locator!
ShowRadioLocator( (UINT8)pSoldier->ubID, SHOW_LOCATOR_NORMAL );
}
}
}
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: reduce action points"));
// Reduce action points!
// HEADROCK HAM Beta 2.2: Enforce a minimum limit via INI.
if (pSoldier->bActionPoints - ubPointsLost < APBPConstants[AP_MIN_LIMIT] )
if (pSoldier->bActionPoints - ubPointsLost <= APBPConstants[AP_MIN_LIMIT] )
{
pSoldier->bActionPoints = APBPConstants[AP_MIN_LIMIT];
}
@@ -7492,7 +7543,7 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
// Remember how many APs were lost. This prevents us from losing more and more APs without receiving
// extra suppression. Note that a specific HAM setting will reset this value after every attack,
// but also resets ubSuppressionPoints.
pSoldier->ubAPsLostToSuppression = ubTotalPointsLost;
pSoldier->ubAPsLostToSuppression = __min(255, pSoldier->ubAPsLostToSuppression + ubPointsLost);
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: check for quote"));
if ( (pSoldier->flags.uiStatusFlags & SOLDIER_PC) && (pSoldier->ubSuppressionPoints > 8) && (pSoldier->ubID == ubTargetedMerc) )
@@ -7554,17 +7605,11 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
pSoldier->flags.fDontChargeAPsForStanceChange = TRUE;
}
// HEADROCK HAM B2: Optional fix for suppression. This clears up the value that measures suppression
// accumulated so far. Previously, the value was NEVER cleared, which means that a character could
// only be suppressed ONCE in the game (unless they die or get deleted).
// With the setting at "2", these two values are cleared every turn. Therefore, suppression doesn't
// accumulate at all, only its effects are cumulative. In the end, it functions almost the same as
// clearing every turn, but I added this as an alternative.
if (gGameExternalOptions.iClearSuppression == 2)
{
pSoldier->ubAPsLostToSuppression = 0;
pSoldier->ubSuppressionPoints = 0;
}
// HEADROCK HAM 3.5: After sufficient testing, suppression clearing now works immediately at the end of
// the attack. ubAPsLostToSuppression is only cleared at the end of the turn, but no longer plays a role
// in affecting the number of APs lost, so it is largely irrelevant now.
pSoldier->ubSuppressionPoints = 0;
} // end of examining one soldier
} // end of loop
@@ -7617,8 +7662,14 @@ BOOLEAN ProcessImplicationsOfPCAttack( SOLDIERTYPE * pSoldier, SOLDIERTYPE ** pp
if ( (pTarget->bTeam == MILITIA_TEAM) && (pTarget->bSide == gbPlayerNum) )
{
// rebel militia attacked by the player!
MilitiaChangesSides();
// HEADROCK HAM 3.6: INI setting controls their response
{
if (gGameExternalOptions.ubCanMilitiaBecomeHostile == 2)
{
// rebel militia attacked by the player!
MilitiaChangesSides();
}
}
}
// JA2 Gold: fix Slay
else if ( (pTarget->bTeam == CIV_TEAM && pTarget->aiData.bNeutral) && pTarget->ubProfile == SLAY && pTarget->stats.bLife >= OKLIFE && CheckFact( 155, 0 ) == FALSE )
@@ -7654,6 +7705,23 @@ BOOLEAN ProcessImplicationsOfPCAttack( SOLDIERTYPE * pSoldier, SOLDIERTYPE ** pp
}
}
}
else if (pTarget->bTeam == CREATURE_TEAM && pTarget->ubBodyType == BLOODCAT && pTarget->aiData.bNeutral)
{
// Attacked a bloodcat.
MakeBloodcatsHostile();
// Are bloodcats in this sector affiliated with a faction?
if ( gBloodcatPlacements[SECTOR(pTarget->sSectorX,pTarget->sSectorY)][0].PlacementType == BLOODCAT_PLACEMENT_STATIC &&
gBloodcatPlacements[SECTOR(pTarget->sSectorX,pTarget->sSectorY)][ gGameOptions.ubDifficultyLevel-1 ].ubFactionAffiliation > NON_CIV_GROUP )
{
// Temporarily change bloodcat's civilian group
UINT8 ubFaction = pTarget->ubCivilianGroup;
pTarget->ubCivilianGroup = gBloodcatPlacements[SECTOR(pTarget->sSectorX,pTarget->sSectorY)][ gGameOptions.ubDifficultyLevel-1 ].ubFactionAffiliation;
// Make entire faction hostile
CivilianGroupMembersChangeSidesWithinProximity( pTarget );
// Change back
pTarget->ubCivilianGroup = ubFaction;
}
}
else
{
if (pTarget->ubProfile == CARMEN)// Carmen
@@ -7692,6 +7760,14 @@ BOOLEAN ProcessImplicationsOfPCAttack( SOLDIERTYPE * pSoldier, SOLDIERTYPE ** pp
// Firing at a civ in a civ group who isn't hostile... if anyone in that civ group can see this
// going on they should become hostile.
CivilianGroupMembersChangeSidesWithinProximity( pTarget );
// HEADROCK HAM 3.6: If there are bloodcats affiliated with his group...
if ( gBloodcatPlacements[SECTOR(pTarget->sSectorX,pTarget->sSectorY)][0].PlacementType == BLOODCAT_PLACEMENT_STATIC &&
gBloodcatPlacements[SECTOR(pTarget->sSectorX,pTarget->sSectorY)][ gGameOptions.ubDifficultyLevel-1 ].ubFactionAffiliation == pTarget->ubCivilianGroup )
{
// Make them hostile.
MakeBloodcatsHostile();
}
}
else if ( pTarget->bTeam == gbPlayerNum && !(gTacticalStatus.uiFlags & INCOMBAT) )
{
@@ -8150,17 +8226,6 @@ SOLDIERTYPE *InternalReduceAttackBusyCount( )
pSoldier->flags.fGettingHit = FALSE;
}
// HEADROCK HAM B2: Optional fix for suppression. This clears up the value that measures suppression
// accumulated so far. Previously, the value was NEVER cleared, which means that a character could
// only be suppressed ONCE in the game (unless they die or get deleted).
// With the setting at "2", these two values are cleared every turn. Therefore, suppression doesn't
// accumulate at all, only its effects are cumulative. In the end, it functions almost the same as
// clearing every turn, but I added this as an alternative.
if (gGameExternalOptions.iClearSuppression == 2)
{
pSoldier->ubAPsLostToSuppression = 0;
pSoldier->ubSuppressionPoints = 0;
}
if (pSoldier->ubAttackerID != NOBODY )
{
if (pSoldier->ubPreviousAttackerID != pSoldier->ubAttackerID)
@@ -8822,3 +8887,79 @@ void RevealAllDroppedEnemyItems()
AllSoldiersLookforItems( TRUE );
}
// HEADROCK HAM 3.2: This function from HAM 2.9 makes a character look around himself and try to find friends. Dead
// friends lower the result, while more friends (ESP good leaders) will raise the result. The result can then be used
// for any purpose, although this was written specifically to alter a character's suppression tolerance.
INT8 CheckStatusNearbyFriendlies( SOLDIERTYPE *pSoldier )
{
SOLDIERTYPE * pLeader;
UINT8 sModifier = 0;
INT16 usEffectiveLeadership = 0;
UINT16 usEffectiveRangeToLeader = 0;
INT16 usBestLeader = 0;
INT16 usFriendBonus = 0;
// Run through each friendly.
for ( UINT8 iCounter = gTacticalStatus.Team[ pSoldier->bTeam ].bFirstID ; iCounter <= gTacticalStatus.Team[ pSoldier->bTeam ].bLastID ; iCounter ++ )
{
pLeader = MercPtrs[ iCounter ];
// Make sure that character is alive, not too shocked, and conscious, and of higher experience level
// than the character being suppressed.
if (pLeader != pSoldier && pLeader->bActive && pLeader->aiData.bShock < pLeader->stats.bLeadership/5 &&
pLeader->stats.bLife >= OKLIFE && pLeader->stats.bExpLevel >= pSoldier->stats.bExpLevel)
{
// Calculate character's leadership and range/3
usEffectiveLeadership = ((EffectiveLeadership( pLeader ) - 25) / 15);
usEffectiveRangeToLeader = PythSpacesAway( pSoldier->sGridNo, pLeader->sGridNo ) / 3;
// If leader is within range of his leadership stat
if (usEffectiveRangeToLeader <= usEffectiveLeadership+1)
{
// The difference in experience level is important!
usEffectiveLeadership += (pLeader->stats.bExpLevel - pSoldier->stats.bExpLevel);
// Reduce effective leadership with every 3 tiles of distance
usEffectiveLeadership -= usEffectiveRangeToLeader-1;
// If this is the best leader we've seen so far,
if (usEffectiveLeadership > usBestLeader)
{
// Set this as the best leader
usBestLeader = usEffectiveLeadership;
}
// Friends within range always give at least one tolerance bonus point.
usFriendBonus += 1;
}
}
// Incapacitated or heavily suppressed friends will not be good for our tolerance!
else if (pLeader != pSoldier && pLeader->bActive && (pLeader->aiData.bShock > pSoldier->aiData.bShock || pLeader->stats.bLife <= OKLIFE) )
{
usEffectiveRangeToLeader = PythSpacesAway( pSoldier->sGridNo, pLeader->sGridNo );
// If they are no more than 5 tiles away,
if (usEffectiveRangeToLeader <= 5)
{
// Penalty is based on the difference between experience levels, and the range between them,
// and is never less than 1 point.
usEffectiveLeadership = (pLeader->stats.bExpLevel - pSoldier->stats.bExpLevel) / __max(1,(usEffectiveRangeToLeader/2));
usFriendBonus -= __max(1, usEffectiveLeadership);
}
}
}
// If we did find someone who's a good enough leader to help us out,
if (usBestLeader > 0)
{
// Add his leadership bonus, minus the point we got for him before. He'll give at least one
// point, like anybody else.
usFriendBonus += __max(usBestLeader-1, 1);
}
// Add no more than five points for nearby friends.
usFriendBonus = __min(usFriendBonus, 5);
usFriendBonus = __max(usFriendBonus, -5);
sModifier += usFriendBonus;
return(sModifier);
}