mirror of
https://github.com/1dot13/source.git
synced 2026-08-26 14:30:26 +02:00
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:
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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++ )
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user