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

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


git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@3323 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Wanne
2010-02-20 15:49:46 +00:00
parent 53821fcf49
commit f010769397
120 changed files with 16937 additions and 2200 deletions
+7 -7
View File
@@ -82,14 +82,13 @@ void ExitBoxing( void )
CancelAIAction( pSoldier, TRUE );
pSoldier->aiData.bAlertStatus = STATUS_GREEN;
pSoldier->aiData.bUnderFire = 0;
// HEADROCK HAM 3.6: Make sure all boxers' APs have been reset to a reasonable number. Otherwise,
// the AI combatant may fail several conditions in subsequent functions, and fail to leave the ring
// as a result.
if (pSoldier->bActionPoints < (APBPConstants[AP_MAXIMUM]*6)/10)
{
pSoldier->bActionPoints = (APBPConstants[AP_MAXIMUM]*6)/10;
}
// the AI combatant may fail several conditions in subsequent functions, and fail to leave the ring
// as a result.
if (pSoldier->bActionPoints < (APBPConstants[AP_MAXIMUM]*6)/10)
{
pSoldier->bActionPoints = (APBPConstants[AP_MAXIMUM]*6)/10;
}
// if necessary, revive boxer so he can leave ring
if (pSoldier->stats.bLife > 0 && (pSoldier->stats.bLife < OKLIFE || pSoldier->bBreath < OKBREATH ) )
@@ -152,6 +151,7 @@ void BoxingPlayerDisqualified( SOLDIERTYPE * pOffender, INT8 bReason )
void TriggerEndOfBoxingRecord( SOLDIERTYPE * pSoldier )
{
// This trigger runs once for each boxer, so only when the SECOND boxer gets out will this function run in its entirely.
// unlock UI
guiPendingOverrideEvent = LU_ENDUILOCK;
+109 -42
View File
@@ -1080,17 +1080,17 @@ 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;
UINT16 HEALTH_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.usHealthSubpointsToImprove;
UINT16 STRENGTH_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.usStrengthSubpointsToImprove;
UINT16 DEXTERITY_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.usDexteritySubpointsToImprove;
UINT16 AGILITY_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.usAgilitySubpointsToImprove;
UINT16 WISDOM_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.usWisdomSubpointsToImprove;
UINT16 MARKSMANSHIP_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.usMarksmanshipSubpointsToImprove;
UINT16 MEDICAL_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.usMedicalSubpointsToImprove;
UINT16 MECHANICAL_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.usMechanicalSubpointsToImprove;
UINT16 LEADERSHIP_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.usLeadershipSubpointsToImprove;
UINT16 EXPLOSIVES_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.usExplosivesSubpointsToImprove;
UINT16 LEVEL_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.usLevelSubpointsToImprove;
// figure out how many subpoints this type of stat needs to change
switch (ubStat)
{
@@ -1299,16 +1299,47 @@ UINT8 CurrentPlayerProgressPercentage(void)
{
UINT32 uiCurrentIncome;
UINT32 uiPossibleIncome;
UINT8 ubCurrentProgress;
UINT8 ubKillsPerPoint;
UINT16 usKillsProgress;
UINT16 usControlProgress;
UINT16 usVisitProgress;
// HEADROCK HAM 3: Changed to UINT16 to avoid overflow
UINT16 usCurrentProgress;
UINT16 ubKillsPerPoint;
UINT16 usKillsProgress;
UINT16 usControlProgress;
UINT16 usVisitProgress;
// HEADROCK HAM 3: Added a separate variable for Income Progress,
// to enable comparing the results from each progress aspect SEPARATELY.
UINT16 usIncomeProgress;
// HEADROCK HAM 3: And another variable to contain the highest result so far.
UINT16 usHighestProgress;
// HEADROCK HAM 3: Four variables to hold the maximum attainable progress from each aspect.
UINT16 usMaxKillsProgress;
UINT16 usMaxIncomeProgress;
UINT16 usMaxControlProgress;
UINT16 usMaxVisitProgress;
if( gfEditMode )
return 0;
// HEADROCK HAM 3: If the alternate progress calculation is used, all four INI settings should be set to 100,
// otherwise progress cannot ever reach 100...
if (gGameExternalOptions.fAlternateProgressCalculation)
{
usMaxKillsProgress = 100;
usMaxIncomeProgress = 100;
usMaxControlProgress = 100;
usMaxVisitProgress = 100;
}
// Else, set to INI-read values. Note that the rest of the function now reads these instead of referring
// to the long variable names.
else
{
usMaxKillsProgress = gGameExternalOptions.ubGameProgressPortionKills;
usMaxIncomeProgress = gGameExternalOptions.ubGameProgressPortionIncome;
usMaxControlProgress = gGameExternalOptions.ubGameProgressPortionControl;
usMaxVisitProgress = gGameExternalOptions.ubGameProgressPortionVisited;
}
// figure out the player's current mine income
uiCurrentIncome = PredictIncomeFromPlayerMines();
@@ -1316,36 +1347,56 @@ UINT8 CurrentPlayerProgressPercentage(void)
uiPossibleIncome = CalcMaxPlayerIncomeFromMines();
// either of these indicates a critical failure of some sort
Assert(uiPossibleIncome > 0);
Assert(uiCurrentIncome <= uiPossibleIncome);
// HEADROCK HAM 3.6: No need to assert this. Max Income can potentially be 0 in modded games.
// Assert(uiPossibleIncome > 0);
// HEADROCK HAM 3.6: It is now possible, with the help of facilities,
// to make more money from mines than normally possible.
// This assertion check is now obsolete.
//Assert(uiCurrentIncome <= uiPossibleIncome);
uiCurrentIncome = __min(uiPossibleIncome, uiCurrentIncome);
// for a rough guess as to how well the player is doing,
// we'll take the current mine income / potential mine income as a percentage
/////////////////////////////////////////////////////////////////////////////////////////////
//
// HEADROCK HAM 3
// Several changes have been made here to accomodate a new type of progress generation.
// With this alternate system, the program determines the current progress from each of the
// four aspects SEPARATELY. It then compares all of them, and only the HIGHEST one determines
// our current progress. Please note that while some changes have been made, the ORIGINAL
// progress control works EXACTLY THE SAME AS IT ALWAYS DID.
//
/////////////////////////////////////////////////////////////////////////////////////////////
//Kris: Make sure you don't divide by zero!!!
if( uiPossibleIncome > 0)
{
ubCurrentProgress = (UINT8) ((uiCurrentIncome * gGameExternalOptions.ubGameProgressPortionIncome) / uiPossibleIncome);
usIncomeProgress = (UINT8) ((uiCurrentIncome * usMaxIncomeProgress) / uiPossibleIncome);
}
else
{
ubCurrentProgress = 0;
usIncomeProgress = 0;
}
// kills per point depends on difficulty, and should match the ratios of starting enemy populations (730/1050/1500)
// HEADROCK HAM 3: Externalized all four Kills-per-point ratios.
switch( gGameOptions.ubDifficultyLevel )
{
case DIF_LEVEL_EASY:
ubKillsPerPoint = 7;
ubKillsPerPoint = gGameExternalOptions.usNumKillsPerProgressPointNovice;
break;
case DIF_LEVEL_MEDIUM:
ubKillsPerPoint = 10;
ubKillsPerPoint = gGameExternalOptions.usNumKillsPerProgressPointExperienced;
break;
case DIF_LEVEL_HARD:
ubKillsPerPoint = 15;
ubKillsPerPoint = gGameExternalOptions.usNumKillsPerProgressPointExpert;
break;
case DIF_LEVEL_INSANE:
ubKillsPerPoint = 60; // Madd - uncertain whether this number is right
ubKillsPerPoint = gGameExternalOptions.usNumKillsPerProgressPointInsane;
break;
default:
Assert(FALSE);
@@ -1354,43 +1405,60 @@ UINT8 CurrentPlayerProgressPercentage(void)
}
usKillsProgress = gStrategicStatus.usPlayerKills / ubKillsPerPoint;
if (usKillsProgress > gGameExternalOptions.ubGameProgressPortionKills)
if (usKillsProgress > usMaxKillsProgress)
{
usKillsProgress = gGameExternalOptions.ubGameProgressPortionKills;
usKillsProgress = usMaxKillsProgress;
}
// add kills progress to income progress
ubCurrentProgress += usKillsProgress;
// 19 sectors in mining towns + 3 wilderness SAMs each count double. Balime & Meduna are extra and not required
// 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 = usMaxControlProgress * CalcImportantSectorControl() / CalcTotalImportantSectors();
if (usControlProgress > usMaxControlProgress)
{
usControlProgress = gGameExternalOptions.ubGameProgressPortionControl;
usControlProgress = usMaxControlProgress;
}
// add control progress
ubCurrentProgress += usControlProgress;
// WDS: Adding more ways to progress in the game
// Get a ratio of sectors visited to the total number of sectors
// 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();
usVisitProgress = CountSurfaceSectorsVisited() * usMaxVisitProgress / TotalVisitableSurfaceSectors();
// add control progress
ubCurrentProgress += usVisitProgress;
// HEADROCK HAM 3: This bit is ugly for now, unless someone can optimize it for me.
// When the "Alternate Progress Calculation" is activated, the program selects only the HIGHEST of the
// progress controls, and sets that to be the current progress, disregarding any advances in the three
// other fields.
return(ubCurrentProgress);
if (gGameExternalOptions.fAlternateProgressCalculation)
{
usHighestProgress = __max(usKillsProgress, usControlProgress);
usHighestProgress = __max(usHighestProgress, usIncomeProgress);
usHighestProgress = __max(usHighestProgress, usVisitProgress);
usCurrentProgress = usHighestProgress;
}
// Else, add them all up as normal (original progress calculation). This replaces all those lines I removed
// above where progress was summed along the way.
else
{
usCurrentProgress = usKillsProgress + usControlProgress + usIncomeProgress + usVisitProgress;
}
// Add a static amount of points, as declared in the INI file.
usCurrentProgress += gGameExternalOptions.ubGameProgressIncrement;
// And failsafes here. I'm not 100% sure about these though: I've never personally seen progress
// values go over 100, and I don't think they SHOULD... Can the game handle values > 100? Should it?
usCurrentProgress = __min(100, usCurrentProgress);
// No less than 0, or the minimum set in the INI file.
usCurrentProgress = __max(gGameExternalOptions.ubGameProgressMinimum, __max(0, usCurrentProgress));
return((UINT8)usCurrentProgress);
}
UINT8 HighestPlayerProgressPercentage(void)
{
if( gfEditMode )
@@ -1399,7 +1467,6 @@ UINT8 HighestPlayerProgressPercentage(void)
return(gStrategicStatus.ubHighestProgress);
}
// monitors the highest level of progress that player has achieved so far (checking hourly),
// as opposed to his immediate situation (which may be worse if he's suffered a setback).
void HourlyProgressUpdate(void)
+4 -1
View File
@@ -556,7 +556,10 @@ void DisplayRangeToTarget( SOLDIERTYPE *pSoldier, INT16 sTargetGridNo )
}
pSoldier->bTargetLevel = bTempTargetLevel;
swprintf( zOutputString, gzDisplayCoverText[DC_MSG__GUN_RANGE_INFORMATION], usRange / 10, Weapon[ pSoldier->inv[HANDPOS].usItem ].usRange / 10, uiHitChance );
// HEADROCK HAM 3.6: Calculate Gun Range using formula.
UINT16 usGunRange = GunRange(&pSoldier->inv[HANDPOS]);
swprintf( zOutputString, gzDisplayCoverText[DC_MSG__GUN_RANGE_INFORMATION], usRange / 10, usGunRange / 10, uiHitChance );
//Display the msg
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, zOutputString );
}
+10 -9
View File
@@ -37,6 +37,9 @@
#include "Interface Items.h"
#include "meanwhile.h"
#include "Map Screen Interface.h"
// HEADROCK HAM 3.2: Added two includes so that a function can read values of the Gun Range/hospital location
#include "Campaign Types.h"
#include "Strategic Event Handler.h"
#endif
// Defines
@@ -1256,7 +1259,6 @@ void HandleRenderFaceAdjustments( FACETYPE *pFace, BOOLEAN fDisplayBuffer, BOOLE
UINT16 usMaximumPts = 0;
CHAR16 sString[ 32 ];
UINT16 usTextWidth;
BOOLEAN fAtGunRange = FALSE;
BOOLEAN fShowNumber = FALSE;
BOOLEAN fShowMaximum = FALSE;
SOLDIERTYPE *pSoldier;
@@ -1474,34 +1476,33 @@ void HandleRenderFaceAdjustments( FACETYPE *pFace, BOOLEAN fDisplayBuffer, BOOLE
case TRAIN_SELF:
case TRAIN_TOWN:
// HEADROCK HAM 3.6: New assignment.
case TRAIN_MOBILE:
case TRAIN_TEAMMATE:
case TRAIN_BY_OTHER:
sIconIndex = 3;
fDoIcon = TRUE;
fShowNumber = TRUE;
fShowMaximum = TRUE;
// there could be bonus pts for training at gun range
if ( ( MercPtrs[ pFace->ubSoldierID ]->sSectorX == 13) && (MercPtrs[ pFace->ubSoldierID ]->sSectorY == MAP_ROW_H) && (MercPtrs[ pFace->ubSoldierID ]->bSectorZ == 0) )
{
fAtGunRange = TRUE;
}
switch( MercPtrs[ pFace->ubSoldierID ]->bAssignment )
{
case( TRAIN_SELF ):
sPtsAvailable = GetSoldierTrainingPts( MercPtrs[ pFace->ubSoldierID ], MercPtrs[ pFace->ubSoldierID ]->bTrainStat, fAtGunRange, &usMaximumPts );
sPtsAvailable = GetSoldierTrainingPts( MercPtrs[ pFace->ubSoldierID ], MercPtrs[ pFace->ubSoldierID ]->bTrainStat, &usMaximumPts );
break;
case( TRAIN_BY_OTHER ):
sPtsAvailable = GetSoldierStudentPts( MercPtrs[ pFace->ubSoldierID ], MercPtrs[ pFace->ubSoldierID ]->bTrainStat, fAtGunRange, &usMaximumPts );
sPtsAvailable = GetSoldierStudentPts( MercPtrs[ pFace->ubSoldierID ], MercPtrs[ pFace->ubSoldierID ]->bTrainStat, &usMaximumPts );
break;
// HEADROCK HAM 3.6: New assignment. Works just like Town Training.
case( TRAIN_TOWN ):
case( TRAIN_MOBILE ):
sPtsAvailable = GetTownTrainPtsForCharacter( MercPtrs[ pFace->ubSoldierID ], &usMaximumPts );
// divide both amounts by 10 to make the displayed numbers a little more user-palatable (smaller)
sPtsAvailable = ( sPtsAvailable + 5 ) / 10;
usMaximumPts = ( usMaximumPts + 5 ) / 10;
break;
case( TRAIN_TEAMMATE ):
sPtsAvailable = GetBonusTrainingPtsDueToInstructor( MercPtrs[ pFace->ubSoldierID ], NULL , MercPtrs[ pFace->ubSoldierID ]->bTrainStat, fAtGunRange, &usMaximumPts );
sPtsAvailable = GetBonusTrainingPtsDueToInstructor( MercPtrs[ pFace->ubSoldierID ], NULL , MercPtrs[ pFace->ubSoldierID ]->bTrainStat, &usMaximumPts );
break;
}
break;
+18 -6
View File
@@ -526,15 +526,22 @@ INT32 HandleItem( SOLDIERTYPE *pSoldier, INT16 sGridNo, INT8 bLevel, UINT16 usHa
if((__min(pSoldier->bDoAutofire,pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft) - startAuto) > 0 && pSoldier->bTeam == OUR_TEAM)
{
// More than 1 round
if (__min(pSoldier->bDoAutofire,pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft) - startAuto > 1)
if (gGameExternalOptions.usBulletHideIntensity > 0)
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, gzLateLocalizedString[ 62 ], pSoldier->name, __min(pSoldier->bDoAutofire,pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft) - startAuto );
// HEADROCK HAM 3.5: Non-accurate assessment.
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113HAMMessage[ 2 ], pSoldier->name );
}
// 1 round
else
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, gzLateLocalizedString[ 63 ], pSoldier->name, __min(pSoldier->bDoAutofire,pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft) - startAuto );
{// More than 1 round
if (__min(pSoldier->bDoAutofire,pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft) - startAuto > 1)
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, gzLateLocalizedString[ 62 ], pSoldier->name, __min(pSoldier->bDoAutofire,pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft) - startAuto );
}
// 1 round
else
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, gzLateLocalizedString[ 63 ], pSoldier->name, __min(pSoldier->bDoAutofire,pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft) - startAuto );
}
}
}
@@ -1957,6 +1964,11 @@ void HandleSoldierPickupItem( SOLDIERTYPE *pSoldier, INT32 iItemIndex, INT16 sGr
// OK, if an enemy, go directly ( skip menu )
if ( pSoldier->bTeam != gbPlayerNum )
{
// HEADROCK HAM 3.5: On-screen message when militia pick up items.
if ( pSoldier->bTeam == MILITIA_TEAM )
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113HAMMessage[4], Item[gWorldItems[ pItemPool->iItemIndex ].object.usItem].szItemName );
}
SoldierGetItemFromWorld( pSoldier, iItemIndex, sGridNo, bZLevel, NULL );
}
else
+12 -12
View File
@@ -296,16 +296,16 @@ UINT8 UsingEDBSystem()
{
if(guiCurrentScreen == MAP_SCREEN) //Strategic
{
if(gGameExternalOptions.fEnhancedDescriptionBox == 0)
if(gGameExternalOptions.iEnhancedDescriptionBox == 0)
return 1;
if(gGameExternalOptions.fEnhancedDescriptionBox == 1)
if(gGameExternalOptions.iEnhancedDescriptionBox == 1)
return 1;
}
else //Tactical
{
if(gGameExternalOptions.fEnhancedDescriptionBox == 0)
if(gGameExternalOptions.iEnhancedDescriptionBox == 0)
return (UsingNewInventorySystem()==true?1:2);
if(gGameExternalOptions.fEnhancedDescriptionBox == 2)
if(gGameExternalOptions.iEnhancedDescriptionBox == 2)
return (UsingNewInventorySystem()==true?1:2);
}
}
@@ -856,8 +856,8 @@ void InitDescStatCoords()
gWeaponStats[18].sX = 268; gWeaponStats[18].sY = 136; gWeaponStats[18].sValDx = 30; // 18) COL 4; ROW 1
gWeaponStats[19].sX = 268; gWeaponStats[19].sY = 148; gWeaponStats[19].sValDx = 30; // 19) COL 4; ROW 2
gWeaponStats[20].sX = 268; gWeaponStats[20].sY = 160; gWeaponStats[20].sValDx = 30; // 20) COL 4; ROW 3
gWeaponStats[21].sX = 203; gWeaponStats[21].sY = 172; gWeaponStats[21].sValDx = 30; // 21) COL 3; ROW 4
gWeaponStats[22].sX = 268; gWeaponStats[22].sY = 172; gWeaponStats[22].sValDx = 30; // 22) COL 4; ROW 4
gWeaponStats[21].sX = 268; gWeaponStats[21].sY = 172; gWeaponStats[21].sValDx = 30; // 21) COL 4; ROW 4
gWeaponStats[22].sX = 203; gWeaponStats[22].sY = 172; gWeaponStats[22].sValDx = 30; // 22) COL 3; ROW 4
// EQUALS signs
gWeaponStats[23].sX = 235; gWeaponStats[23].sY = 44; gWeaponStats[23].sValDx = 0; // 23) COL 1; ROW 1
gWeaponStats[24].sX = 235; gWeaponStats[24].sY = 56; gWeaponStats[24].sValDx = 0; // 24) COL 1; ROW 2
@@ -878,8 +878,8 @@ void InitDescStatCoords()
gWeaponStats[39].sX = 300; gWeaponStats[39].sY = 136; gWeaponStats[39].sValDx = 0; // 39) COL 4; ROW 1
gWeaponStats[40].sX = 300; gWeaponStats[40].sY = 148; gWeaponStats[40].sValDx = 0; // 40) COL 4; ROW 2
gWeaponStats[41].sX = 300; gWeaponStats[41].sY = 160; gWeaponStats[41].sValDx = 0; // 41) COL 4; ROW 3
gWeaponStats[42].sX = 235; gWeaponStats[42].sY = 172; gWeaponStats[42].sValDx = 0; // 42) COL 3; ROW 4
gWeaponStats[43].sX = 300; gWeaponStats[43].sY = 172; gWeaponStats[43].sValDx = 0; // 43) COL 4; ROW 4
gWeaponStats[42].sX = 300; gWeaponStats[42].sY = 172; gWeaponStats[42].sValDx = 0; // 42) COL 4; ROW 4
gWeaponStats[43].sX = 235; gWeaponStats[43].sY = 172; gWeaponStats[43].sValDx = 0; // 43) COL 3; ROW 4
// Nonregular locations for explosive radius values (COL 2; ROW 3)
gWeaponStats[44].sX = 273; gWeaponStats[44].sY = 68; gWeaponStats[44].sValDx = 0; // 44) COL 2; ROW 3; LOC 1 - Starting Radius
gWeaponStats[45].sX = 291; gWeaponStats[45].sY = 68; gWeaponStats[45].sValDx = 0; // 45) COL 2; ROW 3; LOC 2 - Single Radius
@@ -5988,10 +5988,10 @@ void DrawMiscValues( OBJECTTYPE * gpItemDescObject )
// HIDE MUZZLE FLASH
// NO DATA SHOWN, icon either appears or does not appear.
// HEADROCK HAM 3.5 - Fixed this, because the count needs to be increased to skip a line!
if ( Item[ gpItemDescObject->usItem ].hidemuzzleflash > 0 && cnt<=27 )
{
cnt++;
}
if ( Item[ gpItemDescObject->usItem ].hidemuzzleflash > 0 && cnt<=27 )
{
cnt++;
}
// BIPOD
if ( Item[ gpItemDescObject->usItem ].bipod != 0 && cnt<=27 )
+41 -4
View File
@@ -2508,8 +2508,22 @@ void INVRenderItem( UINT32 uiBuffer, SOLDIERTYPE * pSoldier, OBJECTTYPE *pObjec
// SetFontForeground( FONT_MCOLOR_DKGRAY );
// break;
//}
// HEADROCK HAM 3.4: Get estimate of bullets left.
if ( (gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) )
{
// Soldier doesn't know.
EstimateBulletsLeft( pSoldier, pObject );
swprintf( pStr, L"%s", gBulletCount );
}
else
{
swprintf( pStr, L"%d", (*pObject)[iter]->data.gun.ubGunShotsLeft );
}
//swprintf( pStr, L"%d", (*pObject)[iter]->data.gun.ubGunShotsLeft );
//swprintf( pStr, L"%d", GetEstimateBulletsLeft(pSoldier, pObject) );
swprintf( pStr, L"%d", (*pObject)[iter]->data.gun.ubGunShotsLeft );
if ( uiBuffer == guiSAVEBUFFER )
{
RestoreExternBackgroundRect( sNewX, sNewY, 20, 15 );
@@ -2892,7 +2906,7 @@ BOOLEAN InternalInitItemDescriptionBox( OBJECTTYPE *pObject, INT16 sX, INT16 sY,
//CHRISL: Initialize coords based on EDB/NIV settings
InitDescStatCoords();
InitEDBCoords();
InitItemDescriptionBoxStartCoords( gGameExternalOptions.fEnhancedDescriptionBox );
InitItemDescriptionBoxStartCoords( gGameExternalOptions.iEnhancedDescriptionBox );
//CHRISL: We only want this condition to be true when looking at MONEY. Not IC_MONEY since we can't actually split
// things like gold nuggets or wallets.
@@ -2974,10 +2988,33 @@ BOOLEAN InternalInitItemDescriptionBox( OBJECTTYPE *pObject, INT16 sX, INT16 sY,
// Add button
// if( guiCurrentScreen != MAP_SCREEN )
//if( guiCurrentItemDescriptionScreen != MAP_SCREEN )
if ( GetMagSize(gpItemDescObject) <= 99 )
swprintf( pStr, L"%d/%d", (*gpItemDescObject)[ubStatusIndex]->data.gun.ubGunShotsLeft, GetMagSize(gpItemDescObject));
{
// HEADROCK HAM 3.4: "Bullet Hide" feature - bullet count only shown during combat if character is competent enough.
if ( (gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) )
{
EstimateBulletsLeft( pSoldier, pObject );
swprintf(pStr, L"%s/%d", gBulletCount, GetMagSize(gpItemDescObject) );
}
else
{
swprintf( pStr, L"%d/%d", (*gpItemDescObject)[ubStatusIndex]->data.gun.ubGunShotsLeft, GetMagSize(gpItemDescObject));
}
}
else
swprintf( pStr, L"%d", (*gpItemDescObject)[ubStatusIndex]->data.gun.ubGunShotsLeft );
{
// HEADROCK HAM 3.4: "Bullet Hide" feature - bullet count only shown during combat if character is competent enough.
if ( (gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) )
{
EstimateBulletsLeft( pSoldier, pObject );
swprintf( pStr, L"%s", gBulletCount );
}
else
{
swprintf( pStr, L"%d", (*gpItemDescObject)[ubStatusIndex]->data.gun.ubGunShotsLeft );
}
}
FilenameForBPP("INTERFACE\\infobox.sti", ubString);
sForeColour = ITEMDESC_AMMO_FORE;
+181 -23
View File
@@ -72,6 +72,8 @@
#include "MessageBoxScreen.h"
#include "wordwrap.h"
#include "Boxing.h"
// HEADROCK HAM 3.6: This is required for Stat Progress Bars
#include "Campaign.h"
#endif
//forward declarations of common classes to eliminate includes
@@ -1532,27 +1534,27 @@ BOOLEAN InitializeSMPanelCoordsOld()
SM_CAMMO_X = ( 428 + INTERFACE_START_X );
SM_CAMMO_Y = ( 121 + INV_INTERFACE_START_Y );
SM_STATS_WIDTH = 30;
SM_STATS_WIDTH = 16;
SM_STATS_HEIGHT = 8 ;
SM_AGI_X = ( 99 + INTERFACE_START_X );
SM_AGI_X = ( 115 + INTERFACE_START_X );
SM_AGI_Y = ( 7 + INV_INTERFACE_START_Y );
SM_DEX_X = ( 99 + INTERFACE_START_X );
SM_DEX_X = ( 115 + INTERFACE_START_X );
SM_DEX_Y = ( 17 + INV_INTERFACE_START_Y );
SM_STR_X = ( 99 + INTERFACE_START_X );
SM_STR_X = ( 115 + INTERFACE_START_X );
SM_STR_Y = ( 27 + INV_INTERFACE_START_Y );
SM_CHAR_X = ( 99 + INTERFACE_START_X );
SM_CHAR_X = ( 115 + INTERFACE_START_X );
SM_CHAR_Y = ( 37 + INV_INTERFACE_START_Y );
SM_WIS_X = ( 99 + INTERFACE_START_X );
SM_WIS_X = ( 115 + INTERFACE_START_X );
SM_WIS_Y = ( 47 + INV_INTERFACE_START_Y );
SM_EXPLVL_X = ( 148 + INTERFACE_START_X );
SM_EXPLVL_X = ( 163 + INTERFACE_START_X );
SM_EXPLVL_Y = ( 7 + INV_INTERFACE_START_Y );
SM_MRKM_X = ( 148 + INTERFACE_START_X );
SM_MRKM_X = ( 163 + INTERFACE_START_X );
SM_MRKM_Y = ( 17 + INV_INTERFACE_START_Y );
SM_EXPL_X = ( 148 + INTERFACE_START_X );
SM_EXPL_X = ( 163 + INTERFACE_START_X );
SM_EXPL_Y = ( 27 + INV_INTERFACE_START_Y );
SM_MECH_X = ( 148 + INTERFACE_START_X );
SM_MECH_X = ( 163 + INTERFACE_START_X );
SM_MECH_Y = ( 37 + INV_INTERFACE_START_Y );
SM_MED_X = ( 148 + INTERFACE_START_X );
SM_MED_X = ( 163 + INTERFACE_START_X );
SM_MED_Y = ( 47 + INV_INTERFACE_START_Y );
MONEY_X = ( 460 + INTERFACE_START_X );
@@ -1905,27 +1907,27 @@ BOOLEAN InitializeSMPanelCoordsNew()
SM_CAMMO_X = ( 218 + INTERFACE_START_X );
SM_CAMMO_Y = ( 49 + INV_INTERFACE_START_Y );
SM_STATS_WIDTH = 30;
SM_STATS_WIDTH = 16;
SM_STATS_HEIGHT = 8 ;
SM_AGI_X = ( 101 + INTERFACE_START_X );
SM_AGI_X = ( 115 + INTERFACE_START_X );
SM_AGI_Y = ( 7 + INV_INTERFACE_START_Y );
SM_DEX_X = ( 101 + INTERFACE_START_X );
SM_DEX_X = ( 115 + INTERFACE_START_X );
SM_DEX_Y = ( 17 + INV_INTERFACE_START_Y );
SM_STR_X = ( 101 + INTERFACE_START_X );
SM_STR_X = ( 115 + INTERFACE_START_X );
SM_STR_Y = ( 27 + INV_INTERFACE_START_Y );
SM_CHAR_X = ( 101 + INTERFACE_START_X );
SM_CHAR_X = ( 115 + INTERFACE_START_X );
SM_CHAR_Y = ( 37 + INV_INTERFACE_START_Y );
SM_WIS_X = ( 101 + INTERFACE_START_X );
SM_WIS_X = ( 115 + INTERFACE_START_X );
SM_WIS_Y = ( 47 + INV_INTERFACE_START_Y );
SM_EXPLVL_X = ( 150 + INTERFACE_START_X );
SM_EXPLVL_X = ( 163 + INTERFACE_START_X );
SM_EXPLVL_Y = ( 7 + INV_INTERFACE_START_Y );
SM_MRKM_X = ( 150 + INTERFACE_START_X );
SM_MRKM_X = ( 163 + INTERFACE_START_X );
SM_MRKM_Y = ( 17 + INV_INTERFACE_START_Y );
SM_EXPL_X = ( 150 + INTERFACE_START_X );
SM_EXPL_X = ( 163 + INTERFACE_START_X );
SM_EXPL_Y = ( 27 + INV_INTERFACE_START_Y );
SM_MECH_X = ( 150 + INTERFACE_START_X );
SM_MECH_X = ( 163 + INTERFACE_START_X );
SM_MECH_Y = ( 37 + INV_INTERFACE_START_Y );
SM_MED_X = ( 150 + INTERFACE_START_X );
SM_MED_X = ( 163 + INTERFACE_START_X );
SM_MED_Y = ( 47 + INV_INTERFACE_START_Y );
MONEY_X = ( 185 + INTERFACE_START_X );
@@ -2495,6 +2497,133 @@ void RenderSMPanel( BOOLEAN *pfDirty )
}
}
// HEADROCK HAM 3.6: "progress" bars showing how near the character is to "leveling up" in any stat. The bar
// is displayed behind the current stat value, as see on the character's info panel.
// This section draws TACTICAL info pages. Another section is in mapscreen.cpp and draws STRATEGIC info pages.
// The feature is toggled by Options-Menu switch, and its color is determined in the INI files.
if ( gGameSettings.fOptions[TOPTION_STAT_PROGRESS_BARS] )
{
UINT8 *pDestBuf;
UINT32 uiDestPitchBYTES = 0;
SGPRect ClipRect;
UINT8 ubBarWidth;
UINT16 usColor = Get16BPPColor( FROMRGB( gGameExternalOptions.ubStatProgressBarsRed, gGameExternalOptions.ubStatProgressBarsGreen, gGameExternalOptions.ubStatProgressBarsBlue ) );
//pDestBuf = LockVideoSurface( FRAME_BUFFER, &uiDestPitchBYTES );
pDestBuf = LockVideoSurface( guiSAVEBUFFER, &uiDestPitchBYTES );
// AGI
if (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sAgilityGain)
{
ubBarWidth = (SM_STATS_WIDTH * (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sAgilityGain+1)) / SubpointsPerPoint(AGILAMT,0);
ClipRect.iTop = (SM_AGI_Y-1);
ClipRect.iBottom = (SM_AGI_Y-1) + SM_STATS_HEIGHT;
ClipRect.iLeft = SM_AGI_X;
ClipRect.iRight = SM_AGI_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// DEX
if (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sDexterityGain)
{
ubBarWidth = (SM_STATS_WIDTH * (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sDexterityGain+1)) / SubpointsPerPoint(DEXTAMT,0);
ClipRect.iTop = (SM_DEX_Y-1);
ClipRect.iBottom = (SM_DEX_Y-1) + SM_STATS_HEIGHT;
ClipRect.iLeft = SM_DEX_X;
ClipRect.iRight = SM_DEX_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// STR
if (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sStrengthGain)
{
ubBarWidth = (SM_STATS_WIDTH * (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sStrengthGain+1)) / SubpointsPerPoint(STRAMT,0);
ClipRect.iTop = (SM_STR_Y-1);
ClipRect.iBottom = (SM_STR_Y-1) + SM_STATS_HEIGHT;
ClipRect.iLeft = SM_STR_X;
ClipRect.iRight = SM_STR_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// WIS
if (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sWisdomGain)
{
ubBarWidth = (SM_STATS_WIDTH * (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sWisdomGain+1)) / SubpointsPerPoint(WISDOMAMT,0);
ClipRect.iTop = (SM_WIS_Y-1);
ClipRect.iBottom = (SM_WIS_Y-1) + SM_STATS_HEIGHT;
ClipRect.iLeft = SM_WIS_X;
ClipRect.iRight = SM_WIS_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// MRK
if (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sMarksmanshipGain)
{
ubBarWidth = (SM_STATS_WIDTH * (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sMarksmanshipGain+1)) / SubpointsPerPoint(MARKAMT,0);
ClipRect.iTop = (SM_MRKM_Y-1);
ClipRect.iBottom = (SM_MRKM_Y-1) + SM_STATS_HEIGHT;
ClipRect.iLeft = SM_MRKM_X;
ClipRect.iRight = SM_MRKM_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// LDR
if (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sLeadershipGain)
{
ubBarWidth = (SM_STATS_WIDTH * (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sLeadershipGain+1)) / SubpointsPerPoint(LDRAMT,0);
ClipRect.iTop = (SM_CHAR_Y-1);
ClipRect.iBottom = (SM_CHAR_Y-1) + SM_STATS_HEIGHT;
ClipRect.iLeft = SM_CHAR_X;
ClipRect.iRight = SM_CHAR_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// MECH
if (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sMechanicGain)
{
ubBarWidth = (SM_STATS_WIDTH * (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sMechanicGain+1)) / SubpointsPerPoint(MECHANAMT,0);
ClipRect.iTop = (SM_MECH_Y-1);
ClipRect.iBottom = (SM_MECH_Y-1) + SM_STATS_HEIGHT;
ClipRect.iLeft = SM_MECH_X;
ClipRect.iRight = SM_MECH_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// EXPLO
if (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sExplosivesGain)
{
ubBarWidth = (SM_STATS_WIDTH * (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sExplosivesGain+1)) / SubpointsPerPoint(EXPLODEAMT,0);
ClipRect.iTop = (SM_EXPL_Y-1);
ClipRect.iBottom = (SM_EXPL_Y-1) + SM_STATS_HEIGHT;
ClipRect.iLeft = SM_EXPL_X;
ClipRect.iRight = SM_EXPL_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// MED
if (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sMedicalGain)
{
ubBarWidth = (SM_STATS_WIDTH * (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sMedicalGain+1)) / SubpointsPerPoint(MEDICALAMT,0);
ClipRect.iTop = (SM_MED_Y-1);
ClipRect.iBottom = (SM_MED_Y-1) + SM_STATS_HEIGHT;
ClipRect.iLeft = SM_MED_X;
ClipRect.iRight = SM_MED_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// EXPLEVEL
if (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sExpLevelGain)
{
ubBarWidth = (SM_STATS_WIDTH * (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sExpLevelGain+1)) / SubpointsPerPoint(EXPERAMT, gpSMCurrentMerc->stats.bExpLevel);
ClipRect.iTop = (SM_EXPLVL_Y-1);
ClipRect.iBottom = (SM_EXPLVL_Y-1) + SM_STATS_HEIGHT;
ClipRect.iLeft = SM_EXPLVL_X;
ClipRect.iRight = SM_EXPLVL_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
UnLockVideoSurface( guiSAVEBUFFER );
}
// Render faceplate
//BltVideoObjectFromIndex( guiSAVEBUFFER, guiSMObjects2, 1, SM_SELMERC_NAMEPLATE_X, SM_SELMERC_NAMEPLATE_Y, VO_BLT_SRCTRANSPARENCY, NULL );
//RestoreExternBackgroundRect( SM_SELMERC_NAMEPLATE_X, SM_SELMERC_NAMEPLATE_Y, SM_SELMERC_NAMEPLATE_WIDTH, SM_SELMERC_NAMEPLATE_HEIGHT );
@@ -5433,7 +5562,36 @@ void MercFacePanelCallback( MOUSE_REGION * pRegion, INT32 iReason )
}
else
{
HandleLocateSelectMerc( ubSoldierID, 0 );
// HEADROCK HAM 3.5: Shift-Click a merc's face will add him to the current selection.
if (!(gTacticalStatus.uiFlags & INCOMBAT) && _KeyDown( SHIFT ) )
{
if ( ! (MercPtrs[ ubSoldierID ]->flags.uiStatusFlags & SOLDIER_MULTI_SELECTED ) )
{
if ( OK_CONTROLLABLE_MERC( MercPtrs[ ubSoldierID ] ) && !( MercPtrs[ ubSoldierID ]->flags.uiStatusFlags & ( SOLDIER_VEHICLE | SOLDIER_PASSENGER | SOLDIER_DRIVER ) ) )
{
//ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%s added", MercPtrs[ ubSoldierID ]->name );
MercPtrs[ gusSelectedSoldier ]->flags.uiStatusFlags |= SOLDIER_MULTI_SELECTED;
MercPtrs[ ubSoldierID ]->flags.uiStatusFlags |= SOLDIER_MULTI_SELECTED;
EndMultiSoldierSelection( TRUE );
}
}
// A shift-click on a selected character will remove that character from the current selection.
else
{
//ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%s removed", MercPtrs[ ubSoldierID ]->name );
MercPtrs[ ubSoldierID ]->flags.uiStatusFlags &= (~SOLDIER_MULTI_SELECTED );
if (ubSoldierID != gusSelectedSoldier)
{
MercPtrs[ gusSelectedSoldier ]->flags.uiStatusFlags |= SOLDIER_MULTI_SELECTED;
}
EndMultiSoldierSelection( TRUE );
}
}
else
{
//ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%s selected", MercPtrs[ ubSoldierID ]->name );
HandleLocateSelectMerc( ubSoldierID, 0 );
}
}
}
else
+180 -105
View File
@@ -2680,15 +2680,21 @@ UINT32 CalculateCarriedWeight( SOLDIERTYPE * pSoldier )
//ADB the weight of the object is already counting stacked objects, attachments, et al
uiTotalWeight += CalculateObjectWeight(&pSoldier->inv[ubLoop]);
}
// for now, assume soldiers can carry 1/2 their strength in KGs without penalty.
// instead of multiplying by 100 for percent, and then dividing by 10 to account
// for weight units being in 10ths of kilos, not kilos... we just start with 10 instead of 100!
// Every point over 80 counts double.
ubStrengthForCarrying = EffectiveStrength( pSoldier );
if ( ubStrengthForCarrying > 80 )
{
ubStrengthForCarrying += (ubStrengthForCarrying - 80);
}
uiPercent = (10 * uiTotalWeight) / ( ubStrengthForCarrying / 2 );
// for now, assume soldiers can carry 1/2 their strength in KGs without penalty.
// instead of multiplying by 100 for percent, and then dividing by 10 to account
// for weight units being in 10ths of kilos, not kilos... we just start with 10 instead of 100!
// HEADROCK HAM 3: STR required per 1/2 kilo has been externalized. Can someone tidy this up though? The
// formula works great, but it's damn ugly now.
uiPercent = (UINT32)(((FLOAT)10 * (FLOAT)gGameExternalOptions.iStrengthToLiftHalfKilo) * uiTotalWeight) / ( ubStrengthForCarrying / 2 );
return( uiPercent );
}
@@ -3152,9 +3158,12 @@ BOOLEAN EmptyWeaponMagazine( OBJECTTYPE * pWeapon, OBJECTTYPE *pAmmo, UINT32 sub
{
CreateAmmo((*pWeapon)[subObject]->data.gun.usGunAmmoItem, pAmmo, (*pWeapon)[subObject]->data.gun.ubGunShotsLeft);
(*pWeapon)[subObject]->data.gun.ubGunShotsLeft = 0;
(*pWeapon)[subObject]->data.gun.ubGunAmmoType = 0;
//(*pWeapon)[subObject]->data.gun.usGunAmmoItem = 0; // leaving the ammo item the same for auto-reloading purposes
(*pWeapon)[subObject]->data.gun.ubGunShotsLeft = 0;
(*pWeapon)[subObject]->data.gun.ubGunAmmoType = 0;
// HEADROCK HAM 3.5: Leaving the ammo inside the gun causes EDB stats to display values as though the magazine
// still gives some effects (like autopen reduction, range bonus, etcetera). I'm going to try to work around
// this issue.
(*pWeapon)[subObject]->data.gun.usGunAmmoItem = 0; // leaving the ammo item the same for auto-reloading purposes
// Play some effects!
usReloadSound = Weapon[ pWeapon->usItem ].sReloadSound;
@@ -3174,13 +3183,20 @@ BOOLEAN EmptyWeaponMagazine( OBJECTTYPE * pWeapon, OBJECTTYPE *pAmmo, UINT32 sub
}
else
{
// HEADROCK HAM 3.5: Clear the ammo type and magazine on player command. This will remove all bonuses by
// the ammo and allow viewing the gun's normal stats. It will also change the weapon's ammocolor back to grey.
(*pWeapon)[subObject]->data.gun.ubGunAmmoType = 0;
(*pWeapon)[subObject]->data.gun.usGunAmmoItem = 0;
//CHRISL: Clear the contents of pAmmo just in case
pAmmo->initialize();
return( FALSE );
}
}
INT8 FindAmmo( SOLDIERTYPE * pSoldier, UINT8 ubCalibre, UINT16 ubMagSize, INT8 bExcludeSlot )
// HEADROCK HAM 3.3: Added an additional argument which helps the program pick a magazine
// that matches the ammotype currently used in the weapon. This makes for much smarter
// ammo selection.
INT8 FindAmmo( SOLDIERTYPE * pSoldier, UINT8 ubCalibre, UINT16 ubMagSize, UINT8 ubAmmoType, INT8 bExcludeSlot )
{
INT8 bLoop;
INT8 capLoop = 0;
@@ -3211,7 +3227,10 @@ INT8 FindAmmo( SOLDIERTYPE * pSoldier, UINT8 ubCalibre, UINT16 ubMagSize, INT8 b
{
stackCap = __max(stackCap, pSoldier->inv[bLoop][i]->data.ubShotsLeft);
}
if(stackCap > curCap)
// If found a similar-sized magazine to the best one found so far, but this new one
// has the same ammotype as specified in the arguments, then this is a better choice!
if(stackCap > curCap ||
(stackCap == curCap && Magazine[pItem->ubClassIndex].ubAmmoType == ubAmmoType))
{
curCap = stackCap;
capLoop = bLoop;
@@ -3264,7 +3283,7 @@ INT8 FindAmmoToReload( SOLDIERTYPE * pSoldier, INT8 bWeaponIn, INT8 bExcludeSlot
// return( bSlot );
//}
// look for any ammo that matches which is of the same calibre and magazine size
bSlot = FindAmmo( pSoldier, Weapon[pObj->usItem].ubCalibre, GetMagSize(pObj), bExcludeSlot );
bSlot = FindAmmo( pSoldier, Weapon[pObj->usItem].ubCalibre, GetMagSize(pObj), GetAmmoType(pObj), bExcludeSlot );
if (bSlot != NO_SLOT)
{
return( bSlot );
@@ -3272,7 +3291,7 @@ INT8 FindAmmoToReload( SOLDIERTYPE * pSoldier, INT8 bWeaponIn, INT8 bExcludeSlot
else
{
// look for any ammo that matches which is of the same calibre (different size okay)
return( FindAmmo( pSoldier, Weapon[pObj->usItem].ubCalibre, ANY_MAGSIZE, bExcludeSlot ) );
return( FindAmmo( pSoldier, Weapon[pObj->usItem].ubCalibre, ANY_MAGSIZE, GetAmmoType(pObj), bExcludeSlot ) );
}
}
else
@@ -3970,6 +3989,8 @@ void EjectAmmoAndPlace(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj)
CreateAmmo((*pObj)[0]->data.gun.usGunAmmoItem, &gTempObject, (*pObj)[0]->data.gun.ubGunShotsLeft);
(*pObj)[0]->data.gun.ubGunShotsLeft = 0;
(*pObj)[0]->data.gun.usGunAmmoItem = NONE;
// HEADROCK HAM 3.5: Clear ammo type
(*pObj)[0]->data.gun.ubGunAmmoType = NONE;
if ( pSoldier )
{
if ( !AutoPlaceObject( pSoldier, &gTempObject, FALSE ) )
@@ -7104,7 +7125,7 @@ INT16 GetBurstToHitBonus( OBJECTTYPE * pObj, BOOLEAN fProneStance )
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 )
if ( gGameExternalOptions.ubRealisticTracers != 1 )
bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].bursttohitbonus ;
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
@@ -7234,7 +7255,7 @@ INT16 GetAutoToHitBonus( OBJECTTYPE * pObj, BOOLEAN fProneStance )
// 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 )
if ( gGameExternalOptions.ubRealisticTracers != 1 )
bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].autofiretohitbonus ;
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
@@ -7648,6 +7669,26 @@ UINT8 GetPercentTunnelVision( SOLDIERTYPE * pSoldier )
}
}
// HEADROCK HAM 3.2: Further increase tunnel-vision for cowering characters.
if (gGameExternalOptions.ubCoweringReducesSightRange == 1 || gGameExternalOptions.ubCoweringReducesSightRange == 3)
{
INT8 bTolerance = CalcSuppressionTolerance( pSoldier );
// Make sure character is cowering.
if ( pSoldier->aiData.bShock >= bTolerance && gGameExternalOptions.ubMaxSuppressionShock > 0 &&
bonus < 100 )
{
// Calculates a "Flat" tunnel vision percentage
UINT8 ubNormalCoweringTunnelVision = (100 * pSoldier->aiData.bShock) / gGameExternalOptions.ubMaxSuppressionShock;
// Apply that percentage to the current tunnel vision
UINT16 usActualCoweringTunnelVision = bonus + (((100-bonus) * ubNormalCoweringTunnelVision) / 100);
// At shock 0, tunnel vision remains unchanged. At full shock, tunnel vision is full (100%)
bonus = __min(100,usActualCoweringTunnelVision);
}
}
if ( PTR_OURTEAM ) // Madd: adjust tunnel vision by difficulty level
return( bonus );
else
@@ -8495,106 +8536,122 @@ INT16 GetMinRangeForAimBonus( OBJECTTYPE * pObj )
UINT8 AllowedAimingLevels(SOLDIERTYPE * pSoldier)
{
UINT8 aimLevels = 4;
float iScopeBonus = 0;
UINT16 usScopeBonus = 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)
if ( gGameSettings.fOptions[TOPTION_AIM_LEVEL_RESTRICTION] ) // Options Menu setting.
{
// HEADROCK HAM B2.6: Dynamic aiming level restrictions based on gun type and attachments.
// HEADROCK HAM 3.5: Revamped this - it was illogically constructed.
if ( gGameExternalOptions.fDynamicAimingTime )
{
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;
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;
}
else
{
return 4;
}
// Define basic (no attachments), and absolute maximums
if (weaponType == GUN_PISTOL || weaponType == GUN_M_PISTOL || fTwoHanded == 0)
{
maxAimForType = 2;
aimLevels = 1;
maxAimWithoutBipod = 2;
}
else if (weaponType == GUN_SHOTGUN || weaponType == GUN_LMG || weaponType == GUN_SMG)
{
maxAimForType = 3;
aimLevels = 2;
maxAimWithoutBipod = 3;
}
else if ((weaponType == GUN_AS_RIFLE || weaponType == GUN_RIFLE ) && weaponRange <= 500)
{
maxAimForType = 4;
aimLevels = 2;
maxAimWithoutBipod = 3;
}
else if (((weaponType == GUN_AS_RIFLE || weaponType == GUN_RIFLE) && weaponRange > 500) ||
(weaponType == GUN_SN_RIFLE && weaponRange <= 500))
{
maxAimForType = 6;
aimLevels = 3;
maxAimWithoutBipod = 4;
}
else if (weaponType == GUN_SN_RIFLE && weaponRange > 500)
{
maxAimForType = 8;
aimLevels = 4;
maxAimWithoutBipod = 3;
}
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;
// Determine whether a bipod is being used (prone)
if (GetBipodBonus(&pSoldier->inv[pSoldier->ubAttackingHand])>0 && gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE )
{
fUsingBipod = TRUE;
}
usScopeBonus = ( GetMinRangeForAimBonus(&pSoldier->inv[pSoldier->ubAttackingHand]) * 10 ) / gGameExternalOptions.ubStraightSightRange;
if ( usScopeBonus >= 50 ) // Scope Min Range >= 7 Tiles
{
aimLevels *= 2;
}
else if ( usScopeBonus >= 30 ) // Scope Min Range >= 4 Tiles
{
aimLevels = (UINT8)((float)(aimLevels+1) * (float)1.5);
}
else if ( usScopeBonus >= 15 ) // Scope Min Range >= 2 Tiles
{
aimLevels = (UINT8)((float)(aimLevels+1) * (float)1.3);
}
// Smaller scopes increase by one.
else if ( usScopeBonus > 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);
}
}
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)
else // JA2 1.13 Basic aiming restrictions (8 levels for 10x scope, 6 levels for 7x scope)
{
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;
if ( allowed && IsScoped( &pSoldier->inv[pSoldier->ubAttackingHand] ) )
{
iScopeBonus = ( (float)gGameExternalOptions.ubStraightSightRange * GetMinRangeForAimBonus(&pSoldier->inv[pSoldier->ubAttackingHand]) / 100 );
if ( iScopeBonus >= ( (float)gGameExternalOptions.ubStraightSightRange * 0.3) ) // >= 30% of sight range (~4 tiles by default)
{
aimLevels += 2;
}
if ( iScopeBonus >= ( (float)gGameExternalOptions.ubStraightSightRange * 0.6) ) // >= 60% of sight range (~9 tiles by default)
{
aimLevels += 2;
if ( !IsScoped( &pSoldier->inv[pSoldier->ubAttackingHand] ) )
{
// No scope. 4 Allowed.
return (4);
}
usScopeBonus = ( GetMinRangeForAimBonus(&pSoldier->inv[pSoldier->ubAttackingHand]) * 10 ) / gGameExternalOptions.ubStraightSightRange;
if ( usScopeBonus >= 50 ) // Scope Min Range >= 7 Tiles (Sniper Scope)
{
aimLevels += 2;
}
if ( usScopeBonus >= 30 ) // Scope Min Range >= 4 Tiles (Battle Scope)
{
aimLevels += 2;
}
}
}
@@ -8883,3 +8940,21 @@ INT16 GetBasicStealthBonus( OBJECTTYPE * pObj )
return( bonus );
}
// HEADROCK HAM 3.6: This is meant to squash an exploit where a backpack can be moved to your hand to avoid AP penalties.
INT8 FindBackpackOnSoldier( SOLDIERTYPE * pSoldier )
{
INT8 bLoop;
for (bLoop = 0; bLoop < NUM_INV_SLOTS ; bLoop++)
{
if (pSoldier->inv[bLoop].exists())
{
if (Item[pSoldier->inv[bLoop].usItem].usItemClass == IC_LBEGEAR &&
LoadBearingEquipment[Item[pSoldier->inv[bLoop].usItem].ubClassIndex].lbeClass == BACKPACK)
{
return( bLoop );
}
}
}
return( ITEM_NOT_FOUND );
}
+3 -2
View File
@@ -18,7 +18,7 @@ extern UINT8 SlotToPocket[7];
extern BOOLEAN WeaponInHand( SOLDIERTYPE * pSoldier );
INT8 FindAmmo( SOLDIERTYPE * pSoldier, UINT8 ubCalibre, UINT16 ubMagSize, INT8 bExcludeSlot );
INT8 FindAmmo( SOLDIERTYPE * pSoldier, UINT8 ubCalibre, UINT16 ubMagSize, UINT8 ubAmmoType, INT8 bExcludeSlot );
INT8 FindBestWeaponIfCurrentIsOutOfRange(SOLDIERTYPE * pSoldier, INT8 bCurrentWeaponIndex, UINT16 bWantedRange);
@@ -343,7 +343,8 @@ INT16 GetDesertCamoBonus( OBJECTTYPE * pObj );
INT16 GetWornSnowCamo( SOLDIERTYPE * pSoldier );
INT16 GetSnowCamoBonus( OBJECTTYPE * pObj );
// HEADROCK HAM 3.6: Looks for a backpack anywhere on this character.
INT8 FindBackpackOnSoldier( SOLDIERTYPE * pSoldier );
#endif
+47 -14
View File
@@ -48,6 +48,8 @@
#include "fresh_header.h"
#include "test_space.h"
#include "WorldDat.h"
// HEADROCK HAM 3.6: This must be included, for testing whether Bloodcats and Enemies can see one another.
#include "Campaign Types.h"
//forward declarations of common classes to eliminate includes
class OBJECTTYPE;
@@ -2009,20 +2011,47 @@ INT32 SoldierToSoldierLineOfSightTest( SOLDIERTYPE * pStartSoldier, SOLDIERTYPE
fOk = CalculateSoldierZPos( pStartSoldier, LOS_POS, &dStartZPos );
CHECKF( fOk );
if ( gWorldSectorX == 5 && gWorldSectorY == MAP_ROW_N )
// HEADROCK HAM 3.6: Location of static sectors externalized, and there can be more than one. Also, modders can
// determine whether bloodcats really are blind to enemies here at all.
UINT8 ubSectorID = SECTOR(gWorldSectorX,gWorldSectorY);
UINT8 PlacementType = gBloodcatPlacements[ ubSectorID ][ 0 ].PlacementType;
// Does sector contain a Bloodcat Garrison?
if (PlacementType == BLOODCAT_PLACEMENT_STATIC)
{
// in the bloodcat arena sector, skip sight between army & bloodcats
if ( pStartSoldier->bTeam == ENEMY_TEAM && pEndSoldier->bTeam == CREATURE_TEAM )
// Are bloodcats set to forgo attacking enemies?
if (gBloodcatPlacements[ ubSectorID ][ gGameOptions.ubDifficultyLevel-1 ].ubFactionAffiliation == QUEENS_CIV_GROUP)
{
return( 0 );
// skip sight between army & bloodcats
if ( pStartSoldier->bTeam == ENEMY_TEAM && pEndSoldier->bTeam == CREATURE_TEAM && pEndSoldier->ubBodyType == BLOODCAT )
{
return( 0 );
}
if ( pStartSoldier->bTeam == CREATURE_TEAM && pStartSoldier->ubBodyType == BLOODCAT && pEndSoldier->bTeam == ENEMY_TEAM )
{
return( 0 );
}
}
if ( pStartSoldier->bTeam == CREATURE_TEAM && pEndSoldier->bTeam == ENEMY_TEAM )
else if (gBloodcatPlacements[ ubSectorID ][ gGameOptions.ubDifficultyLevel-1 ].ubFactionAffiliation > NON_CIV_GROUP)
{
return( 0 );
// Bloodcats in this sector belong to a faction. They adhere to certain rules as a result.
if ( pEndSoldier->bTeam == CREATURE_TEAM && pEndSoldier->ubBodyType == BLOODCAT && pStartSoldier->bSide != gbPlayerNum)
{
// Target is a bloodcat. He can't be spotted by civilians no matter what.
{
return ( 0 );
}
}
else if ( pStartSoldier->bTeam == CREATURE_TEAM && pStartSoldier->ubBodyType == BLOODCAT )
{
// Source is a bloodcat. He can only spot player-side soldiers, and only if hostile.
if ( pEndSoldier->bSide != gbPlayerNum || pStartSoldier->aiData.bNeutral )
{
return ( 0 );
}
}
}
}
if (pStartSoldier->flags.uiStatusFlags & SOLDIER_MONSTER)
{
// monsters use smell instead of sight!
@@ -4002,11 +4031,11 @@ INT8 FireBulletGivenTarget( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOA
}
// 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)
else if (gGameExternalOptions.ubRealisticTracers > 0 && gGameExternalOptions.ubNumBulletsPerTracer > 0 && (pFirer->bDoAutofire > 0 || pFirer->bDoBurst > 0)
&& AmmoTypes[ pFirer->inv[pFirer->ubAttackingHand][0]->data.gun.ubGunAmmoType ].tracerEffect )
{
UINT16 iBulletsLeft, iBulletsPerTracer;
iBulletsPerTracer = gGameExternalOptions.iNumBulletsPerTracer;
iBulletsPerTracer = gGameExternalOptions.ubNumBulletsPerTracer;
iBulletsLeft = pFirer->inv[pFirer->ubAttackingHand][0]->data.gun.ubGunShotsLeft + pFirer->bDoBurst;
if ((((iBulletsLeft - (pFirer->bDoBurst - 1)) / iBulletsPerTracer) - ((iBulletsLeft - pFirer->bDoBurst) / iBulletsPerTracer)) == 1)
@@ -4345,11 +4374,11 @@ INT8 FireBulletGivenTarget( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOA
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)
if (gGameExternalOptions.ubRealisticTracers > 0 && gGameExternalOptions.ubNumBulletsPerTracer > 0 && (pFirer->bDoAutofire > 0 || pFirer->bDoBurst > 0)
&& AmmoTypes[ pFirer->inv[pFirer->ubAttackingHand][0]->data.gun.ubGunAmmoType ].tracerEffect )
{
UINT16 iBulletsLeft, iBulletsPerTracer;
iBulletsPerTracer = gGameExternalOptions.iNumBulletsPerTracer;
iBulletsPerTracer = gGameExternalOptions.ubNumBulletsPerTracer;
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
@@ -4686,9 +4715,13 @@ void MoveBullet( INT32 iBullet )
if ( IS_MERC_BODY_TYPE( MercPtrs[pStructure->usStructureID] ) )
{
// HEADROCK HAM 3.3: Externalized distance at which characters suffer from friendly suppression.
// previously relied on minimum distance at which characters may suffer from friendly fire HITS.
UINT16 MIN_DIST_FOR_SCARE_FRIENDS = gGameExternalOptions.usMinDistanceFriendlySuppression;
// apply suppression, regardless of friendly or enemy
// except if friendly, not within a few tiles of shooter
if ( MercPtrs[ pStructure->usStructureID ]->bSide != pBullet->pFirer->bSide || pBullet->iLoop > MIN_DIST_FOR_HIT_FRIENDS )
if ( MercPtrs[ pStructure->usStructureID ]->bSide != pBullet->pFirer->bSide || pBullet->iLoop > MIN_DIST_FOR_SCARE_FRIENDS )
{
// buckshot has only a 1 in 2 chance of applying a suppression point
if ( !(pBullet->usFlags & BULLET_FLAG_BUCKSHOT) || Random( 2 ) )
@@ -4915,7 +4948,7 @@ void MoveBullet( INT32 iBullet )
// 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)))
|| ((gGameExternalOptions.ubRealisticTracers > 0 && gGameExternalOptions.ubNumBulletsPerTracer > 0 && pBullet->fTracer == TRUE) || (gGameExternalOptions.ubRealisticTracers == 0 && fTracer == TRUE)))
{
INT8 bStepsPerMove = STEPS_FOR_BULLET_MOVE_TRAILS;
@@ -5205,7 +5238,7 @@ void MoveBullet( INT32 iBullet )
// 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)))
|| ((gGameExternalOptions.ubRealisticTracers > 0 && gGameExternalOptions.ubNumBulletsPerTracer > 0 && pBullet->fTracer == TRUE) || (gGameExternalOptions.ubRealisticTracers == 0 && fTracer == TRUE)))
{
INT8 bStepsPerMove = STEPS_FOR_BULLET_MOVE_TRAILS;
+32 -8
View File
@@ -8,6 +8,8 @@
#include "stdlib.h"
#include "debug.h"
//#include "soldier control.h"
// HEADROCK HAM 3.5: Strange that this wasn't included.
#include "GameSettings.h"
#include "weapons.h"
#include "handle items.h"
#include "worlddef.h"
@@ -39,6 +41,8 @@
#include "Dialogue Control.h"
#include "Music Control.h"
#include "Tactical Save.h"
// HEADROCK HAM 3.5: Need this to see if enemies present at starting sector
#include "Overhead.h"
#endif
@@ -476,7 +480,8 @@ void HandleHeliDrop( )
{
// Add merc to sector
MercPtrs[ gusHeliSeats[ cnt ] ]->ubStrategicInsertionCode = INSERTION_CODE_NORTH;
UpdateMercInSector( MercPtrs[ gusHeliSeats[ cnt ] ], startingX, startingY, startingZ );
// HEADROCK HAM 3.5: Externalized!
UpdateMercInSector( MercPtrs[ gusHeliSeats[ cnt ] ], gGameExternalOptions.ubDefaultArrivalSectorX, gGameExternalOptions.ubDefaultArrivalSectorY, startingZ );
// Check for merc arrives quotes...
HandleMercArrivesQuotes( MercPtrs[ gusHeliSeats[ cnt ] ] );
@@ -612,7 +617,8 @@ void HandleHeliDrop( )
// Change insertion code
MercPtrs[ gusHeliSeats[ gbCurDrop ] ]->ubStrategicInsertionCode = INSERTION_CODE_NORTH;
UpdateMercInSector( MercPtrs[ gusHeliSeats[ gbCurDrop ] ], startingX, startingY, startingZ );
// HEADROCK HAM 3.5: Externalized!
UpdateMercInSector( MercPtrs[ gusHeliSeats[ gbCurDrop ] ], gGameExternalOptions.ubDefaultArrivalSectorX, gGameExternalOptions.ubDefaultArrivalSectorY, startingZ );
//EVENT_SetSoldierPosition( MercPtrs[ gusHeliSeats[ gbCurDrop ] ], sWorldX, sWorldY );
// IF the first guy down, set squad!
@@ -777,6 +783,11 @@ void HandleHeliDrop( )
// End
fFadingHeliOut = TRUE;
// HEADROCK HAM 3.5: Update now, in case the LZ is still in a "RED" airspace sector. This is only
// required if the sector is free of enemies... but still required. Will run immediately after the
// helicopter is gone.
UpdateAirspaceControl( );
break;
}
@@ -812,13 +823,25 @@ void HandleFirstHeliDropOfGame( )
CallAvailableEnemiesTo( gsGridNoSweetSpot );
// Move to header file...
AddExtraItems( startingX, startingY, startingZ, true );
// HEADROCK HAM 3.5: Externalized!
AddExtraItems( gGameExternalOptions.ubDefaultArrivalSectorX, gGameExternalOptions.ubDefaultArrivalSectorY, startingZ, true );
// Say quote.....
SayQuoteFromAnyBodyInSector( QUOTE_ENEMY_PRESENCE );
// Start music
SetMusicMode( MUSIC_TACTICAL_ENEMYPRESENT );
// HEADROCK HAM 3.5: Starting sector externalized - might not contain enemies at all!
if (NumEnemyInSector( ) > 0)
//if ( NumEnemiesInAnySector( gWorldSectorX, gWorldSectorY, 0 ) > 0 )
{
// Say quote.....
SayQuoteFromAnyBodyInSector( QUOTE_ENEMY_PRESENCE );
// Start music
SetMusicMode( MUSIC_TACTICAL_ENEMYPRESENT );
}
else
{
// Say quote.....
SayQuoteFromAnyBodyInSector( QUOTE_MERC_REACHED_DESTINATION );
// Start music
SetMusicMode( MUSIC_TACTICAL_NOTHING );
}
gfFirstHeliRun = FALSE;
@@ -826,6 +849,7 @@ void HandleFirstHeliDropOfGame( )
// Send message to turn on ai again....
CharacterDialogueWithSpecialEvent( 0, 0, 0, DIALOGUE_TACTICAL_UI , FALSE , FALSE , DIALOGUE_SPECIAL_EVENT_ENABLE_AI ,0, 0 );
}
+17 -12
View File
@@ -78,8 +78,9 @@ extern BOOLEAN gfFirstHeliRun;
// ATE: Globals that dictate where the mercs will land once being hired
// Default to Omerta
// Saved in general saved game structure
INT16 gsMercArriveSectorX = 9;
INT16 gsMercArriveSectorY = 1;
// HEADROCK HAM 3.5: Externalized coordinates
INT16 gsMercArriveSectorX = gGameExternalOptions.ubDefaultArrivalSectorX;
INT16 gsMercArriveSectorY = gGameExternalOptions.ubDefaultArrivalSectorY;
void CheckForValidArrivalSector( );
@@ -317,16 +318,20 @@ void MercArrivesCallback( UINT8 ubSoldierID )
if (!is_networked)
{
// hayden - maybe you want to duke it out in omerta ;)
if( !DidGameJustStart() && gsMercArriveSectorX == 9 && gsMercArriveSectorY == 1 )
{
//Mercs arriving in A9. This sector has been deemed as the always safe sector.
//Seeing we don't support entry into a hostile sector (except for the beginning),
//we will nuke any enemies in this sector first.
if( gWorldSectorX != 9 || gWorldSectorY != 1 || gbWorldSectorZ )
{
EliminateAllEnemies( (UINT8)gsMercArriveSectorX, (UINT8)gsMercArriveSectorY );
}
}
// HEADROCK HAM 3.5: Externalized starting (safe) sector
// HEADROCK HAM 3.5: Actually, this is really ridiculous. Why should enemies at the LZ be eliminated at all?
// I'm taking the initiative and removing this from the code. Mainly because it ends up interfering with
// externalized LZs combined with other features like "Always Real Time" and "Forced Turn Based".
//if( !DidGameJustStart() && gsMercArriveSectorX == gGameExternalOptions.ubDefaultArrivalSectorX && gsMercArriveSectorY == gGameExternalOptions.ubDefaultArrivalSectorY )
// {
// //Mercs arriving in A9. This sector has been deemed as the always safe sector.
// //Seeing we don't support entry into a hostile sector (except for the beginning),
// //we will nuke any enemies in this sector first.
// if( gWorldSectorX != gGameExternalOptions.ubDefaultArrivalSectorX || gWorldSectorY != gGameExternalOptions.ubDefaultArrivalSectorY || gbWorldSectorZ )
// {
// EliminateAllEnemies( (UINT8)gsMercArriveSectorX, (UINT8)gsMercArriveSectorY );
// }
// }
}
// This will update ANY soldiers currently schedules to arrive too
+39 -2
View File
@@ -21,6 +21,8 @@
#include "mapscreen.h"
#include "Soldier macros.h"
#include "Event Pump.h"
// HEADROCK HAM 3.5: Added for facility effect on morale
#include "Facilities.h"
#endif
#include "connect.h"
@@ -137,14 +139,19 @@ void DecayTacticalMorale( SOLDIERTYPE * pSoldier )
void DecayStrategicMorale( SOLDIERTYPE * pSoldier )
{
// HEADROCK HAM 3.5: Strategic Morale Mod no longer normalizes to 0 by default. In fact, a local facility can
// cause normalization to another value (positive or negative!), based on the activity that the character is
// currently performing. It can literally reduce morale to ridiculously low amounts if you don't watch your
// assignments in some sectors.
// decay the modifier!
if (pSoldier->aiData.bStrategicMoraleMod > 0)
{
pSoldier->aiData.bStrategicMoraleMod = __max( 0, pSoldier->aiData.bStrategicMoraleMod - (8 - pSoldier->aiData.bStrategicMoraleMod / 10) );
pSoldier->aiData.bStrategicMoraleMod = __max( 0, pSoldier->aiData.bStrategicMoraleMod - (8 - (pSoldier->aiData.bStrategicMoraleMod / 10)) );
}
else
{
pSoldier->aiData.bStrategicMoraleMod = __min( 0, pSoldier->aiData.bStrategicMoraleMod + (6 + pSoldier->aiData.bStrategicMoraleMod / 10) );
pSoldier->aiData.bStrategicMoraleMod = __min( 0, pSoldier->aiData.bStrategicMoraleMod + (6 + (pSoldier->aiData.bStrategicMoraleMod / 10)) );
}
}
@@ -295,6 +302,36 @@ void RefreshSoldierMorale( SOLDIERTYPE * pSoldier )
iActualMorale = __min( 100, iActualMorale );
iActualMorale = __max( 0, iActualMorale );
UINT8 ubMaxMorale = 100;
// HEADROCK HAM 3.5: Local facilities may decrease the total morale allowed.
for (UINT16 cnt = 0; cnt < NUM_FACILITY_TYPES; cnt++)
{
if (gFacilityLocations[SECTOR(pSoldier->sSectorX, pSoldier->sSectorY)][cnt].fFacilityHere)
{
if (cnt == (UINT16)pSoldier->sFacilityTypeOperated && // Soldier is operating this facility
GetSoldierFacilityAssignmentIndex( pSoldier ) != -1)
{
UINT8 ubFacilityType = (UINT8)cnt;
UINT8 ubAssignmentType = GetSoldierFacilityAssignmentIndex( pSoldier );
// Check this facility both for an assignment-specific AND ambient value. Use it if it's the lowest
// encountered yet.
ubMaxMorale = __min(ubMaxMorale, (UINT8)GetFacilityModifier(FACILITY_MAX_MORALE, ubFacilityType, ubAssignmentType ));
}
else // Soldier is not operating this facility
{
// Check this facility for an AMBIENT Maximum Morale limit. Use it if it's the lowest encountered yet.
ubMaxMorale = __min(ubMaxMorale, (UINT8)GetFacilityModifier(FACILITY_MAX_MORALE, (UINT8)cnt, FAC_AMBIENT));
}
}
}
if (ubMaxMorale > 0 && iActualMorale > ubMaxMorale)
{
// Normalize to Max Morale
iActualMorale = (iActualMorale + ubMaxMorale) / 2;
}
pSoldier->aiData.bMorale = (INT8) iActualMorale;
// update mapscreen as needed
+3 -2
View File
@@ -265,8 +265,9 @@ enum WorldDirections
// Starting Sector
const int startingX = 9;
const int startingY = 1;
// HEADROCK HAM 3.5: Externalized.
//UINT8 startingX = 9;
//UINT8 startingY = 1;
const int startingZ = 0;
+309 -168
View File
@@ -180,6 +180,8 @@ void HandleEndDemoInCreatureLevel( );
void DeathTimerCallback( void );
void CaptureTimerCallback( void );
// HEADROCK HAM 3.6: Define now.
void MilitiaChangesSides( void );
extern void CheckForAlertWhenEnemyDies( SOLDIERTYPE * pDyingSoldier );
extern void PlaySoldierFootstepSound( SOLDIERTYPE *pSoldier );
@@ -2224,6 +2226,22 @@ BOOLEAN HandleGotoNewGridNo( SOLDIERTYPE *pSoldier, BOOLEAN *pfKeepMoving, BOOLE
// better stop and reconsider what to do...
SetNewSituation( pSoldier );
ActionDone( pSoldier );
// HEADROCK HAM 3.6: Militia can now place flags when they spot landmines.
if (gGameExternalOptions.fMilitiaPlaceBlueFlags &&
pSoldier->bTeam == MILITIA_TEAM)
{
// This line causes the screen to focus on the gridno if it is not currently visible.
// Is it desirable when militia spot mines? Probably not. Turned off for now.
//LocateGridNo( sMineGridNo );
// Flash gridno
ITEM_POOL *pItemPool = NULL;
GetItemPool( sMineGridNo, &pItemPool, 0 );
SetItemPoolLocator( pItemPool );
// Add flag
AddBlueFlag(sMineGridNo,1);
}
}
}
}
@@ -3593,7 +3611,17 @@ void HandleNPCTeamMemberDeath( SOLDIERTYPE *pSoldierOld )
if ( pSoldierOld->ubAttackerID != NOBODY )
{
// also treat this as murder - but player will never be blamed for militia death he didn't cause
HandleMurderOfCivilian( pSoldierOld, pSoldierOld->flags.fIntendedTarget );
// HEADROCK HAM 3.6: Actually this function never runs for militia (see function for details)
//HandleMurderOfCivilian( pSoldierOld, pSoldierOld->flags.fIntendedTarget );
// HEADROCK HAM 3.6: INI setting can cause militia to turn ONLY of they are killed intentionally
if (pSoldierOld->flags.fIntendedTarget // Must be intentional
&& gGameExternalOptions.ubCanMilitiaBecomeHostile > 0 // INI setting
&& pSoldierOld->bSide == gbPlayerNum // Must not be hostile by now
)
{
MilitiaChangesSides(); // Militia turn on you.
}
}
HandleGlobalLoyaltyEvent( GLOBAL_LOYALTY_NATIVE_KILLED, gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
@@ -3854,7 +3882,12 @@ void MakeCivHostile( SOLDIERTYPE *pSoldier, INT8 bNewSide )
}
if ( pSoldier->aiData.bNeutral )
{
SetSoldierNonNeutral( pSoldier );
// HEADROCK HAM 3.6: INI Setting decides whether non-combat civs can become hostile
if (gGameExternalOptions.fCanTrueCiviliansBecomeHostile ||
!IS_CIV_BODY_TYPE(pSoldier))
{
SetSoldierNonNeutral( pSoldier );
}
RecalculateOppCntsDueToNoLongerNeutral( pSoldier );
}
}
@@ -3979,6 +4012,13 @@ SOLDIERTYPE * CivilianGroupMemberChangesSides( SOLDIERTYPE * pAttacked )
gTacticalStatus.fCivGroupHostile[ pNewAttacked->ubCivilianGroup ] = CIV_GROUP_WILL_EVENTUALLY_BECOME_HOSTILE;
}
// HEADROCK HAM 3.6: If this sector has affiliated bloodcats, make them all hostile.
if ( gBloodcatPlacements[SECTOR(pNewAttacked->sSectorX,pNewAttacked->sSectorY)][0].PlacementType == BLOODCAT_PLACEMENT_STATIC &&
gBloodcatPlacements[SECTOR(pNewAttacked->sSectorX,pNewAttacked->sSectorY)][ gGameOptions.ubDifficultyLevel-1 ].ubFactionAffiliation == pNewAttacked->ubCivilianGroup )
{
MakeBloodcatsHostile();
}
return( pNewAttacked );
}
@@ -6203,26 +6243,27 @@ void DeathNoMessageTimerCallback( void )
}
}
// HEADROCK HAM 3.5: This function needs a Z-Level argument!!! It is screwing up garrisons, when a battle is won underneath
// a sector.
void RemoveStaticEnemiesFromSectorInfo( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
{
if (!bMapZ) // Battle ended Above-ground
{
SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR( sMapX, sMapY ) ] );
if (!bMapZ) // Battle ended Above-ground
{
SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR( sMapX, sMapY ) ] );
pSectorInfo->ubNumAdmins = pSectorInfo->ubNumTroops = pSectorInfo->ubNumElites = 0;
pSectorInfo->ubAdminsInBattle = pSectorInfo->ubTroopsInBattle = pSectorInfo->ubElitesInBattle = 0;
}
else
{
UNDERGROUND_SECTORINFO *pSectorInfo;
pSectorInfo = FindUnderGroundSector( sMapX, sMapY, bMapZ );
pSectorInfo->ubNumAdmins = pSectorInfo->ubNumTroops = pSectorInfo->ubNumElites = 0;
pSectorInfo->ubAdminsInBattle = pSectorInfo->ubTroopsInBattle = pSectorInfo->ubElitesInBattle = 0;
}
pSectorInfo->ubNumAdmins = pSectorInfo->ubNumTroops = pSectorInfo->ubNumElites = 0;
pSectorInfo->ubAdminsInBattle = pSectorInfo->ubTroopsInBattle = pSectorInfo->ubElitesInBattle = 0;
}
else
{
UNDERGROUND_SECTORINFO *pSectorInfo;
pSectorInfo = FindUnderGroundSector( sMapX, sMapY, bMapZ );
pSectorInfo->ubNumAdmins = pSectorInfo->ubNumTroops = pSectorInfo->ubNumElites = 0;
pSectorInfo->ubAdminsInBattle = pSectorInfo->ubTroopsInBattle = pSectorInfo->ubElitesInBattle = 0;
}
}
//!!!!
//IMPORTANT NEW NOTE:
//Whenever returning TRUE, make sure you clear gfBlitBattleSectorLocator;
@@ -6383,6 +6424,9 @@ BOOLEAN CheckForEndOfBattle( BOOLEAN fAnEnemyRetreated )
}
// Kill all enemies. Sometime even after killing all the enemies, there appeares "in battle" enemies in sector info
// HEADROCK HAM 3.5: This has to take Z-Level into account, otherwise winning a battle underground will kill all
// enemies in the sector above! We still need to run the function though, to prevent confusions with the
// strategic screen, which is what it was doing only for aboveground. UNTIL NOW, muahaha.
RemoveStaticEnemiesFromSectorInfo( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
@@ -7221,15 +7265,20 @@ INT8 CalcSuppressionTolerance( SOLDIERTYPE * pSoldier )
}
}
if (bTolerance < gGameExternalOptions.iSuppressionToleranceMin)
// HEADROCK HAM 3.2: This is actually a feature from HAM 2.9. It adds bonuses/penalties for nearby friends.
if (gGameExternalOptions.fFriendliesAffectTolerance)
{
bTolerance = gGameExternalOptions.iSuppressionToleranceMin;
bTolerance += CheckStatusNearbyFriendlies( pSoldier );
}
if (bTolerance > gGameExternalOptions.iSuppressionToleranceMax)
// HEADROCK HAM 3.3: Moving rapidly makes one less prone to suppression.
if (gGameExternalOptions.ubTilesMovedPerBonusTolerancePoint > 0)
{
bTolerance = gGameExternalOptions.iSuppressionToleranceMax;
bTolerance += pSoldier->bTilesMoved / gGameExternalOptions.ubTilesMovedPerBonusTolerancePoint;
}
bTolerance = __max(bTolerance, gGameExternalOptions.ubSuppressionToleranceMin);
bTolerance = __min(bTolerance, gGameExternalOptions.ubSuppressionToleranceMax);
return( bTolerance );
}
@@ -7239,163 +7288,154 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
///////////////////////////////////////////////////////////////////////////////
//
// HEADROCK HAM B2: This entire function has been completely revamped.
// HEADROCK HAM 3.5: Revamped again.
//
///////////////////////////////////////////////////////////////////////////////
// External options.
BOOLEAN APS_SUPPRESSED = gGameExternalOptions.fSuppressionAPLossPerAttack;
BOOLEAN APS_SUPPRESSED_TOTAL = gGameExternalOptions.fSuppressionAPLossPerTurn;
//INT8 SUPPRESSION_AP_LIMIT = gGameExternalOptions.iMinAPLimitFromSuppression;
INT8 MAXIMUM_SUPPRESSION_SHOCK = gGameExternalOptions.iMaxSuppressionShock;
INT8 bTolerance;
INT16 sClosestOpponent, sClosestOppLoc;
UINT8 ubPointsLost, ubTotalPointsLost, ubNewStance;
UINT32 uiLoop;
// This function runs after very attack is completed. It calculates the number
// of "Suppression Points" any character has received during the attack, and
// inflicts various penalties accordingly.
// The most important result of this function is AP loss.
SOLDIERTYPE * pSoldier;
INT8 bTolerance;
INT16 sClosestOpponent, sClosestOppLoc;
UINT8 ubPointsLost, ubNewStance;
UINT32 uiLoop;
UINT8 ubLoop2;
// Flag to determine if the target is cowering (if allowed)
BOOLEAN fCower;
SOLDIERTYPE * pSoldier;
BOOLEAN fCower;
// External options
// JA2_OPTIONS.INI
INT8 MAXIMUM_SUPPRESSION_SHOCK = gGameExternalOptions.ubMaxSuppressionShock;
// APBPConstants.INI
UINT16 usLimitSuppressionAPsLostPerAttack = APBPConstants[AP_MAX_SUPPRESSED];
UINT16 usLimitSuppressionAPsLostPerTurn = APBPConstants[AP_MAX_TURN_SUPPRESSED];
//HEADROCK HAM 3.5: Ratio between AP Loss and Suppression Shock
UINT16 uiShockPerAPLossDivisor = APBPConstants[AP_SUPPRESSION_SHOCK_DIVISOR];
// Loop through every character.
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
{
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: loop = %d, numslots = %d ",uiLoop, guiNumMercSlots));
pSoldier = MercSlots[uiLoop];
// Has this character received any Suppression Points since the last attack?
// HEADROCK: Suppression Points accumulate by bullets flying near the character. It includes
// friendly fire at a certain distance. As of HAM 3.2, it also happens with nearby explosions.
// The number of points accumulated resets to 0 at the end of this function.
if (pSoldier && IS_MERC_BODY_TYPE( pSoldier) && pSoldier->stats.bLife >= OKLIFE && pSoldier->ubSuppressionPoints > 0)
{
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: soldier id = %d, life = %d, suppression points = %d",pSoldier->ubID,pSoldier->stats.bLife, pSoldier->ubSuppressionPoints));
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: calc suppression tolerance"));
// Calculate the character's tolerance to suppression. Helps reduce the severity of the penalties inflicted
// during this function.
bTolerance = CalcSuppressionTolerance( pSoldier );
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: figure out aps lost"));
// multiply by 2, add 1 and divide by 2 to round off to nearest whole number
// HEADROCK: Note that suppression points accumulate by bullets flying near the character. It includes
// friendly fire at a certain distance. Also note that it may be reset either each attack or each turn
// (based on new INI settings), which has a small effect on how suppression builds up (but nothing
// major).
// This formula gives a linear increase in AP loss relative to Suppression Points. The most Suppression
// Points we have, the most APs we're going to lose. Tolerance mitigates this by making the graph angle
// more shallow.
// The relation between AP Loss and Suppression Points is LINEAR.
ubPointsLost = ( ( (pSoldier->ubSuppressionPoints * APBPConstants[AP_SUPPRESSION_MOD]) / (bTolerance + 6) ) * 2 + 1 ) / 2;
// HEADROCK HAM Beta 2.2: SuppressionEffectiveness acts as a percentage for the number of lost APs.
ubPointsLost = ( ubPointsLost * gGameExternalOptions.iSuppressionEffectiveness ) / 100;
// INI-Controlled intensity. SuppressionEffectiveness acts as a percentage applied to the number of lost APs.
// To turn off the entire Suppression system, simply set the INI value to 0. (0% AP Loss)
// The default is obviously 100%. You can increase or decrease it, at will.
// PLEASE NOTE that AP loss governs ALL OTHER SUPPRESSION EFFECTS.
ubPointsLost = ( ubPointsLost * gGameExternalOptions.sSuppressionEffectiveness ) / 100;
// reduce loss of APs based on stance
// ATE: Taken out because we can possibly supress ourselves...
//switch (gAnimControl[ pSoldier->usAnimState ].ubEndHeight)
//{
// case ANIM_PRONE:
// ubPointsLost = ubPointsLost * 2 / 4;
// break;
// case ANIM_CROUCH:
// ubPointsLost = ubPointsLost * 3 / 4;
// break;
// default:
// break;
//}
// cap the # of APs we can lose
// HEADROCK HAM B2: This now reads an external value. 0 means no limit.
if (APS_SUPPRESSED == TRUE)
// This is an upper cap for the number of APs we can lose per attack.
if (usLimitSuppressionAPsLostPerAttack > 0)
{
if (ubPointsLost > APBPConstants[AP_MAX_SUPPRESSED])
if (ubPointsLost > usLimitSuppressionAPsLostPerAttack)
{
ubPointsLost = (UINT8)APBPConstants[AP_MAX_SUPPRESSED];
ubPointsLost = __max(255,(UINT8)usLimitSuppressionAPsLostPerAttack);
}
}
// HEADROCK HAM B2: This makes sure that we never lose more APs than we're allowed per turn,
if (APS_SUPPRESSED_TOTAL = TRUE)
// This makes sure that we never lose more APs than we're allowed per turn.
if (usLimitSuppressionAPsLostPerTurn > 0)
{
if (pSoldier->ubAPsLostToSuppression + ubPointsLost > APBPConstants[AP_MAX_TURN_SUPPRESSED])
{
ubPointsLost = APBPConstants[AP_MAX_TURN_SUPPRESSED] - pSoldier->ubAPsLostToSuppression;
ubPointsLost = usLimitSuppressionAPsLostPerTurn - pSoldier->ubAPsLostToSuppression;
}
}
// Keeps a number for later reference
ubTotalPointsLost = ubPointsLost;
// Make sure we're suffering extra AP loss at all. If the number of APs we're supposed to lose now
// is equal/higher to the number of APs we've already lost, it means we haven't actually gained any
// suppression. This is very important, as this function runs EVERY TIME an attack, ANY attack, ends.
// If the soldier hasn't suffered suppression since the last time this check ran, we'll hit the
// "continue" command. Note that with a certain INI setting, this value is reset after each attack
// or after each turn, but overall the function acts the same in both cases.
if (pSoldier->ubAPsLostToSuppression >= ubPointsLost)
{
continue;
}
// APs actually lost will be the difference between the potential loss and the APs we've already lost
// so far. Would theoretically equal 0 if we haven't suffered sufficient extra suppression this turn to
// cause any AP loss, but then we would've already hit the "continue" command, above.
ubPointsLost -= pSoldier->ubAPsLostToSuppression;
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: check for morale effects"));
// HEADROCK HAM B2: This nifty little bit gives suppression an "extra kick". Soldiers affected by
// suppression (I.E. lost APs) will also suffer from SHOCK. This is similar to getting shot but
// without the health/stamina loss - the soldier will lose 5% CTH for every point of shock they suffer.
// Shock is sliced in half at the start of every turn. Also note that shock may cause "cowering", and
// may also reduce any attacker's aim as well!
if (gGameExternalOptions.fSuppressionShock)
// This nifty little bit gives suppression an "extra kick". Soldiers affected by suppression (I.E. lost APs)
// will also suffer from SHOCK. As shock accumulates, the soldier becomes less accurate and may find it
// difficult to perform certain manual tasks. Additionally, he also becomes harder to hit, because the fear
// causes him to hide as best as he can from incoming fire.
// Shock is sliced in half at the start of every turn. Also note that shock may cause "cowering" (see below).
if (gGameExternalOptions.usSuppressionShockEffect > 0)
{
// Can't get shock if we haven't lost APs.
if (ubPointsLost > 0)
{
// Experienced and/or high-morale soldiers suffer less shock than others.
INT8 bShockValue, bShockLimit;
bShockLimit = MAXIMUM_SUPPRESSION_SHOCK - bTolerance;
// the amount of shock received depends mainly on how many APs we've lost. 8 here is arbitrary,
// as the shock loss can later be adjusted by the external modifier below.
bShockValue = (bShockLimit * ubPointsLost) / 8;
// Limit defined by INI.
bShockLimit = MAXIMUM_SUPPRESSION_SHOCK;
// The amount of shock received depends on how many APs we've lost - Every AP lost will cause one
// point of shock. This is then divided by 4 if using the 100AP system.
bShockValue = ubPointsLost / uiShockPerAPLossDivisor;
if (bShockValue < 0)
bShockValue = 0;
if (bShockLimit < 0)
bShockLimit = 0;
bShockValue = __max(0,bShockValue);
bShockLimit = __max(0,bShockLimit);
// use external value to determine how effective SHOCK really is.
bShockValue = (bShockValue * gGameExternalOptions.iSuppressionShockEffectiveness) / 100;
bShockValue = (bShockValue * gGameExternalOptions.usSuppressionShockEffect) / 100;
// Make sure total shock doesn't go TOO high. Maximum is around 30 (for a CTH effect of -150!),
// including previous shock from suppression and/or wounds. The Maximum is mitigated by
// the character's experience and morale. The shock value can bump above that level
// momentarily, for particularily lousy characters, rendering them practically incapable of firing
// back effectively... But of course, it is halved once the character starts his next turn, so
// shock at turnstart will usually be no higher than 15.
// Make sure total shock doesn't go TOO high. Maximum is around 30, including previous shock
// from suppression and/or wounds. It is possible to breach the maximum after a good suppressive
// attack.
if ( pSoldier->aiData.bShock + bShockValue <= bShockLimit )
{
// Shock limit not yet breached. Add shock to character.
pSoldier->aiData.bShock += bShockValue;
pSoldier->aiData.bShock = __min(127, pSoldier->aiData.bShock + bShockValue);
}
else if ( pSoldier->aiData.bShock < bShockLimit ) // Shock limit will be breached.
{
// Original shock was lower than the limit, so add extra shock and breach the limit.
pSoldier->aiData.bShock += bShockValue;
pSoldier->aiData.bShock = __min(127, pSoldier->aiData.bShock + bShockValue);
}
// Else, original shock was already over the limit. No more shock is added.
}
}
// HEADROCK: Untrained characters won't react well to being fired at (they'll keep standing), but if
// Suppression Shock is activated, they may dive and "COWER" anyway. For this to happen, they must first
// make a check to see if they are in enough shock to cower.
// HEADROCK: Cowering is the panic that grips a character due to suffering too much suppression shock. If
// enough shock has been accumulated, the soldier goes into this panic. Generally, cowering will cause
// the character to drop a stance if he can, overriding other conditions for a stance-change (see below).
// Cowering characters may become considerably easier to suppress with additional firepower. In other
// words, if you're cowering, you've effectively turned from a bad-ass to a wimp.
fCower = false;
if ( gGameExternalOptions.fSuppressionShock && gGameExternalOptions.iAimPenaltyPerTargetShock > 0 )
if ( gGameExternalOptions.usSuppressionShockEffect > 0 )
{
if (pSoldier->aiData.bShock >= bTolerance)
{ fCower = true; }
{
fCower = true;
// If cowering, increase suppression effectiveness by external percentage. If the setting is
// over 100%, then the condition of cowering makes the character even MORE susceptible to suppression.
if (gGameExternalOptions.usCowerEffectOnSuppression > 0)
ubPointsLost = (ubPointsLost * gGameExternalOptions.usCowerEffectOnSuppression) / 100;
// If soldier is visible on-screen, report to player that they are cowering.
if ( pSoldier->bVisible != -1 )
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113HAMMessage[0], pSoldier->name );
}
}
// HEADROCK HAM B2: If enemy cowers in fear, let the player know.
if (fCower)
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113HAMMessage[0], pSoldier->name );
// If cowering, increase suppression effectiveness by external percentage
if (gGameExternalOptions.iCowerEffectOnSuppression > 0)
ubPointsLost = (ubPointsLost * gGameExternalOptions.iCowerEffectOnSuppression) / 100;
}
// morale modifier
// For every 2 APs lost, subtract morale by a certain value.
// HEADROCK: Modified - now externalized to INI.
// Suppression reduces morale. For every X APs lost, morale goes down by a point. X is defined by INI.
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: check for morale effects"));
if (APBPConstants[AP_LOST_PER_MORALE_DROP] > 0 && ubPointsLost > 0)
{
for ( ubLoop2 = 0; ubLoop2 < (ubPointsLost / APBPConstants[AP_LOST_PER_MORALE_DROP]); ubLoop2++ )
@@ -7408,34 +7448,24 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
ubNewStance = 0;
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: check for reaction"));
// merc may get to react
// Headrock: apply suppression effectiveness percentage to this value.
if ( (pSoldier->ubSuppressionPoints * gGameExternalOptions.iSuppressionEffectiveness) / 100 >= ( 130 / (6 + bTolerance) ) || fCower )
// HEADROCK HAM 3.5: Characters who have enough APs to drop WILL DROP. This is strictly for survival reasons,
// because upright characters can easily get themselves killed. Soldiers drop stance for "free", using up
// the APs that they've just lost to do so.
switch (gAnimControl[ pSoldier->usAnimState ].ubEndHeight)
{
// merc gets to use APs to react!
switch (gAnimControl[ pSoldier->usAnimState ].ubEndHeight)
{
case ANIM_PRONE:
// can't change stance below prone!
break;
case ANIM_CROUCH:
if (ubTotalPointsLost >= APBPConstants[AP_PRONE] && IsValidStance( pSoldier, ANIM_PRONE ) )
if (ubPointsLost >= APBPConstants[AP_PRONE] && IsValidStance( pSoldier, ANIM_PRONE ) && gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_PRONE )
{
sClosestOpponent = ClosestKnownOpponent( pSoldier, &sClosestOppLoc, NULL );
// HEADROCK: Added cowering.
if (sClosestOpponent == NOWHERE || SpacesAway( pSoldier->sGridNo, sClosestOppLoc ) > 8 || fCower)
{
if (ubPointsLost < APBPConstants[AP_PRONE])
{
// Have to give APs back so that we can change stance without
// losing more APs
pSoldier->bActionPoints += (APBPConstants[AP_PRONE] - ubPointsLost);
ubPointsLost = 0;
}
else
{
ubPointsLost -= APBPConstants[AP_PRONE];
}
ubPointsLost -= APBPConstants[AP_PRONE];
ubNewStance = ANIM_PRONE;
}
}
@@ -7446,7 +7476,7 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
// can't change stance here!
break;
}
else if (ubTotalPointsLost >= (APBPConstants[AP_CROUCH] + APBPConstants[AP_PRONE]) && ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_PRONE ) && IsValidStance( pSoldier, ANIM_PRONE ) )
else if (ubPointsLost >= (APBPConstants[AP_CROUCH] + APBPConstants[AP_PRONE]) && ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_PRONE ) && IsValidStance( pSoldier, ANIM_PRONE ) )
{
sClosestOpponent = ClosestKnownOpponent( pSoldier, &sClosestOppLoc, NULL );
// HEADROCK: Added cowering.
@@ -7469,19 +7499,40 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
ubNewStance = ANIM_CROUCH;
}
}
else if ( ubTotalPointsLost >= APBPConstants[AP_CROUCH] && ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_CROUCH ) && IsValidStance( pSoldier, ANIM_CROUCH ) )
else if ( ubPointsLost >= APBPConstants[AP_CROUCH] && ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_CROUCH ) && IsValidStance( pSoldier, ANIM_CROUCH ) )
{
// crouch!
ubNewStance = ANIM_CROUCH;
}
break;
}
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: reduce action points"));
// HEADROCK HAM 3.1: If this setting is enabled, it will show an on-screen message that tells us the
// character has lost his entire next turn. This only fires once per turn, the moment a character drops
// to the minimum AP limit.
if (gGameExternalOptions.fShowSuppressionShutdown)
{
// If we're about the hit the lower limit
if (pSoldier->bActionPoints > APBPConstants[AP_MIN_LIMIT] && pSoldier->bActionPoints - ubPointsLost <= APBPConstants[AP_MIN_LIMIT])
{
// And soldier is visible
if ( pSoldier->bVisible != -1 )
{
// "Soldier is pinned down!"
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113HAMMessage[1], pSoldier->name );
// HEADROCK HAM 3.2: Added a radio locator!
ShowRadioLocator( (UINT8)pSoldier->ubID, SHOW_LOCATOR_NORMAL );
}
}
}
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: reduce action points"));
// Reduce action points!
// HEADROCK HAM Beta 2.2: Enforce a minimum limit via INI.
if (pSoldier->bActionPoints - ubPointsLost < APBPConstants[AP_MIN_LIMIT] )
if (pSoldier->bActionPoints - ubPointsLost <= APBPConstants[AP_MIN_LIMIT] )
{
pSoldier->bActionPoints = APBPConstants[AP_MIN_LIMIT];
}
@@ -7492,7 +7543,7 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
// Remember how many APs were lost. This prevents us from losing more and more APs without receiving
// extra suppression. Note that a specific HAM setting will reset this value after every attack,
// but also resets ubSuppressionPoints.
pSoldier->ubAPsLostToSuppression = ubTotalPointsLost;
pSoldier->ubAPsLostToSuppression = __min(255, pSoldier->ubAPsLostToSuppression + ubPointsLost);
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: check for quote"));
if ( (pSoldier->flags.uiStatusFlags & SOLDIER_PC) && (pSoldier->ubSuppressionPoints > 8) && (pSoldier->ubID == ubTargetedMerc) )
@@ -7554,17 +7605,11 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
pSoldier->flags.fDontChargeAPsForStanceChange = TRUE;
}
// HEADROCK HAM B2: Optional fix for suppression. This clears up the value that measures suppression
// accumulated so far. Previously, the value was NEVER cleared, which means that a character could
// only be suppressed ONCE in the game (unless they die or get deleted).
// With the setting at "2", these two values are cleared every turn. Therefore, suppression doesn't
// accumulate at all, only its effects are cumulative. In the end, it functions almost the same as
// clearing every turn, but I added this as an alternative.
if (gGameExternalOptions.iClearSuppression == 2)
{
pSoldier->ubAPsLostToSuppression = 0;
pSoldier->ubSuppressionPoints = 0;
}
// HEADROCK HAM 3.5: After sufficient testing, suppression clearing now works immediately at the end of
// the attack. ubAPsLostToSuppression is only cleared at the end of the turn, but no longer plays a role
// in affecting the number of APs lost, so it is largely irrelevant now.
pSoldier->ubSuppressionPoints = 0;
} // end of examining one soldier
} // end of loop
@@ -7617,8 +7662,14 @@ BOOLEAN ProcessImplicationsOfPCAttack( SOLDIERTYPE * pSoldier, SOLDIERTYPE ** pp
if ( (pTarget->bTeam == MILITIA_TEAM) && (pTarget->bSide == gbPlayerNum) )
{
// rebel militia attacked by the player!
MilitiaChangesSides();
// HEADROCK HAM 3.6: INI setting controls their response
{
if (gGameExternalOptions.ubCanMilitiaBecomeHostile == 2)
{
// rebel militia attacked by the player!
MilitiaChangesSides();
}
}
}
// JA2 Gold: fix Slay
else if ( (pTarget->bTeam == CIV_TEAM && pTarget->aiData.bNeutral) && pTarget->ubProfile == SLAY && pTarget->stats.bLife >= OKLIFE && CheckFact( 155, 0 ) == FALSE )
@@ -7654,6 +7705,23 @@ BOOLEAN ProcessImplicationsOfPCAttack( SOLDIERTYPE * pSoldier, SOLDIERTYPE ** pp
}
}
}
else if (pTarget->bTeam == CREATURE_TEAM && pTarget->ubBodyType == BLOODCAT && pTarget->aiData.bNeutral)
{
// Attacked a bloodcat.
MakeBloodcatsHostile();
// Are bloodcats in this sector affiliated with a faction?
if ( gBloodcatPlacements[SECTOR(pTarget->sSectorX,pTarget->sSectorY)][0].PlacementType == BLOODCAT_PLACEMENT_STATIC &&
gBloodcatPlacements[SECTOR(pTarget->sSectorX,pTarget->sSectorY)][ gGameOptions.ubDifficultyLevel-1 ].ubFactionAffiliation > NON_CIV_GROUP )
{
// Temporarily change bloodcat's civilian group
UINT8 ubFaction = pTarget->ubCivilianGroup;
pTarget->ubCivilianGroup = gBloodcatPlacements[SECTOR(pTarget->sSectorX,pTarget->sSectorY)][ gGameOptions.ubDifficultyLevel-1 ].ubFactionAffiliation;
// Make entire faction hostile
CivilianGroupMembersChangeSidesWithinProximity( pTarget );
// Change back
pTarget->ubCivilianGroup = ubFaction;
}
}
else
{
if (pTarget->ubProfile == CARMEN)// Carmen
@@ -7692,6 +7760,14 @@ BOOLEAN ProcessImplicationsOfPCAttack( SOLDIERTYPE * pSoldier, SOLDIERTYPE ** pp
// Firing at a civ in a civ group who isn't hostile... if anyone in that civ group can see this
// going on they should become hostile.
CivilianGroupMembersChangeSidesWithinProximity( pTarget );
// HEADROCK HAM 3.6: If there are bloodcats affiliated with his group...
if ( gBloodcatPlacements[SECTOR(pTarget->sSectorX,pTarget->sSectorY)][0].PlacementType == BLOODCAT_PLACEMENT_STATIC &&
gBloodcatPlacements[SECTOR(pTarget->sSectorX,pTarget->sSectorY)][ gGameOptions.ubDifficultyLevel-1 ].ubFactionAffiliation == pTarget->ubCivilianGroup )
{
// Make them hostile.
MakeBloodcatsHostile();
}
}
else if ( pTarget->bTeam == gbPlayerNum && !(gTacticalStatus.uiFlags & INCOMBAT) )
{
@@ -8150,17 +8226,6 @@ SOLDIERTYPE *InternalReduceAttackBusyCount( )
pSoldier->flags.fGettingHit = FALSE;
}
// HEADROCK HAM B2: Optional fix for suppression. This clears up the value that measures suppression
// accumulated so far. Previously, the value was NEVER cleared, which means that a character could
// only be suppressed ONCE in the game (unless they die or get deleted).
// With the setting at "2", these two values are cleared every turn. Therefore, suppression doesn't
// accumulate at all, only its effects are cumulative. In the end, it functions almost the same as
// clearing every turn, but I added this as an alternative.
if (gGameExternalOptions.iClearSuppression == 2)
{
pSoldier->ubAPsLostToSuppression = 0;
pSoldier->ubSuppressionPoints = 0;
}
if (pSoldier->ubAttackerID != NOBODY )
{
if (pSoldier->ubPreviousAttackerID != pSoldier->ubAttackerID)
@@ -8822,3 +8887,79 @@ void RevealAllDroppedEnemyItems()
AllSoldiersLookforItems( TRUE );
}
// HEADROCK HAM 3.2: This function from HAM 2.9 makes a character look around himself and try to find friends. Dead
// friends lower the result, while more friends (ESP good leaders) will raise the result. The result can then be used
// for any purpose, although this was written specifically to alter a character's suppression tolerance.
INT8 CheckStatusNearbyFriendlies( SOLDIERTYPE *pSoldier )
{
SOLDIERTYPE * pLeader;
UINT8 sModifier = 0;
INT16 usEffectiveLeadership = 0;
UINT16 usEffectiveRangeToLeader = 0;
INT16 usBestLeader = 0;
INT16 usFriendBonus = 0;
// Run through each friendly.
for ( UINT8 iCounter = gTacticalStatus.Team[ pSoldier->bTeam ].bFirstID ; iCounter <= gTacticalStatus.Team[ pSoldier->bTeam ].bLastID ; iCounter ++ )
{
pLeader = MercPtrs[ iCounter ];
// Make sure that character is alive, not too shocked, and conscious, and of higher experience level
// than the character being suppressed.
if (pLeader != pSoldier && pLeader->bActive && pLeader->aiData.bShock < pLeader->stats.bLeadership/5 &&
pLeader->stats.bLife >= OKLIFE && pLeader->stats.bExpLevel >= pSoldier->stats.bExpLevel)
{
// Calculate character's leadership and range/3
usEffectiveLeadership = ((EffectiveLeadership( pLeader ) - 25) / 15);
usEffectiveRangeToLeader = PythSpacesAway( pSoldier->sGridNo, pLeader->sGridNo ) / 3;
// If leader is within range of his leadership stat
if (usEffectiveRangeToLeader <= usEffectiveLeadership+1)
{
// The difference in experience level is important!
usEffectiveLeadership += (pLeader->stats.bExpLevel - pSoldier->stats.bExpLevel);
// Reduce effective leadership with every 3 tiles of distance
usEffectiveLeadership -= usEffectiveRangeToLeader-1;
// If this is the best leader we've seen so far,
if (usEffectiveLeadership > usBestLeader)
{
// Set this as the best leader
usBestLeader = usEffectiveLeadership;
}
// Friends within range always give at least one tolerance bonus point.
usFriendBonus += 1;
}
}
// Incapacitated or heavily suppressed friends will not be good for our tolerance!
else if (pLeader != pSoldier && pLeader->bActive && (pLeader->aiData.bShock > pSoldier->aiData.bShock || pLeader->stats.bLife <= OKLIFE) )
{
usEffectiveRangeToLeader = PythSpacesAway( pSoldier->sGridNo, pLeader->sGridNo );
// If they are no more than 5 tiles away,
if (usEffectiveRangeToLeader <= 5)
{
// Penalty is based on the difference between experience levels, and the range between them,
// and is never less than 1 point.
usEffectiveLeadership = (pLeader->stats.bExpLevel - pSoldier->stats.bExpLevel) / __max(1,(usEffectiveRangeToLeader/2));
usFriendBonus -= __max(1, usEffectiveLeadership);
}
}
}
// If we did find someone who's a good enough leader to help us out,
if (usBestLeader > 0)
{
// Add his leadership bonus, minus the point we got for him before. He'll give at least one
// point, like anybody else.
usFriendBonus += __max(usBestLeader-1, 1);
}
// Add no more than five points for nearby friends.
usFriendBonus = __min(usFriendBonus, 5);
usFriendBonus = __max(usFriendBonus, -5);
sModifier += usFriendBonus;
return(sModifier);
}
+4
View File
@@ -318,6 +318,8 @@ BOOLEAN HandleGotoNewGridNo( SOLDIERTYPE *pSoldier, BOOLEAN *pfKeepMoving, BOOLE
SOLDIERTYPE * ReduceAttackBusyCount( );
// HEADROCK HAM B2.6: Made this public so it can be used elsewhere.
INT8 CalcSuppressionTolerance( SOLDIERTYPE * pSoldier );
// HEADROCK HAM 3.2: A new function for checking the condition of nearby friendlies and returning a modifier.
INT8 CheckStatusNearbyFriendlies( SOLDIERTYPE *pSoldier );
void CommonEnterCombatModeCode( );
@@ -374,4 +376,6 @@ extern BOOLEAN gogglewarning;
// will a sam site under the players control shoot down an airraid?
BOOLEAN WillAirRaidBeStopped( INT16 sSectorX, INT16 sSectorY );
// HEADROCK HAM 3.5: Externalized for First Arrival enemy check
extern UINT8 NumEnemyInSector();
#endif
+13 -13
View File
@@ -3358,7 +3358,7 @@ INT32 FindBestPath(SOLDIERTYPE *s , INT16 sDestination, INT8 ubLevel, INT16 usMo
case RUNNING:
case ADULTMONSTER_WALKING:
// save on casting
if((UsingNewInventorySystem() == true) && s->inv[BPACKPOCKPOS].exists() == true)
if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( s ) != ITEM_NOT_FOUND )
//ubAPCost = ubAPCost * 10 / ( (UINT8) (RUNDIVISORBPACK * 10));
ubAPCost = ubAPCost + APBPConstants[AP_MODIFIER_RUN] + APBPConstants[AP_MODIFIER_PACK];
else
@@ -3368,19 +3368,19 @@ INT32 FindBestPath(SOLDIERTYPE *s , INT16 sDestination, INT8 ubLevel, INT16 usMo
break;
case WALKING:
case ROBOT_WALK:
if((UsingNewInventorySystem() == true) && s->inv[BPACKPOCKPOS].exists() == true)
if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( s ) != ITEM_NOT_FOUND )
ubAPCost = (ubAPCost + APBPConstants[AP_MODIFIER_WALK] + APBPConstants[AP_MODIFIER_PACK]); //WALKCOSTBPACK);
else
ubAPCost = (ubAPCost + APBPConstants[AP_MODIFIER_WALK]); //WALKCOST);
break;
case SWATTING:
if((UsingNewInventorySystem() == true) && s->inv[BPACKPOCKPOS].exists() == true)
if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( s ) != ITEM_NOT_FOUND )
ubAPCost = (ubAPCost + APBPConstants[AP_MODIFIER_SWAT] + APBPConstants[AP_MODIFIER_PACK]); //SWATCOSTBPACK);
else
ubAPCost = (ubAPCost + APBPConstants[AP_MODIFIER_SWAT]); //SWATCOST);
break;
case CRAWLING:
if((UsingNewInventorySystem() == true) && s->inv[BPACKPOCKPOS].exists() == true)
if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( s ) != ITEM_NOT_FOUND )
ubAPCost = (ubAPCost + APBPConstants[AP_MODIFIER_CRAWL] + APBPConstants[AP_MODIFIER_PACK]); //CRAWLCOSTBPACK);
else
ubAPCost = (ubAPCost + APBPConstants[AP_MODIFIER_CRAWL]); //CRAWLCOST);
@@ -4308,27 +4308,27 @@ INT16 PlotPath( SOLDIERTYPE *pSold, INT16 sDestGridno, INT8 bCopyRoute, INT8 bPl
{
case RUNNING:
sPoints += sTileCost + sExtraCostStand + APBPConstants[AP_MODIFIER_RUN];
if((UsingNewInventorySystem() == true) && pSold->inv[BPACKPOCKPOS].exists() == true)
if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSold ) != ITEM_NOT_FOUND )
sPoints += APBPConstants[AP_MODIFIER_PACK];
break;
case WALKING :
sPoints += sTileCost + sExtraCostStand + APBPConstants[AP_MODIFIER_WALK];
if((UsingNewInventorySystem() == true) && pSold->inv[BPACKPOCKPOS].exists() == true)
if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSold ) != ITEM_NOT_FOUND )
sPoints += APBPConstants[AP_MODIFIER_PACK];
break;
case SWATTING:
sPoints += sTileCost + sExtraCostStand + APBPConstants[AP_MODIFIER_SWAT];
if((UsingNewInventorySystem() == true) && pSold->inv[BPACKPOCKPOS].exists() == true)
if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSold ) != ITEM_NOT_FOUND )
sPoints += APBPConstants[AP_MODIFIER_PACK];
break;
case CRAWLING:
sPoints += sTileCost + sExtraCostStand + APBPConstants[AP_MODIFIER_CRAWL];
if((UsingNewInventorySystem() == true) && pSold->inv[BPACKPOCKPOS].exists() == true)
if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSold ) != ITEM_NOT_FOUND )
sPoints += APBPConstants[AP_MODIFIER_PACK];
break;
default :
sPoints += sPoints + sTileCost;
if((UsingNewInventorySystem() == true) && pSold->inv[BPACKPOCKPOS].exists() == true)
if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSold ) != ITEM_NOT_FOUND )
sPoints += APBPConstants[AP_MODIFIER_PACK];
break;
}
@@ -4344,22 +4344,22 @@ INT16 PlotPath( SOLDIERTYPE *pSold, INT16 sDestGridno, INT8 bCopyRoute, INT8 bPl
// CHRISL: Adjusted system to use different move costs while wearing a backpack
// store WALK cost
sPointsWalk += sTileCost + APBPConstants[AP_MODIFIER_WALK] + sExtraCostStand;
if((UsingNewInventorySystem() == true) && pSold->inv[BPACKPOCKPOS].exists() == true)
if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSold ) != ITEM_NOT_FOUND )
sPointsWalk += APBPConstants[AP_MODIFIER_PACK];
// now get cost as if CRAWLING
sPointsCrawl += sTileCost + APBPConstants[AP_MODIFIER_CRAWL] + sExtraCostCrawl;
if((UsingNewInventorySystem() == true) && pSold->inv[BPACKPOCKPOS].exists() == true)
if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSold ) != ITEM_NOT_FOUND )
sPointsCrawl += APBPConstants[AP_MODIFIER_PACK];
// now get cost as if SWATTING
sPointsSwat += sTileCost + APBPConstants[AP_MODIFIER_SWAT] + sExtraCostSwat;
if((UsingNewInventorySystem() == true) && pSold->inv[BPACKPOCKPOS].exists() == true)
if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSold ) != ITEM_NOT_FOUND )
sPointsSwat += APBPConstants[AP_MODIFIER_PACK];
// now get cost as if RUNNING
sPointsRun += sTileCost + APBPConstants[AP_MODIFIER_RUN] + sExtraCostStand;
if((UsingNewInventorySystem() == true) && pSold->inv[BPACKPOCKPOS].exists() == true)
if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSold ) != ITEM_NOT_FOUND )
sPointsRun += APBPConstants[AP_MODIFIER_PACK];
}
+53 -35
View File
@@ -337,7 +337,7 @@ INT16 ActionPointCost( SOLDIERTYPE *pSoldier, INT16 sGridNo, INT8 bDir, UINT16 u
case BLOODCAT_RUN:
// CHRISL
sPoints = sTileCost + APBPConstants[AP_MODIFIER_RUN];
if((UsingNewInventorySystem() == true) && pSoldier->inv[BPACKPOCKPOS].exists() == true)
if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSoldier ) != ITEM_NOT_FOUND )
sPoints += APBPConstants[AP_MODIFIER_PACK];
break;
@@ -351,7 +351,7 @@ INT16 ActionPointCost( SOLDIERTYPE *pSoldier, INT16 sGridNo, INT8 bDir, UINT16 u
case WALKING :
// CHRISL
sPoints = sTileCost + APBPConstants[AP_MODIFIER_WALK];
if((UsingNewInventorySystem() == true) && pSoldier->inv[BPACKPOCKPOS].exists() == true)
if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSoldier ) != ITEM_NOT_FOUND )
sPoints += APBPConstants[AP_MODIFIER_PACK];
break;
@@ -360,12 +360,12 @@ INT16 ActionPointCost( SOLDIERTYPE *pSoldier, INT16 sGridNo, INT8 bDir, UINT16 u
// CHRISL
case SWATTING:
sPoints = sTileCost + APBPConstants[AP_MODIFIER_SWAT];
if((UsingNewInventorySystem() == true) && pSoldier->inv[BPACKPOCKPOS].exists() == true)
if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSoldier ) != ITEM_NOT_FOUND )
sPoints += APBPConstants[AP_MODIFIER_PACK];
break;
case CRAWLING:
sPoints = sTileCost + APBPConstants[AP_MODIFIER_CRAWL];
if((UsingNewInventorySystem() == true) && pSoldier->inv[BPACKPOCKPOS].exists() == true)
if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSoldier ) != ITEM_NOT_FOUND )
sPoints += APBPConstants[AP_MODIFIER_PACK];
break;
@@ -423,7 +423,7 @@ INT16 EstimateActionPointCost( SOLDIERTYPE *pSoldier, INT16 sGridNo, INT8 bDir,
case BLOODCAT_RUN:
// CHRISL
sPoints = sTileCost + APBPConstants[AP_MODIFIER_RUN];
if((UsingNewInventorySystem() == true) && pSoldier->inv[BPACKPOCKPOS].exists() == true)
if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSoldier ) != ITEM_NOT_FOUND )
sPoints += APBPConstants[AP_MODIFIER_PACK];
break;
@@ -437,7 +437,7 @@ INT16 EstimateActionPointCost( SOLDIERTYPE *pSoldier, INT16 sGridNo, INT8 bDir,
// CHRISL
case WALKING :
sPoints = sTileCost + APBPConstants[AP_MODIFIER_WALK];
if((UsingNewInventorySystem() == true) && pSoldier->inv[BPACKPOCKPOS].exists() == true)
if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSoldier ) != ITEM_NOT_FOUND )
sPoints += APBPConstants[AP_MODIFIER_PACK];
break;
@@ -446,12 +446,12 @@ INT16 EstimateActionPointCost( SOLDIERTYPE *pSoldier, INT16 sGridNo, INT8 bDir,
// CHRISL
case SWATTING:
sPoints = sTileCost + APBPConstants[AP_MODIFIER_SWAT];
if((UsingNewInventorySystem() == true) && pSoldier->inv[BPACKPOCKPOS].exists() == true)
if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSoldier ) != ITEM_NOT_FOUND )
sPoints += APBPConstants[AP_MODIFIER_PACK];
break;
case CRAWLING:
sPoints = sTileCost + APBPConstants[AP_MODIFIER_CRAWL];
if((UsingNewInventorySystem() == true) && pSoldier->inv[BPACKPOCKPOS].exists() == true)
if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSoldier ) != ITEM_NOT_FOUND )
sPoints += APBPConstants[AP_MODIFIER_PACK];
break;
@@ -668,9 +668,11 @@ void DeductPoints( SOLDIERTYPE *pSoldier, INT16 sAPCost, INT32 iBPCost,BOOLEAN f
pSoldier->bActionPoints -= (INT16)( (float)( pSoldier->sBreathRed + iBPCost - BREATH_RED_MAX )
/ (float)( 5 * APBPConstants[BP_RATIO_RED_PTS_TO_NORMAL])
* (float)(4 * (float)APBPConstants[AP_MAXIMUM] / 100));
if ( pSoldier->bActionPoints < 0 )
// HEADROCK HAM 3.1: This may be the problem with suppression - it limits the lower APs to 0, which breaks
// suppression's negative values. Changed instances of "0" to the APBP constant.
if ( pSoldier->bActionPoints < APBPConstants[AP_MIN_LIMIT] )
{
pSoldier->bActionPoints = 0;
pSoldier->bActionPoints = APBPConstants[AP_MIN_LIMIT];
}
pSoldier->sBreathRed = BREATH_RED_MAX;
@@ -1130,46 +1132,63 @@ INT16 CalcTotalAPsToAttack( SOLDIERTYPE *pSoldier, INT16 sGridNo, UINT8 ubAddTur
if (gGameExternalOptions.fIncreasedAimingCost )
{
// HEADROCK HAM B2.6: Changed the number of APs to attack when aiming.
// HEADROCK HAM 3.1: Externalized the entire function to allow customization of each detail.
if (bAimTime > 0)
{
GetAPChargeForShootOrStabWRTGunRaises( pSoldier, sGridNo, ubAddTurningCost, &fAddingTurningCost, &fAddingRaiseGunCost );
if(fAddingRaiseGunCost == TRUE)
{
//CHRISL: I'm disabling this for now. Charging 1/2 ready cost for every shot isn't legitimate
// but for the time being, we have no way to track whether we've previously aimed or not. Until
// we do, this code shouldn't be used.
// 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;
// HEADROCK HAM 3: No idea what should come here... For now I've put my extra gun-raise costs
// outside this IF (see below).
}
// HEADROCK HAM 3: One-time penalty: Add part of the weapon's Ready AP cost. Reinstated because
// it's now externalized.
if (gGameExternalOptions.ubFirstAimReadyCostDivisor > 0)
{
UINT16 usWeaponReadyTime;
UINT8 ubReadyTimeDivisor;
usWeaponReadyTime = Weapon[ usItemNum ].ubReadyTime * (100 - GetPercentReadyTimeAPReduction(&pSoldier->inv[HANDPOS])) / 100;
ubReadyTimeDivisor = gGameExternalOptions.ubFirstAimReadyCostDivisor;
sAPCost += usWeaponReadyTime / ubReadyTimeDivisor;
}
// Add regular aim time for the first 4 aiming actions.
sAPCost += __min((bAimTime*APBPConstants[AP_CLICK_AIM]),(4*APBPConstants[AP_CLICK_AIM]));
// 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)
{
//CHRISL: I'm disabling this for now. Charging an extra "click" every time we use a scope
// isn't legitimate. If we could track whether we previously used a scope on the current
// target, that would be another matter. But for now, we can't, so this should be used.
//sAPCost += APBPConstants[AP_CLICK_AIM];
}
// Add 2 APs for each aiming point between 5 and 6
// Add an individual cost for EACH click, as necessary.
sAPCost += APBPConstants[AP_FIRST_CLICK_AIM_SCOPE];
if (bAimTime > 1)
sAPCost += APBPConstants[AP_SECOND_CLICK_AIM_SCOPE];
if (bAimTime > 2)
sAPCost += APBPConstants[AP_THIRD_CLICK_AIM_SCOPE];
if (bAimTime > 3)
sAPCost += APBPConstants[AP_FOURTH_CLICK_AIM_SCOPE];
if (bAimTime > 4)
{
sAPCost += __min(((bAimTime - 4) * APBPConstants[AP_CLICK_AIM] * 2), (4*APBPConstants[AP_CLICK_AIM]));
}
// Add 3 APs for each aiming point beyond 6.
sAPCost += APBPConstants[AP_FIFTH_CLICK_AIM_SCOPE];
if (bAimTime > 5)
sAPCost += APBPConstants[AP_SIXTH_CLICK_AIM_SCOPE];
if (bAimTime > 6)
{
sAPCost += (bAimTime - 6) * APBPConstants[AP_CLICK_AIM] * 3;
}
sAPCost += APBPConstants[AP_SEVENTH_CLICK_AIM_SCOPE];
if (bAimTime > 7)
sAPCost += APBPConstants[AP_EIGHTTH_CLICK_AIM_SCOPE];
}
// Weapon has no scope or not within requried range. Apply regular AP costs.
else
{
sAPCost += bAimTime * APBPConstants[AP_CLICK_AIM];
}
}
}
// Regular cost system
else
{
sAPCost += bAimTime * APBPConstants[AP_CLICK_AIM];
@@ -1402,7 +1421,6 @@ INT16 BaseAPsToShootOrStab( INT16 bAPs, INT16 bAimSkill, OBJECTTYPE * pObj )
//{
// Top *= 100;
//}
// WANNE : Fixed CTD that occurs when trowing item (grenade, throwing knife, ...)
// with open description box in tactical
INT16 baseAPsToShootOrStab = -1;
+2 -1
View File
@@ -169,7 +169,8 @@ void HandleCrowLeave( SOLDIERTYPE *pSoldier );
void HandleCrowFlyAway( SOLDIERTYPE *pSoldier );
// WDS - increase number of corpses
#define MAX_ROTTING_CORPSES 250
// HEADROCK HAM 3.6: Increase again (250->500).
#define MAX_ROTTING_CORPSES 500
//extern ROTTING_CORPSE gRottingCorpse[ MAX_ROTTING_CORPSES ];
extern std::vector<ROTTING_CORPSE> gRottingCorpse;
+46 -31
View File
@@ -959,6 +959,7 @@ SOLDIERTYPE& SOLDIERTYPE::operator=(const OLDSOLDIERTYPE_101& src)
this->snowCamo = src.snowCamo;
this->wornSnowCamo = src.wornSnowCamo;
}
return *this;
}
@@ -1794,6 +1795,9 @@ void HandleCrowShadowNewPosition( SOLDIERTYPE *pSoldier )
extern INT16 DynamicAdjustAPConstants(INT16 iniReadValue, INT16 iniDefaultValue, BOOLEAN reverse);
// This function calculates how many APs are added to a character's pool at the start of the round. The normal maximum
// amount that can be added is 80% of the Maximum AP value, with the remaining 20% coming from APs reserved in the
// previous round. See also CalcNewActionPoints()
INT16 SOLDIERTYPE::CalcActionPoints( void )
{
INT16 ubPoints,ubMaxAPs;
@@ -1850,8 +1854,11 @@ INT16 SOLDIERTYPE::CalcActionPoints( void )
// If resulting APs are below our permitted minimum, raise them to it!
// HEADROCK: Enforce new minimums due to suppression. I should've done this neater though.
if (ubPoints < APBPConstants[AP_MIN_LIMIT])
ubPoints = APBPConstants[AP_MIN_LIMIT];
// HEADROCK HAM 3.6: This was the wrong place to put AP_MIN_LIMIT. The value here should be AP_MINIMUM, which is
// the minimum amount of APs a character can GAIN each turn on top of what he had last turn. AP_MIN_LIMIT has been
// moved to CalcNewActionPoints() where it belongs.
if (ubPoints < APBPConstants[AP_MINIMUM])
ubPoints = APBPConstants[AP_MINIMUM];
// make sure action points doesn't exceed the permitted maximum
ubMaxAPs = gubMaxActionPoints[ this->ubBodyType ];
@@ -1975,6 +1982,10 @@ void SOLDIERTYPE::CalcNewActionPoints( void )
}
this->bActionPoints += this->CalcActionPoints( );
// HEADROCK HAM 3.6: This should've been here all along. This enforces an absolute minimum limit on APs, which
// can be negative.
if (this->bActionPoints < APBPConstants[AP_MIN_LIMIT])
this->bActionPoints = APBPConstants[AP_MIN_LIMIT];
// Don't max out if we are drugged....
if ( !GetDrugEffect( this, DRUG_TYPE_ADRENALINE ) )
@@ -5511,7 +5522,9 @@ void SoldierGotHitGunFire( SOLDIERTYPE *pSoldier, UINT16 usWeaponIndex, INT16 sD
{
if ( gGameSettings.fOptions[ TOPTION_BLOOD_N_GORE ] )
{
if (SpacesAway( pSoldier->sGridNo, Menptr[ubAttackerID].sGridNo ) <= MAX_DISTANCE_FOR_MESSY_DEATH || (SpacesAway( pSoldier->sGridNo, Menptr[ubAttackerID].sGridNo ) <= MAX_BARRETT_DISTANCE_FOR_MESSY_DEATH && usWeaponIndex == BARRETT ))
// HEADROCK HAM 3.6: Reattached "Max Distance For Messy Death" tag from the XML! God knows why it wasn't attached when they MADE THAT TAG.
//if (SpacesAway( pSoldier->sGridNo, Menptr[ubAttackerID].sGridNo ) <= Weapon[usWeaponIndex].maxdistformessydeath || (SpacesAway( pSoldier->sGridNo, Menptr[ubAttackerID].sGridNo ) <= MAX_BARRETT_DISTANCE_FOR_MESSY_DEATH && usWeaponIndex == BARRETT ))
if (SpacesAway( pSoldier->sGridNo, Menptr[ubAttackerID].sGridNo ) <= Weapon[usWeaponIndex].maxdistformessydeath)
{
sNewGridNo = NewGridNo( (INT16)pSoldier->sGridNo, (INT8)( DirectionInc( pSoldier->ubDirection ) ) );
@@ -5532,7 +5545,9 @@ void SoldierGotHitGunFire( SOLDIERTYPE *pSoldier, UINT16 usWeaponIndex, INT16 sD
{
if ( gGameSettings.fOptions[ TOPTION_BLOOD_N_GORE ] )
{
if (SpacesAway( pSoldier->sGridNo, Menptr[ubAttackerID].sGridNo ) <= MAX_DISTANCE_FOR_MESSY_DEATH || (SpacesAway( pSoldier->sGridNo, Menptr[ubAttackerID].sGridNo ) <= MAX_BARRETT_DISTANCE_FOR_MESSY_DEATH && usWeaponIndex == BARRETT ))
// HEADROCK HAM 3.6: Reattached "Max Distance For Messy Death" tag from the XML! God knows why it wasn't attached when they MADE THAT TAG.
//if (SpacesAway( pSoldier->sGridNo, Menptr[ubAttackerID].sGridNo ) <= Weapon[usWeaponIndex].maxdistformessydeath || (SpacesAway( pSoldier->sGridNo, Menptr[ubAttackerID].sGridNo ) <= MAX_BARRETT_DISTANCE_FOR_MESSY_DEATH && usWeaponIndex == BARRETT ))
if (SpacesAway( pSoldier->sGridNo, Menptr[ubAttackerID].sGridNo ) <= Weapon[usWeaponIndex].maxdistformessydeath)
{
// possibly play torso explosion anim!
@@ -5581,6 +5596,11 @@ void SoldierGotHitGunFire( SOLDIERTYPE *pSoldier, UINT16 usWeaponIndex, INT16 sD
if ( fFallenOver )
{
// HEADROCK HAM 3.2: Critical legshots cost an extra number of APs, based on shot damage.
if (gGameExternalOptions.fCriticalLegshotCausesAPLoss)
{
DeductPoints( pSoldier, APBPConstants[AP_LOSS_PER_LEGSHOT_DAMAGE]*sDamage, 0);
}
SoldierCollapse( pSoldier );
return;
}
@@ -6613,25 +6633,24 @@ void SOLDIERTYPE::EVENT_BeginMercTurn( BOOLEAN fFromRealTime, INT32 iRealTimeCou
this->CalcNewActionPoints( );
// HEADROCK HAM 3.6: If this soldier is in a "moving" animation, but has not moved any tiles
// in the previous turn, then the player has apparently forgotten that he was moving.
// In this case, abort the character's action.
// If hasn't moved since the start of last round
// AND this function is being executed in Turn Based mode
// AND character is a player-controlled merc
if (!fFromRealTime && !this->bTilesMoved && this->bTeam == OUR_TEAM )
{
// but are doing a movement animation
if ( !( gAnimControl[ this->usAnimState ].uiFlags & ANIM_STATIONARY ) )
{
// Stop the merc
this->EVENT_StopMerc( this->sGridNo, this->ubDirection );
this->pathing.sFinalDestination = NOWHERE;
}
// in the previous turn, then the player has apparently forgotten that he was moving.
// In this case, abort the character's action.
// Reset destination
//this->pathing.sFinalDestination = this->sGridNo;
}
// If hasn't moved since the start of last round
// AND this function is being executed in Turn Based mode
// AND character is a player-controlled merc
if (!fFromRealTime && !this->bTilesMoved && this->bTeam == OUR_TEAM )
{
// but is doing a movement animation
if ( !( gAnimControl[ this->usAnimState ].uiFlags & ANIM_STATIONARY ) )
{
// Stop the merc
this->EVENT_StopMerc( this->sGridNo, this->ubDirection );
// Reset destination
//this->pathing.sFinalDestination = this->sGridNo;
this->pathing.sFinalDestination = NOWHERE;
}
}
this->bTilesMoved = 0;
@@ -6711,15 +6730,11 @@ 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;
}
// HEADROCK HAM 3.5: After considerable testing, suppression is now cleared after every attack. Total APs lost
// is cleared every turn (here) and only acts as reference now (no effect on AP loss).
this->ubAPsLostToSuppression = 0;
this->flags.fCloseCall = FALSE;
this->ubMovementNoiseHeard = 0;
+27 -2
View File
@@ -277,6 +277,28 @@ enum
#define SOLDIER_CLASS_ENEMY( bSoldierClass ) ( ( bSoldierClass >= SOLDIER_CLASS_ADMINISTRATOR ) && ( bSoldierClass <= SOLDIER_CLASS_ARMY ) )
#define SOLDIER_CLASS_MILITIA( bSoldierClass ) ( ( bSoldierClass >= SOLDIER_CLASS_GREEN_MILITIA ) && ( bSoldierClass <= SOLDIER_CLASS_ELITE_MILITIA ) )
// Types of uniforms available
enum
{
UNIFORM_ENEMY_ADMIN = 0,
UNIFORM_ENEMY_TROOP,
UNIFORM_ENEMY_ELITE,
UNIFORM_MILITIA_ROOKIE,
UNIFORM_MILITIA_REGULAR,
UNIFORM_MILITIA_ELITE,
NUM_UNIFORMS,
};
// enum of uniform pieces
typedef struct
{
PaletteRepID vest;
PaletteRepID pants;
}UNIFORMCOLORS;
// HEADROCK HAM 3.6: Uniform colors for the different soldier classes
extern UNIFORMCOLORS gUniformColors[NUM_UNIFORMS];
// This macro should be used whenever we want to see if someone is neutral
// IF WE ARE CONSIDERING ATTACKING THEM. Creatures & bloodcats will attack neutrals
// but they can't attack empty vehicles!!
@@ -1021,7 +1043,6 @@ public:
UINT32 uiTimeSoldierWillArrive;
INT8 bVehicleUnderRepairID;
INT32 iTimeCanSignElsewhere;
INT8 bHospitalPriceModifier;
@@ -1050,7 +1071,11 @@ public:
INT8 snowCamo;
INT8 wornSnowCamo;
INT16 filler;
// HEADROCK HAM 3.6: Added integer tracking the facility this character is using.
INT16 sFacilityTypeOperated;
// HEADROCK HAM 3.6: I'm removing this filler to make room for the above variable. I'm very worried though,
// I don't know if this is a good idea at all...
//INT16 filler;
char endOfPOD; // marker for end of POD (plain old data)
+40 -14
View File
@@ -667,7 +667,17 @@ SOLDIERTYPE* TacticalCreateSoldier( SOLDIERCREATE_STRUCT *pCreateStruct, UINT8 *
{
if ( gTacticalStatus.fCivGroupHostile[ Soldier.ubCivilianGroup ] == CIV_GROUP_HOSTILE )
{
Soldier.aiData.bNeutral = FALSE;
// HEADROCK HAM 3.6: Flag to prevent non-combat civilians from becoming hostile and forcing
// you to kill them...
if (!gGameExternalOptions.fCanTrueCiviliansBecomeHostile &&
(Soldier.ubBodyType >= FATCIV && Soldier.ubBodyType <= CRIPPLECIV ))
{
Soldier.aiData.bNeutral = TRUE;
}
else
{
Soldier.aiData.bNeutral = FALSE;
}
}
else
{
@@ -1211,34 +1221,47 @@ void GeneratePaletteForSoldier( SOLDIERTYPE *pSoldier, UINT8 ubSoldierClass )
// OK, After skin, hair we could have a forced color scheme.. use here if so
switch( ubSoldierClass )
{
// HEADROCK HAM 3.6: Now reads default colors from XML.
case SOLDIER_CLASS_ADMINISTRATOR:
SET_PALETTEREP_ID( pSoldier->VestPal, "YELLOWVEST" );
SET_PALETTEREP_ID( pSoldier->PantsPal, "GREENPANTS" );
//SET_PALETTEREP_ID( pSoldier->VestPal, "YELLOWVEST" );
//SET_PALETTEREP_ID( pSoldier->PantsPal, "GREENPANTS" );
SET_PALETTEREP_ID( pSoldier->VestPal, gUniformColors[ UNIFORM_ENEMY_ADMIN ].vest );
SET_PALETTEREP_ID( pSoldier->PantsPal, gUniformColors[ UNIFORM_ENEMY_ADMIN ].pants );
pSoldier->ubSoldierClass = ubSoldierClass;
return;
case SOLDIER_CLASS_ELITE:
SET_PALETTEREP_ID( pSoldier->VestPal, "BLACKSHIRT" );
SET_PALETTEREP_ID( pSoldier->PantsPal, "BLACKPANTS" );
//SET_PALETTEREP_ID( pSoldier->VestPal, "BLACKSHIRT" );
//SET_PALETTEREP_ID( pSoldier->PantsPal, "BLACKPANTS" );
SET_PALETTEREP_ID( pSoldier->VestPal, gUniformColors[ UNIFORM_ENEMY_ELITE ].vest );
SET_PALETTEREP_ID( pSoldier->PantsPal, gUniformColors[ UNIFORM_ENEMY_ELITE ].pants );
pSoldier->ubSoldierClass = ubSoldierClass;
return;
case SOLDIER_CLASS_ARMY:
SET_PALETTEREP_ID( pSoldier->VestPal, "REDVEST" );
SET_PALETTEREP_ID( pSoldier->PantsPal, "GREENPANTS" );
//SET_PALETTEREP_ID( pSoldier->VestPal, "REDVEST" );
//SET_PALETTEREP_ID( pSoldier->PantsPal, "GREENPANTS" );
SET_PALETTEREP_ID( pSoldier->VestPal, gUniformColors[ UNIFORM_ENEMY_TROOP ].vest );
SET_PALETTEREP_ID( pSoldier->PantsPal, gUniformColors[ UNIFORM_ENEMY_TROOP ].pants );
pSoldier->ubSoldierClass = ubSoldierClass;
return;
case SOLDIER_CLASS_GREEN_MILITIA:
SET_PALETTEREP_ID( pSoldier->VestPal, "GREENVEST" );
SET_PALETTEREP_ID( pSoldier->PantsPal, "BEIGEPANTS" );
//SET_PALETTEREP_ID( pSoldier->VestPal, "GREENVEST" );
//SET_PALETTEREP_ID( pSoldier->PantsPal, "BEIGEPANTS" );
SET_PALETTEREP_ID( pSoldier->VestPal, gUniformColors[ UNIFORM_MILITIA_ROOKIE ].vest );
SET_PALETTEREP_ID( pSoldier->PantsPal, gUniformColors[ UNIFORM_MILITIA_ROOKIE ].pants );
pSoldier->ubSoldierClass = ubSoldierClass;
return;
case SOLDIER_CLASS_REG_MILITIA:
SET_PALETTEREP_ID( pSoldier->VestPal, "JEANVEST" );
SET_PALETTEREP_ID( pSoldier->PantsPal, "BEIGEPANTS" );
//SET_PALETTEREP_ID( pSoldier->VestPal, "JEANVEST" );
//SET_PALETTEREP_ID( pSoldier->PantsPal, "BEIGEPANTS" );
SET_PALETTEREP_ID( pSoldier->VestPal, gUniformColors[ UNIFORM_MILITIA_REGULAR ].vest );
SET_PALETTEREP_ID( pSoldier->PantsPal, gUniformColors[ UNIFORM_MILITIA_REGULAR ].pants );
pSoldier->ubSoldierClass = ubSoldierClass;
return;
case SOLDIER_CLASS_ELITE_MILITIA:
SET_PALETTEREP_ID( pSoldier->VestPal, "BLUEVEST" );
SET_PALETTEREP_ID( pSoldier->PantsPal, "BEIGEPANTS" );
//SET_PALETTEREP_ID( pSoldier->VestPal, "BLUEVEST" );
//SET_PALETTEREP_ID( pSoldier->PantsPal, "BEIGEPANTS" );
SET_PALETTEREP_ID( pSoldier->VestPal, gUniformColors[ UNIFORM_MILITIA_ELITE ].vest );
SET_PALETTEREP_ID( pSoldier->PantsPal, gUniformColors[ UNIFORM_MILITIA_ELITE ].pants );
pSoldier->ubSoldierClass = ubSoldierClass;
return;
case SOLDIER_CLASS_MINER:
@@ -1561,6 +1584,7 @@ void InitSoldierStruct( SOLDIERTYPE *pSoldier )
pSoldier->uiXRayActivatedTime = 0;
pSoldier->bBulletsLeft = 0;
pSoldier->bVehicleUnderRepairID = -1;
pSoldier->sFacilityTypeOperated = -1; // HEADROCK HAM 3.6: Facility Operated
}
@@ -1973,7 +1997,9 @@ void CreateDetailedPlacementGivenBasicPlacementInfo( SOLDIERCREATE_STRUCT *pp, B
case BLOODCAT:
pp->bExpLevel = 5 + bExpLevelModifier;
if( SECTOR( gWorldSectorX, gWorldSectorY ) == SEC_I16 )
// HEADROCK HAM 3.6: There can be several lairs now. Find out if this one is.
UINT8 PlacementType = gBloodcatPlacements[ SECTOR(gWorldSectorX, gWorldSectorY) ][0].PlacementType;
if( PlacementType == BLOODCAT_PLACEMENT_LAIR )
{
pp->bExpLevel += gGameOptions.ubDifficultyLevel;
}
+26 -7
View File
@@ -1915,8 +1915,7 @@ void AddSoldierInitListBloodcats()
{ //This map has no bloodcat placements, so don't waste CPU time.
return;
}
if( pSector->bBloodCatPlacements )
else
{ //We don't yet know the number of bloodcat placements in this sector so
//count them now, and permanently record it.
INT8 bBloodCatPlacements = 0;
@@ -1929,7 +1928,18 @@ void AddSoldierInitListBloodcats()
}
curr = curr->next;
}
if( bBloodCatPlacements != pSector->bBloodCatPlacements &&
// No placements on the map itself?
if( !bBloodCatPlacements )
{
// Don't place!
return;
}
// HEADROCK HAM 3.6: Check has been changed completely. We now use whichever value is lower - the ones we've
// set from XML, or the ones existing on the map. Either could override the other, if it is lower.
pSector->bBloodCatPlacements = __min(bBloodCatPlacements, pSector->bBloodCatPlacements);
pSector->bBloodCats = __min(pSector->bBloodCats, pSector->bBloodCatPlacements);
/*if( bBloodCatPlacements != pSector->bBloodCatPlacements &&
ubSectorID != SEC_I16 && ubSectorID != SEC_N5 )
{
#ifdef JA2BETAVERSION
@@ -1938,18 +1948,21 @@ void AddSoldierInitListBloodcats()
pSector->bBloodCatPlacements, gWorldSectorY + 'A' - 1, gWorldSectorX, bBloodCatPlacements );
DoScreenIndependantMessageBox( str, MSG_BOX_FLAG_OK, NULL );
#endif
// WANNE: Fix by Headrock
// HEADROCK HAM 3.5: This "solution" is extremely silly, as it prevents legal placement of bloodcats
// on the map if any discrepancy is encountered, which limits modders severely. Also, because the
// pSector->bBloodCatPlacements value is hardcoded, there is virtually no way for modders to increase
// the number of bloodcats on their own.
//pSector->bBloodCatPlacements = bBloodCatPlacements;
//pSector->bBloodCats = -1;
// A better solution is to limit the number of bloodcats on the map based on whichever is lower - the
// hardcode, or the map-read value.
pSector->bBloodCatPlacements = __min(bBloodCatPlacements, pSector->bBloodCatPlacements);
pSector->bBloodCats = __min(pSector->bBloodCats, pSector->bBloodCatPlacements);
if( !bBloodCatPlacements )
{
return;
}
}
}*/
}
if( pSector->bBloodCats > 0 )
{ //Add them to the world now...
@@ -2565,5 +2578,11 @@ void AddSoldierInitListMilitiaOnEdge( UINT8 ubStrategicInsertionCode, UINT8 ubNu
}
UpdateMercInSector( pSoldier, gWorldSectorX, gWorldSectorY, 0 );
}
// HEADROCK HAM 3.2: Experimental, militia reinforcements arrive with 0 APs.
if (gGameExternalOptions.ubReinforcementsFirstTurnFreeze == 1 || gGameExternalOptions.ubReinforcementsFirstTurnFreeze == 3)
{
pSoldier->bActionPoints = 0;
}
}
}
+100
View File
@@ -447,6 +447,13 @@ BOOLEAN LoadMercProfiles(void)
gMercProfiles[ uiLoop ].bHatedCount[1] = gMercProfiles[ uiLoop ].bHatedTime[1];
gMercProfiles[ uiLoop ].bLearnToHateCount = gMercProfiles[ uiLoop ].bLearnToHateTime;
gMercProfiles[ uiLoop ].bLearnToLikeCount = gMercProfiles[ uiLoop ].bLearnToLikeTime;
if (gGameExternalOptions.fReadProfileDataFromXML)
{
// HEADROCK PROFEX: Overwrite data read from PROF.DAT with data read from XML
OverwriteMercProfileWithXMLData( uiLoop );
OverwriteMercOpinionsWithXMLData( uiLoop );
}
}
// SET SOME DEFAULT LOCATIONS FOR STARTING NPCS
@@ -1664,3 +1671,96 @@ BOOLEAN IsProfileIdAnAimOrMERCMerc( UINT8 ubProfileID )
return( FALSE );
}
void OverwriteMercProfileWithXMLData( UINT32 uiLoop )
{
//////////////////////////////////////////////////////////////////////////////////
//
// HEADROCK PROFEX: Profile Externalization
//
// This is a complete hack which is meant for temporary use until a better system
// can be implemented. This bit OVERWRITES data accumulated so far, by drawing
// new data from XML. This allows making PROEDIT obsolete.
//
//////////////////////////////////////////////////////////////////////////////////
wcscpy(gMercProfiles[ uiLoop ].zName, tempProfiles[ uiLoop ].zName) ;
wcscpy(gMercProfiles[ uiLoop ].zNickname, tempProfiles[ uiLoop ].zNickname) ;
gMercProfiles[ uiLoop ].ubFaceIndex = tempProfiles[ uiLoop ].ubFaceIndex ;
gMercProfiles[ uiLoop ].usEyesX = tempProfiles[ uiLoop ].usEyesX ;
gMercProfiles[ uiLoop ].usEyesY = tempProfiles[ uiLoop ].usEyesY ;
gMercProfiles[ uiLoop ].usMouthX = tempProfiles[ uiLoop ].usMouthX ;
gMercProfiles[ uiLoop ].usMouthY = tempProfiles[ uiLoop ].usMouthY ;
gMercProfiles[ uiLoop ].uiEyeDelay = tempProfiles[ uiLoop ].uiEyeDelay ;
gMercProfiles[ uiLoop ].uiMouthDelay = tempProfiles[ uiLoop ].uiMouthDelay ;
gMercProfiles[ uiLoop ].uiBlinkFrequency = tempProfiles[ uiLoop ].uiBlinkFrequency ;
gMercProfiles[ uiLoop ].uiExpressionFrequency = tempProfiles[ uiLoop ].uiExpressionFrequency ;
strcpy(gMercProfiles[ uiLoop ].PANTS, tempProfiles[ uiLoop ].PANTS) ;
strcpy(gMercProfiles[ uiLoop ].VEST, tempProfiles[ uiLoop ].VEST) ;
strcpy(gMercProfiles[ uiLoop ].SKIN, tempProfiles[ uiLoop ].SKIN) ;
strcpy(gMercProfiles[ uiLoop ].HAIR, tempProfiles[ uiLoop ].HAIR) ;
gMercProfiles[ uiLoop ].bSex = tempProfiles[ uiLoop ].bSex ;
gMercProfiles[ uiLoop ].ubBodyType = tempProfiles[ uiLoop ].ubBodyType ;
gMercProfiles[ uiLoop ].uiBodyTypeSubFlags = tempProfiles[ uiLoop ].uiBodyTypeSubFlags ;
gMercProfiles[ uiLoop ].bAttitude = tempProfiles[ uiLoop ].bAttitude ;
gMercProfiles[ uiLoop ].bPersonalityTrait = tempProfiles[ uiLoop ].bPersonalityTrait ;
gMercProfiles[ uiLoop ].ubNeedForSleep = tempProfiles[ uiLoop ].ubNeedForSleep ;
gMercProfiles[ uiLoop ].bReputationTolerance = tempProfiles[ uiLoop ].bReputationTolerance ;
gMercProfiles[ uiLoop ].bDeathRate = tempProfiles[ uiLoop ].bDeathRate ;
gMercProfiles[ uiLoop ].bLifeMax = tempProfiles[ uiLoop ].bLifeMax ;
gMercProfiles[ uiLoop ].bLife = tempProfiles[ uiLoop ].bLife ;
gMercProfiles[ uiLoop ].bStrength = tempProfiles[ uiLoop ].bStrength ;
gMercProfiles[ uiLoop ].bAgility = tempProfiles[ uiLoop ].bAgility ;
gMercProfiles[ uiLoop ].bDexterity = tempProfiles[ uiLoop ].bDexterity ;
gMercProfiles[ uiLoop ].bWisdom = tempProfiles[ uiLoop ].bWisdom ;
gMercProfiles[ uiLoop ].bMarksmanship = tempProfiles[ uiLoop ].bMarksmanship ;
gMercProfiles[ uiLoop ].bExplosive = tempProfiles[ uiLoop ].bExplosive ;
gMercProfiles[ uiLoop ].bLeadership = tempProfiles[ uiLoop ].bLeadership ;
gMercProfiles[ uiLoop ].bMedical = tempProfiles[ uiLoop ].bMedical ;
gMercProfiles[ uiLoop ].bMechanical = tempProfiles[ uiLoop ].bMechanical ;
gMercProfiles[ uiLoop ].bExpLevel = tempProfiles[ uiLoop ].bExpLevel ;
gMercProfiles[ uiLoop ].bEvolution = tempProfiles[ uiLoop ].bEvolution ;
gMercProfiles[ uiLoop ].bSkillTrait = tempProfiles[ uiLoop ].bSkillTrait ;
gMercProfiles[ uiLoop ].bSkillTrait2 = tempProfiles[ uiLoop ].bSkillTrait2 ;
memcpy( &(gMercProfiles[ uiLoop ].bBuddy), &(tempProfiles[ uiLoop ].bBuddy), 5 * sizeof (INT8));
gMercProfiles[ uiLoop ].bLearnToLike = tempProfiles[ uiLoop ].bLearnToLike ;
gMercProfiles[ uiLoop ].bLearnToLikeTime = tempProfiles[ uiLoop ].bLearnToLikeTime ;
memcpy( &(gMercProfiles[ uiLoop ].bHated), &(tempProfiles[ uiLoop ].bHated), 5 * sizeof (INT8));
memcpy( &(gMercProfiles[ uiLoop ].bHatedTime), &(tempProfiles[ uiLoop ].bHatedTime), 5 * sizeof (INT8));
gMercProfiles[ uiLoop ].bLearnToHate = tempProfiles[ uiLoop ].bLearnToHate ;
gMercProfiles[ uiLoop ].bLearnToHateTime = tempProfiles[ uiLoop ].bLearnToHateTime ;
gMercProfiles[ uiLoop ].sSalary = tempProfiles[ uiLoop ].sSalary ;
gMercProfiles[ uiLoop ].uiWeeklySalary = tempProfiles[ uiLoop ].uiWeeklySalary ;
gMercProfiles[ uiLoop ].uiBiWeeklySalary = tempProfiles[ uiLoop ].uiBiWeeklySalary ;
gMercProfiles[ uiLoop ].bMedicalDeposit = tempProfiles[ uiLoop ].bMedicalDeposit ;
gMercProfiles[ uiLoop ].sMedicalDepositAmount = tempProfiles[ uiLoop ].sMedicalDepositAmount ;
gMercProfiles[ uiLoop ].usOptionalGearCost = tempProfiles[ uiLoop ].usOptionalGearCost ;
gMercProfiles[ uiLoop ].bArmourAttractiveness = tempProfiles[ uiLoop ].bArmourAttractiveness ;
gMercProfiles[ uiLoop ].bMainGunAttractiveness = tempProfiles[ uiLoop ].bMainGunAttractiveness ;
memcpy( &(gMercProfiles[ uiLoop ].usApproachFactor), &(tempProfiles[ uiLoop ].usApproachFactor), 4 * sizeof (UINT16));
if (tempProfiles[ uiLoop ].fGoodGuy)
{
gMercProfiles[ uiLoop ].ubMiscFlags3 |= PROFILE_MISC_FLAG3_GOODGUY;
}
}
void OverwriteMercOpinionsWithXMLData( UINT32 uiLoop )
{
UINT8 cnt;
for (cnt=0; cnt<75; cnt++ )
{
gMercProfiles[ uiLoop ].bMercOpinion[cnt] = tempProfiles[ uiLoop ].bMercOpinion[cnt] ;
}
}
+86
View File
@@ -197,4 +197,90 @@ SOLDIERTYPE * SwapLarrysProfiles( SOLDIERTYPE * pSoldier );
BOOLEAN DoesNPCOwnBuilding( SOLDIERTYPE *pSoldier, INT16 sGridNo );
// HEADROCK PROFEX: Temporary array for merc profile data, read from XML
typedef struct
{
CHAR16 zName[NAME_LENGTH];
CHAR16 zNickname[ NICKNAME_LENGTH ];
UINT8 ubFaceIndex;
UINT16 usEyesX;
UINT16 usEyesY;
UINT16 usMouthX;
UINT16 usMouthY;
UINT32 uiEyeDelay;
UINT32 uiMouthDelay;
UINT32 uiBlinkFrequency;
UINT32 uiExpressionFrequency;
PaletteRepID PANTS;
PaletteRepID VEST;
PaletteRepID SKIN;
PaletteRepID HAIR;
INT8 bSex;
UINT8 ubBodyType;
UINT32 uiBodyTypeSubFlags;
INT8 bAttitude;
INT8 bPersonalityTrait;
UINT8 ubNeedForSleep;
INT8 bReputationTolerance;
INT8 bDeathRate;
INT8 bLifeMax;
INT8 bLife;
INT8 bStrength;
INT8 bAgility;
INT8 bDexterity;
INT8 bWisdom;
INT8 bMarksmanship;
INT8 bExplosive;
INT8 bLeadership;
INT8 bMedical;
INT8 bMechanical;
INT8 bExpLevel;
INT8 bEvolution;
INT8 bSkillTrait;
INT8 bSkillTrait2;
INT8 bBuddy[5];
INT8 bLearnToLike;
INT8 bLearnToLikeTime;
INT8 bHated[5];
INT8 bHatedTime[5];
INT8 bLearnToHate;
INT8 bLearnToHateTime;
INT16 sSalary;
UINT32 uiWeeklySalary;
UINT32 uiBiWeeklySalary;
INT8 bMedicalDeposit;
UINT16 sMedicalDepositAmount;
UINT16 usOptionalGearCost;
INT8 bArmourAttractiveness;
INT8 bMainGunAttractiveness;
// This boolean DOES NOT EXIST in gMercProfiles - it is part of a flag set called ubMiscFlags. This code
// reads the boolean and applies the flag to that flagset, if true.
BOOLEAN fGoodGuy;
UINT16 usApproachFactor[4];
INT8 bMercOpinion[75];
} TEMPPROFILETYPE;
extern TEMPPROFILETYPE tempProfiles[NUM_PROFILES+1];
extern BOOLEAN WriteMercProfiles();
extern BOOLEAN WriteMercOpinions();
void OverwriteMercProfileWithXMLData( UINT32 uiLoop );
void OverwriteMercOpinionsWithXMLData( UINT32 uiLoop );
#endif
+25 -1
View File
@@ -2646,6 +2646,30 @@ BOOLEAN SetSectorFlag( INT16 sMapX, INT16 sMapY, UINT8 bMapZ, UINT32 uiFlagToSet
{
if( uiFlagToSet == SF_ALREADY_VISITED )
{
// HEADROCK HAM 3.5: This is no longer required at all.
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// HEADROCK HAM 3.4: Externalized. Hidden facilities listed on the facility array will be
// added to the sector info now, upon the first visit.
/*for(UINT32 cnt=0; (gFacilityLocations[cnt].uiSectorID >= 0 && gFacilityLocations[cnt].uiSectorID <= 256); cnt++ )
{
// Does the current record match the current sector?
if (gFacilityLocations[cnt].uiSectorID == SECTOR( sMapX, sMapY ))
{
// Is the current record set to be revealed?
if (gFacilityLocations[cnt].fHidden == 1)
{
// Reveal the facility.
SectorInfo[ SECTOR( sMapX, sMapY) ].uiFacilitiesFlags |= (1 << (gFacilityLocations[cnt].uiFacilityType - 1));
}
}
}*/
// HEADROCK HAM 3.4: Externalized.
/*
// do certain things when particular sectors are visited
if ( ( sMapX == TIXA_SECTOR_X ) && ( sMapY == TIXA_SECTOR_Y ) )
{
@@ -2660,7 +2684,7 @@ BOOLEAN SetSectorFlag( INT16 sMapX, INT16 sMapY, UINT8 bMapZ, UINT32 uiFlagToSet
SectorInfo[ SEC_H14 ].uiFacilitiesFlags |= SFCF_GUN_RANGE;
SectorInfo[ SEC_I13 ].uiFacilitiesFlags |= SFCF_GUN_RANGE;
SectorInfo[ SEC_I14 ].uiFacilitiesFlags |= SFCF_GUN_RANGE;
}
}*/
if ( !GetSectorFlagStatus( sMapX, sMapY, bMapZ, SF_ALREADY_VISITED ) )
{
+13 -1
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Version="8,00"
Name="Tactical_2005Express"
ProjectGUID="{D4BDA6AD-9B61-4953-892D-DA3F8CC7E096}"
RootNamespace="Tactical_2005Express"
@@ -600,6 +600,10 @@
RelativePath=".\XML.h"
>
</File>
<File
RelativePath=".\XML_Profiles.h"
>
</File>
</Filter>
<Filter
Name="Source Files"
@@ -994,6 +998,14 @@
RelativePath=".\XML_Merge.cpp"
>
</File>
<File
RelativePath=".\XML_Opinions.cpp"
>
</File>
<File
RelativePath=".\XML_Profiles.cpp"
>
</File>
<File
RelativePath=".\XML_SectorLoadscreens.cpp"
>
+12
View File
@@ -603,6 +603,10 @@
RelativePath="XML.h"
>
</File>
<File
RelativePath=".\XML_Profiles.h"
>
</File>
</Filter>
<Filter
Name="Source Files"
@@ -995,6 +999,14 @@
RelativePath="XML_Merge.cpp"
>
</File>
<File
RelativePath=".\XML_Opinions.cpp"
>
</File>
<File
RelativePath=".\XML_Profiles.cpp"
>
</File>
<File
RelativePath="XML_SectorLoadscreens.cpp"
>
+21 -3
View File
@@ -48,6 +48,8 @@
#include "NPC.h"
#endif
// HEADROCK HAM 3.2: Gamesettings.h for external modifications to team turns.
#include "GameSettings.h"
#include "Reinforcement.h"
#include "fresh_header.h"
//forward declarations of common classes to eliminate includes
@@ -315,9 +317,15 @@ void EndTurn( UINT8 ubNextTeam )
}
else
{
AddPossiblePendingEnemiesToBattle();
AddPossiblePendingMilitiaToBattle();
// HEADROCK HAM 3.2: Experimental fix to force reinforcements enter battle with 0 APs.
if (gGameExternalOptions.ubReinforcementsFirstTurnFreeze != 1 && gGameExternalOptions.ubReinforcementsFirstTurnFreeze != 2)
{
AddPossiblePendingEnemiesToBattle();
}
if (gGameExternalOptions.ubReinforcementsFirstTurnFreeze != 1 && gGameExternalOptions.ubReinforcementsFirstTurnFreeze != 3)
{
AddPossiblePendingMilitiaToBattle();
}
// InitEnemyUIBar( );
@@ -337,6 +345,16 @@ void EndTurn( UINT8 ubNextTeam )
if(is_server || !is_client) BeginTeamTurn( gTacticalStatus.ubCurrentTeam );
// HEADROCK HAM 3.2: Experimental fix to force reinforcements enter battle with 0 APs.
if (gGameExternalOptions.ubReinforcementsFirstTurnFreeze == 1 || gGameExternalOptions.ubReinforcementsFirstTurnFreeze == 2)
{
AddPossiblePendingEnemiesToBattle();
}
if (gGameExternalOptions.ubReinforcementsFirstTurnFreeze == 1 || gGameExternalOptions.ubReinforcementsFirstTurnFreeze == 3)
{
AddPossiblePendingMilitiaToBattle();
}
BetweenTurnsVisibilityAdjustments();
}
}
+295 -125
View File
@@ -1259,9 +1259,11 @@ void GetTBMousePositionInput( UINT32 *puiNewEvent )
}
usOldMapPos = sMapPos;
}
}
void GetPolledKeyboardInput( UINT32 *puiNewEvent )
{
static BOOLEAN fShifted = FALSE;
@@ -1406,6 +1408,7 @@ void GetPolledKeyboardInput( UINT32 *puiNewEvent )
fEndDown = FALSE;
}
}
@@ -3390,9 +3393,20 @@ void GetKeyboardInput( UINT32 *puiNewEvent )
}
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 ) )
// HEADROCK HAM 3.5: When this INI setting is enabled, ALL mercs in the current sector will do a goggle swap.
if (gGameExternalOptions.fGoggleSwapAffectsAllMercsInSector)
{
SwapGogglesUniformly(pTeamSoldier, fToNightVision);
if ( OK_CONTROLLABLE_MERC( pTeamSoldier ) && pTeamSoldier->sSectorX == gWorldSectorX && pTeamSoldier->sSectorY == gWorldSectorY && pTeamSoldier->bSectorZ == gbWorldSectorZ && !AM_A_ROBOT( pTeamSoldier ) )
{
SwapGogglesUniformly(pTeamSoldier, fToNightVision);
}
}
else
{
if ( OK_CONTROLLABLE_MERC( pTeamSoldier ) && pTeamSoldier->bAssignment == CurrentSquad( ) && !AM_A_ROBOT( pTeamSoldier ) )
{
SwapGogglesUniformly(pTeamSoldier, fToNightVision);
}
}
}
}
@@ -3400,9 +3414,20 @@ void GetKeyboardInput( UINT32 *puiNewEvent )
{
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 ) )
// HEADROCK HAM 3.5: When this INI setting is enabled, ALL mercs in the current sector will do a goggle swap.
if (gGameExternalOptions.fGoggleSwapAffectsAllMercsInSector)
{
SwapGoggles(pTeamSoldier);
if ( OK_CONTROLLABLE_MERC( pTeamSoldier ) && pTeamSoldier->sSectorX == gWorldSectorX && pTeamSoldier->sSectorY == gWorldSectorY && pTeamSoldier->bSectorZ == gbWorldSectorZ && !AM_A_ROBOT( pTeamSoldier ) )
{
SwapGoggles(pTeamSoldier);
}
}
else
{
if ( OK_CONTROLLABLE_MERC( pTeamSoldier ) && pTeamSoldier->bAssignment == CurrentSquad( ) && !AM_A_ROBOT( pTeamSoldier ) )
{
SwapGoggles(pTeamSoldier);
}
}
}
}
@@ -3772,11 +3797,11 @@ void GetKeyboardInput( UINT32 *puiNewEvent )
//if the display cover or line of sight is being displayed
if( _KeyDown( END ) || _KeyDown( DEL ) )
{
//f( _KeyDown( DEL ) )
//ChangeSizeOfDisplayCover( gGameSettings.ubSizeOfDisplayCover + 1 );
//if( _KeyDown( DEL ) )
// ChangeSizeOfDisplayCover( gGameSettings.ubSizeOfDisplayCover + 1 );
//if( _KeyDown( END ) )
//ChangeSizeOfLOS( gGameSettings.ubSizeOfLOS + 1 );
// ChangeSizeOfLOS( gGameSettings.ubSizeOfLOS + 1 );
}
else
{
@@ -4019,10 +4044,10 @@ void GetKeyboardInput( UINT32 *puiNewEvent )
if( _KeyDown( END ) || _KeyDown( DEL ) )
{
//if( _KeyDown( DEL ) )
//ChangeSizeOfDisplayCover( gGameSettings.ubSizeOfDisplayCover - 1 );
// ChangeSizeOfDisplayCover( gGameSettings.ubSizeOfDisplayCover - 1 );
//if( _KeyDown( END ) )
//ChangeSizeOfLOS( gGameSettings.ubSizeOfLOS - 1 );
// ChangeSizeOfLOS( gGameSettings.ubSizeOfLOS - 1 );
}
else
{
@@ -5712,149 +5737,274 @@ bool BadGoggles(SOLDIERTYPE *pTeamSoldier) {
void SwapGoggles(SOLDIERTYPE *pTeamSoldier)
{
/* 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++)
// WDS - Smart goggle switching
// NOTE: Investigate using GetItemVisionRangeBonus from Items.cpp???
if (gGameExternalOptions.smartGoggleSwitch)
{
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 )
// 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)
{
itemFound = true;
bestBonus = 0;
pGoggles = FindNightGogglesInInv( pTeamSoldier );
//search for better goggles on the helmet
if (pGoggles)
if ( (Item[pTeamSoldier->inv[headSlot].usItem].brightlightvisionrangebonus > 0) )
{
bestBonus = Item[pGoggles->usItem].nightvisionrangebonus;
}
//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;
}
}
}
if ( pGoggles )
{
SwapObjs( pTeamSoldier, bSlot1, pGoggles, TRUE );
slotToUse = headSlot;
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
}
else if ( (Item[pTeamSoldier->inv[headSlot].usItem].nightvisionrangebonus > 0) )
{
// Remove sungoggles.
PlaceInAnyPocket(pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE);
slotToUse = headSlot;
break;
}
else if (pTeamSoldier->inv[headSlot].exists() == false)
{
slotToUse = headSlot;
}
}
// else if wearing NVGs
else if(Item[pTeamSoldier->inv[bSlot1].usItem].nightvisionrangebonus > 0)
if (slotToUse == -1)
{
itemFound = true;
bestBonus = 0;
pGoggles = FindSunGogglesInInv( pTeamSoldier );
//search for better goggles on the helmet
if (pGoggles)
// 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())
{
bestBonus = Item[pGoggles->usItem].brightlightvisionrangebonus;
SwapObjs( pTeamSoldier, slotToUse, pGoggles, TRUE );
}
else
{
pGoggles->MoveThisObjectTo(pTeamSoldier->inv[slotToUse], 1, pTeamSoldier, slotToUse);
}
//search helmet and vest
for(UINT8 gear = HELMETPOS; gear <= VESTPOS; gear++)
}
else
{
// No goggles to equip, should the current ones be unequiped?
if (pTeamSoldier->inv[slotToUse].exists())
{
pObj = &(pTeamSoldier->inv[gear]);
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
if ((DayTime() && (Item[pTeamSoldier->inv[slotToUse].usItem].nightvisionrangebonus > 0)) ||
(!DayTime() && (Item[pTeamSoldier->inv[slotToUse].usItem].brightlightvisionrangebonus > 0)))
{
if ( Item[ iter->usItem ].brightlightvisionrangebonus > bestBonus && Item[ iter->usItem ].usItemClass == IC_FACE )
// It's day and we're wearing night goggles (or vice-versa), find a place to stash them
if (pTeamSoldier->inv[ HELMETPOS ].exists())
{
pGoggles = &(*iter);
bestBonus = Item[ iter->usItem ].brightlightvisionrangebonus;
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
if (ValidAttachment( pTeamSoldier->inv[slotToUse].usItem, pTeamSoldier->inv[HELMETPOS].usItem ) &&
pTeamSoldier->inv[slotToUse][0]->attachments.size() < MAX_ATTACHMENTS)
{
pTeamSoldier->inv[HELMETPOS].AttachObject( pTeamSoldier, &pTeamSoldier->inv[slotToUse], FALSE, 0 );
}
else
{
// Remove sungoggles.
PlaceInAnyPocket(pTeamSoldier, &pTeamSoldier->inv[slotToUse], FALSE);
}
}
}
else
{
// Try dumping it anywhere in inventory given there's no helemt
if (ValidAttachment( pTeamSoldier->inv[slotToUse].usItem, pTeamSoldier->inv[HELMETPOS].usItem ) &&
pTeamSoldier->inv[slotToUse][0]->attachments.size() < MAX_ATTACHMENTS)
{
pTeamSoldier->inv[HELMETPOS].AttachObject( pTeamSoldier, &pTeamSoldier->inv[slotToUse], FALSE, 0 );
}
else
{
// Remove sungoggles.
PlaceInAnyPocket(pTeamSoldier, &pTeamSoldier->inv[slotToUse], FALSE);
}
}
}
}
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)
}
else
{
// Normal goggle switching
/* 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++)
{
bestBonus = 0;
// search helmet and vest for goggles of some kind
for(UINT8 gear = HELMETPOS; gear <= VESTPOS; gear++)
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 )
{
pObj = &(pTeamSoldier->inv[gear]);
for(attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
itemFound = true;
bestBonus = 0;
pGoggles = FindNightGogglesInInv( pTeamSoldier );
//search for better goggles on the helmet
if (pGoggles)
{
if(DayTime() == TRUE && Item[iter->usItem].brightlightvisionrangebonus > bestBonus && Item[iter->usItem].usItemClass == IC_FACE)
bestBonus = Item[pGoggles->usItem].nightvisionrangebonus;
}
//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)
{
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 ( 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)
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
{
if (ValidAttachment( pTeamSoldier->inv[bSlot1].usItem, pTeamSoldier->inv[HELMETPOS].usItem ) &&
pTeamSoldier->inv[bSlot1][0]->attachments.size() < MAX_ATTACHMENTS)
{
pTeamSoldier->inv[HELMETPOS].AttachObject( pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE, 0 );
break;
}
else
{
// Remove sungoggles.
PlaceInAnyPocket(pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE);
break;
}
}
}
else
// else if wearing NVGs
else if(Item[pTeamSoldier->inv[bSlot1].usItem].nightvisionrangebonus > 0)
{
break;
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
{
if (ValidAttachment( pTeamSoldier->inv[bSlot1].usItem, pTeamSoldier->inv[HELMETPOS].usItem ) &&
pTeamSoldier->inv[bSlot1][0]->attachments.size() < MAX_ATTACHMENTS)
{
pTeamSoldier->inv[HELMETPOS].AttachObject( pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE, 0 );
break;
}
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;
@@ -5922,9 +6072,18 @@ void SwapGogglesUniformly(SOLDIERTYPE *pTeamSoldier, BOOLEAN fToNightVision)
}
else if (Item[pTeamSoldier->inv[bSlot1].usItem].nightvisionrangebonus <= 0)
{
// Remove sungoggles.
PlaceInAnyPocket(pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE);
break;
if (ValidAttachment( pTeamSoldier->inv[bSlot1].usItem, pTeamSoldier->inv[HELMETPOS].usItem ) &&
pTeamSoldier->inv[bSlot1][0]->attachments.size() < MAX_ATTACHMENTS)
{
pTeamSoldier->inv[HELMETPOS].AttachObject( pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE, 0 );
break;
}
else
{
// Remove nightgoggles.
PlaceInAnyPocket(pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE);
break;
}
}
}
}
@@ -5961,9 +6120,18 @@ void SwapGogglesUniformly(SOLDIERTYPE *pTeamSoldier, BOOLEAN fToNightVision)
}
else if (Item[pTeamSoldier->inv[bSlot1].usItem].brightlightvisionrangebonus <= 0)
{
// Remove nightgoggles.
PlaceInAnyPocket(pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE);
break;
if (ValidAttachment( pTeamSoldier->inv[bSlot1].usItem, pTeamSoldier->inv[HELMETPOS].usItem ) &&
pTeamSoldier->inv[bSlot1][0]->attachments.size() < MAX_ATTACHMENTS)
{
pTeamSoldier->inv[HELMETPOS].AttachObject( pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE, 0 );
break;
}
else
{
// Remove nightgoggles.
PlaceInAnyPocket(pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE);
break;
}
}
}
}
@@ -6038,6 +6206,8 @@ void SeperateItems()
CreateAmmo(gWorldItems[ uiLoop ].object[x]->data.gun.usGunAmmoItem, &gTempObject, gWorldItems[ uiLoop ].object[x]->data.gun.ubGunShotsLeft);
gWorldItems[ uiLoop ].object[x]->data.gun.ubGunShotsLeft = 0;
gWorldItems[ uiLoop ].object[x]->data.gun.usGunAmmoItem = NONE;
// HEADROCK HAM 3.5: Clear ammo type
gWorldItems[ uiLoop ].object[x]->data.gun.ubGunAmmoType = NONE;
// put it on the ground
AddItemToPool( gWorldItems[ uiLoop ].sGridNo, &gTempObject, 1, gWorldItems[ uiLoop ].ubLevel, WORLD_ITEM_REACHABLE , -1 );
+12 -10
View File
@@ -387,8 +387,10 @@ UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT16 sMapPos, BOOLEAN
pSoldier->bDoAutofire++;
sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, 0);
}
while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && sAPCosts == sCurAPCosts && pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft >= pSoldier->bDoAutofire);
pSoldier->bDoAutofire--;
}
gfUIAutofireBulletCount = TRUE;
@@ -579,7 +581,7 @@ UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT16 sMapPos, BOOLEAN
// and also a Targetted Bodypart indicator.
if(pSoldier->bDoAutofire == 0 && gGameSettings.fOptions[ TOPTION_CTH_CURSOR ])
{
if (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 2)
if (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 2)
{
// Burst mode only
OBJECTTYPE * pInHand;
@@ -648,7 +650,7 @@ UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT16 sMapPos, BOOLEAN
else if(pSoldier->bDoAutofire > 0 && gGameSettings.fOptions[ TOPTION_CTH_CURSOR ])
{
if (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 3)
if (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 3)
{
gbCtHBurstCount = 1;
@@ -1412,9 +1414,9 @@ void DetermineCursorBodyLocation( UINT8 ubSoldierID, BOOLEAN fDisplay, BOOLEAN f
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) )
else if ( pSoldier->bDoBurst && !pSoldier->bDoAutofire && (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 2) )
gfUIBodyHitLocation = TRUE;
else if ( pSoldier->bDoBurst && pSoldier->bDoAutofire && (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 3) )
else if ( pSoldier->bDoBurst && pSoldier->bDoAutofire && (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 3) )
gfUIBodyHitLocation = TRUE;
return;
}
@@ -1441,9 +1443,9 @@ void DetermineCursorBodyLocation( UINT8 ubSoldierID, BOOLEAN fDisplay, BOOLEAN f
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) )
else if ( pSoldier->bDoBurst && !pSoldier->bDoAutofire && (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 2) )
gfUIBodyHitLocation = TRUE;
else if ( pSoldier->bDoBurst && pSoldier->bDoAutofire && (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 3) )
else if ( pSoldier->bDoBurst && pSoldier->bDoAutofire && (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 3) )
gfUIBodyHitLocation = TRUE;
break;
@@ -1453,9 +1455,9 @@ void DetermineCursorBodyLocation( UINT8 ubSoldierID, BOOLEAN fDisplay, BOOLEAN f
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) )
else if ( pSoldier->bDoBurst && !pSoldier->bDoAutofire && (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 2) )
gfUIBodyHitLocation = TRUE;
else if ( pSoldier->bDoBurst && pSoldier->bDoAutofire && (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 3) )
else if ( pSoldier->bDoBurst && pSoldier->bDoAutofire && (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 3) )
gfUIBodyHitLocation = TRUE;
break;
@@ -1465,9 +1467,9 @@ void DetermineCursorBodyLocation( UINT8 ubSoldierID, BOOLEAN fDisplay, BOOLEAN f
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) )
else if ( pSoldier->bDoBurst && !pSoldier->bDoAutofire && (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 2) )
gfUIBodyHitLocation = TRUE;
else if ( pSoldier->bDoBurst && pSoldier->bDoAutofire && (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 3) )
else if ( pSoldier->bDoBurst && pSoldier->bDoAutofire && (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 3) )
gfUIBodyHitLocation = TRUE;
break;
}
+12 -1
View File
@@ -310,7 +310,18 @@ INT32 AddVehicleToList( INT16 sMapX, INT16 sMapY, INT16 sGridNo, UINT8 ubType )
Assert( 0 );
}
pGroup->ubTransportationMask = (UINT8)iMvtTypes[ ubType ];
// HEADROCK HAM 3.1: An INI setting allows us to turn the Hummer into a true offroad vehicle. It will use the
// "TRUCK" type movement, which allows it to go into mild non-road terrain. I wish I could come with a more
// subtle method than this crude override, but this is what I've got at the moment.
if (gGameExternalOptions.fHumveeOffroad && ubType == HUMMER)
{
pGroup->ubTransportationMask = TRUCK;
}
else
{
pGroup->ubTransportationMask = (UINT8)iMvtTypes[ ubType ];
}
// ARM: setup group movement defaults
pGroup->ubSectorX = ( UINT8 ) sMapX;
+267 -70
View File
@@ -1740,9 +1740,9 @@ BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT16 sTargetGridNo )
// uiHitChance = MINCHANCETOHIT;
//else
// uiHitChance -= 30;
if(uiHitChance <= (UINT16)(__max(30, gGameExternalOptions.iMinimumCTH + 30)))
if(uiHitChance <= (UINT16)(__max(30, gGameExternalOptions.ubMinimumCTH + 30)))
{
uiHitChance = gGameExternalOptions.iMinimumCTH ;
uiHitChance = gGameExternalOptions.ubMinimumCTH ;
}
else
{
@@ -3564,13 +3564,16 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT16 sGridNo, INT16 ubAimTime,
bool highPowerScope = false;
UINT32 pScope;
// HEADROCK HAM 3.5: Variable holds total autofire penalty.
INT16 sTotalAutofirePenalty = 0;
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CalcChanceToHitGun"));
if ( pSoldier->stats.bMarksmanship == 0 )
{
// HEADROCK: (HAM) Altered to accept external arguments
// return( MINCHANCETOHIT );
return( gGameExternalOptions.iMinimumCTH );
return( gGameExternalOptions.ubMinimumCTH );
}
// make sure the guy's actually got a weapon in his hand!
@@ -3766,54 +3769,8 @@ 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;
}
}
// HEADROCK HAM 3.5: Store the penalty
sTotalAutofirePenalty = iPenalty;
}
//ADB we need to calculate the distance visible and SoldierTo...LOSTests that we want to
@@ -4046,7 +4003,7 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT16 sGridNo, INT16 ubAimTime,
// 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 )
if ( gGameExternalOptions.ubAimPenaltyPerTargetShock > 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.
@@ -4058,7 +4015,7 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT16 sGridNo, INT16 ubAimTime,
UINT16 MIN_RANGE_FOR_FULL_COWER;
UINT16 MAX_TARGET_COWERING_PENALTY;
AIM_PENALTY_PER_TARGET_SHOCK = gGameExternalOptions.iAimPenaltyPerTargetShock;
AIM_PENALTY_PER_TARGET_SHOCK = gGameExternalOptions.ubAimPenaltyPerTargetShock;
MIN_RANGE_FOR_FULL_COWER = gGameExternalOptions.usMinRangeForFullCoweringPenalty;
MAX_TARGET_COWERING_PENALTY = gGameExternalOptions.usMaxTargetCoweringPenalty;
@@ -4201,6 +4158,88 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT16 sGridNo, INT16 ubAimTime,
*/
}
// HEADROCK HAM 3.5: Moved this here for now.
// 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.ubRealisticTracers > 0 )
{
UINT16 iBulletsLeft, iTracersFired, iBulletsPerTracer, iBulletsSinceLastTracer;
UINT8 cnt;
//UINT16 iAutoPenaltySinceLastTracer;
iTracersFired = 0;
iBulletsPerTracer = gGameExternalOptions.ubNumBulletsPerTracer;
// 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 )
{
// HEADROCK HAM 3.5: I'm going to revise this - my current system makes no sense at all. What was I
// thinking?!
// Correct all autofire penalty so far
//iBonus = iPenalty;
// Add Tracer Bump if previous bullet was a tracer
//iBonus += (gGameExternalOptions.ubCTHBumpPerTracer * iTracersFired);
iBonus = (gGameExternalOptions.ubCTHBumpPerTracer * iTracersFired);
// Calculate penalty since last tracer was fired
UINT8 ubAutoPenaltySinceLastTracer = GetAutoPenalty(pInHand, gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE) * iBulletsSinceLastTracer;
if ( HAS_SKILL_TRAIT( pSoldier, AUTO_WEAPS ) )
{
ubAutoPenaltySinceLastTracer /= 2 * NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPS );
}
// Add penalty to bonus.
//iBonus -= iAutoPenaltySinceLastTracer;
///////////////////////////////////////////////////
// HEADROCK HAM 3.5: Limit maximum bonus by range.
INT16 sBaseChance = iChance + sTotalAutofirePenalty;
// We don't want to enforce a limit unless the tracers have actually put us over the original CtH.
if (sBaseChance <= iChance+iBonus) // Base_Chance without AutoPen, less or equal to Current_Chance plus tracer bumps
{
// store lowest: Chance+Tracer bumps, or Range-enforced limit
INT16 sChanceLimit = __min(iChance+iBonus, sBaseChance+(((iRange-100) / CELL_X_SIZE) * gGameExternalOptions.ubRangeDifficultyAimingWithTracers));
// store highest: Chance Delta or base CtH
//sChanceDelta = __max(sChanceDelta, sBaseChance);
// iBonus is the distance between the enforced limit (if any) and the current chance with all penalties so far.
// But it can't be negative, 'cause it's a bonus.
iBonus = __max(0,sChanceLimit - iChance);
// Add autopenalty since last tracer
if (iBulletsSinceLastTracer < iBulletsPerTracer)
{
iBonus -= ubAutoPenaltySinceLastTracer;
}
}
iChance += iBonus;
}
}
// adjust for roof/not on roof
if ( pSoldier->pathing.bLevel == 0 )
{
@@ -4407,7 +4446,7 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT16 sGridNo, INT16 ubAimTime,
// 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 (iChance <= gGameExternalOptions.ubMinimumCTH)
{
if ( TANK( pSoldier ) )
{
@@ -4416,10 +4455,10 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT16 sGridNo, INT16 ubAimTime,
}
else
{
iChance = gGameExternalOptions.iMinimumCTH;
if ( gGameExternalOptions.iMinimumCTH == 0 )
iChance = gGameExternalOptions.ubMinimumCTH;
if ( gGameExternalOptions.ubMinimumCTH == 0 )
{
if ( PreRandom( gGameExternalOptions.iMinimumCTHDivisor ) == (gGameExternalOptions.iMinimumCTHDivisor - 1) )
if ( PreRandom( gGameExternalOptions.usMinimumCTHDivisor ) == (gGameExternalOptions.usMinimumCTHDivisor - 1) )
{
iChance = 1;
}
@@ -4431,8 +4470,8 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT16 sGridNo, INT16 ubAimTime,
// HEADROCK (HAM): Externalized maximum to JA2_OPTIONS.INI
// if (iChance > MAXCHANCETOHIT)
// iChance = MAXCHANCETOHIT;
if (iChance > gGameExternalOptions.iMaximumCTH)
iChance = gGameExternalOptions.iMaximumCTH;
if (iChance > gGameExternalOptions.ubMaximumCTH)
iChance = gGameExternalOptions.ubMaximumCTH;
}
// NumMessage("ChanceToHit = ",chance);
@@ -4778,7 +4817,9 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocat
{
case AIM_SHOT_HEAD:
// is the blow deadly enough for an instant kill?
if ( PythSpacesAway( pFirer->sGridNo, pTarget->sGridNo ) <= MAX_DISTANCE_FOR_MESSY_DEATH || (PythSpacesAway( pFirer->sGridNo, pTarget->sGridNo ) <= MAX_BARRETT_DISTANCE_FOR_MESSY_DEATH && pFirer->usAttackingWeapon == BARRETT ))
// HEADROCK HAM 3.6: Reattached "Max Distance For Messy Death" tag from the XML! God knows why it wasn't attached when they MADE THAT TAG.
//if ( PythSpacesAway( pFirer->sGridNo, pTarget->sGridNo ) <= MAX_DISTANCE_FOR_MESSY_DEATH || (PythSpacesAway( pFirer->sGridNo, pTarget->sGridNo ) <= MAX_BARRETT_DISTANCE_FOR_MESSY_DEATH && pFirer->usAttackingWeapon == BARRETT ))
if ( PythSpacesAway( pFirer->sGridNo, pTarget->sGridNo ) <= Weapon[ pFirer->usAttackingWeapon ].maxdistformessydeath )
{
if (iImpactForCrits > MIN_DAMAGE_FOR_INSTANT_KILL && iImpactForCrits < pTarget->stats.bLife)
{
@@ -4825,7 +4866,9 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocat
// normal damage to torso
// is the blow deadly enough for an instant kill?
// since this value is much lower than the others, it only applies at short range...
if ( PythSpacesAway( pFirer->sGridNo, pTarget->sGridNo ) <= MAX_DISTANCE_FOR_MESSY_DEATH || (PythSpacesAway( pFirer->sGridNo, pTarget->sGridNo ) <= MAX_BARRETT_DISTANCE_FOR_MESSY_DEATH && pFirer->usAttackingWeapon == BARRETT ))
// HEADROCK HAM 3.6: Reattached "Max Distance For Messy Death" tag from the XML! God knows why it wasn't attached when they MADE THAT TAG.
//if ( PythSpacesAway( pFirer->sGridNo, pTarget->sGridNo ) <= MAX_DISTANCE_FOR_MESSY_DEATH || (PythSpacesAway( pFirer->sGridNo, pTarget->sGridNo ) <= MAX_BARRETT_DISTANCE_FOR_MESSY_DEATH && pFirer->usAttackingWeapon == BARRETT ))
if ( PythSpacesAway( pFirer->sGridNo, pTarget->sGridNo ) <= Weapon[ pFirer->usAttackingWeapon ].maxdistformessydeath )
{
if (iImpact > MIN_DAMAGE_FOR_INSTANT_KILL && iImpact < pTarget->stats.bLife)
{
@@ -4919,6 +4962,17 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocat
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_HEAD_HIT], pTarget->name );
}
// HEADROCK HAM 3.2: Critical headshots may now cause blindness, based on shot damage.
if (gGameExternalOptions.ubChanceBlindedByHeadshot)
{
if (PreRandom(gGameExternalOptions.ubChanceBlindedByHeadshot) == 0)
{
if (pTarget->bBlindedCounter < iImpact / 10 )
pTarget->bBlindedCounter = iImpact / 10;
}
}
break;
case AIM_SHOT_TORSO:
if (PreRandom( 1 ) == 0 && !(pTarget->flags.uiStatusFlags & SOLDIER_MONSTER) )
@@ -5489,17 +5543,17 @@ UINT32 CalcChanceHTH( SOLDIERTYPE * pAttacker,SOLDIERTYPE *pDefender, INT16 ubAi
// MAKE SURE CHANCE TO HIT IS WITHIN DEFINED LIMITS
// HEADROCK: I urinate on your Defined Limits! Power Rangers, Externalize!
// Disclaimer: No offense meant, all in good fun ;)
if (iChance < gGameExternalOptions.iMinimumCTH)
if (iChance < gGameExternalOptions.ubMinimumCTH)
{
iChance = gGameExternalOptions.iMinimumCTH;
iChance = gGameExternalOptions.ubMinimumCTH;
}
else
{
// HEADROCK (HAM): Externalized maximum to JA2_OPTIONS.INI
//if (iChance > MAXCHANCETOHIT)
// iChance = MAXCHANCETOHIT;
if (iChance > gGameExternalOptions.iMaximumCTH)
iChance = gGameExternalOptions.iMaximumCTH;
if (iChance > gGameExternalOptions.ubMaximumCTH)
iChance = gGameExternalOptions.ubMaximumCTH;
}
//NumMessage("ChanceToStab = ",chance);
@@ -5955,17 +6009,23 @@ 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;
// HEADROCK HAM 3.2: External divisor for CTH with mortars, now that they are more prevalent in the battlefield.
if ( Item[ usHandItem ].mortar )
{
iChance = iChance / gGameExternalOptions.ubMortarCTHDivisor;
}
// 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;
if (iChance < gGameExternalOptions.ubMinimumCTH)
iChance = gGameExternalOptions.ubMinimumCTH;
else
{
// HEADROCK (HAM): Externalized maximum to JA2_OPTIONS.INI
//if (iChance > MAXCHANCETOHIT)
// iChance = MAXCHANCETOHIT;
if (iChance > gGameExternalOptions.iMaximumCTH)
iChance = gGameExternalOptions.iMaximumCTH;
if (iChance > gGameExternalOptions.ubMaximumCTH)
iChance = gGameExternalOptions.ubMaximumCTH;
}
@@ -6163,7 +6223,7 @@ UINT8 GetAutofireShotsPerFiveAPs( OBJECTTYPE *pObj )
// HEADROCK HAM B2.6: Added overall modifier
if (Weapon[ pObj->usItem ].bAutofireShotsPerFiveAP > 0)
{
return __max((Weapon[ pObj->usItem ].bAutofireShotsPerFiveAP + gGameExternalOptions.iAutofireBulletsPer5APModifier), 0);
return __max((Weapon[ pObj->usItem ].bAutofireShotsPerFiveAP + gGameExternalOptions.bAutofireBulletsPer5APModifier), 0);
}
else
return 0;
@@ -6176,6 +6236,13 @@ UINT16 GetMagSize( OBJECTTYPE *pObj )
return Weapon[ pObj->usItem ].ubMagSize + GetMagSizeBonus(pObj);
}
// HEADROCK HAM 3.3: Function to get a weapon's current ammotype.
UINT8 GetAmmoType( OBJECTTYPE *pObj )
{
return (*pObj)[0]->data.gun.ubGunAmmoType;
}
bool WeaponReady(SOLDIERTYPE * pSoldier)
{
#ifdef ROBOT_ALWAYS_READY
@@ -6198,9 +6265,139 @@ INT8 GetAPsToReload( OBJECTTYPE *pObj )
}
// HEADROCK HAM 3.4: Estimates the number of bullets left in the gun. For use during combat.
CHAR16 gBulletCount[10]; // This is a global containing the bullet count string
void EstimateBulletsLeft( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObj )
{
UINT16 usExpLevel;
UINT16 usDexterity;
UINT16 usWisdom;
UINT8 ubMagSize = Weapon[pObj->usItem].ubMagSize;
UINT16 usRealBulletCount = (*pObj)[0]->data.gun.ubGunShotsLeft;
UINT16 i = 0;
BOOLEAN fPsycho = FALSE;
INT16 sEffectiveSkill;
INT8 bDeviation = 0;
// HEADROCK HAM 3.5: Bugfix, failsafe
if ( pSoldier == NULL )
{
// No soldier... Return true count.
swprintf(gBulletCount, L"%d", usRealBulletCount);
return;
}
usExpLevel = EffectiveExpLevel(pSoldier);
usDexterity = EffectiveDexterity(pSoldier);
usWisdom = EffectiveWisdom(pSoldier);
if ( gGameExternalOptions.usBulletHideIntensity <= 0 )
{
// Feature is disabled. Print the real bullet count.
swprintf(gBulletCount, L"%d", usRealBulletCount);
return;
}
// Is this Soldier a psycho?
if ( pSoldier->ubProfile != NO_PROFILE && gMercProfiles[ pSoldier->ubProfile ].bPersonalityTrait == PSYCHO )
{
fPsycho = TRUE;
}
// High EXP Level, Wisdom and Dexterity required for any estimation to be possible.
// When Experience goes up, the required WIS+DEX goes down.
// At ExpLevel 1 -> WIS+DEX must be > 180. A high requirement!
// At ExpLevel 2 -> WIS+DEX must be > 160.
// ...
// At ExpLevel 5 -> WIS+DEX must be > 100. Most characters have already attained estimation ability by now.
// At ExpLevel 10 -> WIS+DEX must be > 0, which is always.
if ( (usWisdom + usDexterity) < (200 - (usExpLevel * 20)) )
{
// Soldier is not skilled enough to know how many bullets are left in the gun. Print a "??" indicating that
// the real bullet count may be anywhere between empty and full.
swprintf(gBulletCount, L"%s", L"??");
return;
}
else // Soldier good enough for at least a rough estimate.
{
// HEADROCK HAM 3.5: Moved this here. If the character fails the above requirement, he shouldn't even know if the
// gun is empty or full.
//-------------------------
// If the magazine is empty or full, he knows it automatically.
if (usRealBulletCount == ubMagSize)
{
// Magazine is fresh. Let the soldier know this.
swprintf(gBulletCount, L"%d", usRealBulletCount);
return;
}
if (usRealBulletCount == 0)
{
// Magazine is empty, so it will also show as empty.
swprintf(gBulletCount, L"%d", usRealBulletCount);
return;
}
//-------------------------
// Let's see by how much we've beaten the requirement!
sEffectiveSkill = ( (usWisdom + usDexterity) - (200 - (usExpLevel * 20)) ) / 2;
}
// So from now on we've got the sEffectiveSkill value, which can go from 0 to 100
// This value represents getting better in all three stats (WIS,DEX,EXP), because as
// they go up the result of the calculation above also goes up. Having a particularly high
// value in any of the three stats, in fact, reduces the need to have high values in others.
//
// The higher your EXP level, the less WIS+DEX you need for an accurate estimate, so even
// inept characters will eventually be able to make a fair estimate, provided the EXP
// level goes high enough.
//
// On the other hand, WIS and DEX work together. In fact, it is the average of these
// skills that determines how soon you can start estimating, and how good your estimation gets
// as you gain levels. So while one high skill can bring better estimates sooner, it requires
// both skills to be improved for a really good estimate.
//
// The range of sEffectiveSkill is 0 to 100
//``````````````````````````````````````````
// Psychos are eligible for an estimate just the same as any other character. But the trait reduces
// effective skill by 10, so It'll take them longer before they can get a good estimate.
sEffectiveSkill -= (fPsycho * (10));
sEffectiveSkill = __max(0, sEffectiveSkill);
sEffectiveSkill = __min(100, sEffectiveSkill);
// Now, we invert the effective skill
bDeviation = 100-sEffectiveSkill; // range is still 0-100, but lower is better
// Use this as a percentage, and figure out the deviation based on magazine size and current bullet. The nearer
// you get to the bottom of a magazine, the harder it is to accurately estimate how many bullets are in there.
bDeviation = ((ubMagSize - usRealBulletCount) * (bDeviation * bDeviation)) / 10000;
// Add externalized difficulty modifier
bDeviation = (bDeviation * gGameExternalOptions.usBulletHideIntensity) / 100;
// If the deviation surpasses the character's EXP level, then he/she is not able to know how many bullets are
// left in the gun, but can still give a rough estimate. There are currently three estimate stages - High, Mid,
// and Low.
if (bDeviation > usExpLevel)
{
if (usRealBulletCount >= (ubMagSize*2)/3)
{
swprintf(gBulletCount, L"%s", L"?H");
}
else if (usRealBulletCount < (ubMagSize*2)/3 && usRealBulletCount >= ubMagSize/3)
{
swprintf(gBulletCount, L"%s", L"?M");
}
else if (usRealBulletCount < ubMagSize/3)
{
swprintf(gBulletCount, L"%s", L"?L");
}
return;
}
// Default - return true count.
swprintf(gBulletCount, L"%d", usRealBulletCount);
return;
}
+5
View File
@@ -391,9 +391,14 @@ UINT8 GetBurstPenalty( OBJECTTYPE *pObj, BOOLEAN fProneStance = FALSE );
UINT8 GetAutoPenalty( OBJECTTYPE *pObj, BOOLEAN fProneStance = FALSE );
UINT8 GetShotsPerBurst( OBJECTTYPE *pObj );
UINT16 GetMagSize( OBJECTTYPE *pObj );
UINT8 GetAmmoType( OBJECTTYPE *pObj );
bool WeaponReady(SOLDIERTYPE * pSoldier);
INT8 GetAPsToReload( OBJECTTYPE *pObj );
// HEADROCK HAM 3.4: Estimate bullets left in gun. Returns an "errorcode" telling the calling function if the check
// was successful and to what degree.
void EstimateBulletsLeft( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObj );
extern CHAR16 gBulletCount[10];
#endif
+42
View File
@@ -125,6 +125,23 @@ typedef PARSE_STAGE;
#define LAPTOPFLORISTLOCATIONFILENAME "Laptop\\FloristPositions.xml"
#define LAPTOPFUNERALLOCATIONFILENAME "Laptop\\FuneralPositions.xml"
// HEADROCK HAM 3.4: Facility Locations [2009-05-19]
#define SECTORFACILITIESFILENAME "Map\\Facilities.xml"
// HEADROCK HAM 3.4: Dynamic Roaming Restrictions [2009-05-19]
#define DYNAMICROAMINGFILENAME "Map\\DynamicRestrictions.xml"
// HEADROCK HAM 3.5: Facility Types [2009-06-14]
#define FACILITYTYPESFILENAME "Map\\FacilityTypes.xml"
// HEADROCK HAM 3.6: Sector Names [2009-07-27]
#define SECTORNAMESFILENAME "Map\\SectorNames.xml"
// HEADROCK PROFEX: Merc Profiles [2009-07-27]
#define MERCPROFILESFILENAME "MercProfiles.xml"
// HEADROCK PROFEX: Merc Opinions [2009-07-27]
#define MERCOPINIONSFILENAME "MercOpinions.xml"
// HEADROCK HAM 3.6: Bloodcat Placements [2009-07-31]
#define BLOODCATPLACEMENTSFILENAME "Map\\BloodcatPlacements.xml"
// HEADROCK HAM 3.6: Uniform Colors [2009-09-29]
#define UNIFORMCOLORSFILENAME "Army\\UniformColors.xml"
extern BOOLEAN ReadInItemStats(STR fileName, BOOLEAN localizedVersion);
extern BOOLEAN WriteItemStats();
@@ -260,4 +277,29 @@ extern BOOLEAN ReadInFloristLocations(STR fileName);
//Gotthard: Laptop Funeral Locations
extern BOOLEAN ReadInFuneralLocations(STR fileName);
// HEADROCK HAM 3.4: Sector Facility Locations
extern BOOLEAN ReadInSectorFacilities(STR fileName);
// HEADROCK HAM 3.4: Dynamic Roaming Restrictions
extern BOOLEAN ReadInDynamicRoamingRestrictions(STR fileName);
// HEADROCK HAM 3.5: Facility Types and bonuses
extern BOOLEAN ReadInFacilityTypes(STR fileName);
// HEADROCK HAM 3.6: Customized Sector Names
extern BOOLEAN ReadInSectorNames(STR fileName);
// HEADROCK PROFEX: Merc Profiles
extern BOOLEAN ReadInMercProfiles(STR fileName);
// HEADROCK PROFEX: Merc Opinions
extern BOOLEAN ReadInMercOpinions(STR fileName);
// HEADROCK HAM 3.6: Customized Bloodcat Placements
extern BOOLEAN ReadInBloodcatPlacements(STR fileName);
// HEADROCK HAM 3.6: Customized Uniform Colors
extern BOOLEAN ReadInUniforms(STR fileName);
#endif
+899
View File
@@ -0,0 +1,899 @@
///////////////////////////////////////////////////////////////////////////////
// HEADROCK PROFEX: PROFile EXternalization
//
// This file handles all reading from Merc Profiles.XML. It offers an external
// alternative to PROEDIT. Values that have no current use in the game were
// EXCLUDED. If you wish to add them simply follow the example set here. You
// can read MERCPROFILESTRUCT in the file "soldier profile type.h" to see
// all profile data. Add the ones you want to externalize to TEMPPROFILESTRUCT
// in "Soldier Profile.h", and then add the appropriate lines where needed,
// in this file, following my example.
///////////////////////////////////////////////////////////////////////////////
#ifdef PRECOMPILEDHEADERS
#include "Tactical All.h"
#else
#include "sgp.h"
#include "Debug Control.h"
#include "expat.h"
#include "gamesettings.h"
#include "XML.h"
#include "Soldier Profile.h"
#endif
//#define MAX_PROFILE_NAME_LENGTH 30
struct
{
PARSE_STAGE curElement;
CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1];
TEMPPROFILETYPE curProfile;
UINT32 maxArraySize;
UINT32 curIndex;
UINT32 currentDepth;
UINT32 maxReadDepth;
}
typedef profileParseData;
//TEMPPROFILETYPE tempProfiles[NUM_PROFILES+1];
static void XMLCALL
opinionStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts)
{
profileParseData * pData = (profileParseData *)userData;
if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element?
{
if(strcmp(name, "MERCOPINIONS") == 0 && pData->curElement == ELEMENT_NONE)
{
pData->curElement = ELEMENT_LIST;
pData->maxReadDepth++; //we are not skipping this element
}
else if(strcmp(name, "OPINION") == 0 && pData->curElement == ELEMENT_LIST)
{
pData->curElement = ELEMENT;
//DebugMsg(TOPIC_JA2, DBG_LEVEL_3,"MergeStartElementHandle: setting memory for curMerge");
memset(&pData->curProfile,0,sizeof(TEMPPROFILETYPE));
pData->maxReadDepth++; //we are not skipping this element
//pData->curIndex++;
}
else if(pData->curElement == ELEMENT &&
(strcmp(name, "zNickname") == 0 ||
strcmp(name, "uiIndex") == 0 ||
strcmp(name, "Opinion0") == 0 ||
strcmp(name, "Opinion1") == 0 ||
strcmp(name, "Opinion2") == 0 ||
strcmp(name, "Opinion3") == 0 ||
strcmp(name, "Opinion4") == 0 ||
strcmp(name, "Opinion5") == 0 ||
strcmp(name, "Opinion6") == 0 ||
strcmp(name, "Opinion7") == 0 ||
strcmp(name, "Opinion8") == 0 ||
strcmp(name, "Opinion9") == 0 ||
strcmp(name, "Opinion10") == 0 ||
strcmp(name, "Opinion11") == 0 ||
strcmp(name, "Opinion12") == 0 ||
strcmp(name, "Opinion13") == 0 ||
strcmp(name, "Opinion14") == 0 ||
strcmp(name, "Opinion15") == 0 ||
strcmp(name, "Opinion16") == 0 ||
strcmp(name, "Opinion17") == 0 ||
strcmp(name, "Opinion18") == 0 ||
strcmp(name, "Opinion19") == 0 ||
strcmp(name, "Opinion20") == 0 ||
strcmp(name, "Opinion21") == 0 ||
strcmp(name, "Opinion22") == 0 ||
strcmp(name, "Opinion23") == 0 ||
strcmp(name, "Opinion24") == 0 ||
strcmp(name, "Opinion25") == 0 ||
strcmp(name, "Opinion26") == 0 ||
strcmp(name, "Opinion27") == 0 ||
strcmp(name, "Opinion28") == 0 ||
strcmp(name, "Opinion29") == 0 ||
strcmp(name, "Opinion30") == 0 ||
strcmp(name, "Opinion31") == 0 ||
strcmp(name, "Opinion32") == 0 ||
strcmp(name, "Opinion33") == 0 ||
strcmp(name, "Opinion34") == 0 ||
strcmp(name, "Opinion35") == 0 ||
strcmp(name, "Opinion36") == 0 ||
strcmp(name, "Opinion37") == 0 ||
strcmp(name, "Opinion38") == 0 ||
strcmp(name, "Opinion39") == 0 ||
strcmp(name, "Opinion40") == 0 ||
strcmp(name, "Opinion41") == 0 ||
strcmp(name, "Opinion42") == 0 ||
strcmp(name, "Opinion43") == 0 ||
strcmp(name, "Opinion44") == 0 ||
strcmp(name, "Opinion45") == 0 ||
strcmp(name, "Opinion46") == 0 ||
strcmp(name, "Opinion47") == 0 ||
strcmp(name, "Opinion48") == 0 ||
strcmp(name, "Opinion49") == 0 ||
strcmp(name, "Opinion50") == 0 ||
strcmp(name, "Opinion51") == 0 ||
strcmp(name, "Opinion52") == 0 ||
strcmp(name, "Opinion53") == 0 ||
strcmp(name, "Opinion54") == 0 ||
strcmp(name, "Opinion55") == 0 ||
strcmp(name, "Opinion56") == 0 ||
strcmp(name, "Opinion57") == 0 ||
strcmp(name, "Opinion58") == 0 ||
strcmp(name, "Opinion59") == 0 ||
strcmp(name, "Opinion60") == 0 ||
strcmp(name, "Opinion61") == 0 ||
strcmp(name, "Opinion62") == 0 ||
strcmp(name, "Opinion63") == 0 ||
strcmp(name, "Opinion64") == 0 ||
strcmp(name, "Opinion65") == 0 ||
strcmp(name, "Opinion66") == 0 ||
strcmp(name, "Opinion67") == 0 ||
strcmp(name, "Opinion68") == 0 ||
strcmp(name, "Opinion69") == 0 ||
strcmp(name, "Opinion70") == 0 ||
strcmp(name, "Opinion71") == 0 ||
strcmp(name, "Opinion72") == 0 ||
strcmp(name, "Opinion73") == 0 ||
strcmp(name, "Opinion74") == 0
))
{
pData->curElement = ELEMENT_PROPERTY;
pData->maxReadDepth++; //we are not skipping this element
}
pData->szCharData[0] = '\0';
}
pData->currentDepth++;
}
static void XMLCALL
opinionCharacterDataHandle(void *userData, const XML_Char *str, int len)
{
profileParseData * pData = (profileParseData *)userData;
if( (pData->currentDepth <= pData->maxReadDepth) &&
(strlen(pData->szCharData) < MAX_CHAR_DATA_LENGTH)
){
strncat(pData->szCharData,str,__min((unsigned int)len,MAX_CHAR_DATA_LENGTH-strlen(pData->szCharData)));
}
}
static void XMLCALL
opinionEndElementHandle(void *userData, const XML_Char *name)
{
profileParseData * pData = (profileParseData *)userData;
if(pData->currentDepth <= pData->maxReadDepth) //we're at the end of an element that we've been reading
{
if(strcmp(name, "MERCOPINIONS") == 0)
{
pData->curElement = ELEMENT_NONE;
}
else if(strcmp(name, "OPINION") == 0)
{
pData->curElement = ELEMENT_LIST;
if(pData->curIndex < pData->maxArraySize)
{
// Write data into a temporary array that holds profiles. We will later copy data from that
// temp array into the REAL profile array, one item at a time, replacing PROF.DAT data.
memcpy( &(tempProfiles[pData->curIndex].bMercOpinion), &(pData->curProfile.bMercOpinion), 75 * sizeof(INT8) );
}
}
else if(strcmp(name, "zNickname") == 0)
{
pData->curElement = ELEMENT;
// Just a formality
}
else if(strcmp(name, "uiIndex") == 0)
{
pData->curElement = ELEMENT;
// Sets new index for writing.
pData->curIndex = (UINT32) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion0") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[0] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion1") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[1] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion2") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[2] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion3") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[3] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion4") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[4] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion5") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[5] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion6") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[6] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion7") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[7] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion8") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[8] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion9") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[9] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion10") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[10] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion11") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[11] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion12") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[12] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion13") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[13] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion14") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[14] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion15") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[15] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion16") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[16] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion17") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[17] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion18") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[18] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion19") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[19] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion20") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[20] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion21") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[21] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion22") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[22] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion23") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[23] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion24") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[24] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion25") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[25] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion26") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[26] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion27") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[27] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion28") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[28] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion29") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[29] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion30") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[30] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion31") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[31] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion32") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[32] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion33") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[33] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion34") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[34] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion35") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[35] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion36") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[36] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion37") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[37] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion38") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[38] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion39") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[39] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion40") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[40] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion41") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[41] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion42") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[42] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion43") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[43] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion44") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[44] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion45") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[45] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion46") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[46] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion47") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[47] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion48") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[48] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion49") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[49] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion50") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[50] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion51") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[51] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion52") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[52] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion53") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[53] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion54") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[54] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion55") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[55] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion56") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[56] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion57") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[57] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion58") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[58] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion59") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[59] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion60") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[60] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion61") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[61] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion62") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[62] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion63") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[63] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion64") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[64] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion65") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[65] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion66") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[66] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion67") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[67] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion68") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[68] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion69") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[69] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion70") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[70] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion71") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[71] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion72") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[72] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion73") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[73] = (INT8) atol(pData->szCharData);
}
else if(strcmp(name, "Opinion74") == 0)
{
pData->curElement = ELEMENT;
pData->curProfile.bMercOpinion[74] = (INT8) atol(pData->szCharData);
}
pData->maxReadDepth--;
}
pData->currentDepth--;
}
BOOLEAN ReadInMercOpinions(STR fileName)
{
HWFILE hFile;
UINT32 uiBytesRead;
UINT32 uiFSize;
CHAR8 * lpcBuffer;
XML_Parser parser = XML_ParserCreate(NULL);
profileParseData pData;
DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading MercOpinions.xml" );
// Open merges file
hFile = FileOpen( fileName, FILE_ACCESS_READ, FALSE );
if ( !hFile )
return( FALSE );
uiFSize = FileGetSize(hFile);
lpcBuffer = (CHAR8 *) MemAlloc(uiFSize+1);
//Read in block
if ( !FileRead( hFile, lpcBuffer, uiFSize, &uiBytesRead ) )
{
MemFree(lpcBuffer);
return( FALSE );
}
lpcBuffer[uiFSize] = 0; //add a null terminator
FileClose( hFile );
XML_SetElementHandler(parser, opinionStartElementHandle, opinionEndElementHandle);
XML_SetCharacterDataHandler(parser, opinionCharacterDataHandle);
memset(&pData,0,sizeof(pData));
pData.maxArraySize = MAXITEMS;
pData.curIndex = -1;
XML_SetUserData(parser, &pData);
if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE))
{
CHAR8 errorBuf[511];
sprintf(errorBuf, "XML Parser Error in MercProfiles.xml: %s at line %d", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser));
LiveMessage(errorBuf);
MemFree(lpcBuffer);
return FALSE;
}
MemFree(lpcBuffer);
XML_ParserFree(parser);
return( TRUE );
}
BOOLEAN WriteMercOpinions()
{
HWFILE hFile;
//Debug code; make sure that what we got from the file is the same as what's there
// Open a new file
hFile = FileOpen( "TABLEDATA\\MercOpinions out.xml", FILE_ACCESS_WRITE | FILE_CREATE_ALWAYS, FALSE );
if ( !hFile )
return( FALSE );
{
UINT32 cnt;
FilePrintf(hFile,"<MERCOPINIONS>\r\n");
for(cnt = 0;cnt < NUM_PROFILES ;cnt++)
{
FilePrintf(hFile,"\t<OPINION>\r\n");
FilePrintf(hFile,"\t\t<uiIndex>%d</uiIndex>\r\n", cnt);
//////////////////////////////
// Write Character's Nickname
FilePrintf(hFile,"\t\t<zNickname>");
STR16 szRemainder = gMercProfiles[cnt].zNickname; //the remaining string to be output (for making valid XML)
while(szRemainder[0] != '\0')
{
//UINT32 uiCharLoc = wcscspn(szRemainder,L"&<>\'\"\0");
UINT32 uiCharLoc = wcscspn(szRemainder,L"&<>\0");
CHAR16 invChar = szRemainder[uiCharLoc];
if(uiCharLoc)
{
szRemainder[uiCharLoc] = '\0';
FilePrintf(hFile,"%S",szRemainder);
szRemainder[uiCharLoc] = invChar;
}
szRemainder += uiCharLoc;
switch(invChar)
{
case '&':
FilePrintf(hFile,"&amp;");
szRemainder++;
break;
case '<':
FilePrintf(hFile,"&lt;");
szRemainder++;
break;
case '>':
FilePrintf(hFile,"&gt;");
szRemainder++;
break;
//case '\'':
// FilePrintf(hFile,"&apos;");
// szRemainder++;
//break;
//case '\"':
// FilePrintf(hFile,"&quot;");
// szRemainder++;
//break;
}
}
FilePrintf(hFile,"</zNickname>\r\n");
UINT8 cnt_b = 0;
for (cnt_b = 0; cnt_b < 75; cnt_b++)
{
FilePrintf(hFile,"\t\t<Opinion%d>%d</Opinion%d>\r\n", cnt_b, gMercProfiles[ cnt ].bMercOpinion[cnt_b], cnt_b);
}
FilePrintf(hFile,"\t</OPINION>\r\n");
}
FilePrintf(hFile,"</MERCOPINIONS>\r\n");
}
FileClose( hFile );
return( TRUE );
}
File diff suppressed because it is too large Load Diff
View File
+1 -1
View File
@@ -396,4 +396,4 @@ int FindSpreadPatternIndex( const STR strName )
}
return n;
}
}
+2 -2
View File
@@ -474,7 +474,7 @@ void AddMissileTrail( BULLET *pBullet, FIXEDPT qCurrX, FIXEDPT qCurrY, FIXEDPT q
// 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 ((gGameExternalOptions.ubRealisticTracers > 0 && gGameExternalOptions.ubNumBulletsPerTracer > 0 && pBullet->fTracer == TRUE) || (gGameExternalOptions.ubRealisticTracers == 0 && fTracer == TRUE))
{
if ( pBullet->iLoop < 5 )
{
@@ -525,7 +525,7 @@ void AddMissileTrail( BULLET *pBullet, FIXEDPT qCurrX, FIXEDPT qCurrY, FIXEDPT q
// 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))
else if ((gGameExternalOptions.ubRealisticTracers > 0 && gGameExternalOptions.ubNumBulletsPerTracer > 0 && pBullet->fTracer == TRUE) || (gGameExternalOptions.ubRealisticTracers == 0 && fTracer == TRUE))
{
INT16 sXPos, sYPos;
+63 -17
View File
@@ -58,7 +58,8 @@
#define WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA
extern void SetSoldierAniSpeed( SOLDIERTYPE *pSoldier );
void MakeBloodcatsHostile( void );
// HEADROCK HAM 3.6: Moved to header
//void MakeBloodcatsHostile( void );
void OurNoise( UINT8 ubNoiseMaker, INT16 sGridNo, INT8 bLevel, UINT8 ubTerrType, UINT8 ubVolume, UINT8 ubNoiseType );
void TheirNoise(UINT8 ubNoiseMaker, INT16 sGridNo, INT8 bLevel, UINT8 ubTerrType, UINT8 ubVolume, UINT8 ubNoiseType );
@@ -490,7 +491,9 @@ void HandleBestSightingPositionInRealtime( void )
// get rid of the item under cursor (we gotta react FAST)
CancelItemPointer();
// select (and center screen on) the merc who saw the enemy
if (gusSelectedSoldier != (UINT16)MercPtrs[gubBestToMakeSighting[ 0 ]]->ubID)
// HEADROCK HAM 3.6: A much-requested toggle.
if (gusSelectedSoldier != (UINT16)MercPtrs[gubBestToMakeSighting[ 0 ]]->ubID &&
!gGameExternalOptions.fNoAutoFocusChangeInRealtimeSneak)
SelectSoldier (MercPtrs[gubBestToMakeSighting[ 0 ]]->ubID, false, true);
// if not quiet, emit a message warning the player
if (!gGameExternalOptions.fQuietRealTimeSneak)
@@ -1251,6 +1254,19 @@ INT16 DistanceVisible( SOLDIERTYPE *pSoldier, INT8 bFacingDir, INT8 bSubjectDir,
if (!sideViewLimit)
{
sDistVisible += sDistVisible * GetTotalVisionRangeBonus(pSoldier, bLightLevel) / 100;
// HEADROCK HAM 3.2: Further reduce sightrange for cowering characters.
if (gGameExternalOptions.ubCoweringReducesSightRange == 1 || gGameExternalOptions.ubCoweringReducesSightRange == 2)
{
INT8 bTolerance = CalcSuppressionTolerance( pSoldier );
// Make sure character is cowering.
if ( pSoldier->aiData.bShock >= bTolerance && gGameExternalOptions.ubMaxSuppressionShock > 0 &&
sDistVisible > 0 )
{
sDistVisible = __max(1,(sDistVisible * (gGameExternalOptions.ubMaxSuppressionShock - pSoldier->aiData.bShock)) / gGameExternalOptions.ubMaxSuppressionShock);
}
}
}
@@ -2299,7 +2315,13 @@ void ManSeesMan(SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, INT16 sOppGridno,
}
else if ( pOpponent->ubBodyType == BLOODCAT && pOpponent->aiData.bNeutral)
{
MakeBloodcatsHostile();
// HEADROCK HAM 3.6: If bloodcats are set as affiliated with civilians, do not trigger hostilities.
if ( gBloodcatPlacements[SECTOR(pSoldier->sSectorX, pSoldier->sSectorY)][ 0 ].PlacementType != BLOODCAT_PLACEMENT_STATIC ||
gBloodcatPlacements[SECTOR(pSoldier->sSectorX, pSoldier->sSectorY)][ gGameOptions.ubDifficultyLevel - 1 ].ubFactionAffiliation == NON_CIV_GROUP ||
gBloodcatPlacements[SECTOR(pSoldier->sSectorX, pSoldier->sSectorY)][ gGameOptions.ubDifficultyLevel - 1 ].ubFactionAffiliation == QUEENS_CIV_GROUP )
{
MakeBloodcatsHostile();
}
/*
SetSoldierNonNeutral( pOpponent );
RecalculateOppCntsDueToNoLongerNeutral( pOpponent );
@@ -5608,20 +5630,44 @@ void ProcessNoise(UINT8 ubNoiseMaker, INT16 sGridNo, INT8 bLevel, UINT8 ubTerrTy
break;
}
if ( gWorldSectorX == 5 && gWorldSectorY == MAP_ROW_N )
// HEADROCK HAM 3.6: Bloodcat "static" sectors have been externalized, and there can be more than one.
// Also, there's a toggle that determines whether or not bloodcats can sense enemies in this sector.
UINT8 ubSectorID = SECTOR(gWorldSectorX, gWorldSectorY);
UINT8 PlacementType = gBloodcatPlacements[ ubSectorID ][0].PlacementType;
if (PlacementType == BLOODCAT_PLACEMENT_STATIC)
{
// in the bloodcat arena sector, skip noises between army & bloodcats
if ( pSoldier->bTeam == ENEMY_TEAM && MercPtrs[ ubNoiseMaker ]->bTeam == CREATURE_TEAM )
if (gBloodcatPlacements[ ubSectorID ][ gGameOptions.ubDifficultyLevel-1 ].ubFactionAffiliation == QUEENS_CIV_GROUP)
{
continue;
// skip noises between army & bloodcats
if ( pSoldier->bTeam == ENEMY_TEAM && MercPtrs[ ubNoiseMaker ]->ubBodyType == BLOODCAT && MercPtrs[ ubNoiseMaker ]->bTeam == CREATURE_TEAM )
{
continue;
}
if ( pSoldier->bTeam == CREATURE_TEAM && pSoldier->ubBodyType == BLOODCAT && MercPtrs[ ubNoiseMaker ]->bTeam == ENEMY_TEAM )
{
continue;
}
}
if ( pSoldier->bTeam == CREATURE_TEAM && MercPtrs[ ubNoiseMaker ]->bTeam == ENEMY_TEAM )
else if (gBloodcatPlacements[ ubSectorID ][ gGameOptions.ubDifficultyLevel-1 ].ubFactionAffiliation > NON_CIV_GROUP)
{
continue;
if ( MercPtrs[ ubNoiseMaker ]->ubBodyType == BLOODCAT && MercPtrs[ ubNoiseMaker ]->bTeam == CREATURE_TEAM && pSoldier->bSide != gbPlayerNum)
{
// Target is a bloodcat. He can't be heard by civilians no matter what.
{
continue;
}
}
else if ( pSoldier->bTeam == CREATURE_TEAM && pSoldier->ubBodyType == BLOODCAT )
{
// Source is a bloodcat. He can only hear player-side soldiers, and only if hostile.
if ( MercPtrs[ ubNoiseMaker ]->bSide != gbPlayerNum || pSoldier->aiData.bNeutral )
{
continue;
}
}
}
}
}
else
{
@@ -7253,12 +7299,12 @@ void MakeBloodcatsHostile( void )
{
if ( pSoldier->ubBodyType == BLOODCAT && pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife > 0 )
{
SetSoldierNonNeutral( pSoldier );
RecalculateOppCntsDueToNoLongerNeutral( pSoldier );
if ( ( gTacticalStatus.uiFlags & INCOMBAT ) )
{
CheckForPotentialAddToBattleIncrement( pSoldier );
}
SetSoldierNonNeutral( pSoldier );
RecalculateOppCntsDueToNoLongerNeutral( pSoldier );
if ( ( gTacticalStatus.uiFlags & INCOMBAT ) )
{
CheckForPotentialAddToBattleIncrement( pSoldier );
}
}
}
+2
View File
@@ -151,4 +151,6 @@ extern INT8 gbLightSighting[1][16];
BOOLEAN SoldierHasLimitedVision(SOLDIERTYPE * pSoldier);
// HEADROCK HAM 3.6: Moved here from cpp
void MakeBloodcatsHostile( void );
#endif