Added Headrock's HAM 2.8

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@2650 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Wanne
2009-04-01 12:20:30 +00:00
parent 5f9261273a
commit 335747c3ff
48 changed files with 3439 additions and 406 deletions
+4
View File
@@ -69,6 +69,10 @@ typedef struct
UINT16 ubItemStatus;
UINT16 fromItem;
INT32 flash;
// HEADROCK HAM B2.5: Experimental bullet tracer info. If the new tracer system is activated, this flag tells
// the bullet animation functions to create a lightpath for this bullet. This means now all bullets in a tracer
// magazine will cause a lightshow (that's the intended result).
BOOLEAN fTracer;
} BULLET;
extern UINT32 guiNumBullets;
+103 -25
View File
@@ -73,7 +73,11 @@ STR16 wDebugStatStrings[]={
// local prototypes
UINT8 CalcImportantSectorControl( void );
// HEADROCK HAM B1: New function to calculate how many important sectors there are in the game at all.
UINT8 CalcTotalImportantSectors( void );
UINT16 CountSurfaceSectorsVisited( void );
// HAEDROCK HAM B1: New function to calculate how many sectors CAN be visited, on the surface.
UINT16 TotalVisitableSurfaceSectors( void );
@@ -1076,30 +1080,58 @@ UINT16 SubpointsPerPoint(UINT8 ubStat, INT8 bExpLevel)
{
UINT16 usSubpointsPerPoint;
UINT16 HEALTH_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.ubHealthSubpointsToImprove;
UINT16 STRENGTH_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.ubStrengthSubpointsToImprove;
UINT16 DEXTERITY_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.ubDexteritySubpointsToImprove;
UINT16 AGILITY_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.ubAgilitySubpointsToImprove;
UINT16 WISDOM_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.ubWisdomSubpointsToImprove;
UINT16 MARKSMANSHIP_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.ubMarksmanshipSubpointsToImprove;
UINT16 MEDICAL_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.ubMedicalSubpointsToImprove;
UINT16 MECHANICAL_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.ubMechanicalSubpointsToImprove;
UINT16 LEADERSHIP_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.ubLeadershipSubpointsToImprove;
UINT16 EXPLOSIVES_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.ubExplosivesSubpointsToImprove;
UINT16 LEVEL_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.ubLevelSubpointsToImprove;
// figure out how many subpoints this type of stat needs to change
switch (ubStat)
{
// Attributes
case HEALTHAMT:
usSubpointsPerPoint = HEALTH_SUBPOINTS_TO_IMPROVE;
break;
case AGILAMT:
usSubpointsPerPoint = AGILITY_SUBPOINTS_TO_IMPROVE;
break;
case DEXTAMT:
usSubpointsPerPoint = DEXTERITY_SUBPOINTS_TO_IMPROVE;
break;
case WISDOMAMT:
case STRAMT:
// attributes
usSubpointsPerPoint = ATTRIBS_SUBPOINTS_TO_IMPROVE;
break;
usSubpointsPerPoint = WISDOM_SUBPOINTS_TO_IMPROVE;
break;
case STRAMT:
usSubpointsPerPoint = STRENGTH_SUBPOINTS_TO_IMPROVE;
break;
// Skills
case MEDICALAMT:
usSubpointsPerPoint = MEDICAL_SUBPOINTS_TO_IMPROVE;
break;
case EXPLODEAMT:
usSubpointsPerPoint = EXPLOSIVES_SUBPOINTS_TO_IMPROVE;
break;
case MECHANAMT:
usSubpointsPerPoint = MECHANICAL_SUBPOINTS_TO_IMPROVE;
break;
case MARKAMT:
case LDRAMT:
// skills
usSubpointsPerPoint = SKILLS_SUBPOINTS_TO_IMPROVE;
break;
usSubpointsPerPoint = MARKSMANSHIP_SUBPOINTS_TO_IMPROVE;
break;
case LDRAMT:
usSubpointsPerPoint = LEADERSHIP_SUBPOINTS_TO_IMPROVE;
break;
// Experience
case EXPERAMT:
usSubpointsPerPoint = LEVEL_SUBPOINTS_TO_IMPROVE * bExpLevel;
break;
usSubpointsPerPoint = LEVEL_SUBPOINTS_TO_IMPROVE * bExpLevel;
break;
default:
// BETA message
@@ -1267,7 +1299,7 @@ UINT8 CurrentPlayerProgressPercentage(void)
{
UINT32 uiCurrentIncome;
UINT32 uiPossibleIncome;
UINT8 ubCurrentProgress = gGameExternalOptions.ubGameProgressIncrement;
UINT8 ubCurrentProgress;
UINT8 ubKillsPerPoint;
UINT16 usKillsProgress;
UINT16 usControlProgress;
@@ -1332,7 +1364,12 @@ UINT8 CurrentPlayerProgressPercentage(void)
// 19 sectors in mining towns + 3 wilderness SAMs each count double. Balime & Meduna are extra and not required
usControlProgress = CalcImportantSectorControl();
// HEADROCK HAM B1: Changed the next line, adding a call to a new function. This allows the weight of Sector
// Control to be altered in JA2_OPTIONS.INI (Previously damaged the game's progress if set over 25... So I've
// made this MOD-Friendly :D )
// BTW, Balime and Meduna _ARE_ required. The function doesn't differentiate! Such carelessness. Tsk tsk tsk.
usControlProgress = gGameExternalOptions.ubGameProgressPortionControl * CalcImportantSectorControl() / CalcTotalImportantSectors();
if (usControlProgress > gGameExternalOptions.ubGameProgressPortionControl)
{
usControlProgress = gGameExternalOptions.ubGameProgressPortionControl;
@@ -1343,21 +1380,14 @@ UINT8 CurrentPlayerProgressPercentage(void)
// WDS: Adding more ways to progress in the game
// Get a ratio of sectors visited to the total number of sectors
usVisitProgress = CountSurfaceSectorsVisited() * gGameExternalOptions.ubGameProgressPortionVisited / ((MAP_WORLD_X - 2) * (MAP_WORLD_Y - 2) - 56 /* note: should be calculated */);
// HEADROCK HAM B1: Fixed this so it doesn't count sectors that can't be visited. Allows progress to go to
// 100 even if the map has some unvisitable sectors (heh, doesn't it always?)
usVisitProgress = CountSurfaceSectorsVisited() * gGameExternalOptions.ubGameProgressPortionVisited / TotalVisitableSurfaceSectors();
// add visit progress
// add control progress
ubCurrentProgress += usVisitProgress;
// Add increment to progress
ubCurrentProgress += gGameExternalOptions.ubGameProgressIncrement;
if (ubCurrentProgress < gGameExternalOptions.ubGameProgressMinimum)
return gGameExternalOptions.ubGameProgressMinimum;
if (ubCurrentProgress < 100)
return ubCurrentProgress;
else
return 100;
return(ubCurrentProgress);
}
@@ -1607,6 +1637,36 @@ UINT8 CalcImportantSectorControl( void )
return( ubSectorControlPts );
}
// HEADROCK HAM B1: function to calculate how many "important sectors" there actually are in the game. This is
// used to fix the weight of strategic control importance on game progress, which was until now not really
// moddable.
UINT8 CalcTotalImportantSectors( void )
{
UINT8 ubMapX, ubMapY;
UINT8 ubSectorControlPts = 0;
for ( ubMapX = 1; ubMapX < MAP_WORLD_X - 1; ubMapX++ )
{
for ( ubMapY = 1; ubMapY < MAP_WORLD_Y - 1; ubMapY++ )
{
// towns where militia can be trained and SAM sites are important sectors
if ( MilitiaTrainingAllowedInSector( ubMapX, ubMapY, 0 ) )
{
ubSectorControlPts++;
// SAM sites count double - they have no income, but have significant air control value
if ( IsThisSectorASAMSector( ubMapX, ubMapY, 0 ) )
{
ubSectorControlPts++;
}
}
}
}
return( ubSectorControlPts );
}
// WDS: Adding more ways to progress in the game
// Count how many surface sectors the player has visited
@@ -1627,6 +1687,24 @@ UINT16 CountSurfaceSectorsVisited( void )
return( ubSectorsVisited );
}
// HEADROCK: Count number of VISITABLE sectors
UINT16 TotalVisitableSurfaceSectors( void )
{
UINT8 ubMapX, ubMapY;
UINT16 ubVisitableSectors = 0;
for ( ubMapX = 1; ubMapX < MAP_WORLD_X - 1; ubMapX++ )
{
for ( ubMapY = 1; ubMapY < MAP_WORLD_Y - 1; ubMapY++ )
{
if( SectorInfo[ SECTOR(ubMapX,ubMapY) ].ubTraversability[ THROUGH_STRATEGIC_MOVE ] != GROUNDBARRIER && SectorInfo[ SECTOR(ubMapX,ubMapY) ].ubTraversability[ THROUGH_STRATEGIC_MOVE ] != EDGEOFWORLD )
++ubVisitableSectors;
}
}
return( ubVisitableSectors );
}
void MERCMercWentUpALevelSendEmail( UINT8 ubMercMercIdValue )
{
+7 -3
View File
@@ -25,9 +25,13 @@
#define MAX_STAT_VALUE 100 // for stats and skills
#define MAXEXPLEVEL 10 // maximum merc experience level
#define SKILLS_SUBPOINTS_TO_IMPROVE 25
#define ATTRIBS_SUBPOINTS_TO_IMPROVE 50
#define LEVEL_SUBPOINTS_TO_IMPROVE 350 // per current level! (Can't go over 6500, 10x must fit in USHORT!)
// HEADROCK HAM B2.7 : Externalizing these (changed from #define)
//#define SKILLS_SUBPOINTS_TO_IMPROVE 25
//#define ATTRIBS_SUBPOINTS_TO_IMPROVE 50
//#define LEVEL_SUBPOINTS_TO_IMPROVE 350 // per current level! (Can't go over 6500, 10x must fit in USHORT!)
extern UINT16 SKILLS_SUBPOINTS_TO_IMPROVE;
extern UINT16 ATTRIBS_SUBPOINTS_TO_IMPROVE;
extern UINT16 LEVEL_SUBPOINTS_TO_IMPROVE;
#define WORKIMPROVERATE 2 // increase to make working mercs improve more
#define TRAINIMPROVERATE 2 // increase to make training mercs improve more
+8 -1
View File
@@ -30,6 +30,8 @@
#include "Text.h"
#include "strategicmap.h"
#include "Render Fun.h"
// HEADROCK HAM B2.7: Allow calling a CTH approximation function for the CTH display ("F" key)
#include "UI Cursors.h"
#endif
@@ -635,7 +637,12 @@ void DisplayRangeToTarget( SOLDIERTYPE *pSoldier, INT16 sTargetGridNo )
//AXP 30.03.2007: Fix CtH calculation for first shot after changing aim level (roof/ground)
INT8 bTempTargetLevel = pSoldier->bTargetLevel;
pSoldier->bTargetLevel = (INT8)gsInterfaceLevel;
uiHitChance = CalcChanceToHitGun( pSoldier, sTargetGridNo, (pSoldier->aiData.bShownAimTime ), pSoldier->bAimShotLocation );
uiHitChance = CalcChanceToHitGun( pSoldier, sTargetGridNo, (INT8)(pSoldier->aiData.bShownAimTime ), pSoldier->bAimShotLocation );
// HEADROCK HAM B2.7: CTH approximation?
if (gGameExternalOptions.fApproximateCTH)
{
uiHitChance = ChanceToHitApproximation( pSoldier, uiHitChance );
}
pSoldier->bTargetLevel = bTempTargetLevel;
swprintf( zOutputString, zNewTacticalMessages[ TCTL_MSG__GUN_RANGE_AND_CTH ], Weapon[ pSoldier->inv[HANDPOS].usItem ].usRange / 10, uiHitChance );
+7 -1
View File
@@ -230,7 +230,11 @@ INT16 gsTreeRevealYPos;
// taken out of header to remove multiple symbol definitions (jonathanl)
BOOLEAN gfUICtHBar;
UINT8 gbCtH;
// HEADROCK HAM B1/2: Created an array to hold CTH of different bullets for Burst/Auto CTH Bar.
UINT8 gbCtH[ 10 ];
UINT8 gbCtHBurstCount;
// HEADROCK HAM B2: This value tracks whether Autofire mode is selected. This value may be redundant... not sure.
BOOLEAN gbCtHAutoFire;
UINT16 gsTotalBulletCount;
UINT16 gsBulletCount;
BOOLEAN gTintBulletCounts;
@@ -514,6 +518,8 @@ UINT32 HandleTacticalUI( void )
gTintBulletCounts = FALSE;
gfUIAutofireBulletCount = FALSE;
gfUICtHBar = FALSE;
// HEADROCK HAM B2: tells the cursor-drawing function to draw two CTH bars (for autofire).
gbCtHAutoFire = FALSE;
// Set old event value
guiOldEvent = uiNewEvent = guiCurrentEvent;
+5 -1
View File
@@ -220,7 +220,11 @@ extern BOOLEAN gTintBulletCounts;
extern BOOLEAN gfUIAutofireBulletCount;
extern BOOLEAN gfUICtHBar;
extern UINT8 gbCtH;
// HEADROCK HAM B1/2: Multiple-bullet CTH bar array (replaces old single integer)
extern UINT8 gbCtH[ 10 ];
extern UINT8 gbCtHBurstCount;
// HEADROCK HAM B2: Track autofire on/off
extern BOOLEAN gbCtHAutoFire;
extern CHAR16 gzIntTileLocation[ 20 ];
extern BOOLEAN gfUIIntTileLocation;
+2 -1
View File
@@ -2241,7 +2241,8 @@ else
// only enemy soldiers use auto-drop system!
// don't use the auto-drop system in auto-resolve: player won't see what's being used & enemies will often win & keep'em
if ( SOLDIER_CLASS_ENEMY( bSoldierClass ) && !IsAutoResolveActive() )
// HEADROCK HAM B2.8: Militia now drop all their equipment... IF not killed by player (see TurnSoldierIntoCorpse() )
if ( (SOLDIER_CLASS_ENEMY( bSoldierClass ) || ( gGameExternalOptions.ubMilitiaDropEquipment > 0 && SOLDIER_CLASS_MILITIA( bSoldierClass ) )) && !IsAutoResolveActive() )
{
// SPECIAL handling for weapons: we'll always drop a weapon type that has never been dropped before
for( i = 0; i < pp->Inv.size(); i++ )
+90
View File
@@ -7102,6 +7102,9 @@ INT16 GetBurstToHitBonus( OBJECTTYPE * pObj, BOOLEAN fProneStance )
bonus += Item[pObj->usItem].bipod;
bonus += BonusReduceMore( Item[pObj->usItem].bursttohitbonus, (*pObj)[0]->data.objectStatus );
// HEADROCK HAM B2.5: A certain setting in the New Tracer System can turn auto/burst penalties off
// entirely, to make up for "Tracer Bump".
if ( gGameExternalOptions.iRealisticTracers != 1 )
bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].bursttohitbonus ;
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
@@ -7228,6 +7231,10 @@ INT16 GetAutoToHitBonus( OBJECTTYPE * pObj, BOOLEAN fProneStance )
bonus += BonusReduceMore( Item[pObj->usItem].autofiretohitbonus, (*pObj)[0]->data.objectStatus );
// HEADROCK HAM B2.5: This external setting determines whether autofire penalty is affected by
// tracer ammo. At setting "1", it is disabled. This goes hand in hand with a new tracer effect that
// "bumps" CTH up after firing a tracer bullet.
if ( gGameExternalOptions.iRealisticTracers != 1 )
bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].autofiretohitbonus ;
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
@@ -8491,6 +8498,88 @@ UINT8 AllowedAimingLevels(SOLDIERTYPE * pSoldier)
float iScopeBonus = 0;
BOOLEAN allowed = TRUE;
// HEADROCK HAM B2.6: Dynamic aiming level restrictions based on gun type and attachments.
if ( gGameExternalOptions.fDynamicAimingTime )
{
UINT16 weaponRange;
UINT8 weaponType, maxAimForType, maxAimWithoutBipod;
BOOLEAN fTwoHanded, fUsingBipod;
// Read weapon data
fTwoHanded = Item[pSoldier->inv[pSoldier->ubAttackingHand].usItem].twohanded;
weaponRange = Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].usRange + GetRangeBonus(&pSoldier->inv[pSoldier->ubAttackingHand]);
weaponType = Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].ubWeaponType;
fUsingBipod = FALSE;
maxAimWithoutBipod = 4;
// Define basic (no attachments), and absolute maximums
if (weaponType == GUN_PISTOL || weaponType == GUN_M_PISTOL || (weaponType == GUN_SMG && fTwoHanded == 0) || fTwoHanded == 0)
{
maxAimForType = 2;
aimLevels = 1;
maxAimWithoutBipod = 2;
}
else if (weaponType == GUN_SHOTGUN || weaponType == GUN_LMG || (weaponType == GUN_SMG && fTwoHanded == 1))
{
maxAimForType = 3;
aimLevels = 2;
maxAimWithoutBipod = 3;
}
else if ((weaponType == GUN_AS_RIFLE || weaponType == GUN_RIFLE || weaponType == GUN_SN_RIFLE) && weaponRange <= 500)
{
maxAimForType = 4;
aimLevels = 2;
maxAimWithoutBipod = 3;
}
else if ((weaponType == GUN_AS_RIFLE || weaponType == GUN_RIFLE || weaponType == GUN_SN_RIFLE) && weaponRange > 500)
{
maxAimForType = 8;
aimLevels = 3;
maxAimWithoutBipod = 4;
}
else
{
return 4;
}
// Determine whether a bipod is being used (prone)
if (GetBipodBonus(&pSoldier->inv[pSoldier->ubAttackingHand])>0 && gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE )
{
fUsingBipod = TRUE;
}
iScopeBonus = ( (float)gGameExternalOptions.ubStraightSightRange * GetMinRangeForAimBonus(&pSoldier->inv[pSoldier->ubAttackingHand]) / 100 );
if ( iScopeBonus >= ( (float)gGameExternalOptions.ubStraightSightRange * 0.6) ) // >= 60% of sight range (~9 tiles by default)
{
aimLevels = (UINT8)((float)aimLevels * (float)2);
}
else if ( iScopeBonus >= ( (float)gGameExternalOptions.ubStraightSightRange * 0.3) ) // >= 30% of sight range (~4 tiles by default)
{
aimLevels = (UINT8)((float)(aimLevels+1) * (float)1.5);
}
// Smaller scopes increase by one.
else if ( iScopeBonus > 0 )
{
aimLevels++;
}
// Make sure not over maximum allowed for weapon type.
if (aimLevels > maxAimForType)
{
aimLevels = maxAimForType;
}
// Make sure not over maximum allowed without a bipod.
if (!fUsingBipod)
{
aimLevels = __min(aimLevels, maxAimWithoutBipod);
}
}
else // JA2 1.13 Basic aiming restrictions (8 levels for 10x scope, 6 levels for 7x scope)
{
if ( gGameSettings.fOptions[TOPTION_AIM_LEVEL_RESTRICTION] && Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].ubWeaponType != GUN_RIFLE && Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].ubWeaponType != GUN_SN_RIFLE )
allowed = FALSE;
@@ -8506,6 +8595,7 @@ UINT8 AllowedAimingLevels(SOLDIERTYPE * pSoldier)
if ( iScopeBonus >= ( (float)gGameExternalOptions.ubStraightSightRange * 0.6) ) // >= 60% of sight range (~9 tiles by default)
{
aimLevels += 2;
}
}
}
+46 -2
View File
@@ -3669,6 +3669,24 @@ INT8 FireBulletGivenTarget( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOA
usBulletFlags |= BULLET_FLAG_FLAME;
ubSpreadIndex = 2;
}
// HEADROCK HAM B2.5: Set tracer effect on/off for individual bullets in a Tracer Magazine, as part of the
// New Tracer System.
else if (gGameExternalOptions.iRealisticTracers > 0 && gGameExternalOptions.iNumBulletsPerTracer > 0 && (pFirer->bDoAutofire > 0 || pFirer->bDoBurst > 0)
&& AmmoTypes[ pFirer->inv[pFirer->ubAttackingHand][0]->data.gun.ubGunAmmoType ].tracerEffect )
{
UINT16 iBulletsLeft, iBulletsPerTracer;
iBulletsPerTracer = gGameExternalOptions.iNumBulletsPerTracer;
iBulletsLeft = pFirer->inv[pFirer->ubAttackingHand][0]->data.gun.ubGunShotsLeft + pFirer->bDoBurst;
if ((((iBulletsLeft - (pFirer->bDoBurst - 1)) / iBulletsPerTracer) - ((iBulletsLeft - pFirer->bDoBurst) / iBulletsPerTracer)) == 1)
{
fTracer = TRUE;
}
else
{
fTracer = FALSE;
}
}
else if ( AmmoTypes[ pFirer->inv[pFirer->ubAttackingHand][0]->data.gun.ubGunAmmoType ].tracerEffect && (pFirer->bDoBurst || gGameSettings.fOptions[ TOPTION_TRACERS_FOR_SINGLE_FIRE ]) )
{
//usBulletFlags |= BULLET_FLAG_TRACER;
@@ -3817,6 +3835,26 @@ INT8 FireBulletGivenTarget( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOA
// this distance limit only applies in a "hard" sense to fake bullets for chance-to-get-through,
// but is used for determining structure hits by the regular code
pBullet->iDistanceLimit = iDistance;
// HEADROCK HAM BETA2.5: New method for signifying whether a bullet is a tracer or not, using an individual
// bullet structure flag. Hehehehe, I think this is kind of reverting to old code, isn't it?
if (gGameExternalOptions.iRealisticTracers > 0 && gGameExternalOptions.iNumBulletsPerTracer > 0 && (pFirer->bDoAutofire > 0 || pFirer->bDoBurst > 0)
&& AmmoTypes[ pFirer->inv[pFirer->ubAttackingHand][0]->data.gun.ubGunAmmoType ].tracerEffect )
{
UINT16 iBulletsLeft, iBulletsPerTracer;
iBulletsPerTracer = gGameExternalOptions.iNumBulletsPerTracer;
iBulletsLeft = pFirer->inv[pFirer->ubAttackingHand][0]->data.gun.ubGunShotsLeft + pFirer->bDoBurst;
// Is this specific bullet a tracer? - based on how many tracers there are per regular bullets in
// a tracer magazine (INI-settable).
if ((((iBulletsLeft - (pFirer->bDoBurst - 1)) / iBulletsPerTracer) - ((iBulletsLeft - pFirer->bDoBurst) / iBulletsPerTracer)) == 1)
{
pBullet->fTracer = TRUE;
}
else
{
pBullet->fTracer = FALSE;
}
}
if (fFake)
{
bCTGT = FireBullet( pFirer, pBullet, TRUE );
@@ -4366,7 +4404,10 @@ void MoveBullet( INT32 iBullet )
}
}
if (( pBullet->usFlags & ( BULLET_FLAG_MISSILE | BULLET_FLAG_SMALL_MISSILE | BULLET_FLAG_TANK_CANNON | BULLET_FLAG_FLAME | BULLET_FLAG_CREATURE_SPIT /*| BULLET_FLAG_TRACER*/ ) ) || fTracer == TRUE)
// HEADROCK HAM B2.5: Changed condition to read fTracer flag directly from bullet's struct.
// This is for the New Tracer System.
if (( pBullet->usFlags & ( BULLET_FLAG_MISSILE | BULLET_FLAG_SMALL_MISSILE | BULLET_FLAG_TANK_CANNON | BULLET_FLAG_FLAME | BULLET_FLAG_CREATURE_SPIT /*| BULLET_FLAG_TRACER*/ ) )
|| ((gGameExternalOptions.iRealisticTracers > 0 && gGameExternalOptions.iNumBulletsPerTracer > 0 && pBullet->fTracer == TRUE) || (gGameExternalOptions.iRealisticTracers == 0 && fTracer == TRUE)))
{
INT8 bStepsPerMove = STEPS_FOR_BULLET_MOVE_TRAILS;
@@ -4653,7 +4694,10 @@ void MoveBullet( INT32 iBullet )
pBullet->iCurrCubesZ = CONVERT_HEIGHTUNITS_TO_INDEX( FIXEDPT_TO_INT32( pBullet->qCurrZ ) );
pBullet->iLoop++;
if (( pBullet->usFlags & ( BULLET_FLAG_MISSILE | BULLET_FLAG_SMALL_MISSILE | BULLET_FLAG_TANK_CANNON | BULLET_FLAG_FLAME | BULLET_FLAG_CREATURE_SPIT /*| BULLET_FLAG_TRACER */) ) || fTracer == TRUE)
// HEADROCK HAM B2.5: Changed condition to read fTracer flag directly from bullet's struct.
// This is for the New Tracer System.
if (( pBullet->usFlags & ( BULLET_FLAG_MISSILE | BULLET_FLAG_SMALL_MISSILE | BULLET_FLAG_TANK_CANNON | BULLET_FLAG_FLAME | BULLET_FLAG_CREATURE_SPIT /*| BULLET_FLAG_TRACER */) )
|| ((gGameExternalOptions.iRealisticTracers > 0 && gGameExternalOptions.iNumBulletsPerTracer > 0 && pBullet->fTracer == TRUE) || (gGameExternalOptions.iRealisticTracers == 0 && fTracer == TRUE)))
{
INT8 bStepsPerMove = STEPS_FOR_BULLET_MOVE_TRAILS;
+158 -15
View File
@@ -7206,12 +7206,24 @@ INT8 CalcSuppressionTolerance( SOLDIERTYPE * pSoldier )
void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
{
///////////////////////////////////////////////////////////////////////////////
//
// HEADROCK HAM B2: This entire function has been completely revamped.
//
///////////////////////////////////////////////////////////////////////////////
// External options.
UINT8 MAX_APS_SUPPRESSED = gGameExternalOptions.iMaxSuppressionAPLossPerAttack;
UINT8 MAX_APS_SUPPRESSED_TOTAL = gGameExternalOptions.iMaxSuppressionAPLossPerTurn;
INT8 SUPPRESSION_AP_LIMIT = gGameExternalOptions.iMinAPLimitFromSuppression;
INT8 MAXIMUM_SUPPRESSION_SHOCK = gGameExternalOptions.iMaxSuppressionShock;
INT8 bTolerance;
INT16 sClosestOpponent, sClosestOppLoc;
UINT8 ubPointsLost, ubTotalPointsLost, ubNewStance;
UINT32 uiLoop;
UINT8 ubLoop2;
UINT16 uiLoop3;
// Flag to determine if the target is cowering (if allowed)
BOOLEAN fCower;
SOLDIERTYPE * pSoldier;
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
@@ -7226,7 +7238,14 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
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
ubPointsLost = (UINT8)( (FLOAT)((pSoldier->ubSuppressionPoints * APBPConstants[AP_SUPPRESSION_MOD]) / (bTolerance + 6)) * 2 + 1 ) / 2;
// 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).
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;
// reduce loss of APs based on stance
// ATE: Taken out because we can possibly supress ourselves...
@@ -7243,37 +7262,125 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
//}
// cap the # of APs we can lose
if (ubPointsLost > APBPConstants[AP_MAX_SUPPRESSED])
// HEADROCK HAM B2: This now reads an external value. 0 means no limit.
if (MAX_APS_SUPPRESSED > 0)
{
ubPointsLost = (UINT8)APBPConstants[AP_MAX_SUPPRESSED];
if (ubPointsLost > APBPConstants[AP_MAX_SUPPRESSED])
{
ubPointsLost = APBPConstants[AP_MAX_SUPPRESSED];
}
}
// HEADROCK HAM B2: This makes sure that we never lose more APs than we're allowed per turn,
if (MAX_APS_SUPPRESSED_TOTAL > 0)
{
if (pSoldier->ubAPsLostToSuppression + ubPointsLost > MAX_APS_SUPPRESSED_TOTAL)
{
ubPointsLost = MAX_APS_SUPPRESSED_TOTAL - pSoldier->ubAPsLostToSuppression;
}
}
// Keeps a number for later reference
ubTotalPointsLost = ubPointsLost;
// Subtract off the APs lost before this point to find out how many points are lost now
// 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"));
// morale modifier
if (ubTotalPointsLost / 2 > pSoldier->ubAPsLostToSuppression / 2)
// 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)
{
//CHRISL: This should dynamically adjust the number of times we run the morale loop based on AP_MAXIMUM
uiLoop3 = (((ubTotalPointsLost / 2) - (pSoldier->ubAPsLostToSuppression / 2)) * APBPConstants[AP_MAXIMUM]) / 100;
for ( ubLoop2 = 0; ubLoop2 < uiLoop3; ubLoop2++ )
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;
if (bShockValue < 0)
bShockValue = 0;
if (bShockLimit < 0)
bShockLimit = 0;
// use external value to determine how effective SHOCK really is.
bShockValue = (bShockValue * gGameExternalOptions.iSuppressionShockEffectiveness) / 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.
if ( pSoldier->aiData.bShock + bShockValue <= bShockLimit )
{
// Shock limit not yet breached. Add shock to character.
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;
}
// 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.
fCower = false;
if ( gGameExternalOptions.fSuppressionShock && gGameExternalOptions.iAimPenaltyPerTargetShock > 0 )
{
if (pSoldier->aiData.bShock >= bTolerance)
{ fCower = true; }
}
// 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.
if (gGameExternalOptions.iAPLostPerMoraleDrop > 0 && ubPointsLost > 0)
{
for ( ubLoop2 = 0; ubLoop2 < (ubPointsLost / gGameExternalOptions.iAPLostPerMoraleDrop); ubLoop2++ )
{
HandleMoraleEvent( pSoldier, MORALE_SUPPRESSED, pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ );
}
}
ubPointsLost -= pSoldier->ubAPsLostToSuppression;
ubNewStance = 0;
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: check for reaction"));
// merc may get to react
if ( pSoldier->ubSuppressionPoints >= ( 130 / (6 + bTolerance) ) )
// Headrock: apply suppression effectiveness percentage to this value.
if ( (pSoldier->ubSuppressionPoints * gGameExternalOptions.iSuppressionEffectiveness) / 100 >= ( 130 / (6 + bTolerance) ) || fCower )
{
// merc gets to use APs to react!
switch (gAnimControl[ pSoldier->usAnimState ].ubEndHeight)
@@ -7285,7 +7392,8 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
if (ubTotalPointsLost >= APBPConstants[AP_PRONE] && IsValidStance( pSoldier, ANIM_PRONE ) )
{
sClosestOpponent = ClosestKnownOpponent( pSoldier, &sClosestOppLoc, NULL );
if (sClosestOpponent == NOWHERE || SpacesAway( pSoldier->sGridNo, sClosestOppLoc ) > 8)
// HEADROCK: Added cowering.
if (sClosestOpponent == NOWHERE || SpacesAway( pSoldier->sGridNo, sClosestOppLoc ) > 8 || fCower)
{
if (ubPointsLost < APBPConstants[AP_PRONE])
{
@@ -7311,7 +7419,8 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
else if (ubTotalPointsLost >= (APBPConstants[AP_CROUCH] + APBPConstants[AP_PRONE]) && ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_PRONE ) && IsValidStance( pSoldier, ANIM_PRONE ) )
{
sClosestOpponent = ClosestKnownOpponent( pSoldier, &sClosestOppLoc, NULL );
if ( sClosestOpponent == NOWHERE || SpacesAway( pSoldier->sGridNo, sClosestOppLoc ) > 8 )
// HEADROCK: Added cowering.
if ( sClosestOpponent == NOWHERE || SpacesAway( pSoldier->sGridNo, sClosestOppLoc ) > 8 ||fCower )
{
if ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND )
{
@@ -7341,7 +7450,18 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: reduce action points"));
// Reduce action points!
pSoldier->bActionPoints -= ubPointsLost;
// HEADROCK HAM Beta 2.2: Enforce a minimum limit via INI.
if (pSoldier->bActionPoints - ubPointsLost < gGameExternalOptions.iMinAPLimitFromSuppression )
{
pSoldier->bActionPoints = gGameExternalOptions.iMinAPLimitFromSuppression;
}
else
{
pSoldier->bActionPoints -= ubPointsLost;
}
// 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;
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: check for quote"));
@@ -7404,6 +7524,18 @@ 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;
}
} // end of examining one soldier
} // end of loop
@@ -7988,6 +8120,17 @@ 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)
+2
View File
@@ -316,6 +316,8 @@ void ResetAllMercSpeeds( );
BOOLEAN HandleGotoNewGridNo( SOLDIERTYPE *pSoldier, BOOLEAN *pfKeepMoving, BOOLEAN fInitialMove, UINT16 usAnimState );
SOLDIERTYPE * ReduceAttackBusyCount( );
// HEADROCK HAM B2.6: Made this public so it can be used elsewhere.
INT8 CalcSuppressionTolerance( SOLDIERTYPE * pSoldier );
void CommonEnterCombatModeCode( );
+37 -1
View File
@@ -1122,7 +1122,43 @@ INT16 CalcTotalAPsToAttack( SOLDIERTYPE *pSoldier, INT16 sGridNo, UINT8 ubAddTur
}
else
{
sAPCost += (bAimTime*APBPConstants[AP_CLICK_AIM]);
if (gGameExternalOptions.fIncreasedAimingCost )
{
// HEADROCK HAM B2.6: Changed the number of APs to attack when aiming.
if (bAimTime > 0)
{
// Add 1/2 ready cost (rounded up) for getting the sights up to the eye
sAPCost += ((Weapon[ usItemNum ].ubReadyTime * (100 - GetPercentReadyTimeAPReduction(&pSoldier->inv[HANDPOS])) / 100) + 1) / 2;
// Add regular aim time for the first 4 aiming actions.
sAPCost += __min(bAimTime,4);
// If the weapon has a scope, and the target is within eligible range for scope use
if ( IsScoped(&pSoldier->inv[HANDPOS])
&& GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sGridNo ) >= GetMinRangeForAimBonus(&pSoldier->inv[HANDPOS]) )
{
// Add time to adjust eye to scope
if (bAimTime > 0)
{
sAPCost += 1;
}
// Add 2 APs for each aiming point between 5 and 6
if (bAimTime > 4)
{
sAPCost += __min(((bAimTime - 4) * 2), 4);
}
// Add 3 APs for each aiming point beyond 6.
if (bAimTime > 6)
{
sAPCost += (bAimTime - 6) * 3;
}
}
}
}
else
{
sAPCost += bAimTime;
}
}
}
+11 -3
View File
@@ -932,9 +932,12 @@ BOOLEAN TurnSoldierIntoCorpse( SOLDIERTYPE *pSoldier, BOOLEAN fRemoveMerc, BOOLE
if ( !(Item[ pObj->usItem ].defaultundroppable ) )
{
ReduceAmmoDroppedByNonPlayerSoldiers( pSoldier, cnt );
//if this soldier was an enemy
// Kaiden: Added from UB's reveal all items after combat feature!
if( pSoldier->bTeam == ENEMY_TEAM )
//if this soldier was an enemy
// Kaiden: Added from UB's reveal all items after combat feature!
// HEADROCK HAM B2.8: Now also reveals equipment dropped by militia, if requirement is met.
if( pSoldier->bTeam == ENEMY_TEAM ||
( gGameExternalOptions.ubMilitiaDropEquipment == 2 && pSoldier->bTeam == MILITIA_TEAM ) ||
( gGameExternalOptions.ubMilitiaDropEquipment == 1 && pSoldier->bTeam == MILITIA_TEAM && Menptr[ pSoldier->ubAttackerID ].bTeam != OUR_TEAM ))
{
//add a flag to the item so when all enemies are killed, we can run through and reveal all the enemies items
usItemFlags |= WORLD_ITEM_DROPPED_FROM_ENEMY;
@@ -946,7 +949,12 @@ BOOLEAN TurnSoldierIntoCorpse( SOLDIERTYPE *pSoldier, BOOLEAN fRemoveMerc, BOOLE
}
}
// HEADROCK HAM B2.8: Militia will drop items only if allowed.
if (!(gGameExternalOptions.ubMilitiaDropEquipment == 0 && pSoldier->bTeam == MILITIA_TEAM ) &&
!(gGameExternalOptions.ubMilitiaDropEquipment == 1 && pSoldier->bTeam == MILITIA_TEAM && Menptr[ pSoldier->ubAttackerID ].bTeam == OUR_TEAM ))
{
AddItemToPool( pSoldier->sGridNo, pObj, bVisible , pSoldier->pathing.bLevel, usItemFlags, -1 );
}
}
}
}
+12 -2
View File
@@ -1849,8 +1849,9 @@ INT16 SOLDIERTYPE::CalcActionPoints( void )
ubPoints = DynamicAdjustAPConstants(ubPoints, ubPoints);
// If resulting APs are below our permitted minimum, raise them to it!
if (ubPoints < APBPConstants[AP_MINIMUM])
ubPoints = APBPConstants[AP_MINIMUM];
// HEADROCK: Enforce new minimums due to suppression. I should've done this neater though.
if (ubPoints < gGameExternalOptions.iMinAPLimitFromSuppression)
ubPoints = gGameExternalOptions.iMinAPLimitFromSuppression;
// make sure action points doesn't exceed the permitted maximum
ubMaxAPs = gubMaxActionPoints[ this->ubBodyType ];
@@ -6688,6 +6689,15 @@ void SOLDIERTYPE::EVENT_BeginMercTurn( BOOLEAN fFromRealTime, INT32 iRealTimeCou
this->usQuoteSaidExtFlags &= ( ~SOLDIER_QUOTE_SAID_EXT_CLOSE_CALL );
this->bNumHitsThisTurn = 0;
this->ubSuppressionPoints = 0;
// 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). There's really no reason to
// keep this in an IF statement though, as it should, by all rights, erase itself each turn at the very
// least to avoid the once-in-a-lifetime suppression problem.
if (gGameExternalOptions.iClearSuppression == 1)
{
this->ubAPsLostToSuppression = 0;
}
this->flags.fCloseCall = FALSE;
this->ubMovementNoiseHeard = 0;
+274 -121
View File
@@ -192,6 +192,8 @@ extern INT16 ITEMDESC_START_Y;
//Little functions called by keyboard input
void SwapGoggles(SOLDIERTYPE *pTeamSoldier);
// HEADROCK HAM B2.8: Function to switch team's goggles uniformly
void SwapGogglesUniformly(SOLDIERTYPE *pTeamSoldier, BOOLEAN fToNightVision);
void SeperateItems();
void StackAndSort( BOOLEAN fRestrictToAmmo );
void CreateRandomItem();
@@ -3315,10 +3317,43 @@ void GetKeyboardInput( UINT32 *puiNewEvent )
case 'N':
SOLDIERTYPE *pTeamSoldier;
INT8 bLoop;
for (bLoop=gTacticalStatus.Team[gbPlayerNum].bFirstID, pTeamSoldier=MercPtrs[bLoop]; bLoop <= gTacticalStatus.Team[gbPlayerNum].bLastID; bLoop++, pTeamSoldier++)
BOOLEAN fToNightVision;
// HEADROCK HAM B2.8: Added call for CTRL-SHIFT-N to switch all soldiers to day/night.
if ( fCtrl )
{
if ( OK_CONTROLLABLE_MERC( pTeamSoldier ) && pTeamSoldier->bAssignment == CurrentSquad( ) && !AM_A_ROBOT( pTeamSoldier ) ) {
SwapGoggles(pTeamSoldier);
for (bLoop=gTacticalStatus.Team[gbPlayerNum].bFirstID, pTeamSoldier=MercPtrs[bLoop]; bLoop <= gTacticalStatus.Team[gbPlayerNum].bLastID; bLoop++, pTeamSoldier++)
{
if ( OK_CONTROLLABLE_MERC( pTeamSoldier ) && pTeamSoldier->bAssignment == CurrentSquad( ) && !AM_A_ROBOT( pTeamSoldier ) )
{
if ( pTeamSoldier->inv[HEAD1POS].exists() || pTeamSoldier->inv[HEAD2POS].exists() )
{
fToNightVision = ( Item[pTeamSoldier->inv[HEAD1POS].usItem].brightlightvisionrangebonus > 0 || Item[pTeamSoldier->inv[HEAD2POS].usItem].brightlightvisionrangebonus > 0 );
break;
}
if ( bLoop == gTacticalStatus.Team[gbPlayerNum].bLastID )
{
// Default to night or day based on game hour
fToNightVision = NightTime();
}
}
}
for (bLoop=gTacticalStatus.Team[gbPlayerNum].bFirstID, pTeamSoldier=MercPtrs[bLoop]; bLoop <= gTacticalStatus.Team[gbPlayerNum].bLastID; bLoop++, pTeamSoldier++)
{
if ( OK_CONTROLLABLE_MERC( pTeamSoldier ) && pTeamSoldier->bAssignment == CurrentSquad( ) && !AM_A_ROBOT( pTeamSoldier ) )
{
SwapGogglesUniformly(pTeamSoldier, fToNightVision);
}
}
}
else // Shift-N
{
for (bLoop=gTacticalStatus.Team[gbPlayerNum].bFirstID, pTeamSoldier=MercPtrs[bLoop]; bLoop <= gTacticalStatus.Team[gbPlayerNum].bLastID; bLoop++, pTeamSoldier++)
{
if ( OK_CONTROLLABLE_MERC( pTeamSoldier ) && pTeamSoldier->bAssignment == CurrentSquad( ) && !AM_A_ROBOT( pTeamSoldier ) )
{
SwapGoggles(pTeamSoldier);
}
}
}
break;
@@ -5638,81 +5673,186 @@ void SwapGoggles(SOLDIERTYPE *pTeamSoldier)
/* CHRISL - Adjusted this option to allow the game to search through Helmet attachments
as well as inventory positions.
*/
// WDS - Smart goggle switching
// NOTE: Investigate using GetItemVisionRangeBonus from Items.cpp???
if (gGameExternalOptions.smartGoggleSwitch) {
// Look through the head slots and find any sort of goggle or an empty spot
int slotToUse = -1;
for (int headSlot = HEAD1POS; headSlot <= HEAD2POS; ++headSlot) {
if ( (Item[pTeamSoldier->inv[headSlot].usItem].brightlightvisionrangebonus > 0) ) {
slotToUse = headSlot;
break;
} else if ( (Item[pTeamSoldier->inv[headSlot].usItem].nightvisionrangebonus > 0) ) {
slotToUse = headSlot;
break;
} else if (pTeamSoldier->inv[headSlot].exists() == false) {
slotToUse = headSlot;
OBJECTTYPE * pObj;
OBJECTTYPE * pGoggles = NULL;
INT8 bSlot1;
int bestBonus;
bool itemFound = false;
//CHRISL: Before doing anything, we should look at both head slots to see if either slot has some sort of goggles
for(bSlot1 = HEAD1POS; bSlot1 <= HEAD2POS; bSlot1++)
{
if(Item[pTeamSoldier->inv[bSlot1].usItem].brightlightvisionrangebonus > 0)
itemFound = true;
if(Item[pTeamSoldier->inv[bSlot1].usItem].nightvisionrangebonus > 0)
itemFound = true;
}
//2 head slots
for (bSlot1 = HEAD1POS; bSlot1 <= HEAD2POS; bSlot1++)
{
// if wearing sungoggles
if ( Item[pTeamSoldier->inv[bSlot1].usItem].brightlightvisionrangebonus > 0 )
{
itemFound = true;
bestBonus = 0;
pGoggles = FindNightGogglesInInv( pTeamSoldier );
//search for better goggles on the helmet
if (pGoggles)
{
bestBonus = Item[pGoggles->usItem].nightvisionrangebonus;
}
}
if (slotToUse == -1) {
// No place to swap in a new goggle, give up
return;
}
// Find the best goggles for the current time of day anywhere in inventory
OBJECTTYPE * pGoggles = 0;
if (DayTime()) {
pGoggles = FindSunGogglesInInv( pTeamSoldier, TRUE );
} else {
pGoggles = FindNightGogglesInInv( pTeamSoldier, TRUE );
}
if (pGoggles) {
// Now either swap or equip the best one that was found
if (pTeamSoldier->inv[slotToUse].exists()) {
SwapObjs( pTeamSoldier, slotToUse, pGoggles, TRUE );
} else {
pGoggles->MoveThisObjectTo(pTeamSoldier->inv[slotToUse], 1, pTeamSoldier, slotToUse);
}
} else {
// No goggles to equip, should the current ones be unequiped?
if (pTeamSoldier->inv[slotToUse].exists()) {
if ((DayTime() && (Item[pTeamSoldier->inv[slotToUse].usItem].nightvisionrangebonus > 0)) ||
(!DayTime() && (Item[pTeamSoldier->inv[slotToUse].usItem].brightlightvisionrangebonus > 0))) {
// It's day and we're wearing night goggles (or vice-versa), find a place to stash them
if (pTeamSoldier->inv[ HELMETPOS ].exists()) {
if (pTeamSoldier->inv[ HELMETPOS ].AttachObject( NULL, &pTeamSoldier->inv[slotToUse] )) {
// It worked!
} else {
// Try dumping it anywhere in inventory because it doesn't attach to the helmet
}
} else {
// Try dumping it anywhere in inventory given there's no helemt
//search helmet and vest
for(UINT8 gear = HELMETPOS; gear <= VESTPOS; gear++)
{
pObj = &(pTeamSoldier->inv[gear]);
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
{
if ( Item[ iter->usItem ].nightvisionrangebonus > bestBonus && Item[ iter->usItem ].usItemClass == IC_FACE )
{
pGoggles = &(*iter);
bestBonus = Item[ iter->usItem ].nightvisionrangebonus;
}
}
}
}
} else {
// Normal goggle switching
OBJECTTYPE * pObj;
OBJECTTYPE * pGoggles = NULL;
INT8 bSlot1;
int bestBonus;
bool itemFound = false;
//CHRISL: Before doing anything, we should look at both head slots to see if either slot has some sort of goggles
for (bSlot1 = HEAD1POS; bSlot1 <= HEAD2POS; bSlot1++) {
if ((Item[pTeamSoldier->inv[bSlot1].usItem].brightlightvisionrangebonus > 0) ||
(Item[pTeamSoldier->inv[bSlot1].usItem].nightvisionrangebonus > 0))
itemFound = true;
}
//2 head slots
for (bSlot1 = HEAD1POS; bSlot1 <= HEAD2POS; bSlot1++)
{
// if wearing sungoggles
if ( (Item[pTeamSoldier->inv[bSlot1].usItem].brightlightvisionrangebonus > 0) )
if ( pGoggles )
{
SwapObjs( pTeamSoldier, bSlot1, pGoggles, TRUE );
break;
}
// HEADROCK HAM B2.8: If no goggles were found to switch to, the character will remove what they're
// wearing, to avoid situations where a character refuses to remove the wrong set of goggles and
// thus suffers a penalty.
else
{
// Remove sungoggles.
PlaceInAnyPocket(pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE);
break;
}
}
// else if wearing NVGs
else if(Item[pTeamSoldier->inv[bSlot1].usItem].nightvisionrangebonus > 0)
{
itemFound = true;
bestBonus = 0;
pGoggles = FindSunGogglesInInv( pTeamSoldier );
//search for better goggles on the helmet
if (pGoggles)
{
bestBonus = Item[pGoggles->usItem].brightlightvisionrangebonus;
}
//search helmet and vest
for(UINT8 gear = HELMETPOS; gear <= VESTPOS; gear++)
{
pObj = &(pTeamSoldier->inv[gear]);
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
{
if ( Item[ iter->usItem ].brightlightvisionrangebonus > bestBonus && Item[ iter->usItem ].usItemClass == IC_FACE )
{
pGoggles = &(*iter);
bestBonus = Item[ iter->usItem ].brightlightvisionrangebonus;
}
}
}
if ( pGoggles )
{
SwapObjs( pTeamSoldier, bSlot1, pGoggles, TRUE );
break;
}
// HEADROCK HAM B2.8: If no goggles were found to switch to, the character will remove what they're
// wearing, to avoid situations where a character refuses to remove the wrong set of goggles and
// thus suffers a penalty.
else
{
// Remove nightgoggles.
PlaceInAnyPocket(pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE);
break;
}
}
// else if not wearing anything and no goggles found
else if(itemFound == false && pTeamSoldier->inv[bSlot1].exists() == false)
{
bestBonus = 0;
// search helmet and vest for goggles of some kind
for(UINT8 gear = HELMETPOS; gear <= VESTPOS; gear++)
{
pObj = &(pTeamSoldier->inv[gear]);
for(attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
{
if(DayTime() == TRUE && Item[iter->usItem].brightlightvisionrangebonus > bestBonus && Item[iter->usItem].usItemClass == IC_FACE)
{
pGoggles = &(*iter);
bestBonus = Item[iter->usItem].brightlightvisionrangebonus;
}
else if(NightTime() == TRUE && Item[iter->usItem].nightvisionrangebonus > bestBonus && Item[iter->usItem].usItemClass == IC_FACE)
{
pGoggles = &(*iter);
bestBonus = Item[iter->usItem].nightvisionrangebonus;
}
}
if(pGoggles)
{
pGoggles->MoveThisObjectTo(pTeamSoldier->inv[bSlot1], 1, pTeamSoldier, bSlot1);
pObj->RemoveAttachment(pGoggles);
break;
}
}
if(pTeamSoldier->inv[bSlot1].exists() == false)
{
if(DayTime() == TRUE)
pGoggles = FindSunGogglesInInv( pTeamSoldier );
else
pGoggles = FindNightGogglesInInv( pTeamSoldier );
if(pGoggles)
{
SwapObjs( pTeamSoldier, bSlot1, pGoggles, TRUE );
break;
}
}
else
{
break;
}
}
}
fCharacterInfoPanelDirty = TRUE;
fTeamPanelDirty = TRUE;
fInterfacePanelDirty = DIRTYLEVEL2;
pTeamSoldier->DeleteSoldierLight( );
pTeamSoldier->PositionSoldierLight( );
}
// HEADROCK HAM B2.8: This function does the same as SwapGoggles, with a twist. It changes all worn goggles in the
// team uniformly, so that everyone is wearing either nightvision or dayvision, regardless of what they were wearing
// before. The check is based on the headgear of the first character in the group (he'll switch, and everyone else
// will switch to match him.
void SwapGogglesUniformly(SOLDIERTYPE *pTeamSoldier, BOOLEAN fToNightVision)
{
/* CHRISL - Adjusted this option to allow the game to search through Helmet attachments
as well as inventory positions.
*/
OBJECTTYPE * pObj;
OBJECTTYPE * pGoggles = NULL;
INT8 bSlot1;
int bestBonus;
bool itemFound = false;
//CHRISL: Before doing anything, we should look at both head slots to see if either slot has some sort of goggles
for(bSlot1 = HEAD1POS; bSlot1 <= HEAD2POS; bSlot1++)
{
if(Item[pTeamSoldier->inv[bSlot1].usItem].brightlightvisionrangebonus > 0)
itemFound = true;
if(Item[pTeamSoldier->inv[bSlot1].usItem].nightvisionrangebonus > 0)
itemFound = true;
}
//2 head slots
for (bSlot1 = HEAD1POS; bSlot1 <= HEAD2POS; bSlot1++)
{
// if wearing sungoggles
if ( Item[pTeamSoldier->inv[bSlot1].usItem].brightlightvisionrangebonus > 0 )
{
if (fToNightVision == TRUE) // Only if we want to switch to nightvision!
{
itemFound = true;
bestBonus = 0;
pGoggles = FindNightGogglesInInv( pTeamSoldier );
//search for better goggles on the helmet
@@ -5738,10 +5878,20 @@ void SwapGoggles(SOLDIERTYPE *pTeamSoldier)
SwapObjs( pTeamSoldier, bSlot1, pGoggles, TRUE );
break;
}
else if (Item[pTeamSoldier->inv[bSlot1].usItem].nightvisionrangebonus <= 0)
{
// Remove sungoggles.
PlaceInAnyPocket(pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE);
break;
}
}
// else if wearing NVGs
else if(Item[pTeamSoldier->inv[bSlot1].usItem].nightvisionrangebonus > 0 )
}
// else if wearing NVGs
else if(Item[pTeamSoldier->inv[bSlot1].usItem].nightvisionrangebonus > 0)
{
if (fToNightVision == FALSE) // Only if we want to switch to dayvision!
{
itemFound = true;
bestBonus = 0;
pGoggles = FindSunGogglesInInv( pTeamSoldier );
//search for better goggles on the helmet
@@ -5767,57 +5917,60 @@ void SwapGoggles(SOLDIERTYPE *pTeamSoldier)
SwapObjs( pTeamSoldier, bSlot1, pGoggles, TRUE );
break;
}
}
// else if not wearing anything and no goggles found
else if(itemFound == false && pTeamSoldier->inv[bSlot1].exists() == false)
{
bestBonus = 0;
// search helmet and vest for goggles of some kind
for(UINT8 gear = HELMETPOS; gear <= VESTPOS; gear++)
{
pObj = &(pTeamSoldier->inv[gear]);
for(attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
{
if(DayTime() == TRUE && Item[iter->usItem].brightlightvisionrangebonus > bestBonus && Item[iter->usItem].usItemClass == IC_FACE)
{
pGoggles = &(*iter);
bestBonus = Item[iter->usItem].brightlightvisionrangebonus;
}
else if(NightTime() == TRUE && Item[iter->usItem].nightvisionrangebonus > bestBonus && Item[iter->usItem].usItemClass == IC_FACE)
{
pGoggles = &(*iter);
bestBonus = Item[iter->usItem].nightvisionrangebonus;
}
}
if(pGoggles)
{
pGoggles->MoveThisObjectTo(pTeamSoldier->inv[bSlot1], 1, pTeamSoldier, bSlot1);
pObj->RemoveAttachment(pGoggles);
break;
}
}
if(pTeamSoldier->inv[bSlot1].exists() == false)
{
if(DayTime() == TRUE)
pGoggles = FindSunGogglesInInv( pTeamSoldier );
else
pGoggles = FindNightGogglesInInv( pTeamSoldier );
if(pGoggles)
{
SwapObjs( pTeamSoldier, bSlot1, pGoggles, TRUE );
break;
}
}
else
else if (Item[pTeamSoldier->inv[bSlot1].usItem].brightlightvisionrangebonus <= 0)
{
// Remove nightgoggles.
PlaceInAnyPocket(pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE);
break;
}
}
}
// else if not wearing anything and no goggles found
else if(itemFound == false && pTeamSoldier->inv[bSlot1].exists() == false)
{
bestBonus = 0;
// search helmet and vest for goggles of some kind
for(UINT8 gear = HELMETPOS; gear <= VESTPOS; gear++)
{
pObj = &(pTeamSoldier->inv[gear]);
for(attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
{
if(fToNightVision == FALSE && Item[iter->usItem].brightlightvisionrangebonus > bestBonus && Item[iter->usItem].usItemClass == IC_FACE)
{
pGoggles = &(*iter);
bestBonus = Item[iter->usItem].brightlightvisionrangebonus;
}
else if(fToNightVision == TRUE && Item[iter->usItem].nightvisionrangebonus > bestBonus && Item[iter->usItem].usItemClass == IC_FACE)
{
pGoggles = &(*iter);
bestBonus = Item[iter->usItem].nightvisionrangebonus;
}
}
if(pGoggles)
{
pGoggles->MoveThisObjectTo(pTeamSoldier->inv[bSlot1], 1, pTeamSoldier, bSlot1);
pObj->RemoveAttachment(pGoggles);
break;
}
}
if(pTeamSoldier->inv[bSlot1].exists() == false)
{
if(fToNightVision == FALSE)
pGoggles = FindSunGogglesInInv( pTeamSoldier );
else
pGoggles = FindNightGogglesInInv( pTeamSoldier );
if(pGoggles)
{
SwapObjs( pTeamSoldier, bSlot1, pGoggles, TRUE );
break;
}
}
else
{
break;
}
}
}
fCharacterInfoPanelDirty = TRUE;
fTeamPanelDirty = TRUE;
fInterfacePanelDirty = DIRTYLEVEL2;
@@ -5963,4 +6116,4 @@ void StackAndSort( BOOLEAN fRestrictToAmmo )
//HandleAllReachAbleItemsInTheSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, pImpButtonText[11] );
}
}
}
+231 -14
View File
@@ -575,19 +575,123 @@ UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT16 sMapPos, BOOLEAN
{
usCursor = ACTION_TARGETCONFIRMBURST_UICURSOR;
// HEADROCK HAM B1: Burst cursor now shows multiple CTH bars (one for each bullet)
// and also a Targetted Bodypart indicator.
if(pSoldier->bDoAutofire == 0 && gGameSettings.fOptions[ TOPTION_CTH_CURSOR ])
{
//AXP 29.03.2007: Rooftop CtH fix. See below.
INT8 bTempTargetLevel = pSoldier->bTargetLevel;
pSoldier->bTargetLevel = (INT8) gsInterfaceLevel;
if (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 2)
{
// Burst mode only
OBJECTTYPE * pInHand;
pInHand = &(pSoldier->inv[pSoldier->ubAttackingHand]);
// Burst size
gbCtHBurstCount = GetShotsPerBurst(pInHand);
UINT8 i, saveDoBurst;
// Save original burst value (should be 1 always, before the burst has been fired, but
// this is just a failsafe
saveDoBurst = pSoldier->bDoBurst;
UINT32 uiHitChance;
uiHitChance = CalcChanceToHitGun( pSoldier, sMapPos, 0, pSoldier->bAimShotLocation );
// For each bullet in the burst
for (i=0;i<gbCtHBurstCount;i++)
{
//AXP 29.03.2007: Rooftop CtH fix. See below.
INT8 bTempTargetLevel = pSoldier->bTargetLevel;
pSoldier->bTargetLevel = (INT8) gsInterfaceLevel;
pSoldier->bTargetLevel = bTempTargetLevel;
// Calculate hit chance (using the current bDoBurst for burst-penalty calculations)
UINT32 uiHitChance;
uiHitChance = CalcChanceToHitGun( pSoldier, sMapPos, 0, pSoldier->bAimShotLocation );
// HEADROCK HAM B2.7: CTH approximation?
if (gGameExternalOptions.fApproximateCTH)
{
uiHitChance = ChanceToHitApproximation( pSoldier, uiHitChance );
}
gfUICtHBar = TRUE;
gbCtH = (gbCtH+uiHitChance)/2;
pSoldier->bTargetLevel = bTempTargetLevel;
// Put result (burst CTH) into the array
gbCtH[i] = (gbCtH[i]+uiHitChance)/2;
// Increase burst size, so that the next time we run CalcChanceToHitGun we'll get a lower
// result, based on our Burst Penalty
pSoldier->bDoBurst++;
}
// Reset original burst status
pSoldier->bDoBurst = saveDoBurst;
// Activate CTH bar display
gfUICtHBar = TRUE;
}
else // One "BASE CTH" bar, JA2 1.13 vanilla
{
//AXP 29.03.2007: Rooftop CtH fix. See below.
INT8 bTempTargetLevel = pSoldier->bTargetLevel;
pSoldier->bTargetLevel = (INT8) gsInterfaceLevel;
UINT32 uiHitChance;
uiHitChance = CalcChanceToHitGun( pSoldier, sMapPos, 0, pSoldier->bAimShotLocation );
// HEADROCK HAM B2.7: CTH approximation?
if (gGameExternalOptions.fApproximateCTH)
{
uiHitChance = ChanceToHitApproximation( pSoldier, uiHitChance );
}
pSoldier->bTargetLevel = bTempTargetLevel;
gfUICtHBar = TRUE;
gbCtH[0] = (gbCtH[0]+uiHitChance)/2;
gbCtHBurstCount = 1;
}
}
// HEADROCK HAM B2: Now autofire will show both its starting CTH and the CTH of the last
// bullet in the volley.
else if(pSoldier->bDoAutofire > 0 && gGameSettings.fOptions[ TOPTION_CTH_CURSOR ])
{
if (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 3)
{
gbCtHBurstCount = 1;
//AXP 29.03.2007: Rooftop CtH fix. See below.
INT8 bTempTargetLevel = pSoldier->bTargetLevel;
pSoldier->bTargetLevel = (INT8) gsInterfaceLevel;
UINT32 uiHitChance;
// Calculate CTH for the first bullet
uiHitChance = CalcChanceToHitGun( pSoldier, sMapPos, 0, pSoldier->bAimShotLocation );
// HEADROCK HAM B2.7: CTH approximation?
if (gGameExternalOptions.fApproximateCTH)
{
uiHitChance = ChanceToHitApproximation( pSoldier, uiHitChance );
}
// CTH for the first bullet is entered into this array, and later displayed
gbCtH[0] = (gbCtH[0]+uiHitChance)/2;
// Fool the CTH formula into thinking we're already firing the last bullet in the volley,
// by artificially altering bDoBurst (which tracks actual burst progression). The CTH formula
// calculates Auto Penalty based on bDoBurst - (Autopen * (bDoBurst-1), basically).
UINT8 saveDoBurst = pSoldier->bDoBurst;
pSoldier->bDoBurst = pSoldier->bDoAutofire;
uiHitChance = CalcChanceToHitGun( pSoldier, sMapPos, 0, pSoldier->bAimShotLocation );
// HEADROCK HAM B2.7: CTH approximation?
if (gGameExternalOptions.fApproximateCTH)
{
uiHitChance = ChanceToHitApproximation( pSoldier, uiHitChance );
}
pSoldier->bTargetLevel = bTempTargetLevel;
// Return Burst State to original value
pSoldier->bDoBurst = saveDoBurst;
// CTH for the last bullet is entered into this array and later displayed.
gbCtH[1] = (gbCtH[1]+uiHitChance)/2;
// Flag to tell the program to draw two CTH bars.
gbCtHAutoFire = TRUE;
gfUICtHBar = TRUE;
}
}
}
}
@@ -603,11 +707,17 @@ UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT16 sMapPos, BOOLEAN
UINT32 uiHitChance;
uiHitChance = CalcChanceToHitGun( pSoldier, sMapPos, (INT8)(pSoldier->aiData.bShownAimTime ), pSoldier->bAimShotLocation );
// HEADROCK HAM B2.7: CTH approximation?
if (gGameExternalOptions.fApproximateCTH)
{
uiHitChance = ChanceToHitApproximation( pSoldier, uiHitChance );
}
pSoldier->bTargetLevel = bTempTargetLevel;
gfUICtHBar = TRUE;
gbCtH = (gbCtH+uiHitChance)/2;
gbCtHBurstCount = 1;
gbCtH[0] = (gbCtH[0]+uiHitChance)/2;
}
switchVal = pSoldier->aiData.bShownAimTime;
@@ -1283,8 +1393,10 @@ void DetermineCursorBodyLocation( UINT8 ubSoldierID, BOOLEAN fDisplay, BOOLEAN f
}
}
if ( fDisplay && !pSoldier->bDoBurst)
// HEADROCK HAM B2: Now shows targetted bodypart for ALL firing modes. Note that the external toggle is not
// taken into account yet.
// if ( fDisplay && !pSoldier->bDoAutofire )
if ( fDisplay )
{
if ( gfUIFullTargetFound )
{
@@ -1296,7 +1408,14 @@ void DetermineCursorBodyLocation( UINT8 ubSoldierID, BOOLEAN fDisplay, BOOLEAN f
wcscpy( gzLocation, TacticalStr[ CROW_HIT_LOCATION_STR ] );
gfUIBodyHitLocation = TRUE;
if ( !pSoldier->bDoBurst )
gfUIBodyHitLocation = TRUE;
// HEADROCK: This'll toggle whether the bodypart targetting indicator shows up in the burst/auto
// CTH cursors.
else if ( pSoldier->bDoBurst && !pSoldier->bDoAutofire && (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 2) )
gfUIBodyHitLocation = TRUE;
else if ( pSoldier->bDoBurst && pSoldier->bDoAutofire && (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 3) )
gfUIBodyHitLocation = TRUE;
return;
}
@@ -1318,16 +1437,37 @@ void DetermineCursorBodyLocation( UINT8 ubSoldierID, BOOLEAN fDisplay, BOOLEAN f
{
wcscpy( gzLocation, TacticalStr[ HEAD_HIT_LOCATION_STR ] );
}
gfUIBodyHitLocation = TRUE;
if ( !pSoldier->bDoBurst )
gfUIBodyHitLocation = TRUE;
// HEADROCK: This'll toggle whether the bodypart targetting indicator shows up in the burst/auto
// CTH cursors.
else if ( pSoldier->bDoBurst && !pSoldier->bDoAutofire && (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 2) )
gfUIBodyHitLocation = TRUE;
else if ( pSoldier->bDoBurst && pSoldier->bDoAutofire && (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 3) )
gfUIBodyHitLocation = TRUE;
break;
case AIM_SHOT_TORSO:
wcscpy( gzLocation, TacticalStr[ TORSO_HIT_LOCATION_STR ] );
gfUIBodyHitLocation = TRUE;
if ( !pSoldier->bDoBurst )
gfUIBodyHitLocation = TRUE;
// HEADROCK: This'll toggle whether the bodypart targetting indicator shows up in the burst/auto
// CTH cursors.
else if ( pSoldier->bDoBurst && !pSoldier->bDoAutofire && (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 2) )
gfUIBodyHitLocation = TRUE;
else if ( pSoldier->bDoBurst && pSoldier->bDoAutofire && (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 3) )
gfUIBodyHitLocation = TRUE;
break;
case AIM_SHOT_LEGS:
wcscpy( gzLocation, TacticalStr[ LEGS_HIT_LOCATION_STR ] );
if ( !pSoldier->bDoBurst )
gfUIBodyHitLocation = TRUE;
// HEADROCK: This'll toggle whether the bodypart targetting indicator shows up in the burst/auto
// CTH cursors.
else if ( pSoldier->bDoBurst && !pSoldier->bDoAutofire && (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 2) )
gfUIBodyHitLocation = TRUE;
else if ( pSoldier->bDoBurst && pSoldier->bDoAutofire && (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 3) )
gfUIBodyHitLocation = TRUE;
break;
}
@@ -2384,3 +2524,80 @@ void HandleUICursorRTFeedback( SOLDIERTYPE *pSoldier )
}
}
// HEADROCK HAM B2.7: This function gives us an "approximate" CTH bar, that doesn't show the exact value of
// CTH unless the character is well-trained. The worse trained a character is, the wilder the speculation.
UINT32 ChanceToHitApproximation( SOLDIERTYPE * pSoldier, UINT32 uiChance )
{
UINT16 bExpLevel = pSoldier->stats.bExpLevel;
UINT16 bMarksmanship = pSoldier->stats.bMarksmanship;
UINT16 bWisdom = pSoldier->stats.bWisdom;
UINT16 iNumStages, iNumStagesBase, StageSize, SubStageSize;
UINT8 iSniper;
UINT16 uiNewChance;
UINT16 i;
if ( pSoldier->ubProfile != NO_PROFILE )
{
iSniper = NUM_SKILL_TRAITS( pSoldier, PROF_SNIPER );
}
else
{
// Dunno, but I get the strong feeling that we don't want CTH bars for non-mercs.
return(0);
}
if (uiChance == 100)
{
// Sure hit. The player needs to set Maximum_CTH to 100 for this to happen. Normally, the
// max chance is only 99.
return(100);
}
if (uiChance == 0)
{
// Sure Miss. The player needs to set Minimum_CTH to 0 for this to happen. Normally, the
// min chance is 1.
return(0);
}
uiNewChance = uiChance;
iNumStagesBase = __min(165,__max(0, ((bExpLevel * 10) - 30) + (bMarksmanship - 25) + (bWisdom - 50)));
//iNumStagesBase = __max(255, iNumStagesBase);
iNumStagesBase = __min(165, iNumStagesBase + (10 * iSniper));
iNumStagesBase = (UINT16)((float)iNumStagesBase * (float)((float)iNumStagesBase / 195.0));
// Gives a number between 2 and 51.
iNumStages = __max(2,(100 * iNumStagesBase) / 300);
// Find out how large the slices are
StageSize = 100/iNumStages;
// Correct iNumStages to match StageSize, +1 compensates for the rounding down of StageSize.
iNumStages = (100/StageSize) + 1;
// These sub-stages are used to determine which way to round the results.
SubStageSize = __max(1, StageSize / 2);
if (StageSize == 1)
// CTH assessment is perfect. No need for the rest of this function
return (uiChance);
// Jump each "stage" and see whether the CTH is within this slice of the scale
for (i=0; i<iNumStages; i++)
{
UINT16 CurrentStage = i * StageSize;
UINT16 NextStage = (i+1) * StageSize;
// Check whether the CTH should be rounded down or up.
if ( (CurrentStage <= (UINT16) uiChance) && (CurrentStage + SubStageSize > (UINT16) uiChance) )
{
return (CurrentStage);
}
else if ( (CurrentStage + SubStageSize <= (UINT16) uiChance) && (NextStage > (UINT16) uiChance))
{
return (NextStage);
}
}
// Something went wrong. Return 50, as in "God Knows"
return (50);
}
+3
View File
@@ -24,5 +24,8 @@ void HandleEndConfirmCursor( SOLDIERTYPE *pSoldier );
BOOLEAN GetMouseRecalcAndShowAPFlags( UINT32 *puiCursorFlags, BOOLEAN *pfShowAPs );
// HEADROCK HAM B2.7: This function calculates the nearest value (display purposes only)
// based on how trained the shooter is.
UINT32 ChanceToHitApproximation( SOLDIERTYPE * pSoldier, UINT32 uiChance );
#endif
+224 -27
View File
@@ -59,8 +59,9 @@ extern INT8 gbCurrentRainIntensity;
//end rain
#define MINCHANCETOHIT 1
#define MAXCHANCETOHIT 99
// HEADROCK HAM B1: Externalized both values to INI
//#define MINCHANCETOHIT 1
//#define MAXCHANCETOHIT 99
// NB this is arbitrary, chances in DG ranged from 1 in 6 to 1 in 20
#define BASIC_DEPRECIATE_CHANCE 15
@@ -105,6 +106,10 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO
BOOLEAN gfNextShotKills = FALSE;
BOOLEAN gfReportHitChances = FALSE;
// HEADROCK HAM B2.5:Using this boolean to tell the CTH formula that it is being called by UseGun(), rather than
// by other functions. This is mostly to assist the new Tracer Fire system...
BOOLEAN fCalculateCTHDuringGunfire = FALSE;
//GLOBALS
// TODO: Move strings to extern file
@@ -1683,8 +1688,10 @@ BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT16 sTargetGridNo )
}
else
{
uiHitChance = CalcChanceToHitGun( pSoldier, sTargetGridNo, pSoldier->aiData.bAimTime, pSoldier->bAimShotLocation );
fCalculateCTHDuringGunfire = TRUE;
uiHitChance = CalcChanceToHitGun( pSoldier, sTargetGridNo, pSoldier->aiData.bAimTime, pSoldier->bAimShotLocation );
}
fCalculateCTHDuringGunfire = FALSE;
//DIGICRAB: Barrel extender wear code
// Relocated from CalcChanceToHitGun
@@ -1728,10 +1735,19 @@ BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT16 sTargetGridNo )
// big penalty to hit
// WDS 07/06/2008 fix randoms
//if(uiHitChance < 30)
if(uiHitChance <= 30)
uiHitChance = MINCHANCETOHIT;
// HEADROCK: Altered formula to accept variable MINIMUM CTH.
//if(uiHitChance <= 30)
// uiHitChance = MINCHANCETOHIT;
//else
// uiHitChance -= 30;
if(uiHitChance <= (UINT16)(__max(30, gGameExternalOptions.iMinimumCTH + 30)))
{
uiHitChance = gGameExternalOptions.iMinimumCTH ;
}
else
{
uiHitChance -= 30;
}
// curse!
if ( pSoldier->bTeam == OUR_TEAM )
@@ -3552,8 +3568,9 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT16 sGridNo, INT16 ubAimTime,
if ( pSoldier->stats.bMarksmanship == 0 )
{
// always min chance
return( MINCHANCETOHIT );
// HEADROCK: (HAM) Altered to accept external arguments
// return( MINCHANCETOHIT );
return( gGameExternalOptions.iMinimumCTH );
}
// make sure the guy's actually got a weapon in his hand!
@@ -3724,7 +3741,7 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT16 sGridNo, INT16 ubAimTime,
}
// If in burst mode, deduct points for change to hit for each shot after the first
if ( pSoldier->bDoBurst > 0 && pSoldier->bDoAutofire == 0 )
if ( pSoldier->bDoBurst && pSoldier->bDoAutofire == 0 )
{
// Snap: bipod may reduce burst penalty
iPenalty = GetBurstPenalty(pInHand, gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE)
@@ -3749,6 +3766,54 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT16 sGridNo, INT16 ubAimTime,
iPenalty /= 2 * NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPS );
}
iChance -= iPenalty;
// HEADROCK HAM B2.5: One of every X bullets in a tracer magazine is a tracer round, which will
// bump the CTH up by a certain amount.
if (AmmoTypes[(*pInHand)[0]->data.gun.ubGunAmmoType].tracerEffect == 1 && gGameExternalOptions.iRealisticTracers > 0 )
{
UINT16 iBulletsLeft, iTracersFired, iBulletsPerTracer, iBulletsSinceLastTracer;
UINT8 cnt;
UINT16 iAutoPenaltySinceLastTracer;
iTracersFired = 0;
iBulletsPerTracer = gGameExternalOptions.iNumBulletsPerTracer;
// Calculate number of bullets left right before firing this bullet
if (fCalculateCTHDuringGunfire)
{
iBulletsLeft = (*pInHand)[0]->data.gun.ubGunShotsLeft + (pSoldier->bDoBurst - 1);
}
else
{
iBulletsLeft = (*pInHand)[0]->data.gun.ubGunShotsLeft;
}
iBulletsSinceLastTracer = 0;
for (cnt=0;cnt<pSoldier->bDoBurst;cnt++)
{
iBulletsSinceLastTracer++;
if ((( iBulletsLeft - (cnt - 1) ) / iBulletsPerTracer) - ((iBulletsLeft - cnt) / iBulletsPerTracer) == 1)
{
iBulletsSinceLastTracer = 0;
}
}
iTracersFired = ((iBulletsLeft+1) / iBulletsPerTracer) - (((iBulletsLeft+1) - (pSoldier->bDoBurst)) / iBulletsPerTracer);
if ( iTracersFired > 0 )
{
// Correct all autofire penalty so far
iBonus = iPenalty;
// Add Tracer Bump if previous bullet was a tracer
//if (iBulletsSinceLastTracer == 0)
iBonus += (gGameExternalOptions.iCTHBumpPerTracer * iTracersFired);
// Calculate penalty since last tracer was fired
iAutoPenaltySinceLastTracer = GetAutoPenalty(pInHand, gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE) * iBulletsSinceLastTracer;
// Add penalty to bonus.
iBonus -= iAutoPenaltySinceLastTracer;
iChance += iBonus;
}
}
}
//ADB we need to calculate the distance visible and SoldierTo...LOSTests that we want to
@@ -3866,7 +3931,22 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT16 sGridNo, INT16 ubAimTime,
// if shooter is still in shock
if (pSoldier->aiData.bShock)
iChance -= (pSoldier->aiData.bShock * AIM_PENALTY_PER_SHOCK);
{
// HEADROCK HAM B2.8: Placed a maximum here, as shock is now also used in suppression.
UINT16 usShockPenalty;
usShockPenalty = pSoldier->aiData.bShock * AIM_PENALTY_PER_SHOCK;
if (gGameExternalOptions.usMaxShooterCoweringPenalty > 0)
{
if ( usShockPenalty > gGameExternalOptions.usMaxShooterCoweringPenalty )
usShockPenalty = gGameExternalOptions.usMaxShooterCoweringPenalty;
}
if ( usShockPenalty < 1 )
usShockPenalty = 1;
iChance -= usShockPenalty;
}
// WANNE: Changed this, because RPGs are not in the calculation, only guns
//if ( Item[ usInHand ].usItemClass == IC_GUN )
@@ -3962,6 +4042,92 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT16 sGridNo, INT16 ubAimTime,
{
iSightRange = 1;
}
// HEADROCK HAM B2.1 : The TARGET's shock now also affects aiming. If the target is prone
// and in shock, they are harder to hit! This represents a target that's cowering as close
// to the ground (and as close to any possible cover, like a small dune or a fold of earth
// or anything like that).
if ( gGameExternalOptions.iAimPenaltyPerTargetShock > 0 )
{
// HEADROCK HAM B2.1 : This value determines how much penalty the target's shock-value gives the shooter.
// As of HAM B2.3: There's a maximum range at which 100% penalty is given.
// As of HAM B2.8: Target's stance and the targetted bodypart will affect the end result.
INT8 AIM_PENALTY_PER_TARGET_SHOCK;
INT16 sCoweringPenalty = 0;
UINT8 ubCoweringDivisor;
UINT16 MIN_RANGE_FOR_FULL_COWER;
UINT16 MAX_TARGET_COWERING_PENALTY;
AIM_PENALTY_PER_TARGET_SHOCK = gGameExternalOptions.iAimPenaltyPerTargetShock;
MIN_RANGE_FOR_FULL_COWER = gGameExternalOptions.usMinRangeForFullCoweringPenalty;
MAX_TARGET_COWERING_PENALTY = gGameExternalOptions.usMaxTargetCoweringPenalty;
pTarget = SimpleFindSoldier( sGridNo, pSoldier->bTargetLevel );
if (pTarget != NULL)
{
if (pTarget->aiData.bShock )
{
if (gAnimControl[ pTarget->usAnimState ].ubHeight == ANIM_PRONE)
{
ubCoweringDivisor = gGameExternalOptions.ubCoweringPenaltyDivisorProne;
sCoweringPenalty = (pTarget->aiData.bShock * AIM_PENALTY_PER_TARGET_SHOCK);
sCoweringPenalty = sCoweringPenalty / ubCoweringDivisor;
sCoweringPenalty = (sCoweringPenalty * __min(iSightRange,MIN_RANGE_FOR_FULL_COWER)) / MIN_RANGE_FOR_FULL_COWER;
if (gGameExternalOptions.usMaxTargetCoweringPenalty > 0)
{
if ( sCoweringPenalty > gGameExternalOptions.usMaxTargetCoweringPenalty )
sCoweringPenalty = gGameExternalOptions.usMaxTargetCoweringPenalty;
}
if ( sCoweringPenalty < 1 )
sCoweringPenalty = 1;
iChance -= sCoweringPenalty;
}
else if (gAnimControl[ pTarget->usAnimState ].ubHeight == ANIM_CROUCH)
{
switch ( ubAimPos )
{
case AIM_SHOT_HEAD:
ubCoweringDivisor = gGameExternalOptions.ubCoweringPenaltyDivisorCrouchedHead;
break;
case AIM_SHOT_TORSO:
case AIM_SHOT_RANDOM:
case AIM_SHOT_GLAND:
ubCoweringDivisor = gGameExternalOptions.ubCoweringPenaltyDivisorCrouchedTorso;
break;
case AIM_SHOT_LEGS:
ubCoweringDivisor = gGameExternalOptions.ubCoweringPenaltyDivisorCrouchedLegs;
break;
}
sCoweringPenalty = (pTarget->aiData.bShock * AIM_PENALTY_PER_TARGET_SHOCK);
sCoweringPenalty = sCoweringPenalty / ubCoweringDivisor;
sCoweringPenalty = (sCoweringPenalty * __min(iSightRange,MIN_RANGE_FOR_FULL_COWER)) / MIN_RANGE_FOR_FULL_COWER;
if (gGameExternalOptions.usMaxTargetCoweringPenalty > 0)
{
if ( sCoweringPenalty > gGameExternalOptions.usMaxTargetCoweringPenalty )
sCoweringPenalty = gGameExternalOptions.usMaxTargetCoweringPenalty;
}
if ( sCoweringPenalty < 1 )
sCoweringPenalty = 1;
// HEADROCK HAM B2.8.1: Added formula to make sure that cowering target penalties
// are not given when on the roof.
if (pSoldier->pathing.bLevel == pTarget->pathing.bLevel && pSoldier->pathing.bLevel > 0)
sCoweringPenalty = 0; // No cowering penalties when both are on the roof!
else if (pSoldier->pathing.bLevel < pSoldier->pathing.bLevel && gAnimControl[ pTarget->usAnimState ].ubHeight == ANIM_PRONE)
sCoweringPenalty *= 2; // Much harder to shoot at anyone cowering above you.
else if (pSoldier->pathing.bLevel > pSoldier->pathing.bLevel)
sCoweringPenalty /= 2; // Much easier to shoot at cowerers below you.
iChance -= sCoweringPenalty;
}
}
}
}
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CalcChanceToHitGun: after scope bonus - ubAimTime = %d, iSightRange = %d, iChance = %d ", ubAimTime, iSightRange, iChance));
UINT8 bLightLevel = LightTrueLevel(sGridNo, pSoldier->bTargetLevel);
@@ -4123,7 +4289,8 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT16 sGridNo, INT16 ubAimTime,
}
// penalty for amount that enemy has moved
iPenalty = __min( ((pTarget->bTilesMoved * 3) / 2), 30 );
// HEADROCK HAM B2.6: Externalized the value
iPenalty = __min( (UINT16)((float)pTarget->bTilesMoved * (float)gGameExternalOptions.iMovementEffectOnAiming), 30 );
iChance -= iPenalty;
// if target sees us, he may have a chance to dodge before the gun goes off
@@ -4235,7 +4402,12 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT16 sGridNo, INT16 ubAimTime,
}
// MAKE SURE CHANCE TO HIT IS WITHIN DEFINED LIMITS
if (iChance < MINCHANCETOHIT)
// HEADROCK: (HAM) Altered so called "Defined Limits" to accept external arguments.
// The divisor argument only works when the minimum is set to 0. It has a chance of 1 in X to
// bump the minimum back to 1, where X = the Divisor value. So a divisor value of 50 gives a 1/50
// chance of getting some actual chance to hit despite the 0 minimum. The overall total would then
// be an effective CTH of only 1/5000 (50 chances to get a 1 out of 100 CTH, hehehe)
if (iChance <= gGameExternalOptions.iMinimumCTH)
{
if ( TANK( pSoldier ) )
{
@@ -4244,14 +4416,24 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT16 sGridNo, INT16 ubAimTime,
}
else
{
iChance = MINCHANCETOHIT;
iChance = gGameExternalOptions.iMinimumCTH;
if ( gGameExternalOptions.iMinimumCTH == 0 )
{
if ( PreRandom( gGameExternalOptions.iMinimumCTHDivisor ) == (gGameExternalOptions.iMinimumCTHDivisor - 1) )
{
iChance = 1;
}
}
}
}
else
{
if (iChance > MAXCHANCETOHIT)
iChance = MAXCHANCETOHIT;
}
else
{
// HEADROCK (HAM): Externalized maximum to JA2_OPTIONS.INI
// if (iChance > MAXCHANCETOHIT)
// iChance = MAXCHANCETOHIT;
if (iChance > gGameExternalOptions.iMaximumCTH)
iChance = gGameExternalOptions.iMaximumCTH;
}
// NumMessage("ChanceToHit = ",chance);
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CalcChanceToHitGun: ichance = %d",iChance));
@@ -5305,14 +5487,19 @@ UINT32 CalcChanceHTH( SOLDIERTYPE * pAttacker,SOLDIERTYPE *pDefender, INT16 ubAi
// MAKE SURE CHANCE TO HIT IS WITHIN DEFINED LIMITS
if (iChance < MINCHANCETOHIT)
// HEADROCK: I urinate on your Defined Limits! Power Rangers, Externalize!
// Disclaimer: No offense meant, all in good fun ;)
if (iChance < gGameExternalOptions.iMinimumCTH)
{
iChance = MINCHANCETOHIT;
iChance = gGameExternalOptions.iMinimumCTH;
}
else
{
if (iChance > MAXCHANCETOHIT)
iChance = MAXCHANCETOHIT;
// HEADROCK (HAM): Externalized maximum to JA2_OPTIONS.INI
//if (iChance > MAXCHANCETOHIT)
// iChance = MAXCHANCETOHIT;
if (iChance > gGameExternalOptions.iMaximumCTH)
iChance = gGameExternalOptions.iMaximumCTH;
}
//NumMessage("ChanceToStab = ",chance);
@@ -5768,13 +5955,17 @@ UINT32 CalcThrownChanceToHit(SOLDIERTYPE *pSoldier, INT16 sGridNo, INT16 ubAimTi
// reduce iChance to hit DIRECTLY by the item's working condition
iChance = (iChance * WEAPON_STATUS_MOD(pSoldier->inv[HANDPOS][0]->data.objectStatus)) / 100;
// MAKE SURE CHANCE TO HIT IS WITHIN DEFINED LIMITS
if (iChance < MINCHANCETOHIT)
iChance = MINCHANCETOHIT;
// What's with all these defined limits? Let's think out of the box for a minute, shall we?
// HEADROCK (HAM): externalized, effective immediately.
if (iChance < gGameExternalOptions.iMinimumCTH)
iChance = gGameExternalOptions.iMinimumCTH;
else
{
if (iChance > MAXCHANCETOHIT)
iChance = MAXCHANCETOHIT;
// HEADROCK (HAM): Externalized maximum to JA2_OPTIONS.INI
//if (iChance > MAXCHANCETOHIT)
// iChance = MAXCHANCETOHIT;
if (iChance > gGameExternalOptions.iMaximumCTH)
iChance = gGameExternalOptions.iMaximumCTH;
}
@@ -5969,7 +6160,13 @@ UINT8 GetAutofireShotsPerFiveAPs( OBJECTTYPE *pObj )
{
// DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("GetAutofireShotsPerFiveAPs"));
return Weapon[ pObj->usItem ].bAutofireShotsPerFiveAP;
// HEADROCK HAM B2.6: Added overall modifier
if (Weapon[ pObj->usItem ].bAutofireShotsPerFiveAP > 0)
{
return __max((Weapon[ pObj->usItem ].bAutofireShotsPerFiveAP + gGameExternalOptions.iAutofireBulletsPer5APModifier), 0);
}
else
return 0;
}
UINT16 GetMagSize( OBJECTTYPE *pObj )
+2 -1
View File
@@ -19,7 +19,8 @@ enum WeaponMode
void HandleTacticalEffectsOfEquipmentChange( SOLDIERTYPE *pSoldier, UINT32 uiInvPos, UINT16 usOldItem, UINT16 usNewItem );
#define MAXCHANCETOHIT 99
// HEADROCK: Removed this and externalized to JA2_OPTIONS.INI as part of HAM project.
//#define MAXCHANCETOHIT 99
#define BAD_DODGE_POSITION_PENALTY 20
#define GUN_BARREL_RANGE_BONUS 100
+10 -2
View File
@@ -470,7 +470,11 @@ void AddMissileTrail( BULLET *pBullet, FIXEDPT qCurrX, FIXEDPT qCurrY, FIXEDPT q
}
}
if (fTracer == TRUE)
// HEADROCK HAM B2.5: Created new bullet flag that tells us whether this specific bullet is a tracer.
// The condition now reads that flag and creates a lightshow only for tracer bullets. This flag is only
// used if the new Tracer System is on.
//if (fTracer == TRUE)
if ((gGameExternalOptions.iRealisticTracers > 0 && gGameExternalOptions.iNumBulletsPerTracer > 0 && pBullet->fTracer == TRUE) || (gGameExternalOptions.iRealisticTracers == 0 && fTracer == TRUE))
{
if ( pBullet->iLoop < 5 )
{
@@ -517,7 +521,11 @@ void AddMissileTrail( BULLET *pBullet, FIXEDPT qCurrX, FIXEDPT qCurrY, FIXEDPT q
AniParams.sDelay = (INT16)( 100 );
}
//else if ( pBullet->usFlags & ( BULLET_FLAG_TRACER ) )
else if (fTracer == TRUE)
// HEADROCK HAM B2.5: Created new bullet flag that tells us whether this specific bullet is a tracer.
// The condition now reads that flag and creates a lightshow only for tracer bullets. This flag is only
// used if the new Tracer System is on.
// else if (fTracer == TRUE)
else if ((gGameExternalOptions.iRealisticTracers > 0 && gGameExternalOptions.iNumBulletsPerTracer > 0 && pBullet->fTracer == TRUE) || (gGameExternalOptions.iRealisticTracers == 0 && fTracer == TRUE))
{
INT16 sXPos, sYPos;