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

* 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
+1 -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="Editor_2005Express"
ProjectGUID="{60D793F2-90B4-43C9-83B5-221EE11B37E6}"
RootNamespace="Editor_2005Express"
+254 -71
View File
@@ -172,6 +172,7 @@ BOOLEAN LoadGameSettings()
gGameSettings.fOptions[TOPTION_LOW_CPU_USAGE] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_LOW_CPU_USAGE" , FALSE );
gGameSettings.fOptions[TOPTION_ENHANCED_DESC_BOX] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_ENHANCED_DESC_BOX" , FALSE );
gGameSettings.fOptions[TOPTION_TOGGLE_TURN_MODE] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_TOGGLE_TURN_MODE" , FALSE );
gGameSettings.fOptions[TOPTION_STAT_PROGRESS_BARS] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_STAT_PROGRESS_BARS" , FALSE ); // HEADROCK HAM 3.6: Progress Bars
gGameSettings.fOptions[TOPTION_CHEAT_MODE_OPTIONS_HEADER] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_CHEAT_MODE_OPTIONS_HEADER" , FALSE );
gGameSettings.fOptions[TOPTION_FORCE_BOBBY_RAY_SHIPMENTS] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_FORCE_BOBBY_RAY_SHIPMENTS" , FALSE );
gGameSettings.fOptions[TOPTION_CHEAT_MODE_OPTIONS_END] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_CHEAT_MODE_OPTIONS_END" , FALSE );
@@ -342,6 +343,7 @@ BOOLEAN SaveGameSettings()
settings << "TOPTION_LOW_CPU_USAGE = " << (gGameSettings.fOptions[TOPTION_LOW_CPU_USAGE] ? "TRUE" : "FALSE" ) << endl;
settings << "TOPTION_ENHANCED_DESC_BOX = " << (gGameSettings.fOptions[TOPTION_ENHANCED_DESC_BOX] ? "TRUE" : "FALSE" ) << endl;
settings << "TOPTION_TOGGLE_TURN_MODE = " << (gGameSettings.fOptions[TOPTION_TOGGLE_TURN_MODE] ? "TRUE" : "FALSE" ) << endl;
settings << "TOPTION_STAT_PROGRESS_BARS = " << (gGameSettings.fOptions[TOPTION_STAT_PROGRESS_BARS] ? "TRUE" : "FALSE" ) << endl; // HEADROCK HAM 3.6: Progress Bars
settings << "TOPTION_CHEAT_MODE_OPTIONS_HEADER = " << (gGameSettings.fOptions[TOPTION_CHEAT_MODE_OPTIONS_HEADER] ? "TRUE" : "FALSE" ) << endl;
settings << "TOPTION_FORCE_BOBBY_RAY_SHIPMENTS = " << (gGameSettings.fOptions[TOPTION_FORCE_BOBBY_RAY_SHIPMENTS] ? "TRUE" : "FALSE" ) << endl;
settings << "TOPTION_CHEAT_MODE_OPTIONS_END = " << (gGameSettings.fOptions[TOPTION_CHEAT_MODE_OPTIONS_END] ? "TRUE" : "FALSE" ) << endl;
@@ -448,6 +450,11 @@ void InitGameSettings()
// arynn
gGameSettings.fOptions[ TOPTION_TOGGLE_TURN_MODE ] = FALSE;
// HEADROCK HAM 3.6:
gGameSettings.fOptions[ TOPTION_STAT_PROGRESS_BARS ] = FALSE;
// arynn: Cheat/Debug Menu
gGameSettings.fOptions[ TOPTION_CHEAT_MODE_OPTIONS_HEADER ] = FALSE;
gGameSettings.fOptions[ TOPTION_FORCE_BOBBY_RAY_SHIPMENTS ] = FALSE; // force all pending Bobby Ray shipments
gGameSettings.fOptions[ TOPTION_CHEAT_MODE_OPTIONS_END ] = FALSE;
@@ -745,6 +752,7 @@ void LoadGameExternalOptions()
gGameExternalOptions.ubMovementEffectiveness = iniReader.ReadInteger("JA2 Tactical Settings", "MOVEMENT_EFFECTIVENESS", 50, 0, 100);
gGameExternalOptions.ubCoverDisplayUpdateWait = iniReader.ReadInteger("JA2 Tactical Settings", "COVER_DISPLAY_UPDATE_WAIT", 500, -1, 10000);
//################# Rain Settings ##################
// Rain settings
@@ -929,9 +937,10 @@ void LoadGameExternalOptions()
gGameExternalOptions.guiCreateEachNHours = iniReader.ReadInteger("JA2 Gameplay Settings","CREATE_EACH_N_HOURS",24, 1, 96);
gGameExternalOptions.guiDivOfOriginalMilitia = iniReader.ReadInteger("JA2 Gameplay Settings","DIV_OF_ORIGINAL_MILITIA",4, 1, 100);
gGameExternalOptions.guiMinMilitiaSquadSize = iniReader.ReadInteger("JA2 Gameplay Settings","MINIMUM_MILITIA_SQUAD_SIZE",5, 1, CODE_MAXIMUM_NUMBER_OF_REBELS);
gGameExternalOptions.guiMaxMilitiaSquadSize = iniReader.ReadInteger("JA2 Gameplay Settings","MAXIMUM_MILITIA_SQUAD_SIZE",20, gGameExternalOptions.guiMinMilitiaSquadSize, CODE_MAXIMUM_NUMBER_OF_REBELS);
gGameExternalOptions.guiMaxMilitiaSquadSizeBattle = gGameExternalOptions.guiMaxMilitiaSquadSize;
// HEADROCK HAM 3.6: These settings are REDUNDANT.
//gGameExternalOptions.guiMinMilitiaSquadSize = iniReader.ReadInteger("JA2 Gameplay Settings","MINIMUM_MILITIA_SQUAD_SIZE",5, 1, CODE_MAXIMUM_NUMBER_OF_REBELS);
//gGameExternalOptions.guiMaxMilitiaSquadSize = iniReader.ReadInteger("JA2 Gameplay Settings","MAXIMUM_MILITIA_SQUAD_SIZE",20, gGameExternalOptions.guiMinMilitiaSquadSize, CODE_MAXIMUM_NUMBER_OF_REBELS);
//gGameExternalOptions.guiMaxMilitiaSquadSizeBattle = gGameExternalOptions.guiMaxMilitiaSquadSize;
gGameExternalOptions.iMaxMilitiaPerSector = iniReader.ReadInteger("JA2 Gameplay Settings","MAX_MILITIA_PER_SECTOR",20, 1, CODE_MAXIMUM_NUMBER_OF_REBELS);
gGameExternalOptions.iTrainingSquadSize = iniReader.ReadInteger("JA2 Gameplay Settings","MAX_TRAINING_SQUAD_SIZE",10, 1, CODE_MAXIMUM_NUMBER_OF_REBELS);
@@ -961,9 +970,11 @@ void LoadGameExternalOptions()
gGameExternalOptions.ubTrainingSkillMax = iniReader.ReadInteger("JA2 Gameplay Settings","TRAINING_SKILL_MAX",100, 0, 100);
gGameExternalOptions.ubSelfTrainingDivisor = iniReader.ReadInteger("JA2 Gameplay Settings","SELF_TRAINING_DIVISOR",1000, 1, 10000);
gGameExternalOptions.ubInstructedTrainingDivisor = iniReader.ReadInteger("JA2 Gameplay Settings","INSTRUCTED_TRAINING_DIVISOR",3000, 1, 10000);
gGameExternalOptions.ubGunRangeTrainingBonus = iniReader.ReadInteger("JA2 Gameplay Settings","GUN_RANGE_TRAINING_BONUS",25, 0, 100);
// HEADROCK HAM 3.5: No longer necessary
//gGameExternalOptions.ubGunRangeTrainingBonus = iniReader.ReadInteger("JA2 Gameplay Settings","GUN_RANGE_TRAINING_BONUS",25, 0, 100);
gGameExternalOptions.ubTownMilitiaTrainingRate = iniReader.ReadInteger("JA2 Gameplay Settings","MILITIA_TRAINING_RATE",4, 1, 10);
gGameExternalOptions.ubMaxMilitiaTrainersPerSector = iniReader.ReadInteger("JA2 Gameplay Settings","MAX_MILITIA_TRAINERS_PER_SECTOR",2, 1, gGameExternalOptions.ubGameMaximumNumberOfPlayerMercs);
// HEADROCK HAM 3.5: No longer necessary
//gGameExternalOptions.ubMaxMilitiaTrainersPerSector = iniReader.ReadInteger("JA2 Gameplay Settings","MAX_MILITIA_TRAINERS_PER_SECTOR",2, 1, gGameExternalOptions.ubGameMaximumNumberOfPlayerMercs);
gGameExternalOptions.ubTeachBonusToTrain = iniReader.ReadInteger("JA2 Gameplay Settings","TEACH_BONUS_TO_TRAIN",30, 0, 100);
gGameExternalOptions.ubRpcBonusToTrainMilitia = iniReader.ReadInteger("JA2 Gameplay Settings","RPC_BONUS_TO_TRAIN_MILITIA",10, 0, 100);
gGameExternalOptions.ubMinSkillToTeach = iniReader.ReadInteger("JA2 Gameplay Settings","MIN_RATING_TO_TEACH",25, 0, 100);
@@ -1008,62 +1019,55 @@ void LoadGameExternalOptions()
gGameExternalOptions.fRestrictFemaleEnemiesExceptElite = iniReader.ReadBoolean("JA2 Gameplay Settings","RESTRICT_FEMALE_ENEMIES_EXCEPT_ELITE",FALSE);
// HEADROCK: Use Enhanced Item Description Box?
gGameExternalOptions.fEnhancedDescriptionBox = iniReader.ReadInteger("JA2 Gameplay Settings","USE_ENHANCED_DESCRIPTION_BOX",0, 0, 2);
gGameExternalOptions.iEnhancedDescriptionBox = iniReader.ReadInteger("JA2 Gameplay Settings","USE_ENHANCED_DESCRIPTION_BOX",0, 0, 2);
// WANNE: Always use prof.dat??
gGameExternalOptions.fAlwaysUseProfDat = iniReader.ReadBoolean("JA2 Gameplay Settings", "ALWAYS_USE_PROF_DAT", FALSE);
// HEADROCK HAM B2.4
gGameExternalOptions.iMineIncomePercentage = iniReader.ReadInteger("JA2 HAM Settings","MINE_INCOME_PERCENTAGE", 100, 1, 1000);
/////////////////////////////////////////////////////////////////////////
// JA2 HAM Settings
/////////////////////////////////////////////////////////////////////////
// HEADROCK HAM B1: Set % of mine income, where 100% = normal
gGameExternalOptions.usMineIncomePercentage = iniReader.ReadInteger("JA2 HAM Settings","MINE_INCOME_PERCENTAGE", 100, 1, 1000);
// HEADROCK HAM B1: Set minimum and maximum CTH
gGameExternalOptions.iMaximumCTH = iniReader.ReadInteger("JA2 HAM Settings","MAXIMUM_POSSIBLE_CTH",99);
gGameExternalOptions.ubMaximumCTH = iniReader.ReadInteger("JA2 HAM Settings","MAXIMUM_POSSIBLE_CTH", 99, 1, 100);
gGameExternalOptions.iMinimumCTH = iniReader.ReadInteger("JA2 HAM Settings","MINIMUM_POSSIBLE_CTH",0);
gGameExternalOptions.ubMinimumCTH = iniReader.ReadInteger("JA2 HAM Settings","MINIMUM_POSSIBLE_CTH", 1, 0, 99);
// HEADROCK HAM B1: Set minimum CTH at fraction between 0 and 1 ( MINCTH = 1/(100*divisor) ) Note Minimum above must be 0.
gGameExternalOptions.iMinimumCTHDivisor = iniReader.ReadInteger("JA2 HAM Settings","MINIMUM_CTH_DIVISOR",100);
gGameExternalOptions.usMinimumCTHDivisor = iniReader.ReadInteger("JA2 HAM Settings","MINIMUM_CTH_DIVISOR", 100, 1, 250);
// HEADROCK HAM B1: Allow restricted militia to move through visited sectors?
gGameExternalOptions.bUnrestrictVisited = iniReader.ReadBoolean("JA2 HAM Settings","ALLOW_RESTRICTED_MILITIA_THROUGH_VISITED_SECTORS",FALSE);
gGameExternalOptions.fUnrestrictVisited = iniReader.ReadBoolean("JA2 HAM Settings","ALLOW_RESTRICTED_MILITIA_THROUGH_VISITED_SECTORS", FALSE);
gGameExternalOptions.bDynamicRestrictRoaming = iniReader.ReadBoolean("JA2 HAM Settings","ALLOW_DYNAMIC_RESTRICTED_ROAMING",TRUE);
// HEADROCK HAM B2: Reset suppression counter. 0 = never (oldskool), 1 = Every turn, 2 = Every attack.
gGameExternalOptions.iClearSuppression = iniReader.ReadInteger("JA2 HAM Settings","CLEAR_SUPPRESSION_COUNTER",1);
// HEADROCK HAM B1: Allow dynamic restrictions?
gGameExternalOptions.fDynamicRestrictRoaming = iniReader.ReadBoolean("JA2 HAM Settings","ALLOW_DYNAMIC_RESTRICTED_ROAMING", TRUE);
// HEADROCK HAM B2.1: This controls how effective suppression is, by increasing the number of ubSuppressionPoints accumulated by combatants (percentage);
gGameExternalOptions.iSuppressionEffectiveness = iniReader.ReadInteger("JA2 HAM Settings","SUPPRESSION_EFFECTIVENESS",0);
gGameExternalOptions.sSuppressionEffectiveness = iniReader.ReadInteger("JA2 HAM Settings","SUPPRESSION_EFFECTIVENESS", 0, 0, 1000);
// HEADROCK HAM B2: MAXIMUM number of APs that can be lost to suppression in a given turn (0=unlimited)
gGameExternalOptions.fSuppressionAPLossPerTurn = iniReader.ReadBoolean("JA2 HAM Settings","LIMITED_SUPPRESSION_AP_LOSS_PER_TURN",TRUE);
// HEADROCK HAM B2: MAXIMUM number of APs that can be lost to suppression in a given attack (0=unlimited)
gGameExternalOptions.fSuppressionAPLossPerAttack = iniReader.ReadBoolean("JA2 HAM Settings","LIMITED_SUPPRESSION_AP_LOSS_PER_ATTACK",TRUE);
gGameExternalOptions.iSuppressionToleranceMax = iniReader.ReadInteger("JA2 HAM Settings","SUPPRESSION_TOLERANCE_MAX", 18, 1, 24);
gGameExternalOptions.iSuppressionToleranceMin = iniReader.ReadInteger("JA2 HAM Settings","SUPPRESSION_TOLERANCE_MIN", 1, 0, 24);
// HEADROCK HAM B2: Suppression Shock ON/OFF
gGameExternalOptions.fSuppressionShock = iniReader.ReadBoolean("JA2 HAM Settings","SUPPRESSION_SHOCK",FALSE);
gGameExternalOptions.ubSuppressionToleranceMax = iniReader.ReadInteger("JA2 HAM Settings","SUPPRESSION_TOLERANCE_MAX", 18, 1, 24);
gGameExternalOptions.ubSuppressionToleranceMin = iniReader.ReadInteger("JA2 HAM Settings","SUPPRESSION_TOLERANCE_MIN", 1, 0, 24);
// HEADROCK HAM B2: Suppression Shock effectiveness (percentage, 100 = "normal", 0 = deactivated. Range 0-65535)
gGameExternalOptions.iSuppressionShockEffectiveness = iniReader.ReadInteger("JA2 HAM Settings","SUPPRESSION_SHOCK_EFFECTIVENESS",0);
gGameExternalOptions.usSuppressionShockEffect = iniReader.ReadInteger("JA2 HAM Settings","SUPPRESSION_SHOCK_EFFECTIVENESS", 100, 0, 1000);
// HEADROCK HAM B2.1: CTH penalty given by a "Cowering" target to any enemy shooter.
gGameExternalOptions.iAimPenaltyPerTargetShock = iniReader.ReadInteger("JA2 HAM Settings","AIM_PENALTY_PER_TARGET_SHOCK",0);
gGameExternalOptions.ubAimPenaltyPerTargetShock = iniReader.ReadInteger("JA2 HAM Settings","AIM_PENALTY_PER_TARGET_SHOCK", 5, 0, 100 );
// HEADROCK HAM B2.3: A "cowering" soldier is twice as susceptible to suppression.
gGameExternalOptions.iCowerEffectOnSuppression = iniReader.ReadInteger("JA2 HAM Settings","COWER_EFFECT_ON_SUPPRESSION",0);
gGameExternalOptions.usCowerEffectOnSuppression = iniReader.ReadInteger("JA2 HAM Settings","COWER_EFFECT_ON_SUPPRESSION", 150, 0, 1000 );
// HEADROCK HAM B2.5: Turn on Realistic Tracers. 0 = off (regular tracers). 1 = Fully realistic tracers. 2 = Tracer Bump + 1.13 Autofire Penalty Reduction
gGameExternalOptions.iRealisticTracers = iniReader.ReadInteger("JA2 HAM Settings","REALISTIC_TRACERS",0);
gGameExternalOptions.ubRealisticTracers = iniReader.ReadInteger("JA2 HAM Settings","REALISTIC_TRACERS", 0, 0, 2);
// HEADROCK HAM B2.5: Realistic tracers - one of every X bullets in a tracer magazines will be a tracer bullet. 0 = off (JA2 normal)
gGameExternalOptions.iNumBulletsPerTracer = __max(iniReader.ReadInteger("JA2 HAM Settings","NUM_BULLETS_PER_TRACER",1),1);
gGameExternalOptions.ubNumBulletsPerTracer = __max(iniReader.ReadInteger("JA2 HAM Settings","NUM_BULLETS_PER_TRACER", 5, 1, 255),1);
// HEADROCK HAM B2.5: Realistic tracers - CTH increased by this amount whenever a tracer is fired. 0 = off.
gGameExternalOptions.iCTHBumpPerTracer = iniReader.ReadInteger("JA2 HAM Settings","CTH_BUMP_PER_TRACER",0);
gGameExternalOptions.ubCTHBumpPerTracer = iniReader.ReadInteger("JA2 HAM Settings","CTH_BUMP_PER_TRACER", 30, 0, 100 );
// HEADROCK HAM B2.6: Increased aiming costs?
gGameExternalOptions.fIncreasedAimingCost = iniReader.ReadBoolean("JA2 HAM Settings","INCREASED_AIM_COST", FALSE);
@@ -1076,33 +1080,33 @@ void LoadGameExternalOptions()
gGameExternalOptions.iMovementEffectOnAiming = (float)iniReader.ReadDouble("JA2 HAM Settings","MOVEMENT_EFFECT_ON_AIMING", 1.5, 0.0, 255.0);
// HEADROCK HAM B2.6: Autofire Bullets/5AP modifier
gGameExternalOptions.iAutofireBulletsPer5APModifier = iniReader.ReadInteger("JA2 HAM Settings","AUTOFIRE_BULLETS_PER_5AP_MODIFIER", 0);
gGameExternalOptions.bAutofireBulletsPer5APModifier = iniReader.ReadInteger("JA2 HAM Settings","AUTOFIRE_BULLETS_PER_5AP_MODIFIER", 0, -100, 100 );
// HEADROCK HAM B2.6/B1: Adjustable "luck" factor in Auto-Resolve
//gGameExternalOptions.iAutoResolveLuckFactor = (float)(__max(iniReader.ReadFloat("JA2 HAM Settings","AUTORESOLVE_LUCK_FACTOR", 2.0),1.0));
gGameExternalOptions.iAutoResolveLuckFactor = (float)(__max(iniReader.ReadDouble("JA2 HAM Settings","AUTORESOLVE_LUCK_FACTOR", 2.0, 0.0, 255.0),1.0));
// HEADROCK HAM B2.6: Adjustable maximum for Suppression Shock effect. This has the added effect of reducing overall susceptibility to shock and may render some enemies unshockable.
gGameExternalOptions.iMaxSuppressionShock = iniReader.ReadInteger("JA2 HAM Settings","MAXIMUM_SUPPRESSION_SHOCK", 0);
gGameExternalOptions.ubMaxSuppressionShock = iniReader.ReadInteger("JA2 HAM Settings","MAXIMUM_SUPPRESSION_SHOCK", 30, 0, 200 );
// HEADROCK HAM B2.6/2/1: Toggle new Burst/Auto CTH bars: 0=neither, 1=both, 2=Burst, 3=Auto
gGameExternalOptions.iNewCTHBars = iniReader.ReadInteger("JA2 HAM Settings","NEW_BURST-AUTO_CTH_BARS", 0);
gGameExternalOptions.ubNewCTHBars = iniReader.ReadInteger("JA2 HAM Settings","NEW_BURST-AUTO_CTH_BARS", 0, 0, 3);
// HEADROCK HAM B2.6: Toggle whether AI checks for larger magazine when wanting to suppress at a distance
gGameExternalOptions.fIncreaseAISuppressionFire = iniReader.ReadBoolean("JA2 HAM Settings","INCREASE_AI_WILLINGNESS_TO_SUPPRESS", FALSE);
// HEADROCK HAM B2.7: Change the speed of skill progression. (defaults set to JA2 normal)
gGameExternalOptions.ubHealthSubpointsToImprove = __max(1,iniReader.ReadInteger("JA2 HAM Settings","HEALTH_SUBPOINTS_TO_IMPROVE", 50));
gGameExternalOptions.ubStrengthSubpointsToImprove = __max(1,iniReader.ReadInteger("JA2 HAM Settings","STRENGTH_SUBPOINTS_TO_IMPROVE", 50));
gGameExternalOptions.ubDexteritySubpointsToImprove = __max(1,iniReader.ReadInteger("JA2 HAM Settings","DEXTERITY_SUBPOINTS_TO_IMPROVE", 50));
gGameExternalOptions.ubAgilitySubpointsToImprove = __max(1,iniReader.ReadInteger("JA2 HAM Settings","AGILITY_SUBPOINTS_TO_IMPROVE", 50));
gGameExternalOptions.ubWisdomSubpointsToImprove = __max(1,iniReader.ReadInteger("JA2 HAM Settings","WISDOM_SUBPOINTS_TO_IMPROVE", 50));
gGameExternalOptions.ubMarksmanshipSubpointsToImprove = __max(1,iniReader.ReadInteger("JA2 HAM Settings","MARKSMANSHIP_SUBPOINTS_TO_IMPROVE", 25));
gGameExternalOptions.ubMedicalSubpointsToImprove = __max(1,iniReader.ReadInteger("JA2 HAM Settings","MEDICAL_SUBPOINTS_TO_IMPROVE", 25));
gGameExternalOptions.ubMechanicalSubpointsToImprove = __max(1,iniReader.ReadInteger("JA2 HAM Settings","MECHANICAL_SUBPOINTS_TO_IMPROVE", 25));
gGameExternalOptions.ubExplosivesSubpointsToImprove = __max(1,iniReader.ReadInteger("JA2 HAM Settings","EXPLOSIVES_SUBPOINTS_TO_IMPROVE", 25));
gGameExternalOptions.ubLeadershipSubpointsToImprove = __max(1,iniReader.ReadInteger("JA2 HAM Settings","LEADERSHIP_SUBPOINTS_TO_IMPROVE", 25));
gGameExternalOptions.ubLevelSubpointsToImprove = __max(1,__min(iniReader.ReadInteger("JA2 HAM Settings","LEVEL_SUBPOINTS_TO_IMPROVE", 350), 6500));
gGameExternalOptions.usHealthSubpointsToImprove = iniReader.ReadInteger("JA2 HAM Settings","HEALTH_SUBPOINTS_TO_IMPROVE", 50, 1, 1000 );
gGameExternalOptions.usStrengthSubpointsToImprove = iniReader.ReadInteger("JA2 HAM Settings","STRENGTH_SUBPOINTS_TO_IMPROVE", 50, 1, 1000 );
gGameExternalOptions.usDexteritySubpointsToImprove = iniReader.ReadInteger("JA2 HAM Settings","DEXTERITY_SUBPOINTS_TO_IMPROVE", 50, 1, 1000 );
gGameExternalOptions.usAgilitySubpointsToImprove = iniReader.ReadInteger("JA2 HAM Settings","AGILITY_SUBPOINTS_TO_IMPROVE", 50, 1, 1000 );
gGameExternalOptions.usWisdomSubpointsToImprove = iniReader.ReadInteger("JA2 HAM Settings","WISDOM_SUBPOINTS_TO_IMPROVE", 50, 1, 1000 );
gGameExternalOptions.usMarksmanshipSubpointsToImprove = iniReader.ReadInteger("JA2 HAM Settings","MARKSMANSHIP_SUBPOINTS_TO_IMPROVE", 25, 1, 1000 );
gGameExternalOptions.usMedicalSubpointsToImprove = iniReader.ReadInteger("JA2 HAM Settings","MEDICAL_SUBPOINTS_TO_IMPROVE", 25, 1, 1000 );
gGameExternalOptions.usMechanicalSubpointsToImprove = iniReader.ReadInteger("JA2 HAM Settings","MECHANICAL_SUBPOINTS_TO_IMPROVE", 25, 1, 1000 );
gGameExternalOptions.usExplosivesSubpointsToImprove = iniReader.ReadInteger("JA2 HAM Settings","EXPLOSIVES_SUBPOINTS_TO_IMPROVE", 25, 1, 1000 );
gGameExternalOptions.usLeadershipSubpointsToImprove = iniReader.ReadInteger("JA2 HAM Settings","LEADERSHIP_SUBPOINTS_TO_IMPROVE", 25, 1, 1000 );
gGameExternalOptions.usLevelSubpointsToImprove = iniReader.ReadInteger("JA2 HAM Settings","LEVEL_SUBPOINTS_TO_IMPROVE", 350, 1, 6500);
// HEADROCK HAM B2.7: When turned on, this will give a CTH approximation instead of an exact value, on CTH Bars and "F" key feedback.
gGameExternalOptions.fApproximateCTH = iniReader.ReadBoolean("JA2 HAM Settings","APPROXIMATE_CTH", FALSE);
@@ -1110,42 +1114,208 @@ void LoadGameExternalOptions()
// HEADROCK HAM B2.7: Augmented Roaming Militia code - turn this to TRUE to allow militia free travel through San Mona, Tixa, Orta, Omerta, and Estoni.
gGameExternalOptions.fAllowMilitiaMoveThroughMinorCities = iniReader.ReadBoolean("JA2 HAM Settings","ALLOW_MILITIA_MOVE_THROUGH_MINOR_CITIES", FALSE);
// HEADROCK HAM B2.7: Smarter Roaming Militia Generator will generate Roamers in any available city perimeter square, allowing us to avoid "wasting" training sessions more easily.
gGameExternalOptions.fSmartRoamingMilitiaGenerator = iniReader.ReadBoolean("JA2 HAM Settings","SMART_ROAMING_MILITIA_GENERATOR", FALSE);
// HEADROCK HAM B2.7: When "TRUE", Roaming Militia will be created on a 25% Veteran, 25% Regular, 50% green basis. If new militia is placed into a full group, it will upgrade greens/regulars in that group.
gGameExternalOptions.fDiverseRoamingMilitiaGroups = iniReader.ReadBoolean("JA2 HAM Settings","DIVERSE_ROAMING_MILITIA_GROUPS", FALSE);
// HEADROCK HAM B2.8: This setting controls whether militia will try to join up into the largest groups they can, or average out the size of the groups to cover more territory.
gGameExternalOptions.ubRoamingMilitiaSpreadsOutChance = iniReader.ReadInteger("JA2 HAM Settings","ROAMING_MILITIA_SPREADOUT_CHANCE", 0);
// HEADROCK HAM B2.8: These are new cowering penalty divisors that help us determine how effective cowering is in different stances and when the shooter is targetting different bodyparts
gGameExternalOptions.ubCoweringPenaltyDivisorProne = __max(1,iniReader.ReadInteger("JA2 HAM Settings","CTH_PENALTY_FOR_COWERING_PRONE_TARGET_DIVISOR", 1));
gGameExternalOptions.ubCoweringPenaltyDivisorCrouchedHead = __max(1,iniReader.ReadInteger("JA2 HAM Settings","CTH_PENALTY_FOR_COWERING_CROUCHED_TARGET_HEAD_DIVISOR", 3));
gGameExternalOptions.ubCoweringPenaltyDivisorCrouchedTorso = __max(1,iniReader.ReadInteger("JA2 HAM Settings","CTH_PENALTY_FOR_COWERING_CROUCHED_TARGET_TORSO_DIVISOR", 4));
gGameExternalOptions.ubCoweringPenaltyDivisorCrouchedLegs = __max(1,iniReader.ReadInteger("JA2 HAM Settings","CTH_PENALTY_FOR_COWERING_CROUCHED_TARGET_LEGS_DIVISOR", 5));
gGameExternalOptions.ubCoweringPenaltyDivisorProne = iniReader.ReadInteger("JA2 HAM Settings","CTH_PENALTY_FOR_COWERING_PRONE_TARGET_DIVISOR", 1, 1, 100 );
gGameExternalOptions.ubCoweringPenaltyDivisorCrouchedHead = iniReader.ReadInteger("JA2 HAM Settings","CTH_PENALTY_FOR_COWERING_CROUCHED_TARGET_HEAD_DIVISOR", 3, 1, 100);
gGameExternalOptions.ubCoweringPenaltyDivisorCrouchedTorso = iniReader.ReadInteger("JA2 HAM Settings","CTH_PENALTY_FOR_COWERING_CROUCHED_TARGET_TORSO_DIVISOR", 4, 1, 100);
gGameExternalOptions.ubCoweringPenaltyDivisorCrouchedLegs = iniReader.ReadInteger("JA2 HAM Settings","CTH_PENALTY_FOR_COWERING_CROUCHED_TARGET_LEGS_DIVISOR", 5, 1, 100);
// HEADROCK HAM B2.8: This is the maximum range at which a target gives out the full CTH penalty for cowering. At lower range, it'll give proportionally less penalty.
gGameExternalOptions.usMinRangeForFullCoweringPenalty = __max(10,iniReader.ReadInteger("JA2 HAM Settings","MIN_RANGE_FOR_FULL_COWERING_TARGET_PENALTY", 300));
gGameExternalOptions.usMinRangeForFullCoweringPenalty = iniReader.ReadInteger("JA2 HAM Settings","MIN_RANGE_FOR_FULL_COWERING_TARGET_PENALTY", 300, 10, 10000 );
// HEADROCK HAM B2.8: Absolute maximum CTH penalty from target/shooter cowering
gGameExternalOptions.usMaxShooterCoweringPenalty = __max(1,iniReader.ReadInteger("JA2 HAM Settings","MAX_SHOOTER_COWERING_PENALTY", 0));
gGameExternalOptions.usMaxTargetCoweringPenalty = __max(1,iniReader.ReadInteger("JA2 HAM Settings","MAX_TARGET_COWERING_PENALTY", 0));
gGameExternalOptions.usMaxShooterCoweringPenalty = iniReader.ReadInteger("JA2 HAM Settings","MAX_SHOOTER_COWERING_PENALTY", 0, 0, 250 );
gGameExternalOptions.usMaxTargetCoweringPenalty = iniReader.ReadInteger("JA2 HAM Settings","MAX_TARGET_COWERING_PENALTY", 0, 0, 250 );
// HEADROCK HAM B2.8: If this is turned on, Militia will drop their equipment similar to enemies, IF killed by non-player character.
gGameExternalOptions.ubMilitiaDropEquipment = iniReader.ReadInteger("JA2 HAM Settings","MILITIA_DROP_EQUIPMENT", 0);
// HEADROCK HAM B2.8: At "1", Militia will drop their equipment similar to enemies, IF killed by non-player character. At "2" they drop whenever killed.
gGameExternalOptions.ubMilitiaDropEquipment = iniReader.ReadInteger("JA2 HAM Settings","MILITIA_DROP_EQUIPMENT", 0, 0, 2 );
// HEADROCK HAM B2.8: New Trainer Relations: 2 = Trainees will go to sleep when their trainer goes to sleep. 3 = Trainer will go to sleep if all trainees are asleep. 1 = Both. 0 = Neither.
gGameExternalOptions.ubSmartTrainingSleep = iniReader.ReadInteger("JA2 HAM Settings","SMART_TRAINING-SLEEP_HANDLER", 0);
gGameExternalOptions.ubSmartTrainingSleep = iniReader.ReadInteger("JA2 HAM Settings","SMART_TRAINING-SLEEP_HANDLER", 0, 0, 3);
// HEADROCK HAM B2.8: New Trainer Relations: 2 = Trainees will wake up when their trainer wakes up. 3 = Trainer will wake up if all trainees wake up. 1 = Both. 0 = Neither.
gGameExternalOptions.ubSmartTrainingWake = iniReader.ReadInteger("JA2 HAM Settings","SMART_TRAINING-WAKE_HANDLER", 0);
gGameExternalOptions.ubSmartTrainingWake = iniReader.ReadInteger("JA2 HAM Settings","SMART_TRAINING-WAKE_HANDLER", 0, 0, 3);
// HEADROCK HAM B2.8: New Trainer Relations: 2 = Trainers will rest if no trainees available. 3 = Trainees will rest if no trainers available (not recommended). 1 = Both. 0 = Neither.
gGameExternalOptions.ubSmartTrainingRest = iniReader.ReadInteger("JA2 HAM Settings","SMART_TRAINING_REST", 0);
gGameExternalOptions.ubSmartTrainingRest = iniReader.ReadInteger("JA2 HAM Settings","SMART_TRAINING_REST", 0, 0, 3);
// WANNE: HEADROCK HAM 3: Bobby Rays attachment tooltips
gGameExternalOptions.fBobbyRayTooltipsShowAttachments = iniReader.ReadBoolean("JA2 HAM Settings","BOBBY_RAY_TOOLTIPS_SHOW_POSSIBLE_ATTACHMENTS", FALSE);
// HEADROCK HAM 3: Externalized ratio between Weight and Strength. This value determines how many strength points we need to lift 0.5kg with no encumberance.
gGameExternalOptions.iStrengthToLiftHalfKilo = (float)iniReader.ReadDouble("JA2 HAM Settings","STRENGTH_TO_LIFT_HALF_KILO", 1.0, 0.1, 100.0);
// HEADROCK HAM 3: Define minimum leadership required for training militia. Set to 0 for "no limit".
gGameExternalOptions.ubMinimumLeadershipToTrainMilitia = iniReader.ReadInteger("JA2 HAM Settings","MINIMUM_LEADERSHIP_TO_TRAIN_MILITIA", 0, 0, 99);
// HEADROCK HAM 3: Define effect of "TEACHER" trait in increasing effective leadership, for purposes of eligibility for training militia. This is a percentage value. HAM Default would be 200 = double effective leadership for each TEACHING level.
gGameExternalOptions.usTeacherTraitEffectOnLeadership = iniReader.ReadInteger("JA2 HAM Settings","TEACHER_TRAIT_EFFECT_ON_LEADERSHIP", 100, 1, 10000);
// HEADROCK HAM 3: If enabled, the trainer's "effective" leadership skill determines HOW MANY militia he/she creates per session.
gGameExternalOptions.fLeadershipAffectsMilitiaQuantity = iniReader.ReadBoolean("JA2 HAM Settings","LEADERSHIP_AFFECTS_MILITIA_QUANTITY", FALSE);
// HEADROCK HAM 3: If "LEADERSHIP_AFFECTS_MILITIA_QUANTITY" is true, this value determines the lowest leadership required to train a full (default size 10) squad of town militia in one training session.
gGameExternalOptions.ubReqLeadershipForFullTraining = iniReader.ReadInteger("JA2 HAM Settings","REQ_LEADERSHIP_FOR_MAX_MILITIA", 100, 1, 100);
// HEADROCK HAM 3: Four INI settings to control the number of kills you must accumulate to win one progress point, one setting per difficulty level
gGameExternalOptions.usNumKillsPerProgressPointNovice = iniReader.ReadInteger("JA2 HAM Settings","NUM_KILLS_PER_PROGRESS_POINT_NOVICE", 7, 1, 1000);
gGameExternalOptions.usNumKillsPerProgressPointExperienced = iniReader.ReadInteger("JA2 HAM Settings","NUM_KILLS_PER_PROGRESS_POINT_EXPERIENCED", 10, 1, 1000);
gGameExternalOptions.usNumKillsPerProgressPointExpert = iniReader.ReadInteger("JA2 HAM Settings","NUM_KILLS_PER_PROGRESS_POINT_EXPERT", 15, 1, 1000);
gGameExternalOptions.usNumKillsPerProgressPointInsane = iniReader.ReadInteger("JA2 HAM Settings","NUM_KILLS_PER_PROGRESS_POINT_INSANE", 60, 1, 1000);
// HEADROCK HAM 3: If enabled, changes the way the game calculates progress. It will look at each progress control separately (Kills/Income/Control/Visited) and set the progress to the HIGHEST scoring control.
gGameExternalOptions.fAlternateProgressCalculation = iniReader.ReadBoolean("JA2 HAM Settings","ALTERNATE_PROGRESS_CALCULATION", FALSE);
// HEADROCK HAM 3: If enabled, tooltipping over Bobby Ray's weapons will show a list of possible attachments to those weapons.
gGameExternalOptions.fBobbyRayTooltipsShowAttachments = iniReader.ReadBoolean("JA2 HAM Settings","BOBBY_RAY_TOOLTIPS_SHOW_POSSIBLE_ATTACHMENTS", FALSE);
// HEADROCK HAM 3.1: Divisor for the AP-to-Ready cost charge on first aiming click, when extra aiming costs are enabled. 0 = No ready-time-based charge.
gGameExternalOptions.ubFirstAimReadyCostDivisor = iniReader.ReadInteger("JA2 HAM Settings","FIRST_AIM_READY_COST_DIVISOR", 0, 0, 255);
// HEADROCK HAM 3.1: This is a suppression tool that not everyone will like. It gives an on-screen message when any character has been suppressed so much he's lost his next turn completely!
gGameExternalOptions.fShowSuppressionShutdown = iniReader.ReadBoolean("JA2 HAM Settings","SHOW_MSG_FULLY_SUPPRESSED", FALSE);
// HEADROCK HAM 3.1: Set whether you'd like to determine yourself which mine (if any) will shut down during the campaign.
gGameExternalOptions.fManuallySelectMineShutdown = iniReader.ReadBoolean("JA2 HAM Settings","MANUALLY_SELECT_MINE_TO_RUN_OUT", FALSE);
// HEADROCK HAM 3.1: Select which mine will run out. 0 = no mine. 1 = San Mona (unused), 2 = Drassen, 3 = Alma, 4 = Cambria, 5 = Chitzena, 6 = Grumm.
gGameExternalOptions.ubWhichMineRunsOut = iniReader.ReadInteger("JA2 HAM Settings","WHICH_MINE_RUNS_OUT", 0, 0, 6);
// HEADROCK HAM 3.1: Can the Humvee go off-road?
gGameExternalOptions.fHumveeOffroad = iniReader.ReadBoolean("JA2 HAM Settings","HUMVEE_OFFROAD", FALSE);
// HEADROCK HAM 3.2: If activated, reinforcements (militia/enemy) arrive in the battle with 0 APs. This makes them less of a diablo-ex-machina. 0 = Diabled. 2 = Enemies. 3 = Militia. 1 = both
gGameExternalOptions.ubReinforcementsFirstTurnFreeze = iniReader.ReadInteger("JA2 HAM Settings","REINFORCEMENTS_ARRIVE_WITH_NO_AP", 0, 0, 3);
// HEADROCK HAM 3.2: This feature allows the status, leadership and experience of nearby friendlies help/hinder a character's tolerance, based on their distance from him.
gGameExternalOptions.fFriendliesAffectTolerance = iniReader.ReadBoolean("JA2 HAM Settings","FRIENDLIES_AFFECT_TOLERANCE", FALSE);
// HEADROCK HAM 3.2: Set a divisor for the CtH of Mortar weapons.
gGameExternalOptions.ubMortarCTHDivisor = iniReader.ReadInteger("JA2 HAM Settings","MORTAR_CTH_DIVISOR", 1, 1, 255);
// HEADROCK HAM 3.2: This enabled reduced sight for cowering characters. 0 = disabled. 2 = Reduced Sightrange. 3 = Tunnel-vision. 1 = Both.
gGameExternalOptions.ubCoweringReducesSightRange = iniReader.ReadInteger("JA2 HAM Settings","COWERING_REDUCES_SIGHTRANGE", 0, 0, 3);
// HEADROCK HAM 3.2: Critical Headshots may cause blindness. Rolls 1 to X change of being blinded. 0 = disabled.
gGameExternalOptions.ubChanceBlindedByHeadshot = iniReader.ReadInteger("JA2 HAM Settings","CHANCE_BLINDED_BY_HEADSHOT", 0, 0, 10);
// HEADROCK HAM 3.2: Critical Legshots cause additional AP loss
gGameExternalOptions.fCriticalLegshotCausesAPLoss = iniReader.ReadBoolean("JA2 HAM Settings","CRITICAL_LEGSHOT_CAUSES_AP_LOSS", FALSE);
// HEADROCK HAM 3.2: When enabled, this setting removes the player's omniscience inside his own sectors. The player will no longer see the movement of enemy groups unless someone is nearby to scout them.
gGameExternalOptions.fNoEnemyDetectionWithoutRecon = iniReader.ReadBoolean("JA2 HAM Settings","NO_ENEMY_DETECTION_WITHOUT_RECON", FALSE);
// HEADROCK HAM 3.2: Determines the training bonus for the Medical skill, when training in "hospital" sectors
gGameExternalOptions.ubHospitalTrainingBonus = iniReader.ReadInteger("JA2 HAM Settings","HOSPITAL_TRAINING_BONUS", 0, 0, 100);
// HEADROCK HAM 3.2: Determines the repaid bonus when training in factory ("industrial") sectors - in percentage of the character's original repair points!
gGameExternalOptions.ubFactoryRepairBonus = iniReader.ReadInteger("JA2 HAM Settings","FACTORY_REPAIR_BONUS", 0, 0, 100);
// HEADROCK HAM 3.2: How much MECHANICAL skill do we need to gain a repair bonus from a factory?
gGameExternalOptions.ubMinMechanicalForFactoryRepairBonus = iniReader.ReadInteger("JA2 HAM Settings","MIN_MECHANICAL_FOR_FACTORY_REPAIR_BONUS", 0, 0, 100);
// HEADROCK HAM 3.3: Externalized maximum possible penalty for hitting a moving target. JA2 Default = 30.
gGameExternalOptions.usMaxCTHPenaltyForMovingTarget = iniReader.ReadInteger("JA2 HAM Settings","MAX_CTH_PENALTY_FOR_MOVING_TARGET", 30, 0, 300);
// HEADROCK HAM 3.3: Increases tolerance while moving.
gGameExternalOptions.ubTilesMovedPerBonusTolerancePoint = iniReader.ReadInteger("JA2 HAM Settings","TILES_MOVED_PER_BONUS_TOLERANCE_POINT", 5, 0, 20);
// HEADROCK HAM 3.3: New militia feature, Minimum Leadership required to train Roaming Militia
gGameExternalOptions.ubMinimumLeadershipToTrainMobileMilitia = iniReader.ReadInteger("JA2 HAM Settings","MIN_LEADERSHIP_TO_TRAIN_MOBILE_MILITIA", 0, 0, 100);
// HEADROCK HAM 3.3: If enabled, the trainer's "effective" leadership skill determines HOW MANY Mobile Militia he/she creates per session.
gGameExternalOptions.fLeadershipAffectsMobileMilitiaQuantity = iniReader.ReadBoolean("JA2 HAM Settings","LEADERSHIP_AFFECTS_MOBILE_MILITIA_QUANTITY", FALSE);
// HEADROCK HAM 3.3: If "LEADERSHIP_AFFECTS_MILITIA_QUANTITY" is true, this value determines the lowest leadership required to train a full (default size 5) squad of Mobile Militia in one training session.
gGameExternalOptions.ubReqLeadershipForFullMobileTraining = iniReader.ReadInteger("JA2 HAM Settings","REQ_LEADERSHIP_FOR_MAX_MOBILE_MILITIA", 1, 1, 100);
// HEADROCK HAM 3.3: Minimum distance (in METERS) at which character suffer from friendly suppression.
gGameExternalOptions.usMinDistanceFriendlySuppression = iniReader.ReadInteger("JA2 HAM Settings","MIN_DISTANCE_FRIENDLY_SUPPRESSION", 30, 0, 65000);
// HEADROCK HAM 3.3: If enabled, Roaming Militia can automatically reinforce city garrisons.
gGameExternalOptions.fAllowMobileReinforceCities = iniReader.ReadBoolean("JA2 HAM Settings","ALLOW_MOBILE_MILITIA_REINFORCE_TOWN_GARRISONS", FALSE);
// HEADROCK HAM 3.3: If enabled, Roaming Militia can automatically reinforce city garrisons.
gGameExternalOptions.fAllowMobileReinforceSAM = iniReader.ReadBoolean("JA2 HAM Settings","ALLOW_MOBILE_MILITIA_REINFORCE_SAM_GARRISONS", FALSE);
// HEADROCK HAM 3.4: This controls the intensity of Hiding the Bullet Count during combat. The higher it is, the more intense the effect. Negative values reduce the effect.
gGameExternalOptions.usBulletHideIntensity = iniReader.ReadInteger("JA2 HAM Settings","BULLET_HIDE_INTENSITY", 100, 0, 1000);
// HEADROCK HAM 3.4: What percentage of a new Mobile Militia group will be made of Elites? If >0, then at least one of every new group will be an Elite. 100 = All Elites.
gGameExternalOptions.ubPercentRoamingMilitiaElites = iniReader.ReadInteger("JA2 HAM Settings","PERCENT_ROAMING_MILITIA_ELITES", 100, 0, 100);
// HEADROCK HAM 3.4: What percentage of a new Mobile Militia group will be made of Regulars? If >0, then at least one of every new group will be a Regular. 100 = All Regulars.
gGameExternalOptions.ubPercentRoamingMilitiaRegulars = iniReader.ReadInteger("JA2 HAM Settings","PERCENT_ROAMING_MILITIA_REGULARS", 0, 0, 100);
// HEADROCK HAM 3.5: Does leadership affect the Quality of new Mobile Militia groups?
gGameExternalOptions.fLeadershipAffectsMobileMilitiaQuality = iniReader.ReadBoolean("JA2 HAM Settings","LEADERSHIP_AFFECTS_MOBILE_MILITIA_QUALITY", FALSE);
// HEADROCK HAM 3.5: Explosive Suppression Effectiveness alters the amount of Suppression Points you get from nearby blasts.
gGameExternalOptions.usExplosionSuppressionEffect = iniReader.ReadInteger("JA2 HAM Settings","EXPLOSIVE_SUPPRESSION_EFFECTIVENESS", 100, 0, 1000);
// HEADROCK HAM 3.5: When enabled, goggle-switching affects every merc in the sector, not just those belonging to the current squad.
gGameExternalOptions.fGoggleSwapAffectsAllMercsInSector = iniReader.ReadBoolean("JA2 HAM Settings","GOGGLE_SWAP_AFFECTS_ALL_MERCS_IN_SECTOR", FALSE);
// HEADROCK HAM 3.5: Helicopter - Base cost per tile in "GREEN" airspace
gGameExternalOptions.usHelicopterBaseCostPerGreenTile = iniReader.ReadInteger("JA2 HAM Settings","HELICOPTER_BASE_COST_PER_GREEN_TILE", 100, 0, 60000);
// HEADROCK HAM 3.5: Helicopter - Base cost per tile in "RED" airspace
gGameExternalOptions.usHelicopterBaseCostPerRedTile = iniReader.ReadInteger("JA2 HAM Settings","HELICOPTER_BASE_COST_PER_RED_TILE", 1000, 0, 60000);
// HEADROCK HAM 3.5: Experimental, arrival sectorX/Y.
gGameExternalOptions.ubDefaultArrivalSectorX = iniReader.ReadInteger("JA2 HAM Settings","DEFAULT_ARRIVAL_SECTOR_X", 9, 1, 16);
gGameExternalOptions.ubDefaultArrivalSectorY = iniReader.ReadInteger("JA2 HAM Settings","DEFAULT_ARRIVAL_SECTOR_Y", 1, 1, 16);
// HEADROCK HAM 3.5: Limit bonus from tracers based on range to target. This is a multiplier factor - higher means harder to aim with tracers.
gGameExternalOptions.ubRangeDifficultyAimingWithTracers = iniReader.ReadInteger("JA2 HAM Settings","RANGE_EFFECT_ON_MAX_TRACER_CTH_BONUS", 3, 1, 10);
// HEADROCK HAM 3.6: Militia can now place blue flags when they spot a landmine.
gGameExternalOptions.fMilitiaPlaceBlueFlags = iniReader.ReadBoolean("JA2 HAM Settings","MILITIA_PLACE_FLAGS_ON_MINES", FALSE);
// HEADROCK PROFEX/3.6: Activate this to read Profile data from MercProfiles.XML and MercOpinions.XML
gGameExternalOptions.fReadProfileDataFromXML = iniReader.ReadBoolean("JA2 HAM Settings","READ_PROFILE_DATA_FROM_XML", FALSE);
// HEADROCK PROFEX/3.6: Activate this to write Profile data to MercProfiles Out.XML and MercOpinions Out.XML. This can be used to convert PROF.DAT to XML format.
gGameExternalOptions.fWriteProfileDataToXML = iniReader.ReadBoolean("JA2 HAM Settings","WRITE_PROFILE_DATA_TO_XML", FALSE);
// HEADROCK HAM 3.6: Progress bars for each stat, displayed behind the stat value on the merc panel. INI settings give RGB color, Menu setting toggles on/off.
gGameExternalOptions.ubStatProgressBarsRed = iniReader.ReadInteger("JA2 HAM Settings","STAT_PROGRESS_BARS_RED", 200, 0, 255);
gGameExternalOptions.ubStatProgressBarsGreen = iniReader.ReadInteger("JA2 HAM Settings","STAT_PROGRESS_BARS_GREEN", 0, 0, 255);
gGameExternalOptions.ubStatProgressBarsBlue = iniReader.ReadInteger("JA2 HAM Settings","STAT_PROGRESS_BARS_BLUE", 0, 0, 255);
// HEADROCK HAM 3.6: Determines how likely a character is, every hour, to trigger a facility event. The actual chance is X in every Y attempts, where X is facility-specific, and Y is the value adjusted here.
gGameExternalOptions.usFacilityEventRarity = iniReader.ReadInteger("JA2 HAM Settings","FACILITY_EVENT_RARITY", 1000, 0, 50000);
// HEADROCK HAM 3.6: Controls how important the character's stats are, in insuring he/she gets better results (or smaller damage) from using facilities. The higher this is, the more dangerous all facilities are.
gGameExternalOptions.ubFacilityDangerRate = iniReader.ReadInteger("JA2 HAM Settings","FACILITY_DANGER_RATE", 50, 0, 100);
// HEADROCK HAM 3.6: Determines whether the extrapolated daily costs of mercs are figured into the "Daily Expenses" display. 0 = No, just facility costs. 1 = Only mercs with a fixed daily rate. 2 = All mercs, including AIM contracts.
gGameExternalOptions.ubIncludeContractsInExpenses = iniReader.ReadInteger("JA2 HAM Settings","INCLUDE_CONTRACTS_IN_EXPENSES_DISPLAY", 1, 0, 2);
// HEADROCK HAM 3.6: Maximum number of messages displayed in Tactical view
gGameExternalOptions.ubMaxMessagesTactical = iniReader.ReadInteger("JA2 HAM Settings","MAXIMUM_MESSAGES_IN_TACTICAL", 6, 1, 36);
switch (iResolution)
{
case 0:
gGameExternalOptions.ubMaxMessagesTactical = __max(20, gGameExternalOptions.ubMaxMessagesTactical);
break;
case 1:
gGameExternalOptions.ubMaxMessagesTactical = __max(26, gGameExternalOptions.ubMaxMessagesTactical);
break;
}
// HEADROCK HAM 3.6: Daily upkeep costs for militia
gGameExternalOptions.usDailyCostTownGreen = iniReader.ReadInteger("JA2 HAM Settings","DAILY_MILITIA_UPKEEP_TOWN_GREEN", 0, 0, 10000);
gGameExternalOptions.usDailyCostTownRegular = iniReader.ReadInteger("JA2 HAM Settings","DAILY_MILITIA_UPKEEP_TOWN_REGULAR", 0, 0, 10000);
gGameExternalOptions.usDailyCostTownElite = iniReader.ReadInteger("JA2 HAM Settings","DAILY_MILITIA_UPKEEP_TOWN_ELITE", 0, 0, 10000);
gGameExternalOptions.usDailyCostMobileGreen = iniReader.ReadInteger("JA2 HAM Settings","DAILY_MILITIA_UPKEEP_MOBILE_GREEN", 0, 0, 10000);
gGameExternalOptions.usDailyCostMobileRegular = iniReader.ReadInteger("JA2 HAM Settings","DAILY_MILITIA_UPKEEP_MOBILE_REGULAR", 0, 0, 10000);
gGameExternalOptions.usDailyCostMobileElite = iniReader.ReadInteger("JA2 HAM Settings","DAILY_MILITIA_UPKEEP_MOBILE_ELITE", 0, 0, 10000);
// HEADROCK HAM 3.6: Non-Combat Bodytypes shouldn't become hostile
gGameExternalOptions.fCanTrueCiviliansBecomeHostile = iniReader.ReadBoolean("JA2 HAM Settings","CAN_TRUE_CIVILIANS_BECOME_HOSTILE", TRUE);
// HEADROCK HAM 3.6: Militia become hostile when attacked. 0 = No. 1 = If killed. 2 = If attacked (JA2 Default)
gGameExternalOptions.ubCanMilitiaBecomeHostile = iniReader.ReadInteger("JA2 HAM Settings","CAN_MILITIA_BECOME_HOSTILE", 2, 0, 2);
// HEADROCK HAM 3.6: If activated, the game does not switch focus to a merc who spots an enemy in real-time mode. This fixes issues with Real-Time Sneak.
gGameExternalOptions.fNoAutoFocusChangeInRealtimeSneak = iniReader.ReadBoolean("JA2 HAM Settings","NO_AUTO_FOCUS_CHANGE_IN_REALTIME_SNEAK", FALSE);
}
INT16 DynamicAdjustAPConstants(INT16 iniReadValue, INT16 iniDefaultValue, BOOLEAN reverse)
@@ -1259,6 +1429,15 @@ void LoadGameAPBPConstants()
APBPConstants[AP_OPEN_ZIPPER] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_OPEN_ZIPPER",24),24);
APBPConstants[AP_CLOSE_ZIPPER] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_CLOSE_ZIPPER",28),28);
APBPConstants[AP_CLICK_AIM] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_CLICK_AIM",4),4);
// HEADROCK HAM 3.1: Separate costs for each aiming click (when using a scope):
APBPConstants[AP_FIRST_CLICK_AIM_SCOPE] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_FIRST_CLICK_AIM_SCOPE",4),4);
APBPConstants[AP_SECOND_CLICK_AIM_SCOPE] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_SECOND_CLICK_AIM_SCOPE",4),4);
APBPConstants[AP_THIRD_CLICK_AIM_SCOPE] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_THIRD_CLICK_AIM_SCOPE",4),4);
APBPConstants[AP_FOURTH_CLICK_AIM_SCOPE] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_FOURTH_CLICK_AIM_SCOPE",4),4);
APBPConstants[AP_FIFTH_CLICK_AIM_SCOPE] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_FIFTH_CLICK_AIM_SCOPE",4),4);
APBPConstants[AP_SIXTH_CLICK_AIM_SCOPE] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_SIXTH_CLICK_AIM_SCOPE",4),4);
APBPConstants[AP_SEVENTH_CLICK_AIM_SCOPE] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_SEVENTH_CLICK_AIM_SCOPE",4),4);
APBPConstants[AP_EIGHTTH_CLICK_AIM_SCOPE] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_EIGHTTH_CLICK_AIM_SCOPE",4),4);
APBPConstants[AUTOFIRE_SHOTS_AP_VALUE] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AUTOFIRE_SHOTS_AP_VALUE",20),20);
APBPConstants[BAD_AP_COST] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","BAD_AP_COST",36),36);
APBPConstants[AP_RELOAD_LOOSE] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_RELOAD_LOOSE",8),8);
@@ -1268,6 +1447,10 @@ void LoadGameAPBPConstants()
APBPConstants[AP_MIN_LIMIT] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_MIN_LIMIT",-100),-100);
APBPConstants[AP_LOST_PER_MORALE_DROP] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_LOST_PER_MORALE_DROP",12),12);
APBPConstants[AP_SUPPRESSION_MOD] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_SUPPRESSION_MOD",24),24);
// HEADROCK HAM 3.5: Determines divisor for AP/Shock ratio. 100AP will have this set at 4, 25AP will have this set at 1.
APBPConstants[AP_SUPPRESSION_SHOCK_DIVISOR] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_SUPPRESSION_SHOCK_DIVISOR",4),4);
// HEADROCK HAM 3.2: Modifier for legshot AP loss based on damage
APBPConstants[AP_LOSS_PER_LEGSHOT_DAMAGE] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_LOSS_PER_LEGSHOT_DAMAGE",4),4);
APBPConstants[DEFAULT_APS] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","DEFAULT_APS",80),80);
APBPConstants[DEFAULT_AIMSKILL] = iniReader.ReadInteger("APConstants","DEFAULT_AIMSKILL",80);
+212 -60
View File
@@ -54,9 +54,14 @@ enum
TOPTION_SILENT_SKYRIDER,
TOPTION_LOW_CPU_USAGE,
TOPTION_ENHANCED_DESC_BOX,
// arynn
TOPTION_TOGGLE_TURN_MODE,
TOPTION_TOGGLE_TURN_MODE,
// HEADROCK HAM 3.6:
TOPTION_STAT_PROGRESS_BARS,
// arynn: Debug/Cheat
TOPTION_CHEAT_MODE_OPTIONS_HEADER,
TOPTION_FORCE_BOBBY_RAY_SHIPMENTS, // force all pending Bobby Ray shipments
TOPTION_CHEAT_MODE_OPTIONS_END,
@@ -80,7 +85,6 @@ enum
TOPTION_HIDE_BULLETS,
TOPTION_TRACKING_MODE,
NUM_ALL_GAME_OPTIONS,
};
@@ -276,9 +280,10 @@ typedef struct
UINT32 guiTrainVeteranMilitiaDelay;
UINT32 guiCreateEachNHours;
UINT32 guiDivOfOriginalMilitia;
UINT32 guiMinMilitiaSquadSize;
UINT32 guiMaxMilitiaSquadSize;
UINT32 guiMaxMilitiaSquadSizeBattle;
// HEADROCK HAM 3.6: These settings are REDUNDANT.
//UINT32 guiMinMilitiaSquadSize;
//UINT32 guiMaxMilitiaSquadSize;
//UINT32 guiMaxMilitiaSquadSizeBattle;
//BOOLEAN gfAllowSoldierToolTips; // moved to prefereces - SANDRO
@@ -419,9 +424,11 @@ typedef struct
INT32 ubTrainingSkillMax;
INT32 ubSelfTrainingDivisor;
INT32 ubInstructedTrainingDivisor;
INT32 ubGunRangeTrainingBonus;
// HEADROCK HAM 3.5: No longer necessary.
//INT32 ubGunRangeTrainingBonus;
INT32 ubTownMilitiaTrainingRate;
INT32 ubMaxMilitiaTrainersPerSector;
// HEADROCK HAM 3.5: No longer necessary.
//INT32 ubMaxMilitiaTrainersPerSector;
INT32 ubTeachBonusToTrain;
INT32 ubRpcBonusToTrainMilitia;
INT32 ubMinSkillToTeach;
@@ -502,7 +509,7 @@ BOOLEAN gbBulletTracer;
// HEADROCK: Enhanced Item Description Box ON/OFF
// WANNE: Changed from BOOLEAN to INT32!
INT32 fEnhancedDescriptionBox;
INT32 iEnhancedDescriptionBox;
// WANNE: Always use "prof.dat".
BOOLEAN fAlwaysUseProfDat;
@@ -518,58 +525,46 @@ BOOLEAN gbBulletTracer;
UINT8 ubCoverDisplayUpdateWait;
// HEADROCK HAM B1: Global modifier for mine income (0 is automatically turned to 1 to avoid divide-by-zero.)
INT16 iMineIncomePercentage;
INT16 usMineIncomePercentage;
// HEADROCK HAM B1: Allows changing the maximum CTH possible, for any attack 0-100
UINT8 iMaximumCTH;
UINT8 ubMaximumCTH;
// HEADROCK HAM B1: Allows changing the minimum CTH possible, for any attack 0-100
UINT8 iMinimumCTH;
UINT8 ubMinimumCTH;
// HEADROCK HAM B1: Allows reducing the chance of scoring a hit fractionally, if CTH = Minimum CTH
UINT8 iMinimumCTHDivisor;
UINT16 usMinimumCTHDivisor;
// HEADROCK HAM B1: Allows Restricted Roaming Militia to move through previously visited sectors, even if restricted.
BOOLEAN bUnrestrictVisited;
BOOLEAN fUnrestrictVisited;
// HEADROCK HAM B1: Allows the capture of towns to dynamically alter roaming restrictions
BOOLEAN bDynamicRestrictRoaming;
// HEADROCK HAM B2: Reset suppression counter. 0 = never (oldskool), 1 = Every turn, 2 = Every attack.
UINT8 iClearSuppression;
BOOLEAN fDynamicRestrictRoaming;
// HEADROCK HAM B2.1: This controls how effective suppression is, by increasing the number of ubSuppressionPoints accumulated by combatants (percentage);
INT16 iSuppressionEffectiveness;
INT16 sSuppressionEffectiveness;
// HEADROCK HAM B2: MAXIMUM number of APs that can be lost to suppression in a given turn (0=unlimited)
BOOLEAN fSuppressionAPLossPerTurn;
// HEADROCK HAM B2: MAXIMUM number of APs that can be lost to suppression in a given attack (0=unlimited)
BOOLEAN fSuppressionAPLossPerAttack;
UINT8 iSuppressionToleranceMax;
UINT8 iSuppressionToleranceMin;
// HEADROCK HAM B2: Suppression Shock ON/OFF
BOOLEAN fSuppressionShock;
UINT8 ubSuppressionToleranceMax;
UINT8 ubSuppressionToleranceMin;
// HEADROCK HAM B2: Suppression Shock effectiveness (percentage, 100 = "normal", 0 = deactivated. Range 0-65535)
UINT16 iSuppressionShockEffectiveness;
UINT16 usSuppressionShockEffect;
// HEADROCK HAM B2.1: CTH penalty given by a "Cowering" target to any enemy shooter.
INT8 iAimPenaltyPerTargetShock;
UINT8 ubAimPenaltyPerTargetShock;
// HEADROCK HAM B2.3: It is now possible for "cowering" to increase a target's suppression.
UINT16 iCowerEffectOnSuppression;
UINT16 usCowerEffectOnSuppression;
// HEADROCK HAM B2.5: Turn on Realistic Tracers. 0 = off (regular tracers). 1 = Fully realistic tracers. 2 = Tracer Bump + 1.13 Autofire Penalty Reduction
UINT8 iRealisticTracers;
UINT8 ubRealisticTracers;
// HEADROCK HAM B2.5: Realistic tracers - one of every X bullets in a tracer magazines will be a tracer bullet. 0 = off (JA2 normal)
UINT8 iNumBulletsPerTracer;
UINT8 ubNumBulletsPerTracer;
// HEADROCK HAM B2.5: Realistic tracers - CTH increased by this amount whenever a tracer is fired. 0 = off.
INT16 iCTHBumpPerTracer;
UINT8 ubCTHBumpPerTracer;
// HEADROCK HAM B2.6: Increased aiming costs?
BOOLEAN fIncreasedAimingCost;
@@ -581,32 +576,32 @@ BOOLEAN gbBulletTracer;
FLOAT iMovementEffectOnAiming;
// HEADROCK HAM B2.6: Autofire Bullets/5AP modifier
INT16 iAutofireBulletsPer5APModifier;
INT8 bAutofireBulletsPer5APModifier;
// HEADROCK HAM B2.6/B1: Adjustable "luck" factor in Auto-Resolve
FLOAT iAutoResolveLuckFactor;
// HEADROCK HAM B2.6: Adjustable maximum for Suppression Shock effect. This has the added effect of reducing overall susceptibility to shock and may render some enemies unshockable.
UINT8 iMaxSuppressionShock;
UINT8 ubMaxSuppressionShock;
// HEADROCK HAM B2.6/2/1: Toggle new Burst/Auto CTH bars: 0=neither, 1=both, 2=Burst, 3=Auto
UINT8 iNewCTHBars;
UINT8 ubNewCTHBars;
// HEADROCK HAM B2.6: Toggle whether AI checks for larger magazine when wanting to suppress at a distance
BOOLEAN fIncreaseAISuppressionFire;
// HEADROCK HAM B2.7: Change the speed of skill progression. (defaults set to JA2 normal)
UINT16 ubHealthSubpointsToImprove;
UINT16 ubStrengthSubpointsToImprove;
UINT16 ubDexteritySubpointsToImprove;
UINT16 ubAgilitySubpointsToImprove;
UINT16 ubWisdomSubpointsToImprove;
UINT16 ubMarksmanshipSubpointsToImprove;
UINT16 ubMedicalSubpointsToImprove;
UINT16 ubMechanicalSubpointsToImprove;
UINT16 ubExplosivesSubpointsToImprove;
UINT16 ubLeadershipSubpointsToImprove;
UINT16 ubLevelSubpointsToImprove;
UINT16 usHealthSubpointsToImprove;
UINT16 usStrengthSubpointsToImprove;
UINT16 usDexteritySubpointsToImprove;
UINT16 usAgilitySubpointsToImprove;
UINT16 usWisdomSubpointsToImprove;
UINT16 usMarksmanshipSubpointsToImprove;
UINT16 usMedicalSubpointsToImprove;
UINT16 usMechanicalSubpointsToImprove;
UINT16 usExplosivesSubpointsToImprove;
UINT16 usLeadershipSubpointsToImprove;
UINT16 usLevelSubpointsToImprove;
// HEADROCK HAM B2.7: When turned on, this will give a CTH approximation instead of an exact value, on CTH Bars and "F" key feedback.
BOOLEAN fApproximateCTH;
@@ -614,15 +609,6 @@ BOOLEAN gbBulletTracer;
// HEADROCK HAM B2.7: Augmented Roaming Militia code - turn this to TRUE to allow militia free travel through San Mona, Tixa, Orta, Omerta, and Estoni.
BOOLEAN fAllowMilitiaMoveThroughMinorCities;
// HEADROCK HAM B2.7: Smarter Roaming Militia Generator will generate Roamers in any available city perimeter square, allowing us to avoid "wasting" training sessions more easily.
BOOLEAN fSmartRoamingMilitiaGenerator;
// HEADROCK HAM B2.7: When "TRUE", Roaming Militia will be created on a 25% Veteran, 25% Regular, 50% green basis. If new militia is placed into a full group, it will upgrade greens/regulars in that group.
BOOLEAN fDiverseRoamingMilitiaGroups;
// HEADROCK HAM B2.8: This setting controls whether militia will try to join up into the largest groups they can, or average out the size of the groups to cover more territory.
UINT8 ubRoamingMilitiaSpreadsOutChance;
// HEADROCK HAM B2.8: These are new cowering penalty divisors that help us determine how effective cowering is in different stances and when the shooter is targetting different bodyparts
UINT8 ubCoweringPenaltyDivisorProne;
UINT8 ubCoweringPenaltyDivisorCrouchedHead;
@@ -648,9 +634,175 @@ BOOLEAN gbBulletTracer;
// HEADROCK HAM B2.8: New Trainer Relations: 2 = Trainers will rest if no trainees available. 3 = Trainees will rest if no trainers available (not recommended). 1 = Both. 0 = Neither.
UINT8 ubSmartTrainingRest;
// HEADROCK HAM 3: Show Tooltips from Attachments in Bobby Rays shop=
// HEADROCK HAM 3: Externalized ratio between Weight and Strength. This value determines how many strength points we need to lift 0.5kg with no encumberance.
FLOAT iStrengthToLiftHalfKilo;
// HEADROCK HAM 3: Define minimum leadership required for training militia. Set to 0 for "no limit".
UINT8 ubMinimumLeadershipToTrainMilitia;
// HEADROCK HAM 3: Define effect of "TEACHER" trait in increasing effective leadership, for purposes of eligibility for training militia
UINT16 usTeacherTraitEffectOnLeadership;
// HEADROCK HAM 3: If enabled, the trainer's "effective" leadership skill determines HOW MANY militia he/she creates per session (only works in town militia training).
BOOLEAN fLeadershipAffectsMilitiaQuantity;
// HEADROCK HAM 3: If "LEADERSHIP_AFFECTS_MILITIA_QUANTITY" is true, this value determines the lowest leadership required to train a full (default size 10) squad of town militia in one training session.
UINT8 ubReqLeadershipForFullTraining;
// HEADROCK HAM 3: Four INI settings to control the number of kills you must accumulate to win one progress point, one setting per difficulty level
UINT16 usNumKillsPerProgressPointNovice;
UINT16 usNumKillsPerProgressPointExperienced;
UINT16 usNumKillsPerProgressPointExpert;
UINT16 usNumKillsPerProgressPointInsane;
// HEADROCK HAM 3: If enabled, changes the way the game calculates progress. It will look at each progress control separately (Kills/Income/Control/Visited) and set the progress to the HIGHEST scoring control.
BOOLEAN fAlternateProgressCalculation;
// HEADROCK HAM 3: If enabled, tooltipping over Bobby Ray's weapons will show a list of possible attachments to those weapons.
BOOLEAN fBobbyRayTooltipsShowAttachments;
// HEADROCK HAM 3.1: Divisor for the AP-to-Ready cost charge on first aiming click, when extra aiming costs are enabled. 0 = No ready-time-based charge.
UINT8 ubFirstAimReadyCostDivisor;
// HEADROCK HAM 3.1: This is a suppression tool that not everyone will like. It gives an on-screen message when any character has been suppressed so much he's lost his next turn completely!
BOOLEAN fShowSuppressionShutdown;
// HEADROCK HAM 3.1: Set whether you'd like to determine yourself which mine (if any) will shut down during the campaign.
BOOLEAN fManuallySelectMineShutdown;
// HEADROCK HAM 3.1: Select which mine will run out. 0 = no mine. 1 = San Mona (unused), 2 = Drassen, 3 = Alma, 4 = Cambria, 5 = Chitzena, 6 = Grumm.
UINT8 ubWhichMineRunsOut;
// HEADROCK HAM 3.1: Can the Humvee go off-road?
BOOLEAN fHumveeOffroad;
// HEADROCK HAM 3.2: If activated, reinforcements (militia/enemy) arrive in the battle with 0 APs. This makes them less of a diablo-ex-machina.
UINT8 ubReinforcementsFirstTurnFreeze;
// HEADROCK HAM 3.2: This feature allows the status, leadership and experience of nearby friendlies help/hinder a character's tolerance, based on their distance from him.
BOOLEAN fFriendliesAffectTolerance;
// HEADROCK HAM 3.2: Set a divisor for the CtH of Mortar weapons.
UINT8 ubMortarCTHDivisor;
// HEADROCK HAM 3.2: This enabled reduced sight for cowering characters. 0 = disabled. 2 = Reduced Sightrange. 3 = Tunnel-vision. 1 = Both.
UINT8 ubCoweringReducesSightRange;
// HEADROCK HAM 3.2: Critical Headshots may cause blindness. Rolls 1 to X change of being blinded. 0 = disabled.
UINT8 ubChanceBlindedByHeadshot;
// HEADROCK HAM 3.2: Critical Legshots cause additional AP loss
BOOLEAN fCriticalLegshotCausesAPLoss;
// HEADROCK HAM 3.2: When enabled, this setting removes the player's omniscience inside his own sectors. The player will no longer see the movement of enemy groups unless someone is nearby to scout them.
BOOLEAN fNoEnemyDetectionWithoutRecon;
// HEADROCK HAM 3.2: Determines the training bonus for the Medical skill, when training in "hospital" sectors
UINT8 ubHospitalTrainingBonus;
// HEADROCK HAM 3.2: Determines the repaid bonus when training in factory ("industrial") sectors
UINT8 ubFactoryRepairBonus;
// HEADROCK HAM 3.2: How much MECHANICAL skill do we need to gain a repair bonus from a factory?
UINT8 ubMinMechanicalForFactoryRepairBonus;
// HEADROCK HAM 3.3: Externalized maximum possible penalty for hitting a moving target. JA2 Default = 30.
UINT16 usMaxCTHPenaltyForMovingTarget;
// HEADROCK HAM 3.3: Increases tolerance while moving.
UINT8 ubTilesMovedPerBonusTolerancePoint;
// HEADROCK HAM 3.3: New militia feature, Minimum Leadership required to train Roaming Militia
UINT8 ubMinimumLeadershipToTrainMobileMilitia;
// HEADROCK HAM 3.3: If enabled, the trainer's "effective" leadership skill determines HOW MANY militia he/she creates per session.
BOOLEAN fLeadershipAffectsMobileMilitiaQuantity;
// HEADROCK HAM 3.3: If "LEADERSHIP_AFFECTS_MILITIA_QUANTITY" is true, this value determines the lowest leadership required to train a full (default size 10) squad of town militia in one training session.
UINT8 ubReqLeadershipForFullMobileTraining;
// HEADROCK HAM 3.3: Minimum distance (in METERS) at which character suffer from friendly suppression.
UINT16 usMinDistanceFriendlySuppression;
// HEADROCK HAM 3.3: If enabled, Roaming Militia can automatically reinforce city garrisons.
BOOLEAN fAllowMobileReinforceCities;
// HEADROCK HAM 3.3: If enabled, Roaming Militia can automatically reinforce city garrisons.
BOOLEAN fAllowMobileReinforceSAM;
// HEADROCK HAM 3.4: This controls the intensity of Hiding the Bullet Count during combat. The higher it is, the more intense the effect. Negative values reduce the effect.
UINT16 usBulletHideIntensity;
// HEADROCK HAM 3.4: What percentage of a new Mobile Militia group will be made of Elites? If >0, then at least one of every group will be an Elite. 100 = All Elites.
UINT8 ubPercentRoamingMilitiaElites;
// HEADROCK HAM 3.4: What percentage of a new Mobile Militia group will be made of Elites? If >0, then at least one of every group will be an Elite. 100 = All Elites.
UINT8 ubPercentRoamingMilitiaRegulars;
// HEADROCK HAM 3.5: Does leadership affect the Quality of new Mobile Militia groups?
BOOLEAN fLeadershipAffectsMobileMilitiaQuality;
// HEADROCK HAM 3.5: Explosive Suppression Effectiveness alters the amount of Suppression Points you get from nearby blasts.
UINT16 usExplosionSuppressionEffect;
// HEADROCK HAM 3.5: When enabled, goggle-switching affects every merc in the sector, not just those belonging to the current squad.
BOOLEAN fGoggleSwapAffectsAllMercsInSector;
// HEADROCK HAM 3.5: Helicopter - Base cost per tile in "GREEN" airspace
UINT16 usHelicopterBaseCostPerGreenTile;
// HEADROCK HAM 3.5: Helicopter - Base cost per tile in "RED" airspace
UINT16 usHelicopterBaseCostPerRedTile;
// HEADROCK HAM 3.5: Experimental, arrival sectorX/Y.
UINT8 ubDefaultArrivalSectorX;
UINT8 ubDefaultArrivalSectorY;
// HEADROCK HAM 3.5: Limit bonus from tracers based on range to target. This is a divisor for the effect.
UINT8 ubRangeDifficultyAimingWithTracers;
// HEADROCK HAM 3.6: Militia can now place flags on discovered mines.
BOOLEAN fMilitiaPlaceBlueFlags;
// HEADROCK PROFEX: Activate this to read Profile data from Profiles.XML and Opinions.XML
BOOLEAN fReadProfileDataFromXML;
// HEADROCK PROFEX: Activate this to read Profile data from Profiles.XML and Opinions.XML
BOOLEAN fWriteProfileDataToXML;
// HEADROCK HAM 3.6: Progress bars for each stat, displayed behind the stat value on the merc panel.
UINT8 ubStatProgressBarsRed;
UINT8 ubStatProgressBarsGreen;
UINT8 ubStatProgressBarsBlue;
// HEADROCK HAM 3.6: Determines how likely a character is, every hour, to trigger a facility event. The actual chance is X in every Y attempts, where X is facility-specific, and Y is the value adjusted here.
UINT16 usFacilityEventRarity;
// HEADROCK HAM 3.6: Controls how important the character's stats are, in insuring he/she gets better results (or smaller damage) from using facilities. The higher this is, the more dangerous all facilities are.
UINT8 ubFacilityDangerRate;
// HEADROCK HAM 3.6: Determines whether the extrapolated daily costs of mercs are figured into the "Daily Expenses" display. 0 = No, just facility costs. 1 = Only mercs with a fixed daily rate. 2 = All mercs, including AIM contracts.
UINT8 ubIncludeContractsInExpenses;
// HEADROCK HAM 3.6: Maximum number of messages displayed in Tactical view
UINT8 ubMaxMessagesTactical;
// HEADROCK HAM 3.6: Daily upkeep costs for militia
UINT16 usDailyCostTownGreen;
UINT16 usDailyCostTownRegular;
UINT16 usDailyCostTownElite;
UINT16 usDailyCostMobileGreen;
UINT16 usDailyCostMobileRegular;
UINT16 usDailyCostMobileElite;
// HEADROCK HAM 3.6: Non-Combat Bodytypes can't become hostile
BOOLEAN fCanTrueCiviliansBecomeHostile;
// HEADROCK HAM 3.6: Militia become hostile when attacked. 0 = No. 1 = If killed. 2 = If attacked (JA2 Default)
UINT8 ubCanMilitiaBecomeHostile;
// HEADROCK HAM 3.6: If activated, the game does not switch focus to a merc who spots an enemy in real-time mode. This fixes issues with Real-Time Sneak.
BOOLEAN fNoAutoFocusChangeInRealtimeSneak;
// The_Bob - real time sneaking code 01/06/09
// Suport disabling/silencing real time sneaking via external .ini file
BOOLEAN fAllowRealTimeSneak;
+4 -4
View File
@@ -13,12 +13,12 @@
#ifdef JA2EDITOR
//MAP EDITOR BUILD VERSION
CHAR16 zVersionLabel[256] = { L"Map Editor v1.13.3023" };
CHAR16 zVersionLabel[256] = { L"Map Editor v1.13.3322" };
#elif defined JA2BETAVERSION
//BETA/TEST BUILD VERSION
CHAR16 zVersionLabel[256] = { L"Debug v1.13.3287" };
CHAR16 zVersionLabel[256] = { L"Debug v1.13.3322" };
#elif defined CRIPPLED_VERSION
@@ -28,11 +28,11 @@ CHAR16 zVersionLabel[256] = { L"Beta v. 0.98" };
#else
//RELEASE BUILD VERSION
CHAR16 zVersionLabel[256] = { L"Release v1.13.3287" };
CHAR16 zVersionLabel[256] = { L"Release v1.13.3322" };
#endif
CHAR8 czVersionNumber[16] = { "Build 09.10.23" }; //YY.MM.DD
CHAR8 czVersionNumber[16] = { "Build 10.02.20" }; //YY.MM.DD
CHAR16 zTrackingNumber[16] = { L"Z" };
+51
View File
@@ -524,6 +524,57 @@ BOOLEAN LoadExternalGameplayData(STR directoryName)
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName));
THROWIFFALSE(ReadInDeliveryMethods(fileName),DELIVERYMETHODSFILENAME);
// HEADROCK HAM 3.5: Read in facility types
strcpy(fileName, directoryName);
strcat(fileName, FACILITYTYPESFILENAME);
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName));
THROWIFFALSE(ReadInFacilityTypes(fileName), FACILITYTYPESFILENAME);
// HEADROCK HAM 3.4: Read in facility locations
strcpy(fileName, directoryName);
strcat(fileName, SECTORFACILITIESFILENAME);
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName));
THROWIFFALSE(ReadInSectorFacilities(fileName), SECTORFACILITIESFILENAME);
// HEADROCK HAM 3.4: Read in dynamic roaming restrictions
strcpy(fileName, directoryName);
strcat(fileName, DYNAMICROAMINGFILENAME);
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName));
THROWIFFALSE(ReadInDynamicRoamingRestrictions(fileName), DYNAMICROAMINGFILENAME);
// HEADROCK HAM 3.6: Read in customized sector names
strcpy(fileName, directoryName);
strcat(fileName, SECTORNAMESFILENAME);
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName));
THROWIFFALSE(ReadInSectorNames(fileName), SECTORNAMESFILENAME);
if (gGameExternalOptions.fReadProfileDataFromXML)
{
// HEADROCK PROFEX: Read in Merc Profile data to replace PROF.DAT data
strcpy(fileName, directoryName);
strcat(fileName, MERCPROFILESFILENAME);
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName));
THROWIFFALSE(ReadInMercProfiles(fileName), MERCPROFILESFILENAME);
// HEADROCK PROFEX: Read in Merc Opinion data to replace PROF.DAT data
strcpy(fileName, directoryName);
strcat(fileName, MERCOPINIONSFILENAME);
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName));
THROWIFFALSE(ReadInMercOpinions(fileName), MERCOPINIONSFILENAME);
}
// HEADROCK HAM 3.6: Read in customized Bloodcat Placements
strcpy(fileName, directoryName);
strcat(fileName, BLOODCATPLACEMENTSFILENAME);
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName));
THROWIFFALSE(ReadInBloodcatPlacements(fileName), BLOODCATPLACEMENTSFILENAME);
// HEADROCK HAM 3.6: Read in customized Uniform Colors
strcpy(fileName, directoryName);
strcat(fileName, UNIFORMCOLORSFILENAME);
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName));
THROWIFFALSE(ReadInUniforms(fileName), UNIFORMCOLORSFILENAME);
return TRUE;
}
+13
View File
@@ -86,6 +86,15 @@ AP_BACK_PACK,
AP_OPEN_ZIPPER,
AP_CLOSE_ZIPPER,
AP_CLICK_AIM,
// HEADROCK HAM 3.1: Eight different settings for each aiming click with a scope.
AP_FIRST_CLICK_AIM_SCOPE,
AP_SECOND_CLICK_AIM_SCOPE,
AP_THIRD_CLICK_AIM_SCOPE,
AP_FOURTH_CLICK_AIM_SCOPE,
AP_FIFTH_CLICK_AIM_SCOPE,
AP_SIXTH_CLICK_AIM_SCOPE,
AP_SEVENTH_CLICK_AIM_SCOPE,
AP_EIGHTTH_CLICK_AIM_SCOPE,
AP_RELOAD_LOOSE,
AP_UNJAM,
AP_WRONG_MAG,
@@ -94,6 +103,10 @@ AP_MAX_TURN_SUPPRESSED,
AP_MIN_LIMIT,
AP_LOST_PER_MORALE_DROP,
AP_SUPPRESSION_MOD,
// HEADROCK HAM 3.5: Ratio of AP loss to Suppression Shock gain.
AP_SUPPRESSION_SHOCK_DIVISOR,
// HEADROCK HAM 3.3: AP loss per point of damage, inflicted when a character is knocked down by a hit to the legs.
AP_LOSS_PER_LEGSHOT_DAMAGE,
AUTOFIRE_SHOTS_AP_VALUE,
BAD_AP_COST,
DEFAULT_APS,
+10 -1
View File
@@ -13,6 +13,7 @@
#include "Text.h"
#include "aimsort.h"
#include "Assignments.h"
#include "GameSettings.h"
#endif
@@ -98,7 +99,15 @@ BOOLEAN EnterAimFacialIndex()
MSYS_AddRegion( &gMercFaceMouseRegions[ i ] );
MSYS_SetRegionUserData( &gMercFaceMouseRegions[ i ], 0, i);
sprintf(sTemp, "%s%02d.sti", sFaceLoc, AimMercArray[i]);
if (gGameExternalOptions.fReadProfileDataFromXML)
{
// HEADROCK PROFEX: Do not read direct profile number, instead, look inside the profile for a ubFaceIndex value.
sprintf(sTemp, "%s%02d.sti", sFaceLoc, gMercProfiles[AimMercArray[i]].ubFaceIndex);
}
else
{
sprintf(sTemp, "%s%02d.sti", sFaceLoc, AimMercArray[i]);
}
VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE;
FilenameForBPP(sTemp, VObjectDesc.ImageFile);
if( !AddVideoObject(&VObjectDesc, &guiAimFiFace[i]) )
+9 -1
View File
@@ -1432,7 +1432,15 @@ BOOLEAN DisplayMercsFace()
BltVideoObject(FRAME_BUFFER, hPortraitHandle, 0,PORTRAIT_X, PORTRAIT_Y, VO_BLT_SRCTRANSPARENCY,NULL);
// load the Face graphic and add it
sprintf(sTemp, "%s%02d.sti", sFaceLoc, gbCurrentSoldier);
if (gGameExternalOptions.fReadProfileDataFromXML)
{
// HEADROCK PROFEX: Do not read direct profile number, instead, look inside the profile for a ubFaceIndex value.
sprintf(sTemp, "%s%02d.sti", sFaceLoc, gMercProfiles[gbCurrentSoldier].ubFaceIndex);
}
else
{
sprintf(sTemp, "%s%02d.sti", sFaceLoc, gbCurrentSoldier);
}
VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE;
FilenameForBPP(sTemp, VObjectDesc.ImageFile);
CHECKF(AddVideoObject(&VObjectDesc, &guiFace));
+3 -1
View File
@@ -604,7 +604,9 @@ void HandleBeginScreenTextEvent( UINT32 uiKey )
uiKey >= 'a' && uiKey <= 'z' ||
uiKey >= '0' && uiKey <= '9' ||
uiKey == '_' || uiKey == '.' ||
uiKey == ' ' )
uiKey == ' ' || uiKey == '"' ||
uiKey == 39 // This is ' which cannot be written explicitly here of course
)
#else
if( charSet::IsFromSet( uiKey, charSet::CS_SPACE|charSet::CS_ALPHA_NUM|charSet::CS_SPECIAL_ALPHA ) )
#endif
+1 -1
View File
@@ -222,7 +222,7 @@ public:
UINT16 RemoveDestination(UINT16 usDestinationID);
RefToDestinationStruct GetDestination(UINT16 usDestinationID) const;
RefToDestinationList LookupDestinationList(void) const;
// WANNE:
BOOLEAN IsSectorAShipmentSector(UINT8 ubMapX, UINT8 ubMapY, UINT8 ubMapZ);
+21 -4
View File
@@ -15,6 +15,9 @@
#include "cursors.h"
#include "email.h"
#include "text.h"
// HEADROCK PROFEX: This is required to display the proper facial image.
#include "Soldier Profile.h"
#include "GameSettings.h"
#endif
#define TOP_X LAPTOP_SCREEN_UL_X
@@ -1759,16 +1762,30 @@ BOOLEAN HandleSpecialTerroristFile( INT32 iFileNumber, STR sPictureName )
// show picture
if( ( giFilesPage == 0 ) && ( iCounter == 5 ) )
{
if( usProfileIdsForTerroristFiles[ iFileNumber + 1 ] < 100 )
if (gGameExternalOptions.fReadProfileDataFromXML)
{
sprintf(sTemp, "%s%02d.sti", "FACES\\BIGFACES\\", usProfileIdsForTerroristFiles[ iFileNumber + 1 ]);
// HEADROCK PROFEX: Do not read direct profile number, instead, look inside the profile for a ubFaceIndex value.
if( usProfileIdsForTerroristFiles[ iFileNumber + 1 ] < 100 )
{
sprintf(sTemp, "%s%02d.sti", "FACES\\BIGFACES\\", gMercProfiles[ usProfileIdsForTerroristFiles[ iFileNumber + 1 ] ].ubFaceIndex);
}
else
{
sprintf(sTemp, "%s%03d.sti", "FACES\\BIGFACES\\", gMercProfiles[ usProfileIdsForTerroristFiles[ iFileNumber + 1 ] ].ubFaceIndex);
}
}
else
{
sprintf(sTemp, "%s%03d.sti", "FACES\\BIGFACES\\", usProfileIdsForTerroristFiles[ iFileNumber + 1 ]);
if( usProfileIdsForTerroristFiles[ iFileNumber + 1 ] < 100 )
{
sprintf(sTemp, "%s%02d.sti", "FACES\\BIGFACES\\", usProfileIdsForTerroristFiles[ iFileNumber + 1 ]);
}
else
{
sprintf(sTemp, "%s%03d.sti", "FACES\\BIGFACES\\", usProfileIdsForTerroristFiles[ iFileNumber + 1 ]);
}
}
VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE;
FilenameForBPP(sTemp, VObjectDesc.ImageFile);
CHECKF(AddVideoObject(&VObjectDesc, &uiPicture));
+37 -2
View File
@@ -17,6 +17,10 @@
#include "LaptopSave.h"
#include "Campaign Types.h"
#include "strategicmap.h"
// HEADROCK HAM 3.6: Added facilities for calculating hourly expenses
#include "Facilities.h"
// HEADROCK HAM 3.6: Militia upkeep
#include "Town Militia.h"
#endif
// the global defines
@@ -402,7 +406,27 @@ INT32 GetProjectedTotalDailyIncome( void )
// then there is how many deposits have been made, now look at how many mines we have, thier rate, amount of ore left and predict if we still
// had these mines how much more would we get?
return( PredictIncomeFromPlayerMines() );
// HEADROCK HAM 3.6: Facilities can make you money, and this is figured into your daily income.
INT32 iRate = 0;
iRate = PredictIncomeFromPlayerMines() + (15 * GetTotalFacilityHourlyCosts( TRUE )); // 15 hours is the average time a merc can work per day
return( iRate );
}
// HEADROCK HAM 3.6: Predict expenses today. Takes into account facilities, and in the future merc contracts.
INT32 GetProjectedExpenses( void )
{
INT32 iTotalExpenses = 0;
INT32 iFacilityExpenses = GetTotalFacilityHourlyCosts( FALSE );
INT32 iContractExpenses = GetTotalContractExpenses();
iTotalExpenses += (iFacilityExpenses*15); // 15 hours is the average time a merc can work every day.
iTotalExpenses += iContractExpenses;
iTotalExpenses += guiTotalUpkeepForMilitia;
return (iTotalExpenses);
}
INT32 GetProjectedBalance( void )
@@ -1224,7 +1248,8 @@ UINT32 ProcessAndEnterAFinacialRecord( UINT8 ubCode, UINT32 uiDate, INT32 iAmoun
else
{
// alloc space
uiId = ReadInLastElementOfFinanceListAndReturnIdNumber( );
// HEADROCK HAM 3.6: Fix by Warmsteel to prevent repetitive entries on finance list. Next line commented out.
// uiId = ReadInLastElementOfFinanceListAndReturnIdNumber( );
pFinance = (FinanceUnitPtr) MemAlloc(sizeof(FinanceUnit));
// setup info passed
@@ -1534,6 +1559,16 @@ void ProcessTransactionString(STR16 pString, FinanceUnitPtr pFinance)
swprintf(pString, pTransactionText[ MERC_DEPOSITED_MONEY_TO_PLAYER_ACCOUNT ], gMercProfiles[ pFinance->ubSecondCode ].zNickname );
break;
// HEADROCK HAM 3.6: Paid for Facility Use
case( FACILITY_OPERATIONS ):
swprintf(pString, L"%s", pTransactionText[ FACILITY_OPERATIONS ]);
break;
// HEADROCK HAM 3.6: Paid for militia upkeep
case( MILITIA_UPKEEP ):
swprintf(pString, L"%s", pTransactionText[ MILITIA_UPKEEP ]);
break;
}
+4 -1
View File
@@ -50,7 +50,9 @@ enum
TRAIN_TOWN_MILITIA,
PURCHASED_ITEM_FROM_DEALER,
MERC_DEPOSITED_MONEY_TO_PLAYER_ACCOUNT,
SOLD_ITEMS
SOLD_ITEMS,
FACILITY_OPERATIONS, // HEADROCK HAM 3.6: Facility costs (daily payment)
MILITIA_UPKEEP, // HEADROCK HAM 3.6: Militia Upkeep Costs (daily payment)
};
@@ -64,6 +66,7 @@ void InsertDollarSignInToString( STR16 pString );
void InsertCommasForDollarFigure( STR16 pString );
INT32 GetTodaysDaysIncome( void );
INT32 GetProjectedTotalDailyIncome( void );
INT32 GetProjectedExpenses( void ); // HEADROCK HAM 3.6: Projected daily expenses.
#endif
Binary file not shown.
+74 -14
View File
@@ -824,10 +824,21 @@ void RenderPersonnelFace(INT32 iId, INT32 iSlot, BOOLEAN fDead, BOOLEAN fFired,
// special case?..player generated merc
if (fCurrentTeamMode) {
if( ( 50 < MercPtrs[iId]->ubProfile )&&( 57 > MercPtrs[iId]->ubProfile ) ) {
if( ( 50 < MercPtrs[iId]->ubProfile )&&( 57 > MercPtrs[iId]->ubProfile ) )
{
sprintf( sTemp, "%s%03d.sti", FACES_DIR, gMercProfiles[ MercPtrs[iId]->ubProfile ].ubFaceIndex );
} else {
sprintf(sTemp, "%s%02d.sti", FACES_DIR, Menptr[ iId ].ubProfile);
}
else
{
if (gGameExternalOptions.fReadProfileDataFromXML)
{
// HEADROCK PROFEX: Do not read direct profile number, instead, look inside the profile for a ubFaceIndex value.
sprintf(sTemp, "%s%02d.sti", FACES_DIR, gMercProfiles[Menptr[ iId ].ubProfile].ubFaceIndex);
}
else
{
sprintf(sTemp, "%s%02d.sti", FACES_DIR, Menptr[ iId ].ubProfile);
}
}
if( MercPtrs[iId]->flags.uiStatusFlags & SOLDIER_VEHICLE ) {
@@ -839,10 +850,21 @@ void RenderPersonnelFace(INT32 iId, INT32 iSlot, BOOLEAN fDead, BOOLEAN fFired,
return;
}
if( ( 50 < iId )&&( 57 > iId ) ) {
if( ( 50 < iId )&&( 57 > iId ) )
{
sprintf( sTemp, "%s%03d.sti", FACES_DIR, gMercProfiles[ iId ].ubFaceIndex );
} else {
sprintf(sTemp, "%s%02d.sti", FACES_DIR, iId );
}
else
{
if (gGameExternalOptions.fReadProfileDataFromXML)
{
// HEADROCK PROFEX: Do not read direct profile number, instead, look inside the profile for a ubFaceIndex value.
sprintf(sTemp, "%s%02d.sti", FACES_DIR, gMercProfiles[Menptr[ iId ].ubProfile].ubFaceIndex );
}
else
{
sprintf(sTemp, "%s%02d.sti", FACES_DIR, iId );
}
}
}
@@ -1943,10 +1965,29 @@ void DisplayPicturesOfCurrentTeam( void )
if ((50 < pSoldier->ubProfile) && (57 > pSoldier->ubProfile)) {
sprintf( sTemp, "%s%03d.sti", SMALL_FACES_DIR, gMercProfiles[ pSoldier->ubProfile ].ubFaceIndex );
} else {
if ( pSoldier->ubProfile < 100 ) {
sprintf(sTemp, "%s%02d.sti", SMALL_FACES_DIR, pSoldier->ubProfile);
} else {
sprintf(sTemp, "%s%03d.sti", SMALL_FACES_DIR, pSoldier->ubProfile);
if ( pSoldier->ubProfile < 100 )
{
if (gGameExternalOptions.fReadProfileDataFromXML)
{
// HEADROCK PROFEX: Do not read direct profile number, instead, look inside the profile for a ubFaceIndex value.
sprintf(sTemp, "%s%02d.sti", SMALL_FACES_DIR, gMercProfiles[ pSoldier->ubProfile ].ubFaceIndex);
}
else
{
sprintf(sTemp, "%s%02d.sti", SMALL_FACES_DIR, pSoldier->ubProfile);
}
}
else
{
if (gGameExternalOptions.fReadProfileDataFromXML)
{
// HEADROCK PROFEX: Do not read direct profile number, instead, look inside the profile for a ubFaceIndex value.
sprintf(sTemp, "%s%03d.sti", SMALL_FACES_DIR, gMercProfiles[ pSoldier->ubProfile ].ubFaceIndex);
}
else
{
sprintf(sTemp, "%s%03d.sti", SMALL_FACES_DIR, pSoldier->ubProfile);
}
} // else
} // else
@@ -4462,10 +4503,29 @@ void DisplayPortraitOfPastMerc( INT32 iId , INT32 iCounter, BOOLEAN fDead, BOOLE
if( ( 50 < iId )&&( 57 > iId ) ) {
sprintf( sTemp, "%s%03d.sti", SMALL_FACES_DIR, gMercProfiles[ iId ].ubFaceIndex );
} else {
if( iId < 100 ) {
sprintf(sTemp, "%s%02d.sti", SMALL_FACES_DIR, iId );
} else {
sprintf(sTemp, "%s%03d.sti", SMALL_FACES_DIR, iId );
if( iId < 100 )
{
if (gGameExternalOptions.fReadProfileDataFromXML)
{
// HEADROCK PROFEX: Do not read direct profile number, instead, look inside the profile for a ubFaceIndex value.
sprintf(sTemp, "%s%02d.sti", SMALL_FACES_DIR, gMercProfiles[ iId ].ubFaceIndex );
}
else
{
sprintf(sTemp, "%s%02d.sti", SMALL_FACES_DIR, iId );
}
}
else
{
if (gGameExternalOptions.fReadProfileDataFromXML)
{
// HEADROCK PROFEX: Do not read direct profile number, instead, look inside the profile for a ubFaceIndex value.
sprintf(sTemp, "%s%03d.sti", SMALL_FACES_DIR, gMercProfiles[ iId ].ubFaceIndex );
}
else
{
sprintf(sTemp, "%s%03d.sti", SMALL_FACES_DIR, iId );
}
}
}
+51 -4
View File
@@ -108,6 +108,10 @@
#include "postalservice.h"
// HEADROCK HAM B1: Additional Include for HAM
#include "MilitiaSquads.h"
// HEADROCK HAM 3.5: Another include for HAM
#include "Facilities.h"
// HEADROCK HAM 3.6: Yet another include, goddammit
#include "Town Militia.h"
#endif
#include "BobbyR.h"
@@ -389,7 +393,20 @@ typedef struct
INT8 fPlayerTeamSawJoey;
INT8 fMikeShouldSayHi;
UINT8 ubFiller[550]; //This structure should be 1024 bytes
// HEADROCK HAM 3.6: New global variable that tracks money owed for facility use.
INT32 iTotalOwedForFacilityOperationsToday;
// HEADROCK HAM 3.6: Now saving Skyrider Cost Modifier variable;
INT16 sSkyriderCostModifier;
// HEADROCK HAM 3.6: New global variable indicating whether we owe cash for facility work.
BOOLEAN fOutstandingFacilityDebt;
// HEADROCK HAM 3.6: Global variable keeping track of Militia Upkeep Costs at last midnight.
UINT32 uiTotalUpkeepForMilitia;
// HEADROCK HAM 3.6: Removed 16 fillers (16 bytes) to accomodate the above new variables.
UINT8 ubFiller[534]; //This structure should be 1024 bytes
} GENERAL_SAVE_INFO;
@@ -4390,7 +4407,6 @@ BOOLEAN LoadSavedGame( int ubSavedGameID )
UpdateMercMercContractInfo();
}
if ( guiCurrentSaveGameVersion <= 89 )
{
// ARM: A change was made in version 89 where refuel site availability now also depends on whether the player has
@@ -4441,11 +4457,17 @@ BOOLEAN LoadSavedGame( int ubSavedGameID )
// fix squads
CheckSquadMovementGroups();
// HEADROCK HAM B1: Re-Adjust Dynamic Roaming Militia restrictions
if (gGameExternalOptions.bDynamicRestrictRoaming)
if (gGameExternalOptions.fDynamicRestrictRoaming)
{
AdjustRoamingRestrictions();
}
// HEADROCK HAM 3.5: Tells the rest of the program whether we've got mercs working on detecting enemy units.
UpdateStrategicDetectionLevel( );
// HEADROCK HAM 3.5: recalculate a modifier to Skyrider's costs, based on mercs working in certain facilities.
UpdateSkyriderCostModifier( );
//The above function LightSetBaseLevel adjusts ALL the level node light values including the merc node,
//we must reset the values
HandlePlayerTogglingLightEffects( FALSE );
@@ -6133,6 +6155,18 @@ BOOLEAN SaveGeneralInfo( HWFILE hFile )
sGeneralInfo.fPlayerTeamSawJoey = gfPlayerTeamSawJoey;
sGeneralInfo.fMikeShouldSayHi = gfMikeShouldSayHi;
// HEADROCK HAM 3.6: Save new global variable for facility costs
sGeneralInfo.iTotalOwedForFacilityOperationsToday = giTotalOwedForFacilityOperationsToday;
// HEADROCK HAM 3.6: Save Skyrider Costs Modifier
sGeneralInfo.sSkyriderCostModifier = gsSkyriderCostModifier;
// HEADROCK HAM 3.6: Save new global variable for facility debt
sGeneralInfo.fOutstandingFacilityDebt = gfOutstandingFacilityDebt;
// HEADROCK HAM 3.6: Save new global variable for militia upkeep
sGeneralInfo.uiTotalUpkeepForMilitia = guiTotalUpkeepForMilitia;
//Setup the
//Save the current music mode
FileWrite( hFile, &sGeneralInfo, sizeof( GENERAL_SAVE_INFO ), &uiNumBytesWritten );
@@ -6155,7 +6189,8 @@ BOOLEAN LoadGeneralInfo( HWFILE hFile )
GENERAL_SAVE_INFO sGeneralInfo;
memset( &sGeneralInfo, 0, sizeof( GENERAL_SAVE_INFO ) );
// HEADROCK HAM 3.6: Hi. If you can see this comment, please delete the next line. Sorry! :)
INT32 blah = sizeof( GENERAL_SAVE_INFO );
//Load the current music mode
FileRead( hFile, &sGeneralInfo, sizeof( GENERAL_SAVE_INFO ), &uiNumBytesRead );
@@ -6405,6 +6440,18 @@ BOOLEAN LoadGeneralInfo( HWFILE hFile )
gfPlayerTeamSawJoey = sGeneralInfo.fPlayerTeamSawJoey;
gfMikeShouldSayHi = sGeneralInfo.fMikeShouldSayHi;
// HEADROCK HAM 3.6: Load new global variable for facility costs
giTotalOwedForFacilityOperationsToday = sGeneralInfo.iTotalOwedForFacilityOperationsToday;
// HEADROCK HAM 3.6: Load Skyrider Costs Modifier
gsSkyriderCostModifier = sGeneralInfo.sSkyriderCostModifier;
// HEADROCK HAM 3.6: Load new global variable for facility debt
gfOutstandingFacilityDebt = sGeneralInfo.fOutstandingFacilityDebt;
// HEADROCK HAM 3.6: Load new global variable for militia upkeep
guiTotalUpkeepForMilitia = sGeneralInfo.uiTotalUpkeepForMilitia;
return( TRUE );
}
+24 -18
View File
@@ -1296,6 +1296,8 @@ INT16 GetNumberOfLinesInHeight( const STR16 pStringA )
{
STR16 pToken;
INT16 sCounter = 0;
// HEADROCK HAM 3.6: This is a serious limitation... Increasing size
//CHAR16 pString[ 512 ];
CHAR16 pString[ 4096 ];
wcscpy( pString, pStringA );
@@ -1305,16 +1307,14 @@ INT16 GetNumberOfLinesInHeight( const STR16 pStringA )
while( pToken != NULL )
{
// WANNE: Fix by Headrock
// HEADROCK HAM 3.6: Make sure that all lines can appear on screen. If impossible, reduce number of lines
// artificially.
if ( (sCounter+1) * (GetFontHeight(FONT10ARIAL)+1) > (SCREEN_HEIGHT - 10) )
{
break;
}
pToken = wcstok( NULL, L"\n" );
sCounter++;
/*pToken = wcstok( NULL, L"\n" );
sCounter++;*/
{
break;
}
pToken = wcstok( NULL, L"\n" );
sCounter++;
}
return( sCounter );
@@ -1347,7 +1347,10 @@ void DisplayFastHelp( MOUSE_REGION *region )
if ( (iX + iW) >= SCREEN_WIDTH )
iX = (SCREEN_WIDTH - iW - 4);
iY = (INT32)region->RegionTopLeftY - (iH * 3 / 4);
// HEADROCK HAM 3.6: This formula causes the tooltip to appear UNDERNEATH the cursor if
// the tooltip's parent region is small. That makes reading the tooltip very difficult. Not desirable.
//iY = (INT32)region->RegionTopLeftY - (iH * 3 / 4);
iY = (INT32)region->RegionTopLeftY - iH;
if (iY < 0)
iY = 0;
@@ -1384,6 +1387,8 @@ void DisplayFastHelp( MOUSE_REGION *region )
INT16 GetWidthOfString( const STR16 pStringA )
{
// HEADROCK HAM 3.6: This is a serious limitation... Increasing size.
//CHAR16 pString[ 512 ];
CHAR16 pString[ 4096 ];
STR16 pToken;
INT16 sWidth = 0;
@@ -1411,6 +1416,8 @@ void DisplayHelpTokenizedString( const STR16 pStringA, INT16 sX, INT16 sY )
STR16 pToken;
INT32 iCounter = 0, i;
UINT32 uiCursorXPos;
// HEADROCK HAM 3.6: This is a serious limitation... Increasing size
//CHAR16 pString[ 512 ];
CHAR16 pString[ 4096 ];
INT32 iLength;
@@ -1421,15 +1428,14 @@ void DisplayHelpTokenizedString( const STR16 pStringA, INT16 sX, INT16 sY )
while( pToken != NULL )
{
// WANNE: Fix by Headrock
// HEADROCK HAM 3.6: If height of screen exceeds screen height, replace the last VISIBLE line with "..."
// and break the cycle.
if ( (iCounter+2) * (GetFontHeight(FONT10ARIAL)+1) > (SCREEN_HEIGHT - 10) )
{
mprintf( sX, sY + iCounter * (GetFontHeight(FONT10ARIAL)+1), L"..." );
break;
}
iLength = (INT32)wcslen( pToken );
//iLength = (INT32)wcslen( pToken );
{
mprintf( sX, sY + iCounter * (GetFontHeight(FONT10ARIAL)+1), L"..." );
break;
}
iLength = (INT32)wcslen( pToken );
for( i = 0; i < iLength; i++ )
{
uiCursorXPos = StringPixLengthArgFastHelp( FONT10ARIAL, FONT10ARIALBOLD, i, pToken );
+2 -1
View File
@@ -1256,7 +1256,8 @@ void TestIncoming4SidesCallback( GUI_BUTTON *btn, INT32 reason )
UINT32 uiWorldMin;
Compression0Callback( ButtonList[ iViewerButton[ COMPRESSION0 ] ], MSYS_CALLBACK_REASON_LBUTTON_UP );
if( ( gsSelSectorX == 0 ) || ( gsSelSectorY == 0 ) )
gsSelSectorX = 9, gsSelSectorY = 1;
// HEADROCK HAM 3.5: Not sure what this function does at all... But this is externalized now anyway.
gsSelSectorX = gGameExternalOptions.ubDefaultArrivalSectorX, gsSelSectorY = gGameExternalOptions.ubDefaultArrivalSectorY;
ubSector = SECTOR( gsSelSectorX, gsSelSectorY );
uiWorldMin = GetWorldTotalMin();
+3553 -316
View File
File diff suppressed because it is too large Load Diff
+54 -5
View File
@@ -26,7 +26,7 @@
#define VEHICLE_REPAIR_POINTS_DIVISOR 10
// HEADROCK HAM 3.6: Added separate Mobile Militia training assignment.
// Assignments Defines
enum{
SQUAD_1 =0,
@@ -57,8 +57,11 @@ enum{
REPAIR,
TRAIN_SELF,
TRAIN_TOWN,
TRAIN_MOBILE, // HEADROCK HAM 3.6: Training mobile militia.
TRAIN_TEAMMATE,
TRAIN_BY_OTHER,
FACILITY_STAFF, // HEADROCK HAM 3.6: Operating a facility for strategic gain.
FACILITY_REST, // HEADROCK HAM 3.6: Facility equivalent of resting (no assignment)
ASSIGNMENT_DEAD,
ASSIGNMENT_UNCONCIOUS, // unused
ASSIGNMENT_POW,
@@ -83,6 +86,16 @@ enum{
// NOTE: Wisdom isn't trainable!
};
// HEADROCK HAM 3.2: Set bitwise flags for locating facilities in current sector (for training/otherwise)
// facilities flags
// HEADROCK HAM 3.4: Removed due to facility externalization.
/*#define AT_HOSPITAL 0x00000001
#define AT_INDUSTRY 0x00000002
#define AT_PRISON 0x00000004
#define AT_MILITARY 0x00000008
#define AT_AIRPORT 0x00000010
#define AT_GUN_RANGE 0x00000020*/
typedef struct TOWN_TRAINER_TYPE
{
@@ -106,6 +119,7 @@ BOOLEAN CanCharacterPatient( SOLDIERTYPE *pCharacter );
// can character train militia?
BOOLEAN CanCharacterTrainMilitia( SOLDIERTYPE *pCharacter );
BOOLEAN CanCharacterTrainMobileMilitia( SOLDIERTYPE *pSoldier );
// can character train stat?..as train self or as trainer?
BOOLEAN CanCharacterTrainStat( SOLDIERTYPE *pSoldier, INT8 bStat, BOOLEAN fTrainSelf, BOOLEAN fTrainTeammate );
@@ -116,6 +130,9 @@ BOOLEAN CanCharacterPractise( SOLDIERTYPE *pCharacter );
// can this character train others?
BOOLEAN CanCharacterTrainTeammates( SOLDIERTYPE *pSoldier );
// HEADROCK HAM 3.6: Can character use a specific facility?
BOOLEAN CanCharacterFacility( SOLDIERTYPE *pSoldier, UINT8 ubFacilityType, UINT8 ubAssignmentType );
// put character on duty?
BOOLEAN CanCharacterOnDuty( SOLDIERTYPE *pCharacter );
@@ -183,16 +200,18 @@ UINT8 CalculateRepairPointsForRepairman(SOLDIERTYPE *pSoldier, UINT16 *pusMaxPts
// get bonus tarining pts due to an instructor for this student
INT16 GetBonusTrainingPtsDueToInstructor( SOLDIERTYPE *pInstructor, SOLDIERTYPE *pStudent, INT8 bTrainStat, BOOLEAN fAtGunRange, UINT16 *pusMaxPts );
// HEADROCK HAM 3.5: Three functions below have lost an argument which is no longer required ("uiAtGunRange", which was "uiAtFacility" in HAM 3.4)
INT16 GetBonusTrainingPtsDueToInstructor( SOLDIERTYPE *pInstructor, SOLDIERTYPE *pStudent, INT8 bTrainStat, UINT16 *pusMaxPts );
// get training pts for this soldier
INT16 GetSoldierTrainingPts( SOLDIERTYPE *pSoldier, INT8 bTrainStat, BOOLEAN fAtGunRange, UINT16 *pusMaxPts );
INT16 GetSoldierTrainingPts( SOLDIERTYPE *pSoldier, INT8 bTrainStat, UINT16 *pusMaxPts );
// pts for being a student for this soldier
INT16 GetSoldierStudentPts( SOLDIERTYPE *pSoldier, INT8 bTrainStat, BOOLEAN fAtGunRange, UINT16 *pusMaxPts );
INT16 GetSoldierStudentPts( SOLDIERTYPE *pSoldier, INT8 bTrainStat, UINT16 *pusMaxPts );
// HEADROCK HAM 3.6: Completely unused.
// reset these soldiers
void ResetAssignmentsForAllSoldiersInSectorWhoAreTrainingTown( SOLDIERTYPE *pSoldier );
//void ResetAssignmentsForAllSoldiersInSectorWhoAreTrainingTown( SOLDIERTYPE *pSoldier );
// Handle assignment done
void AssignmentDone( SOLDIERTYPE *pSoldier, BOOLEAN fSayQuote, BOOLEAN fMeToo );
@@ -207,6 +226,9 @@ extern INT32 ghAttributeBox;
extern INT32 ghRemoveMercAssignBox;
extern INT32 ghContractBox;
extern INT32 ghMoveBox;
// HEADROCK HAM 3.6: Facility Menu, Submenu
extern INT32 ghFacilityBox;
extern INT32 ghFacilityAssignmentBox;
//extern INT32 ghUpdateBox;
@@ -219,6 +241,9 @@ extern MOUSE_REGION gSquadMenuRegion[ ];
extern MOUSE_REGION gContractMenuRegion[ ];
extern MOUSE_REGION gRemoveMercAssignRegion[ ];
extern MOUSE_REGION gVehicleMenuRegion[];
// HEADROCK HAM 3.6: Facility Menu.
extern MOUSE_REGION gFacilityMenuRegion[];
extern MOUSE_REGION gFacilityMenuRegion[];
extern BOOLEAN fShownContractMenu;
extern BOOLEAN fShownAssignmentMenu;
@@ -260,6 +285,16 @@ void CreateDestroyMouseRegionForRepairMenu( void );
void RepairMenuMvtCallback(MOUSE_REGION * pRegion, INT32 iReason );
void RepairMenuBtnCallback( MOUSE_REGION * pRegion, INT32 iReason );
// HEADROCK HAM 3.6: Facility Menu
void CreateDestroyMouseRegionForFacilityMenu( void );
void FacilityMenuMvtCallback(MOUSE_REGION * pRegion, INT32 iReason );
void FacilityMenuBtnCallback( MOUSE_REGION * pRegion, INT32 iReason );
// HEADROCK HAM 3.6: Facility sub-menu
void CreateDestroyMouseRegionsForFacilityAssignmentMenu( void );
void FacilityAssignmentMenuMvtCallBack( MOUSE_REGION * pRegion, INT32 iReason );
void FacilityAssignmentMenuBtnCallback( MOUSE_REGION * pRegion, INT32 iReason );
// contract menu
void CreateDestroyMouseRegionsForContractMenu( void );
void ContractMenuBtnCallback( MOUSE_REGION * pRegion, INT32 iReason );
@@ -334,6 +369,20 @@ void HandleTrainingWakeSynchronize( SOLDIERTYPE *pSoldier );
BOOLEAN FindAnyAwakeTrainers( SOLDIERTYPE *pTrainee );
BOOLEAN FindAnyAwakeTrainees( SOLDIERTYPE *pTrainer );
// HEADROCK HAM 3.6: Functions for testing and reporting reasons why character can't train here.
BOOLEAN CanCharacterTrainMilitiaWithErrorReport( SOLDIERTYPE *pSoldier );
BOOLEAN CanCharacterTrainMobileMilitiaWithErrorReport( SOLDIERTYPE *pSoldier );
// HEADROCK HAM 3.6: Function for testing and reporting reasons why character can't staff a facility.
BOOLEAN CanCharacterFacilityWithErrorReport( SOLDIERTYPE *pSoldier, UINT8 ubFacilityType, UINT8 ubAssignmentType );
void HandleInterfaceMessageForCostOfOperatingFacility( SOLDIERTYPE *pSoldier, UINT8 ubAssignmentType );
void PayFacilityCostsYesNoBoxCallback( UINT8 bExitValue );
void FacilityStaffingRejected( void );
void ResetAllExpensiveFacilityAssignments();
BOOLEAN IsOutstandingFacilityDebtWithErrorReport();
extern INT8 gubFacilityInSubmenu;
extern UINT8 gubFacilityLineForSubmenu;
extern SOLDIERTYPE *gpFacilityStaffer;
#endif
+4 -3
View File
@@ -339,7 +339,8 @@ void RenderSoldierCellHealth( SOLDIERCELL *pCell );
void RenderSoldierCell( SOLDIERCELL *pCell );
void RenderSoldierCellBars( SOLDIERCELL *pCell );
void GenerateDirectionInfos( INT16 sMapX, INT16 sMapY, UINT8* uiDirNumber, UINT16 pMoveDir[4][3], BOOLEAN fWithCities, BOOLEAN fForBattle, BOOLEAN fOnlyCitySectors );
// HEADROCK HAM 3.4: New argument configuration to make use of revamped movement controls
void GenerateDirectionInfos( INT16 sMapX, INT16 sMapY, UINT8* uiDirNumber, UINT16 pMoveDir[4][3], BOOLEAN fForTraining, BOOLEAN fForBattle );
//Dynamic globals -- to conserve memory, all global variables are allocated upon entry
@@ -2146,8 +2147,8 @@ void CreateAutoResolveInterface()
ARCreateMilitiaSquad( &cnt, ubEliteMilitia, ubRegMilitia, ubGreenMilitia, gpAR->ubSectorX, gpAR->ubSectorY);
// Add the militia in the surrounding sectors
GenerateDirectionInfos( gpAR->ubSectorX, gpAR->ubSectorY, &uiDirNumber, pMoveDir,
( GetTownIdForSector( gpAR->ubSectorX, gpAR->ubSectorY ) != BLANK_SECTOR ? TRUE : FALSE ), TRUE, FALSE );
// HEADROCK HAM 3.4: Changed argument configuration.
GenerateDirectionInfos( gpAR->ubSectorX, gpAR->ubSectorY, &uiDirNumber, pMoveDir, FALSE, TRUE );
for( i=0; i<uiDirNumber; i++)
{
INT16 sX = SECTORX( pMoveDir[ i ][0] );
+27 -3
View File
@@ -273,8 +273,28 @@ UNDERGROUND_SECTORINFO* NewUndergroundNode( UINT8 ubSectorX, UINT8 ubSectorY, UI
// setup which know facilities are in which cities
void InitKnowFacilitiesFlags( )
{
SECTORINFO *pSector;
/////////////////////////////////////////////////////////////////
// HEADROCK HAM 3.5: No longer required. Function disconnected.
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//SECTORINFO *pSector;
// HEADROCK HAM 3.4: Externalized. All "known" facilities are read from gFacilityLocations. The
// ones that have (fHidden=0) will be added to the sector info now, and thus visible immediately.
// The others are added only once the player visits those sectors.
/*for(UINT32 cnt=0; (gFacilityLocations[cnt].uiSectorID >= 0 && gFacilityLocations[cnt].uiSectorID <= 256); cnt++ )
{
// Is the current sector valid? Is the facility set to be revealed on game-start?
if (gFacilityLocations[cnt].uiSectorID > 0 && gFacilityLocations[cnt].uiSectorID < 257 &&
gFacilityLocations[cnt].fHidden == 0)
{
// Reveal the facility.
pSector = &SectorInfo[gFacilityLocations[cnt].uiSectorID];
pSector->uiFacilitiesFlags |= (1 << (gFacilityLocations[cnt].uiFacilityType-1));
}
}*/
/* HEADROCK HAM 3.4: Externalized.
// Cambria hospital
pSector = &SectorInfo[SEC_G8];
pSector->uiFacilitiesFlags |= SFCF_HOSPITAL;
@@ -304,6 +324,7 @@ void InitKnowFacilitiesFlags( )
pSector->uiFacilitiesFlags |= SFCF_AIRPORT;
pSector = &SectorInfo[SEC_O4];
pSector->uiFacilitiesFlags |= SFCF_AIRPORT;
*/
return;
}
@@ -603,13 +624,16 @@ void InitNewCampaign()
InitWorld(); // Lesh: generate different world each time using alternative maps
InitMiningLocations();
InitKnowFacilitiesFlags( );
// HEADROCK HAM 3.5: This is no longer required.
//InitKnowFacilitiesFlags( );
BuildUndergroundSectorInfoList();
if (!is_networked)
// allow overhead view of omerta A9 on game onset
SetSectorFlag( startingX, startingY, startingZ, SF_ALREADY_VISITED ); //hayden
// HEADROCK HAM 3.5: Externalized.
SetSectorFlag( gGameExternalOptions.ubDefaultArrivalSectorX, gGameExternalOptions.ubDefaultArrivalSectorY, startingZ, SF_ALREADY_VISITED ); //hayden
//Generates the initial forces in a new campaign. The idea is to randomize numbers and sectors
//so that no two games are the same.
+210 -8
View File
@@ -112,19 +112,214 @@ enum
MAX_MILITIA_LEVELS
};
// facilities flags
// HEADROCK HAM 3.5: No longer needed. Facility types externalized.
/*// facilities flags
#define SFCF_HOSPITAL 0x00000001
#define SFCF_INDUSTRY 0x00000002
#define SFCF_PRISON 0x00000004
#define SFCF_MILITARY 0x00000008
#define SFCF_AIRPORT 0x00000010
#define SFCF_GUN_RANGE 0x00000020
#define SFCF_GUN_RANGE 0x00000020*/
// coordinates of shooting range sector
// HEADROCK HAM 3.4: These are no longer needed anywhere in the code.
/*// coordinates of shooting range sector
#define GUN_RANGE_X 13
#define GUN_RANGE_Y MAP_ROW_H
#define GUN_RANGE_Z 0
// HEADROCK HAM 3.2: New values for the location of an Industrial sector in Grumm H2. This sector boosts repair rates.
#define INDUSTRIAL_X 2
#define INDUSTRIAL_Y MAP_ROW_H
#define INDUSTRIAL_Z 0*/
// HEADROCK HAM 3.4: Facility Locations
typedef struct FACILITYLOCATIONS
{
BOOLEAN fFacilityHere;
UINT8 ubHidden;
}FACILITYLOCATIONS;
enum
{
// Enumerate the different assignments that a facility can emulate.
FAC_AMBIENT = 0,
FAC_STAFF,
FAC_REST,
FAC_REPAIR_ITEMS,
FAC_REPAIR_VEHICLE,
FAC_REPAIR_ROBOT,
FAC_DOCTOR,
FAC_PATIENT,
FAC_PRACTICE_STRENGTH,
FAC_PRACTICE_DEXTERITY,
FAC_PRACTICE_AGILITY,
FAC_PRACTICE_HEALTH,
FAC_PRACTICE_MARKSMANSHIP,
FAC_PRACTICE_MEDICAL,
FAC_PRACTICE_MECHANICAL,
FAC_PRACTICE_LEADERSHIP,
FAC_PRACTICE_EXPLOSIVES,
FAC_STUDENT_STRENGTH,
FAC_STUDENT_DEXTERITY,
FAC_STUDENT_AGILITY,
FAC_STUDENT_HEALTH,
FAC_STUDENT_MARKSMANSHIP,
FAC_STUDENT_MEDICAL,
FAC_STUDENT_MECHANICAL,
FAC_STUDENT_LEADERSHIP,
FAC_STUDENT_EXPLOSIVES,
FAC_TRAINER_STRENGTH,
FAC_TRAINER_DEXTERITY,
FAC_TRAINER_AGILITY,
FAC_TRAINER_HEALTH,
FAC_TRAINER_MARKSMANSHIP,
FAC_TRAINER_MEDICAL,
FAC_TRAINER_MECHANICAL,
FAC_TRAINER_LEADERSHIP,
FAC_TRAINER_EXPLOSIVES,
NUM_FACILITY_ASSIGNMENTS,
};
// Enumerated list of risk types
enum
{
RISK_STRENGTH = 0,
RISK_HEALTH,
RISK_AGILITY,
RISK_DEXTERITY,
RISK_WISDOM,
RISK_MARKSMANSHIP,
RISK_LEADERSHIP,
RISK_EXPLOSIVES,
RISK_MECHANICAL,
RISK_MEDICAL,
RISK_INJURY,
RISK_MORALE,
RISK_FATIGUE,
RISK_DRUNK,
RISK_LOYALTY_LOCAL,
RISK_LOYALTY_GLOBAL,
NUM_RISKS,
};
typedef struct FACILITYRISKTYPE
{
// The risks involved with perfoming an assignment at a specific facility.
UINT8 ubChance; // Chance out of X that this risk will trigger every hour. X is INI-defined and is normally 1000.
INT8 bBaseEffect; // Base result. If negative, result will always be negative. If positive, result will always be positive.
// If 0, result can be either negative or positive.
UINT8 ubRange; // Range of deviation for the base effect.
} FACILITYRISKTYPE;
typedef struct FACILITYASSIGNMENTTYPE
{
// This contains data about performing a specific assignment at a specific facility.
UINT8 ubStaffLimit; // Maximum number of people who can perform this assignment simultaneously
CHAR16 szTooltipText[300]; // Tooltip explaining the assignment in general terms.
INT16 sCostPerHour; // Cost per hour. Can be negative to indicate FLAT PROFIT per hour.
UINT16 usPerformance; // Percentage effectiveness of this assignment compared to non-emulated assignment (100 = normal)
UINT16 usFatigue; // Percentage speed of losing Max Breath (100 = normal)
UINT16 usSleep; // Percentage effectiveness of sleeping on the job (100 = normal)
UINT16 usKitDegrade; // Percentage speed of kit degrade (100 = normal)
UINT8 ubMaximumMorale; // Maximum morale achievable while performing this assignment
UINT8 ubMaximumBreath; // Maximum breath achievable while performing this assignment
UINT8 ubDetectEnemiesImmediate; // Detection of enemies in adjacent sectors, value = range of detection.
BOOLEAN fDetectEnemiesLongrange; // Detection of enemies in explored territory
BOOLEAN fDetectEnemiesDynamic; // Detection of enemies in Mobile Militia areas
BOOLEAN fDetectEnemiesAnywhere; // Detection of enemies all over the map
BOOLEAN fCountEnemiesInWild; // Count number of enemies in wilderness sectors
BOOLEAN fCountEnemiesInCities; // Count number of enemies in city sectors
INT16 sSkyriderCostModifier; // Flat modifier for Skyrider's Cost Per Tile
UINT16 usMineIncomeModifier; // Percentage income adjustment
BOOLEAN fOnlyLocalMineAffected; // Determines whether income modifier applies to local mine only, or all mines.
UINT8 ubMinimumStrength; // Minimum STR Requirement to begin this assignment
UINT8 ubMinimumHealth; // Minimum HLT Requirement to begin this assignment
UINT8 ubMinimumWisdom; // Minimum WIS Requirement to begin this assignment
UINT8 ubMinimumAgility; // Minimum AGI Requirement to begin this assignment
UINT8 ubMinimumDexterity; // Minimum DEX Requirement to begin this assignment
UINT8 ubMinimumMarksmanship; // Minimum MRK Requirement to begin this assignment
UINT8 ubMinimumLeadership; // Minimum LDR Requirement to begin this assignment
UINT8 ubMinimumExplosives; // Minimum EXP Requirement to begin this assignment
UINT8 ubMinimumMechanical; // Minimum MEC Requirement to begin this assignment
UINT8 ubMinimumMedical; // Minimum MED Requirement to begin this assignment
UINT8 ubMinimumLevel; // Minimum LVL Requirement to begin this assignment
UINT8 ubMinimumLoyaltyHere; // Minimum loyalty required in the town where the facility is placed (if any)
UINT8 ubMinimumBreath; // Minimum Breath Requirement to begin this assignment
UINT8 ubMinimumMorale; // Minimum Morale Requirement to begin this assignment
FACILITYRISKTYPE Risk[ NUM_RISKS ]; // Data about risks/chances possible when doing this assignment
} FACILITYASSIGNMENTTYPE;
// HEADROCK HAM 3.5: Facility Type
typedef struct FACILITYTYPE
{
// Basic data about the facility
CHAR16 szFacilityName[30]; // Long facility name
CHAR16 szFacilityShortName[15]; // Short facility name
UINT8 ubTotalStaffLimit; // Total number of people who can work here simultaneously
UINT8 ubMilitiaTrainersAllowed; // Number of Militia trainers allowed simultaneously
UINT8 ubMobileMilitiaTrainersAllowed; // Number of Mobile Militia trainers allowed simultaneously
UINT16 usMilitiaTraining; // Percentage effectiveness of Militia training (100 = normal)
UINT16 usMobileMilitiaTraining; // Percentage effectiveness of Mobile Militia training (100 = normal)
FACILITYASSIGNMENTTYPE AssignmentData[ NUM_FACILITY_ASSIGNMENTS ]; // Data about possible assignments that can be done here
} FACILITYTYPE;
// HEADROCK HAM 3.5: Maximum number of different facility types
#define MAX_NUM_FACILITY_TYPES 255
// HEADROCK HAM 3.5: Number of facilities placed on the map
extern UINT16 NUM_FACILITIES;
// HEADROCK HAM 3.5: Number of facility types read from XML
extern UINT16 NUM_FACILITY_TYPES;
// HEADROCK HAM 3.4: Array to hold facilities in each sector
extern FACILITYLOCATIONS gFacilityLocations[256][MAX_NUM_FACILITY_TYPES];
// HEADROCK HAM 3.5: Array to hold all different facility types
extern FACILITYTYPE gFacilityTypes[MAX_NUM_FACILITY_TYPES];
// HEADROCK HAM 3.6: Bloodcat Placement and Encounter data.
typedef struct BLOODCATPLACEMENT
{
UINT8 PlacementType;
UINT8 ubMinBloodcats;
UINT8 ubMaxBloodcats;
UINT8 ubAmbushChance;
BOOLEAN ubFactionAffiliation;
BOOLEAN fRespawn;
}BLOODCATPLACEMENT;
// HEADROCK HAM 3.6: Array to hold bloodcat placements and user-set bloodcat encounter data. There are 256 of these
// (one for each sector), with 4 sublevels (one for each difficulty)
extern BLOODCATPLACEMENT gBloodcatPlacements[256][4];
// Location of the Bloodcat Lair. There can be only one, as there's a quest that relies on its location. This is a
// sectorID, 0-255.
extern UINT8 gubBloodcatLairSectorId;
// HEADROCK HAM 3.6: Enumerated Bloodcat Placement types
enum
{
BLOODCAT_PLACEMENT_AMBUSH = 0,
BLOODCAT_PLACEMENT_STATIC,
BLOODCAT_PLACEMENT_LAIR,
NUM_BLOODCAT_PLACEMENT_TYPES
};
//Vehicle types
#define FOOT 0x01 //anywhere
@@ -227,8 +422,8 @@ typedef struct SECTORINFO
//throught the sector without entering it.
INT8 bNameId;
INT8 bUSUSED;
INT8 bBloodCats;
INT8 bBloodCatPlacements;
INT8 bBloodCats; // Actual number of bloodcats existing on this map.
INT8 bBloodCatPlacements; // "Maximum" potential bloodcats that can appear on this map.
INT8 UNUSEDbSAMCondition;
UINT8 ubTravelRating; //Represents how travelled a sector is. Typically, the higher the travel rating,
@@ -236,15 +431,22 @@ typedef struct SECTORINFO
//around. This value is used for determining how often items would "vanish" from
//a sector (nice theory, except it isn't being used that way. Stealing is only in towns. ARM)
UINT8 ubNumberOfCivsAtLevel[ MAX_MILITIA_LEVELS ]; // town militia per experience class, 0/1/2 is GREEN/REGULAR/ELITE
UINT16 usUNUSEDMilitiaLevels; // unused (ARM)
UINT8 ubUNUSEDNumberOfJoeBlowCivilians; // unused (ARM)
// HEADROCK HAM 3.6: Adding separate training percentage for MOBILES.
UINT8 ubMobileMilitiaTrainingPercentDone;
UINT8 ubMobileMilitiaTrainingHundredths;
BOOLEAN fMobileMilitiaTrainingPaid;
// Replacing these variables with the ones above. They really are unused.
//UINT16 usUNUSEDMilitiaLevels; // unused (ARM)
//UINT8 ubUNUSEDNumberOfJoeBlowCivilians; // unused (ARM)
UINT32 uiTimeCurrentSectorWasLastLoaded; //Specifies the last time the player was in the sector
UINT8 ubUNUSEDNumberOfEnemiesThoughtToBeHere; // using bLastKnownEnemies instead
UINT32 uiTimeLastPlayerLiberated; //in game seconds (used to prevent the queen from attacking for awhile)
BOOLEAN fSurfaceWasEverPlayerControlled;
UINT8 bFiller1;
// HEADROCK HAM 3.6: Flag to determine whether enemy units in this sector can be seen, and whether their numbers
// should be displayed. One filler was replaced to make room.
UINT8 ubDetectionLevel;
UINT8 bFiller2;
UINT8 bFiller3;
File diff suppressed because it is too large Load Diff
+78
View File
@@ -0,0 +1,78 @@
#ifndef _FACILITIES_H
#define _FACILITIES_H
#include "campaign types.h"
#include "Soldier Control.h"
// Get a specific modifier for a specific assignment at a specific facility. Includes Ambient (non-assignment based)
// effects, if any.
INT16 GetFacilityModifier( UINT8 ubModifierType, UINT8 ubFacilityType, UINT8 ubAssignmentType );
// Get a specific modifier from all facilities in the soldier's sector. This utilizes the above function.
INT16 GetSectorModifier( SOLDIERTYPE *pSoldier, UINT8 ubModifierType );
// Level of awareness to enemy movements, bestowed by facilities
extern void UpdateStrategicDetectionLevel( );
// Adjustment to Skyrider's cost-per-tile, bestowed by facilities
extern void UpdateSkyriderCostModifier( );
extern INT16 gsSkyriderCostModifier; // This variable is SAVED/LOADED
// HEADROCK HAM 3.6: Strategic info variable, total of costs accumulated for the use of facilities today. Deducted
// from account and reset at midnight, unless player can't pay (in which case, carries over to the next day).
extern INT32 giTotalOwedForFacilityOperationsToday; // This variable is SAVED and LOADED.
// Do we have outstanding debts for facility operation?
extern BOOLEAN gfOutstandingFacilityDebt; // This variable is SAVED and LOADED.
// Place this here for facility staffing checks.
extern UINT32 GetWorldTotalMin( );
// These are all the different modifiers we could be checking for.
enum
{
FACILITY_PERFORMANCE_MOD = 0,
FACILITY_SLEEP_MOD,
FACILITY_FATIGUE_MOD,
FACILITY_KIT_DEGRADE_MOD,
FACILITY_MAX_MORALE,
FACILITY_MAX_BREATH,
FACILITY_DETECT_IMMEDIATE,
FACILITY_DETECT_DYNAMIC,
FACILITY_DETECT_LONGRANGE,
FACILITY_DETECT_ANYWHERE,
FACILITY_COUNT_INWILD,
FACILITY_COUNT_INCITIES,
FACILITY_MINE_INCOME_MOD,
FACILITY_SKYRIDER_COST_MOD,
};
// HEADROCK HAM 3.6: Different enemy detection and counting levels
enum
{
DETECT_ENEMIES_DYNAMIC = 0,
DETECT_ENEMIES_LONGRANGE,
DETECT_ENEMIES_ANYWHERE,
COUNT_ENEMIES_IN_WILD,
COUNT_ENEMIES_IN_CITIES,
};
void UpdateGlobalVariablesFromFacilities( void );
void UpdateFacilityUsageCosts( void );
void HandleDailyPaymentFacilityDebt( void );
void HandleManualPaymentFacilityDebt( void );
void HandleHourlyRisks( void );
INT32 MineIncomeModifierFromFacility( UINT8 ubMine );
INT8 GetSoldierFacilityAssignmentIndex( SOLDIERTYPE *pSoldier );
void HandleRisksForSoldier( SOLDIERTYPE *pSoldier );
void HandleRisksForSoldierFacilityAssignment( SOLDIERTYPE *pSoldier, UINT8 ubFacilityType, UINT8 ubAssignmentType );
INT16 FacilityRiskResult( SOLDIERTYPE *pSoldier, UINT8 ubRiskType, UINT8 ubFacilityType, UINT8 ubAssignmentType );
INT32 GetTotalFacilityHourlyCosts( BOOLEAN fPositive );
void InitFacilities();
#endif
+78 -2
View File
@@ -61,6 +61,8 @@
#include "Interface.h"
#include "cheats.h"
#include "Interface Panels.h"
// HEADROCK HAM 3.6: Include for adding facility debt reset
#include "Facilities.h"
#endif
#include "Vehicles.h"
@@ -233,6 +235,64 @@ void InitNPCs( void )
void InitBloodCatSectors()
{
///////////////////////////////////////////////////
// HEADROCK HAM 3.6: Bloodcat Placement Externalization
//
// It is now possible for the user/modder to set the maximum number of bloodcats that may appear in the sector.
// We can now place bloodcats anywhere we'd like (aboveground), stretching the limits of maps without disturbing
// the game. The placements defined here are still the absolute MAXIMUM, so if the map has more placements available
// they will be ignored.
// Please note that if the mapfile has LESS placements than indicated here, then the game will reduce the number of
// placements automatically to fit the MAP, not the XML.
UINT16 x = 0;
UINT8 PlacementType = 0;
UINT8 ubMaxBloodcats = 0;
UINT8 ubDifficulty = gGameOptions.ubDifficultyLevel-1; // This way, novice=0.
INT16 ubLairSectorId = -1; // Location of ONE lair sector (the first one found)
// Clean all bloodcat data.
for( x = 0; x < 256; x++ )
{
SectorInfo[ x ].bBloodCats = 0;
SectorInfo[ x ].bBloodCatPlacements = 0;
}
// Begin loop for every sector.
for (x = 0; x < 256; x++)
{
// Set "maximum placements" value to whatever is defined in the XML file for this difficulty level.
SectorInfo[ x ].bBloodCatPlacements = gBloodcatPlacements[x][ubDifficulty].ubMaxBloodcats;
PlacementType = gBloodcatPlacements[x][0].PlacementType;
// Record the first sector you can find which is defined as a LAIR sector. Only one sector can serve
// this purpose, because the quests rely on it.
if (PlacementType == BLOODCAT_PLACEMENT_LAIR && ubLairSectorId == -1)
{
ubLairSectorId = x;
}
if (PlacementType != 0)
{
// Sector is a lair or static bloodcat sector. Fill it up with actual bloodcats please.
SectorInfo[ x ].bBloodCats = gBloodcatPlacements[x][ubDifficulty].ubMaxBloodcats;
// "Ambush" sectors (PlacementType 0) do not have bloodcats in them until triggered.
}
}
if (ubLairSectorId >= 0)
{
gubBloodcatLairSectorId = (UINT8)ubLairSectorId;
}
else
{
THROWEXCEPTION(L"At least one Bloodcat Lair must be defined in BloodcatPlacements.XML!");
}
/*
INT32 i;
//Hard coded table of bloodcat populations. We don't have
//access to the real population (if different) until we physically
@@ -296,7 +356,7 @@ void InitBloodCatSectors()
SectorInfo[ SEC_N5 ].bBloodCatPlacements = 18;
SectorInfo[ SEC_N5 ].bBloodCats = 18;
break;
}
}*/
}
@@ -334,6 +394,8 @@ void InitStrategicLayer( void )
// make Orta, Tixa, SAM sites not found
InitMapSecrets();
// HEADROCK HAM 3.6: Initialize facilities.
InitFacilities();
// free up any leave list arrays that were left allocated
ShutDownLeaveList( );
@@ -344,7 +406,8 @@ void InitStrategicLayer( void )
SetGameTimeCompressionLevel( TIME_COMPRESS_X0 );
// select A9 Omerta as the initial selected sector
ChangeSelectedMapSector( startingX, startingY, startingZ );
// HEADROCK HAM 3.5: Actually, this is where we set the starting sector based on external variables.
ChangeSelectedMapSector( gGameExternalOptions.ubDefaultArrivalSectorX, gGameExternalOptions.ubDefaultArrivalSectorY, startingZ );
// Reset these flags or mapscreen could be disabled and cause major headache.
fDisableDueToBattleRoster = FALSE;
@@ -498,6 +561,10 @@ BOOLEAN InitNewGame( BOOLEAN fReset )
AddFutureDayStrategicEvent( EVENT_DAY3_ADD_EMAIL_FROM_SPECK, 60*7, 0, uiDaysTimeMercSiteAvailable );
}
// HEADROCK HAM 3.5: Reset LZ to default arrival
gsMercArriveSectorX = gGameExternalOptions.ubDefaultArrivalSectorX;
gsMercArriveSectorY = gGameExternalOptions.ubDefaultArrivalSectorY;
#ifdef CRIPPLED_VERSION
{
UINT32 cnt;
@@ -864,6 +931,15 @@ void ReStartingGame()
//Reload the Merc profiles
LoadMercProfiles( );
if (gGameExternalOptions.fWriteProfileDataToXML)
{
// HEADROCK PROFEX: Create mercprofiles xml output
WriteMercProfiles();
// HEADROCK PROFEX: Create mercopinions xml output
WriteMercOpinions();
}
// Reload quote files
ReloadAllQuoteFiles();
+10
View File
@@ -24,6 +24,8 @@
#include "SaveLoadGame.h"
#include "GameSettings.h"
#include "connect.h"
// HEADROCK HAM 3.5: Add facility code for hourly update of detection levels
#include "Facilities.h"
void HourlyQuestUpdate( void );
void HourlyLarryUpdate( void );
@@ -56,9 +58,17 @@ void HandleHourlyUpdate()
// hourly update of team assignments
UpdateAssignments();
// HEADROCK HAM 3.5: Tells the rest of the program whether we've got mercs working on detecting enemy units.
UpdateStrategicDetectionLevel();
// HEADROCK HAM 3.5: Re-calculates a modifier to Skyrider's flight costs based on mercs working in specific facilities.
UpdateSkyriderCostModifier();
// hourly update of hated/liked mercs
UpdateBuddyAndHatedCounters();
HandleHourlyRisks();
// update morale!
HourlyMoraleUpdate();
+11 -2
View File
@@ -38,6 +38,8 @@
#include "soundman.h"
#include "Isometric Utils.h"
#include "Scheduling.h"
// HEADROCK HAM 3.5: Added facility-based skyrider costs modifier
#include "Facilities.h"
#endif
@@ -527,16 +529,23 @@ INT32 GetCostOfPassageForHelicopter( INT16 sX, INT16 sY )
// check if sector is air controlled or not, if so, then normal cost, otherwise increase the cost
INT32 iCost = 0;
// HEADROCK HAM 3.5: Costs externalized
INT32 iBaseCostPerGreenTile = gGameExternalOptions.usHelicopterBaseCostPerGreenTile;
INT32 iBaseCostPerRedTile = gGameExternalOptions.usHelicopterBaseCostPerRedTile;
// if they don't control it
if( StrategicMap[ CALCULATE_STRATEGIC_INDEX( sX, sY ) ].fEnemyAirControlled == FALSE )
{
iCost = COST_AIRSPACE_SAFE;
iCost = iBaseCostPerGreenTile;
}
else
{
iCost = COST_AIRSPACE_UNSAFE;
iCost = iBaseCostPerRedTile;
}
// HEADROCK HAM 3.5: Apply facility-based modifiers from global integer recalculated hourly
iCost = __max(0, iCost + gsSkyriderCostModifier);
return( iCost );
}
+3 -1
View File
@@ -773,7 +773,9 @@ void ToggleShowMilitiaMode( void )
// no - so put up a message explaining how it works
// if he's already training some
if( IsAnyOneOnPlayersTeamOnThisAssignment( TRAIN_TOWN ) )
// HEADROCK HAM 3.6: Also for Mobile trainers.
if( IsAnyOneOnPlayersTeamOnThisAssignment( TRAIN_TOWN ) ||
IsAnyOneOnPlayersTeamOnThisAssignment( TRAIN_MOBILE ) )
{
// say they'll show up when training is completed
pwString = pMapErrorString[ 28 ];
+105 -16
View File
@@ -68,8 +68,12 @@ want to have the new inventory panel not overlap the message text area. */
#define MESSAGE_SCROLL_AREA_HEIGHT ( MESSAGE_SCROLL_AREA_END_Y - MESSAGE_SCROLL_AREA_START_Y + 1 )
// CHRISL: Use these if we want scroll bar based on left edge of screen
#define MESSAGE_SCROLL_AREA_START_X 330
#define MESSAGE_SCROLL_AREA_END_X 344
// HEADROCK HAM 3.6: Now global variables to be changed when initializing map mode.
// See InitMapScreenInterfaceBottomCoords()
//#define MESSAGE_SCROLL_AREA_START_X 330
//#define MESSAGE_SCROLL_AREA_END_X 344
UINT16 MESSAGE_SCROLL_AREA_START_X;
UINT16 MESSAGE_SCROLL_AREA_END_X;
#define SLIDER_HEIGHT 11
#define SLIDER_WIDTH 11
@@ -184,6 +188,7 @@ void DeleteMapScreenBottomMessageScrollRegion( void );
void DisplayCurrentBalanceForMapBottom( void );
void DisplayCurrentBalanceTitleForMapBottom( void );
void DisplayProjectedDailyMineIncome( void );
void DisplayProjectedDailyExpenses( void ); // HEADROCK HAM 3.6: New expenses window shows running costs today.
void DrawNameOfLoadedSector( void );
void EnableDisableBottomButtonsAndRegions( void );
@@ -296,7 +301,8 @@ void RenderMapScreenInterfaceBottom( BOOLEAN fForceMapscreenFullRender )
// render whole panel
// HEADROCK Changed this line to accept outside influence through the new boolean:
//if ( fForceMapscreenFullRender == TRUE || fMapScreenBottomDirty == TRUE)
if ( fMapScreenBottomDirty )
// HEADROCK HAM 3.6: OK, let's always render this panel, as long as the team inventory screen isn't open.
if ( fMapScreenBottomDirty || !fShowInventoryFlag )
{
// get and blt panel
GetVideoObject(&hHandle, guiMAPBOTTOMPANEL );
@@ -334,12 +340,20 @@ void RenderMapScreenInterfaceBottom( BOOLEAN fForceMapscreenFullRender )
// Headrock: Moved this next line from the above marker ^
fMapScreenBottomDirty = FALSE;
// CHRISL: Don't display messagelist if inventory panel is open
// CHRISL: Only run this condition if we're drawing the message list on the left
// display messages that can be scrolled through
// HEADROCK HAM 3.6: Hmmmm, why not draw them? LEt's just move this whole segment here, shall we?
//if(!fShowInventoryFlag)
DisplayStringsInMapScreenMessageList( );
}
DisplayCompressMode( );
DisplayCurrentBalanceForMapBottom( );
DisplayProjectedDailyMineIncome( );
DisplayProjectedDailyExpenses( );
// draw the name of the loaded sector
DrawNameOfLoadedSector( );
@@ -347,12 +361,7 @@ void RenderMapScreenInterfaceBottom( BOOLEAN fForceMapscreenFullRender )
// display slider on the scroll bar
DisplayScrollBarSlider( );
// CHRISL: Don't display messagelist if inventory panel is open
// CHRISL: Only run this condition if we're drawing the message list on the left
// display messages that can be scrolled through
if(!fShowInventoryFlag)
DisplayStringsInMapScreenMessageList( );
// handle auto scroll
//CheckForAndHandleAutoMessageScroll( );
@@ -427,10 +436,12 @@ BOOLEAN CreateButtonsForMapScreenInterfaceBottom( void )
// BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1,
// (GUI_CALLBACK)BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnMessageDownMapScreenCallback);
// CHRISL: Use these if we want buttons based on left edge of screen
guiMapMessageScrollButtons[ MAP_SCROLL_MESSAGE_UP ] = QuickCreateButton( guiMapMessageScrollButtonsImage[ MAP_SCROLL_MESSAGE_UP ], 331, (SCREEN_HEIGHT - 109),
// HEADROCK HAM 3.6: Message window is now as wide as possible.
guiMapMessageScrollButtons[ MAP_SCROLL_MESSAGE_UP ] = QuickCreateButton( guiMapMessageScrollButtonsImage[ MAP_SCROLL_MESSAGE_UP ], (SCREEN_WIDTH - 306), (SCREEN_HEIGHT - 109),
BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1,
(GUI_CALLBACK)BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnMessageUpMapScreenCallback);
guiMapMessageScrollButtons[ MAP_SCROLL_MESSAGE_DOWN ] = QuickCreateButton( guiMapMessageScrollButtonsImage[ MAP_SCROLL_MESSAGE_DOWN ], 331, (SCREEN_HEIGHT - 28),
guiMapMessageScrollButtons[ MAP_SCROLL_MESSAGE_DOWN ] = QuickCreateButton( guiMapMessageScrollButtonsImage[ MAP_SCROLL_MESSAGE_DOWN ], (SCREEN_WIDTH - 306), (SCREEN_HEIGHT - 28),
BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1,
(GUI_CALLBACK)BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnMessageDownMapScreenCallback);
@@ -1334,7 +1345,8 @@ BOOLEAN AllowedToTimeCompress( void )
return( FALSE );
}
if( fShowAssignmentMenu || fShowTrainingMenu || fShowAttributeMenu || fShowSquadMenu || fShowContractMenu || fShowRemoveMenu )
// HEADROCK HAM 3.6: Added Facility Menus
if( fShowAssignmentMenu || fShowTrainingMenu || fShowAttributeMenu || fShowSquadMenu || fShowContractMenu || fShowRemoveMenu || fShowFacilityAssignmentMenu || fShowFacilityMenu )
{
return( FALSE );
}
@@ -1428,7 +1440,9 @@ void DisplayCurrentBalanceTitleForMapBottom( void )
// CHRISL: Replaced X coordinate with dynamic coordinate set from right edge of screen
//VarFindFontCenterCoordinates( (SCREEN_WIDTH - 637), (SCREEN_HEIGHT - 107), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// CHRISL: Use this if we want to display from the left edge
VarFindFontCenterCoordinates( 359, (SCREEN_HEIGHT - 107), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
//VarFindFontCenterCoordinates( 359, (SCREEN_HEIGHT - 107), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// HEADROCK HAM 3.6: The balance/income box has been moved to the right side, near the laptop button.
VarFindFontCenterCoordinates( (SCREEN_WIDTH - 278), (SCREEN_HEIGHT - 111), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// print it
mprintf( sFontX, sFontY, L"%s", sString );
@@ -1439,7 +1453,18 @@ void DisplayCurrentBalanceTitleForMapBottom( void )
// CHRISL: Replaced X coordinate with dynamic coordinate set from right edge of screen
//VarFindFontCenterCoordinates( (SCREEN_WIDTH - 637), (SCREEN_HEIGHT - 61), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// CHRISL: Use this if we want to display from the left edge
VarFindFontCenterCoordinates( 359, (SCREEN_HEIGHT - 61), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
//VarFindFontCenterCoordinates( 359, (SCREEN_HEIGHT - 61), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// HEADROCK HAM 3.6: The balance/income box has been moved to the right side, near the laptop button.
VarFindFontCenterCoordinates( (SCREEN_WIDTH - 278), (SCREEN_HEIGHT - 74), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// print it
mprintf( sFontX, sFontY, L"%s", sString );
swprintf( sString, L"%s", New113HAMMessage[ 20 ] );
// HEADROCK HAM 3.6: Projected expenses for today, with facilities (and in the future, merc contracts) taken into
// account.
VarFindFontCenterCoordinates( (SCREEN_WIDTH - 278), (SCREEN_HEIGHT - 37), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// print it
mprintf( sFontX, sFontY, L"%s", sString );
@@ -1474,7 +1499,9 @@ void DisplayCurrentBalanceForMapBottom( void )
// CHRISL: Replaced X coordinate with dynamic coordinate set from right edge of screen
//VarFindFontCenterCoordinates( (SCREEN_WIDTH - 637), (SCREEN_HEIGHT - 91), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// CHRISL: Use this if we want to display from the left edge
VarFindFontCenterCoordinates( 359, (SCREEN_HEIGHT - 91), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
//VarFindFontCenterCoordinates( 359, (SCREEN_HEIGHT - 91), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// HEADROCK HAM 3.6: The balance/income box has been moved to the right side, near the laptop button.
VarFindFontCenterCoordinates( (SCREEN_WIDTH - 278), (SCREEN_HEIGHT - 95), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// print it
mprintf( sFontX, sFontY, L"%s", sString );
@@ -1588,7 +1615,9 @@ void DisplayProjectedDailyMineIncome( void )
// CHRISL: Replaced X coordinate with dynamic coordinate set from right edge of screen
//VarFindFontCenterCoordinates( (SCREEN_WIDTH - 637), (SCREEN_HEIGHT - 45), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// CHRISL: Use this if we want to display from the left edge
VarFindFontCenterCoordinates( 359, (SCREEN_HEIGHT - 45), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
//VarFindFontCenterCoordinates( 359, (SCREEN_HEIGHT - 45), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// HEADROCK HAM 3.6: The balance/income box has been moved to the right side, near the laptop button.
VarFindFontCenterCoordinates( (SCREEN_WIDTH - 278), (SCREEN_HEIGHT - 58), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// print it
mprintf( sFontX, sFontY, L"%s", sString );
@@ -1596,6 +1625,58 @@ void DisplayProjectedDailyMineIncome( void )
return;
}
void DisplayProjectedDailyExpenses( void )
{
INT32 iRate = 0;
static INT32 iOldExpensesRate = -1;
CHAR16 sString[ 128 ];
INT16 sFontX, sFontY;
// grab the rate from the financial system
iRate = GetProjectedExpenses( );
if( iRate != iOldExpensesRate )
{
iOldExpensesRate = iRate;
fMapScreenBottomDirty = TRUE;
// if screen was not dirtied, leave
if( fMapBottomDirtied == FALSE )
{
return;
}
}
// set the font buffer
SetFontDestBuffer( FRAME_BUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
// set up the font
SetFont( COMPFONT );
if (iRate == 0)
{
SetFontForeground( 183 );
}
else
{
SetFontForeground( FONT_MCOLOR_LTRED );
}
SetFontBackground( FONT_BLACK );
swprintf( sString, L"%d", iRate );
// insert extra characters
InsertCommasForDollarFigure( sString );
InsertDollarSignInToString( sString );
// center it
VarFindFontCenterCoordinates( (SCREEN_WIDTH - 278), (SCREEN_HEIGHT - 21), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// print it
mprintf( sFontX, sFontY, L"%s", sString );
return;
}
BOOLEAN CommonTimeCompressionChecks( void )
{
@@ -1950,3 +2031,11 @@ void ChangeCurrentMapscreenMessageIndex( UINT8 ubNewMessageIndex )
// refresh screen
fMapScreenBottomDirty = TRUE;
}
void InitMapScreenInterfaceBottomCoords( void )
{
// HEADROCK HAM 3.6: Message window is now as wide as possible.
MESSAGE_SCROLL_AREA_START_X = SCREEN_WIDTH - 307;
MESSAGE_SCROLL_AREA_END_X = SCREEN_WIDTH - 293;
}
+3
View File
@@ -65,4 +65,7 @@ void MapScreenMsgScrollUp( UINT8 ubLinesUp );
void ChangeCurrentMapscreenMessageIndex( UINT8 ubNewMessageIndex );
void MoveToEndOfMapScreenMessageList( void );
// HEADROCK HAM 3.6: Reset coordinates for slider bar and message window
void InitMapScreenInterfaceBottomCoords( void );
#endif
@@ -582,6 +582,8 @@ void CreateDestroyMapInventoryPoolButtons( BOOLEAN fExitFromMapScreen )
fMapPanelDirty = TRUE;
fTeamPanelDirty = TRUE;
fCharacterInfoPanelDirty = TRUE;
// HEADROCK HAM 3.6: Yet again, make sure to refresh the bottom panel on closing.
fMapScreenBottomDirty = TRUE;
//CHRISL: close stack popup and item description windows
DeleteItemStackPopup();
@@ -1471,8 +1473,6 @@ void BeginInventoryPoolPtr( OBJECTTYPE *pInventorySlot )
{
for( UINT32 iNumber = 0 ; iNumber < pInventoryPoolList.size() ; ++iNumber)
{
// WANNE: Fix by Headrock
//if ( pInventoryPoolList[ iNumber ].object.usItem == gItemPointer.usItem )
if ( pInventoryPoolList[ iNumber ].object.usItem == gItemPointer.usItem && pInventoryPoolList[ iNumber ].usFlags & WORLD_ITEM_REACHABLE)
{
iPrice += SellItem( pInventoryPoolList[ iNumber ].object );
+134 -30
View File
@@ -48,6 +48,9 @@
#include "Quests.h"
#include "connect.h"
// HEADROCK HAM 3.5: included for detectionlevels
#include "Facilities.h"
#include "MilitiaSquads.h"
// zoom x and y coords for map scrolling
INT32 iZoomX = 0;
@@ -355,8 +358,9 @@ extern BOOLEAN fMapScreenBottomDirty;
BOOLEAN fFoundTixa = FALSE;
// selected sector
UINT16 sSelMapX = 9;
UINT16 sSelMapY = 1;
// HEADROCK HAM 3.5: Default selected sector doesn't have to be Omerta does it? :)
UINT16 sSelMapX = gGameExternalOptions.ubDefaultArrivalSectorX;
UINT16 sSelMapY = gGameExternalOptions.ubDefaultArrivalSectorY;
// highlighted sector
INT16 gsHighlightSectorX=-1;
@@ -522,6 +526,7 @@ void CreateMilitiaPanelBottomButton( void );
void DeleteMilitiaPanelBottomButton( void );
void MilitiaDoneButtonCallback(GUI_BUTTON *btn,INT32 reason);
void MilitiaAutoButtonCallback(GUI_BUTTON *btn,INT32 reason);
void MilitiaDisbandYesNoBoxCallback( UINT8 bExitValue ); // HEADROCK HAM 3.6: Disband militia callback
void RenderShadingForUnControlledSectors( void );
void DrawTownMilitiaForcesOnMap( void );
void CheckAndUpdateStatesOfSelectedMilitiaSectorButtons( void );
@@ -4381,7 +4386,10 @@ void DisplayDistancesForHelicopter( void )
// calculate the cost of the trip based on the number of safe and unsafe sectors it will pass through
uiTripCost = ( sNumSafeSectors * COST_AIRSPACE_SAFE ) + ( sNumUnSafeSectors * COST_AIRSPACE_UNSAFE );
// HEADROCK HAM 3.5: Externalized Base Cost. Also includes hourly-calculated facility modifier.
UINT32 uiCostGreen = __max(0,gGameExternalOptions.usHelicopterBaseCostPerGreenTile + gsSkyriderCostModifier);
UINT32 uiCostRed = __max(0,gGameExternalOptions.usHelicopterBaseCostPerRedTile + gsSkyriderCostModifier);
uiTripCost = ( sNumSafeSectors * uiCostGreen ) + ( sNumUnSafeSectors * uiCostRed );
swprintf( sString, L"%d", uiTripCost );
InsertCommasForDollarFigure( sString );
@@ -6092,13 +6100,22 @@ void MilitiaDoneButtonCallback(GUI_BUTTON *btn,INT32 reason)
{
btn->uiFlags &= ~( BUTTON_CLICKED_ON );
// reset fact we are in the box
sSelectedMilitiaTown = 0;
fMapPanelDirty = TRUE;
// Go ahead and reset the militia in the selected sector (even if we didn't change it here)
if (gfStrategicMilitiaChangesMade)
// HEADROCK HAM 3.6: Clicking the done button while militia are on the cursor causes a pop-up
// for authorizing DISBANDING those militia.
if (sGreensOnCursor || sRegularsOnCursor || sElitesOnCursor)
{
ResetMilitia();
DoMapMessageBox( MSG_BOX_BASIC_STYLE, pMilitiaString[ 3 ], MAP_SCREEN, MSG_BOX_FLAG_YESNO, MilitiaDisbandYesNoBoxCallback );
}
else
{
// reset fact we are in the box
sSelectedMilitiaTown = 0;
fMapPanelDirty = TRUE;
// Go ahead and reset the militia in the selected sector (even if we didn't change it here)
if (gfStrategicMilitiaChangesMade)
{
ResetMilitia();
}
}
}
}
@@ -6279,13 +6296,17 @@ void CheckAndUpdateStatesOfSelectedMilitiaSectorButtons( void )
iNumberOfRegulars = SectorInfo[ sGlobalMapSector ].ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] + sRegularsOnCursor;
iNumberOfElites = SectorInfo[ sGlobalMapSector ].ubNumberOfCivsAtLevel[ ELITE_MILITIA ] + sElitesOnCursor;
// HEADROCK HAM 3.6: This button is no longer disabled when there are unassigned militia. In fact,
// clicking the button when militia are unassigned will prompt the player to authorize disbanding them.
if( ( sGreensOnCursor > 0 ) || ( sRegularsOnCursor > 0 ) || ( sElitesOnCursor > 0 ) )
{
DisableButton( giMapMilitiaButton[ 4 ] ); // DONE
// DisableButton( giMapMilitiaButton[ 4 ] ); // DONE
SpecifyButtonText( giMapMilitiaButton[ 4 ], pMilitiaButtonString[ 2 ] );
}
else
{
EnableButton( giMapMilitiaButton[ 4 ] ); // DONE
// EnableButton( giMapMilitiaButton[ 4 ] ); // DONE
SpecifyButtonText( giMapMilitiaButton[ 4 ], pMilitiaButtonString[ 1 ] );
}
// greens button
@@ -6445,34 +6466,59 @@ void ClearAnySectorsFlashingNumberOfEnemies()
UINT32 WhatPlayerKnowsAboutEnemiesInSector( INT16 sSectorX, INT16 sSectorY )
{
UINT32 uiSectorFlags = SectorInfo[ SECTOR( sSectorX, sSectorY ) ].uiFlags;
BOOLEAN fDetection = FALSE;
BOOLEAN fCount = FALSE;
Assert(sSectorX > 0 && sSectorY > 0 && sSectorX < 17 && sSectorY < 17);
// if player has militia close enough to scout this sector out, if there are mercs who can scout here, OR
//Special case flag used when players encounter enemies in a sector, then retreat. The number of enemies
//will display on mapscreen until time is compressed. When time is compressed, the flag is cleared, and
//a question mark is displayed to reflect that the player no longer knows.
// HEADROCK HAM 3.5: There are now several ways to control the detection of enemy units. This function has been revamped
// to consider all options. Depending on externalized settings, different conditions yield different results.
//
// Option #1: Vanilla Default.
// It is possible to detect all enemies in explored territory, including cities.
// Militia in an adjacent sector can count how many enemies are there, except standing garrisons.
// Option #2: HAM 3.2. No Detection without Recon.
// Mobile enemy groups are only detected if there are militia in any adjacent sector. Otherwise, they can
// travel through explored sectors without being seen.
//
// Option #3: This is a new feature for HAM 3.5, which ties together with Facility Externalization.
// In simple words, facilities can enhance detection abilities. Facilities that do so may be placed around the
// map in any sector. When a merc with sufficient wisdom is resting here, he increases the detection "level",
// making it easier to detect or even count enemies in distant sectors.
// This option can be combined with either of the two above.
// Detection through active recon.
// Mercs provide recon in the same sector they're in.
// Militia provide recon in any adjacent sector (diagonals included)
// There's also a special case flag used when players encounter enemies in a sector, then retreat. You can only
// see the size of their force while the clock is paused. When unpaused, the flag is reset.
if ( CanMercsScoutThisSector( sSectorX, sSectorY, 0 ) ||
CanNearbyMilitiaScoutThisSector( sSectorX, sSectorY ) ||
( uiSectorFlags & SF_PLAYER_KNOWS_ENEMIES_ARE_HERE ) )
{
// if the enemies are stationary (i.e. mercs attacking a garrison)
if ( NumStationaryEnemiesInSector( sSectorX, sSectorY ) > 0 )
fDetection = TRUE;
// if all enemies are mobile (I.E. not garrison troops)
if ( NumStationaryEnemiesInSector( sSectorX, sSectorY ) == 0 )
{
// inside a garrison - hide their # (show question mark) to match what the PBI is showing
return KNOWS_THEYRE_THERE;
}
else
{
// other situations - show exactly how many there are
return KNOWS_HOW_MANY;
// They're also counted by default.
fCount = TRUE;
}
}
// if the player has visited the sector during this game
// Explored Sector Detection
// Enemy can be detected in any previously-visited sector.
// This is also enabled by some facilities, provided a merc is present and available to do it.
if( GetSectorFlagStatus( sSectorX, sSectorY, 0, SF_ALREADY_VISITED ) == TRUE )
{
// then he always knows about any enemy presence for the remainder of the game, but not exact numbers
return KNOWS_THEYRE_THERE;
// HEADROCK HAM 3.2: When enabled, this INI setting disallows detection of enemy roamers beyond merc/militia
// recon range.
if (!gGameExternalOptions.fNoEnemyDetectionWithoutRecon)
{
// then he always knows about any enemy presence for the remainder of the game, but not exact numbers
fDetection = TRUE;
}
}
// if Skyrider noticed the enemis in the sector recently
@@ -6482,7 +6528,7 @@ UINT32 WhatPlayerKnowsAboutEnemiesInSector( INT16 sSectorX, INT16 sSectorY )
if( IsSkyriderIsFlyingInSector( sSectorX, sSectorY ) )
{
// player remains aware of them as long as Skyrider remains in the sector
return KNOWS_THEYRE_THERE;
fDetection = TRUE;
}
else
{
@@ -6491,9 +6537,32 @@ UINT32 WhatPlayerKnowsAboutEnemiesInSector( INT16 sSectorX, INT16 sSectorY )
}
}
// Facilities can set a flag that allows detection in some sectors. We can read flags directly from the sector
// data to know whether we should show the enemies there. This overrides ANYTHING else.
if (SectorInfo[ SECTOR( sSectorX, sSectorY ) ].ubDetectionLevel & 1)
{
fDetection = TRUE;
}
if (SectorInfo[ SECTOR( sSectorX, sSectorY ) ].ubDetectionLevel & (1<<2) )
{
fCount = TRUE;
}
// no information available
return KNOWS_NOTHING;
if (!fDetection)
{
// no information available
return KNOWS_NOTHING;
}
else if (!fCount)
{
// No accurate information
return KNOWS_THEYRE_THERE;
}
else
{
// Accurate information
return KNOWS_HOW_MANY;
}
}
@@ -7126,3 +7195,38 @@ BOOLEAN CanRedistributeMilitiaInSector( INT16 sClickedSectorX, INT16 sClickedSec
// the fight is elsewhere - ok to redistribute
return( TRUE );
}
// Callback for disbanding militia in the Militia Box
void MilitiaDisbandYesNoBoxCallback( UINT8 bExitValue )
{
// yes
if( bExitValue == MSG_BOX_RETURN_YES )
{
if( sSelectedMilitiaTown != BLANK_SECTOR )
{
// HEADROCK HAM 3.6: Adjust loyalty based on how many militia were disbanded, compared to
// how many can be trained in a single session (max).
UINT32 uiMilitiaToDisband = sGreensOnCursor + (2*sRegularsOnCursor) + (3*sElitesOnCursor);
UINT32 uiTownLoyaltyBonus = (LOYALTY_BONUS_FOR_TOWN_TRAINING * uiMilitiaToDisband) / gGameExternalOptions.iTrainingSquadSize;
// loyalty in this town increases a bit because we obviously care about them...
DecrementTownLoyalty( (UINT8)sSelectedMilitiaTown, uiTownLoyaltyBonus );
}
// zero out numbers on the cursor
sGreensOnCursor = 0;
sRegularsOnCursor = 0;
sElitesOnCursor = 0;
// reset fact we are in the box
sSelectedMilitiaTown = 0;
fMapPanelDirty = TRUE;
// Go ahead and reset the militia in the selected sector
ResetMilitia();
}
else if( bExitValue == MSG_BOX_RETURN_NO )
{
return;
}
return;
}
@@ -340,11 +340,8 @@ void AddTextToTownBox( void )
AddSecondColumnMonoString( &hStringHandle, wString );
// main facilities
swprintf( wString, L"%s:", pwTownInfoStrings[ 8 ] );
AddMonoString( &hStringHandle, wString );
wcscpy(wString, L"");
GetSectorFacilitiesFlags( bCurrentTownMineSectorX, bCurrentTownMineSectorY, wString );
AddSecondColumnMonoString( &hStringHandle, wString );
// HEADROCK HAM 3.6: This function now does all the work of assembling a facility entry.
AddFacilitiesToBox( bCurrentTownMineSectorX, bCurrentTownMineSectorY, &hStringHandle, TRUE );
// the concept of control is only meaningful in sectors where militia can be trained
if ( MilitiaTrainingAllowedInSector( bCurrentTownMineSectorX, bCurrentTownMineSectorY, 0 ) )
@@ -551,6 +548,9 @@ void AddTextToBlankSectorBox( void )
// sector
AddSectorToBox();
// HEADROCK HAM 3.6: Facilities
AddFacilitiesToBox( bCurrentTownMineSectorX, bCurrentTownMineSectorY, &hStringHandle, FALSE );
}
@@ -639,12 +639,64 @@ void AddCommonInfoToBox(void)
AddSecondColumnMonoString( &hStringHandle, wString );
}
// HEADROCK HAM 3.6: Only show these for sectors that have a training facility
BOOLEAN fMilitiaTrainingAllowed = FALSE;
BOOLEAN fMobileTrainingAllowed = FALSE;
// percentage of current militia squad training completed
swprintf( wString, L"%s:", pwTownInfoStrings[ 10 ] );
AddMonoString( &hStringHandle, wString );
swprintf( wString, L"%d%%%%", SectorInfo[ SECTOR( bCurrentTownMineSectorX, bCurrentTownMineSectorY ) ].ubMilitiaTrainingPercentDone );
AddSecondColumnMonoString( &hStringHandle, wString );
// Sector contains Militia training facility?
for (UINT8 ubCounter = 0; ubCounter < MAX_NUM_FACILITY_TYPES; ubCounter++)
{
if (gFacilityLocations[SECTOR(bCurrentTownMineSectorX, bCurrentTownMineSectorY)][ubCounter].fFacilityHere)
{
if (gFacilityTypes[ubCounter].ubMilitiaTrainersAllowed)
{
fMilitiaTrainingAllowed = TRUE;
}
}
}
if (fMilitiaTrainingAllowed)
{
// Show percent completed
swprintf( wString, L"%d%%%%", SectorInfo[ SECTOR( bCurrentTownMineSectorX, bCurrentTownMineSectorY ) ].ubMilitiaTrainingPercentDone );
AddSecondColumnMonoString( &hStringHandle, wString );
}
else
{
// Show N/A
AddSecondColumnMonoString( &hStringHandle, New113HAMMessage[19] );
}
// HEADROCK HAM 3.6: percentage of current Mobile Militia squad training completed
swprintf( wString, L"%s:", pwTownInfoStrings[ 12 ] );
AddMonoString( &hStringHandle, wString );
// Sector contains Mobile training facility?
for (UINT8 ubCounter = 0; ubCounter < MAX_NUM_FACILITY_TYPES; ubCounter++)
{
if (gFacilityLocations[SECTOR(bCurrentTownMineSectorX, bCurrentTownMineSectorY)][ubCounter].fFacilityHere)
{
if (gFacilityTypes[ubCounter].ubMobileMilitiaTrainersAllowed)
{
fMobileTrainingAllowed = TRUE;
}
}
}
if (fMobileTrainingAllowed)
{
// Show percentage completed
swprintf( wString, L"%d%%%%", SectorInfo[ SECTOR( bCurrentTownMineSectorX, bCurrentTownMineSectorY ) ].ubMobileMilitiaTrainingPercentDone );
AddSecondColumnMonoString( &hStringHandle, wString );
}
else
{
// Show N/A
AddSecondColumnMonoString( &hStringHandle, New113HAMMessage[19] );
}
}
+81 -18
View File
@@ -313,6 +313,8 @@ BOOLEAN fShowContractMenu = FALSE;
BOOLEAN fShowRemoveMenu = FALSE;
BOOLEAN fShowMilitiaControlMenu = FALSE; //lal
//BOOLEAN fShowTalkToAllMenu = FALSE;//lal
BOOLEAN fShowFacilityMenu = FALSE; // HEADROCK HAM 3.6: Facility Menu
BOOLEAN fShowFacilityAssignmentMenu = FALSE; // HEADROCK HAM 3.6: Facility Sub-menu
BOOLEAN fRebuildMoveBox = FALSE;
@@ -325,6 +327,12 @@ SGPRect TrainDimensions={0,0,100,95};
SGPPoint TrainPosition={160,150};
SGPRect VehicleDimensions={0,0,80,60};
SGPPoint VehiclePosition={160,150};
// HEADROCK HAM 3.6: Facility Menu Position/Size:
SGPRect FacilityDimensions={0,0,80,60};
SGPPoint FacilityPosition={160,150};
// HEADROCK HAM 3.6: Facility Sub-menu Position/Size:
SGPRect FacilityAssignmentDimensions={0,0,80,60};
SGPPoint FacilityAssignmentPosition={220,150};
SGPPoint RepairPosition={160,150};
SGPRect RepairDimensions={0,0,80,80};
@@ -350,6 +358,8 @@ SGPPoint OrigAssignmentPosition = { 120, 150 };
SGPPoint OrigTrainPosition={160,150};
SGPPoint OrigVehiclePosition={160,150};
SGPPoint OrigMilitiaControlPosition = { 120, 150 }; //lal
SGPPoint OrigFacilityPosition = { 160, 150 }; // HEADROCK HAM 3.6
SGPPoint OrigFacilityAssignmentPosition = { 220,150 }; // HEADROCK HAM 3.6
//SGPPoint OrigTalkToAllPosition = { 160, 150 };
//extern BOOLEAN fMapExitDueToMessageBox;
@@ -542,7 +552,7 @@ BOOLEAN MultipleCharacterListEntriesSelected( void )
void ResetAssignmentsForMercsTrainingUnpaidSectorsInSelectedList( INT8 bAssignment )
void ResetAssignmentsForMercsTrainingUnpaidSectorsInSelectedList( UINT8 ubMilitiaType )
{
INT32 iCounter = 0;
SOLDIERTYPE *pSoldier = NULL;
@@ -563,18 +573,31 @@ void ResetAssignmentsForMercsTrainingUnpaidSectorsInSelectedList( INT8 bAssignme
continue;
}
if( pSoldier->bAssignment == TRAIN_TOWN )
if (ubMilitiaType == TOWN_MILITIA)
{
if ( SectorInfo[ SECTOR( pSoldier->sSectorX, pSoldier->sSectorY ) ].fMilitiaTrainingPaid == FALSE )
if( pSoldier->bAssignment == TRAIN_TOWN )
{
ResumeOldAssignment( pSoldier );
if ( SectorInfo[ SECTOR( pSoldier->sSectorX, pSoldier->sSectorY ) ].fMilitiaTrainingPaid == FALSE )
{
ResumeOldAssignment( pSoldier );
}
}
}
else if (ubMilitiaType == MOBILE_MILITIA)
{
if( pSoldier->bAssignment == TRAIN_MOBILE )
{
if ( SectorInfo[ SECTOR( pSoldier->sSectorX, pSoldier->sSectorY ) ].fMobileMilitiaTrainingPaid == FALSE )
{
ResumeOldAssignment( pSoldier );
}
}
}
}
}
void ResetAssignmentOfMercsThatWereTrainingMilitiaInThisSector( INT16 sSectorX, INT16 sSectorY )
// HEADROCK HAM 3.6: Added argument for Militia Type
void ResetAssignmentOfMercsThatWereTrainingMilitiaInThisSector( INT16 sSectorX, INT16 sSectorY, UINT8 ubMilitiaType )
{
INT32 iCounter = 0;
SOLDIERTYPE *pSoldier = NULL;
@@ -595,11 +618,24 @@ void ResetAssignmentOfMercsThatWereTrainingMilitiaInThisSector( INT16 sSectorX,
continue;
}
if( pSoldier->bAssignment == TRAIN_TOWN )
if( ubMilitiaType == TOWN_MILITIA )
{
if( ( pSoldier->sSectorX == sSectorX ) && ( pSoldier->sSectorY == sSectorY ) && ( pSoldier->bSectorZ == 0 ) )
if( pSoldier->bAssignment == TRAIN_TOWN )
{
ResumeOldAssignment( pSoldier );
if( ( pSoldier->sSectorX == sSectorX ) && ( pSoldier->sSectorY == sSectorY ) && ( pSoldier->bSectorZ == 0 ) )
{
ResumeOldAssignment( pSoldier );
}
}
}
else if (ubMilitiaType == MOBILE_MILITIA )
{
if( pSoldier->bAssignment == TRAIN_MOBILE )
{
if( ( pSoldier->sSectorX == sSectorX ) && ( pSoldier->sSectorY == sSectorY ) && ( pSoldier->bSectorZ == 0 ) )
{
ResumeOldAssignment( pSoldier );
}
}
}
}
@@ -890,6 +926,7 @@ void RestoreBackgroundForAssignmentGlowRegionList( void )
// restore background
RestoreExternBackgroundRect( 66, Y_START - 1, 118 + 1 - 67, yHeight );
// ARM: not good enough! must reblit the whole panel to erase glow chunk restored by help text disappearing!!!
fTeamPanelDirty = TRUE;
@@ -2285,7 +2322,24 @@ void UpdateMapScreenAssignmentPositions( void )
SetBoxPosition( ghRepairBox, pPoint );
}
// HEADROCK HAM 3.6: Facility Menu
if( fShowFacilityMenu )
{
GetBoxPosition( ghFacilityBox, &pPoint);
pPoint.iY = giBoxY + ( GetFontHeight( MAP_SCREEN_FONT ) + 2 ) * ASSIGN_MENU_FACILITY;
SetBoxPosition( ghFacilityBox, pPoint );
}
// HEADROCK HAM 3.6: Facility Sub-menu
if( fShowFacilityAssignmentMenu )
{
GetBoxPosition( ghFacilityAssignmentBox, &pPoint);
pPoint.iY = giBoxY + ( GetFontHeight( MAP_SCREEN_FONT ) + 2 ) * ASSIGN_MENU_FACILITY;
SetBoxPosition( ghFacilityAssignmentBox, pPoint );
}
return;
}
@@ -5655,7 +5709,8 @@ BOOLEAN HandleTimeCompressWithTeamJackedInAndGearedToGo( void )
if (!is_networked)
// select starting sector (A9 - Omerta)
ChangeSelectedMapSector( startingX, startingY, startingZ );
// HEADROCK HAM 3.5: Externalized.
ChangeSelectedMapSector( gGameExternalOptions.ubDefaultArrivalSectorX, gGameExternalOptions.ubDefaultArrivalSectorY, startingZ );
if (is_networked)
{
@@ -5671,22 +5726,30 @@ BOOLEAN HandleTimeCompressWithTeamJackedInAndGearedToGo( void )
else
{
// load starting sector
if ( !SetCurrentWorldSector( startingX, startingY, startingZ ) )
// Externalized
if ( !SetCurrentWorldSector( gGameExternalOptions.ubDefaultArrivalSectorX, gGameExternalOptions.ubDefaultArrivalSectorY, startingZ ) )
{
return( FALSE );
}
gubPBSectorX = startingX;
gubPBSectorY = startingY;
gubPBSectorX = gGameExternalOptions.ubDefaultArrivalSectorX;
gubPBSectorY = gGameExternalOptions.ubDefaultArrivalSectorY;
}
gubPBSectorZ = 0;
//Setup variables in the PBI for this first battle. We need to support the
//non-persistant PBI in case the user goes to mapscreen.
gfBlitBattleSectorLocator = TRUE;
gubPBSectorZ = 0;
gubEnemyEncounterCode = ENTERING_ENEMY_SECTOR_CODE;
// HEADROCK HAM 3.5: Arrival sector externalized. Fix for entering non-hostile sector/
if ( NumEnemiesInAnySector( gubPBSectorX, gubPBSectorY, 0 ) > 0 )
{
gfBlitBattleSectorLocator = TRUE;
gubEnemyEncounterCode = ENTERING_ENEMY_SECTOR_CODE;
}
else
{
gfBlitBattleSectorLocator = FALSE;
gubEnemyEncounterCode = NO_ENCOUNTER_CODE;
}
InitHelicopterEntranceByMercs( );
+21 -3
View File
@@ -113,15 +113,17 @@ enum {
ASSIGN_MENU_VEHICLE,
ASSIGN_MENU_REPAIR,
ASSIGN_MENU_TRAIN,
ASSIGN_MENU_FACILITY, // HEAROCK HAM 3.6: Facility List menu
ASSIGN_MENU_CANCEL,
MAX_ASSIGN_STRING_COUNT,
};
// HEADROCK HAM 3.6: Added new option to train Mobile Militia separately.
// training assignment menu defines
enum {
TRAIN_MENU_SELF,
TRAIN_MENU_TOWN,
TRAIN_MENU_MOBILE,
TRAIN_MENU_TEAMMATES,
TRAIN_MENU_TRAIN_BY_OTHER,
TRAIN_MENU_CANCEL,
@@ -202,6 +204,12 @@ enum{
STOP_YELLOW_SECTOR_LOCATOR,
};
// HEADROCK HAM 3.6: Enums for Militia Training Types
enum{
TOWN_MILITIA = 0,
MOBILE_MILITIA,
NUM_MILITIA_TRAINING_TYPES
};
// dimensions and offset for merc update box
#define UPDATE_MERC_FACE_X_WIDTH 50
@@ -254,6 +262,8 @@ extern BOOLEAN fShowContractMenu ;
extern BOOLEAN fShowRemoveMenu ;
extern BOOLEAN fShowMilitiaControlMenu ; //lal
//extern BOOLEAN fShowTalkToAllMenu ;
extern BOOLEAN fShowFacilityMenu; // HEADROCK HAM 3.6
extern BOOLEAN fShowFacilityAssignmentMenu; // HEADROCK HAM 3.6
extern BOOLEAN fFirstTimeInMapScreen;
extern BOOLEAN fLockOutMapScreenInterface;
@@ -299,6 +309,11 @@ extern SGPRect AssignmentDimensions ;
extern SGPPoint AssignmentPosition ;
extern SGPPoint SquadPosition ;
extern SGPRect SquadDimensions ;
// HEADROCK HAM 3.6: Facility Menu variables
extern SGPPoint FacilityPosition;
extern SGPRect FacilityDimensions;
extern SGPPoint FacilityAssignmentPosition;
extern SGPRect FacilityAssignmentDimensions;
extern SGPPoint RepairPosition;
extern SGPRect RepairDimensions;
@@ -316,6 +331,8 @@ extern SGPPoint OrigAssignmentPosition ;
extern SGPPoint OrigTrainPosition;
extern SGPPoint OrigVehiclePosition;
extern SGPPoint OrigMilitiaControlPosition ; //lal
extern SGPPoint OrigFacilityPosition; // HEADROCK HAM 3.6: Facility Menu
extern SGPPoint OrigFacilityAssignmentPosition; // HEADROCK HAM 3.6
//extern SGPPoint OrigTalkToAllPosition ;
// disble team info panel due to showing of battle roster
@@ -374,7 +391,8 @@ BOOLEAN MultipleCharacterListEntriesSelected( void );
void ToggleEntryInSelectedList( INT8 bEntry );
// reset assignments for mercs on selected list who have this assignment
void ResetAssignmentsForMercsTrainingUnpaidSectorsInSelectedList( INT8 bAssignment );
// HEADROCK HAM 3.6: Argument was unused... adding my own.
void ResetAssignmentsForMercsTrainingUnpaidSectorsInSelectedList( UINT8 ubMilitiaType );
/*
// plot path for selected character list
@@ -553,7 +571,7 @@ BOOLEAN SetUpFastHelpListRegions( INT32 iXPosition[], INT32 iYPosition[], INT32
void InitializeMovingLists( void );
// reset assignment for mercs trainign militia in this sector
void ResetAssignmentOfMercsThatWereTrainingMilitiaInThisSector( INT16 sSectorX, INT16 sSectorY );
void ResetAssignmentOfMercsThatWereTrainingMilitiaInThisSector( INT16 sSectorX, INT16 sSectorY, UINT8 ubMilitiaType );
// the sector move box
+1250 -430
View File
File diff suppressed because it is too large Load Diff
+25 -3
View File
@@ -5,6 +5,7 @@
#include "Types.h"
#include "Soldier Control.h"
#include "campaign types.h"
//#define MAXIMUM_MILITIA_SQUAD_SIZE 30
@@ -18,7 +19,8 @@ void UpdateMilitiaSquads(INT16 sMapX, INT16 sMapY );
void CreateMilitiaSquads(INT16 sMapX, INT16 sMapY );
void MilitiaHelpFromAdjacentSectors( INT16 sMapX, INT16 sMapY );
void GenerateDirectionInfos( INT16 sMapX, INT16 sMapY, UINT8* uiDirNumber, UINT16 pMoveDir[4][3], BOOLEAN fWithCities, BOOLEAN fForBattle, BOOLEAN fOnlyCitySectors );
// HEADROCK HAM 3.4: Now using different arguments for this function. All relevent instances have also been altered.
void GenerateDirectionInfos( INT16 sMapX, INT16 sMapY, UINT8* uiDirNumber, UINT16 pMoveDir[4][3], BOOLEAN fForTraining, BOOLEAN fForBattle );
BOOLEAN MoveOneBestMilitiaMan(INT16 sMapX, INT16 sMapY, INT16 sTMapX, INT16 sTMapY);
void MilitiaFollowPlayer( INT16 sMapX, INT16 sMapY, INT16 sDMapX, INT16 sDMapY );
@@ -29,9 +31,29 @@ extern BOOLEAN gDynamicRestrictMilitia[ 256 ];
// HEADROCK HAM B2.7: Wonder why this function wasn't declared here. It is now, to allow Town Militia.cpp to
// access it.
BOOLEAN CheckStandardConditionsForDirection( INT16 sSMapX, INT16 sSMapY, INT16 sMapX, INT16 sMapY, BOOLEAN fWithCities, BOOLEAN fForBattle, BOOLEAN fOnlyCitySectors );
BOOLEAN CheckStandardConditionsForDirection( INT16 sSMapX, INT16 sSMapY, INT16 sMapX, INT16 sMapY, BOOLEAN fForTraining, BOOLEAN fForBattle );
// HEADROCK HAM B2.7: Generates possible movement directions - this is used only in CreateMilitiaGroup(), and
// makes sure that the target sector has room for more militia.
void GenerateDirectionInfosWithCapacityCheck( INT16 sMapX, INT16 sMapY, UINT8* uiDirNumber, UINT16 pMoveDir[4][3], BOOLEAN fWithCities, BOOLEAN fForBattle, BOOLEAN fOnlyCitySectors );
void GenerateDirectionInfosForTraining( INT16 sMapX, INT16 sMapY, UINT8* uiDirNumber, UINT16 pMoveDir[4][3] );
// HEADROCK HAM 3.4: Stores restriction data from XML, including required cities for each sector to be allowed.
typedef struct DYNAMICRESTRICTIONS
{
INT8 bSectorID;
UINT32 uiReqTownFlags;
} DYNAMICRESTRICTIONS;
// HEADROCK HAM 3.4: New function for simple Roaming Restriction testing.
BOOLEAN IsSectorRoamingAllowed( UINT32 uiSector );
// HEADROCK HAM 3.6: New upgrade check returns the amount of militia that can be upgraded at target sector, in
// "upgrade points"
UINT16 MilitiaUpgradeSlotsCheck( SECTORINFO * pSectorInfo );
// HEADROCK HAM 3.6: This needs to be accessible.
void AddToBlockMoveList(INT16 sMapX, INT16 sMapY);
// And this:
UINT8 CountMilitia(SECTORINFO *pSectorInfo);
#endif
+76 -17
View File
@@ -25,6 +25,8 @@
#include "Tactical Save.h"
#include "interface Dialogue.h"
#include "Random.h"
// HEADROCK HAM 3.6: Added for facility string printing...
#include "PopUpBox.h"
#endif
#include "postalservice.h"
@@ -32,26 +34,70 @@
extern BOOLEAN fMapScreenBottomDirty;
extern CPostalService gPostalService;
void GetSectorFacilitiesFlags( INT16 sMapX, INT16 sMapY, STR16 sFacilitiesString )
void AddFacilitiesToBox( INT16 sMapX, INT16 sMapY, UINT32 *uiHandle, BOOLEAN fCityInfoBox )
{
// will build a string stating current facilities present in sector
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags == 0 )
// HEADROCK HAM 3.5: Facilities are now read from XMLs, including their names.
UINT32 cnt = 0;
UINT32 uiNumFacilities = 0;
BOOLEAN fHeaderAdded = FALSE;
CHAR16 szFacilityString[30];
Assert(sMapX > 0 && sMapY > 0 && sMapX < 17 && sMapY < 17);
for ( cnt = 0; cnt < NUM_FACILITY_TYPES; cnt++ )
{
// none
swprintf( sFacilitiesString, L"%s", sFacilitiesStrings[ 0 ] );
if (fCityInfoBox && uiNumFacilities == 0 && !fHeaderAdded )
{
// For a city info box, always show this line on the left side.
swprintf( szFacilityString, L"%s:", pwTownInfoStrings[ 8 ] );
AddMonoString( uiHandle, szFacilityString );
fHeaderAdded = TRUE;
}
// Facility type exists at this location?
if (gFacilityLocations[SECTOR(sMapX,sMapY)][cnt].fFacilityHere)
{
if (gFacilityLocations[SECTOR(sMapX,sMapY)][cnt].ubHidden == 0 ||
(gFacilityLocations[SECTOR(sMapX,sMapY)][cnt].ubHidden == 1 && SectorInfo[SECTOR(sMapX,sMapY)].fSurfaceWasEverPlayerControlled) )
{
if (!fCityInfoBox && uiNumFacilities == 0 && !fHeaderAdded )
{
// For a non-city info box, show this line on the left side only if there's at least one facility.
swprintf( szFacilityString, L"%s:", pwTownInfoStrings[ 8 ] );
AddMonoString( uiHandle, szFacilityString );
}
else if (uiNumFacilities > 0)
{
// Add empty line on the left size to make room for text on the right.
AddMonoString( uiHandle, L"" );
}
AddSecondColumnMonoString( uiHandle, gFacilityTypes[cnt].szFacilityName );
uiNumFacilities++;
}
}
}
if( uiNumFacilities == 0 && fCityInfoBox )
{
// Add "NONE" on the right side. Only happens when the sector is a city.
AddSecondColumnMonoString( uiHandle, sFacilitiesStrings[0] );
return;
}
/* HEADROCK HAM 3.4: Hardcodes removed.
// hospital
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & SFCF_HOSPITAL )
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & (1 << FACILITY_HOSPITAL) )
{
swprintf( sFacilitiesString, L"%s", sFacilitiesStrings[ 1 ] );
swprintf( sFacilitiesString, L"%s", sFacilitiesStrings[ FACILITY_HOSPITAL ] );
}
// industry
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & SFCF_INDUSTRY )
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & (1 << FACILITY_INDUSTRY) )
{
if( wcslen( sFacilitiesString ) == 0 )
{
@@ -59,13 +105,13 @@ void GetSectorFacilitiesFlags( INT16 sMapX, INT16 sMapY, STR16 sFacilitiesString
}
else
{
wcscat( sFacilitiesString, L",");
wcscat( sFacilitiesString, L", ");
wcscat( sFacilitiesString, sFacilitiesStrings[ 2 ]);
}
}
// prison
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & SFCF_PRISON )
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & (1 << FACILITY_PRISON) )
{
if( wcslen( sFacilitiesString ) == 0 )
{
@@ -73,13 +119,27 @@ void GetSectorFacilitiesFlags( INT16 sMapX, INT16 sMapY, STR16 sFacilitiesString
}
else
{
wcscat( sFacilitiesString, L",");
wcscat( sFacilitiesString, L", ");
wcscat( sFacilitiesString, sFacilitiesStrings[ 3 ]);
}
}
// HEADROCK HAM 3.4: What about the military base!
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & (1 << FACILITY_MILITARY) )
{
if( wcslen( sFacilitiesString ) == 0 )
{
swprintf( sFacilitiesString, L"%s", sFacilitiesStrings[ 4 ] );
}
else
{
wcscat( sFacilitiesString, L", ");
wcscat( sFacilitiesString, sFacilitiesStrings[ 4 ]);
}
}
// airport
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & SFCF_AIRPORT )
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & (1 << FACILITY_AIRPORT) )
{
if( wcslen( sFacilitiesString ) == 0 )
{
@@ -87,13 +147,13 @@ void GetSectorFacilitiesFlags( INT16 sMapX, INT16 sMapY, STR16 sFacilitiesString
}
else
{
wcscat( sFacilitiesString, L",");
wcscat( sFacilitiesString, L", ");
wcscat( sFacilitiesString, sFacilitiesStrings[ 5 ]);
}
}
// gun range
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & SFCF_GUN_RANGE )
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & (1 << FACILITY_GUNRANGE) )
{
if( wcslen( sFacilitiesString ) == 0 )
{
@@ -101,12 +161,11 @@ void GetSectorFacilitiesFlags( INT16 sMapX, INT16 sMapY, STR16 sFacilitiesString
}
else
{
wcscat( sFacilitiesString, L",");
wcscat( sFacilitiesString, L", ");
wcscat( sFacilitiesString, sFacilitiesStrings[ 6 ]);
}
}
sFacilitiesString[ wcslen( sFacilitiesString ) ] = 0;
*/
return;
}
+1 -1
View File
@@ -6,7 +6,7 @@
// build main facilities strings for sector
void GetSectorFacilitiesFlags( INT16 sMapX, INT16 sMapY, STR16 sFacilitiesString );
void AddFacilitiesToBox( INT16 sMapX, INT16 sMapY, UINT32 *uiHandle, BOOLEAN fCityInfoBox );
// set sector as enemy controlled
BOOLEAN SetThisSectorAsEnemyControlled( INT16 sMapX, INT16 sMapY, INT8 bMapZ, BOOLEAN fContested );
+16 -12
View File
@@ -210,15 +210,15 @@ UINT8 NumEnemiesInSector( INT16 sSectorX, INT16 sSectorY )
GROUP *pGroup;
UINT8 ubNumTroops;
// HEADROCK: This is a TEMPORARY fix to avoid the assertion error. Not sure this is the best solution,
// probably isn't. But I need this bit to work.
if (sSectorX < MINIMUM_VALID_X_COORDINATE ||
sSectorX > MAXIMUM_VALID_X_COORDINATE ||
sSectorY < MINIMUM_VALID_Y_COORDINATE ||
sSectorY > MAXIMUM_VALID_Y_COORDINATE)
{
return (0);
}
// HEADROCK HAM 3.5: This is a TEMPORARY fix to avoid the assertion error. Not sure this is the best solution,
// probably isn't. But I need this bit to work.
if (sSectorX < MINIMUM_VALID_X_COORDINATE ||
sSectorX > MAXIMUM_VALID_X_COORDINATE ||
sSectorY < MINIMUM_VALID_Y_COORDINATE ||
sSectorY > MAXIMUM_VALID_Y_COORDINATE)
{
return (0);
}
AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE);
AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
@@ -503,8 +503,7 @@ BOOLEAN PrepareEnemyForSectorBattle()
// They arrived in multiple groups, so here they come
pThisSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ];
GenerateDirectionInfos( gWorldSectorX, gWorldSectorY, &ubDirNumber, pusMoveDir,
( GetTownIdForSector( gWorldSectorX, gWorldSectorY ) != BLANK_SECTOR ? TRUE : FALSE ), TRUE, IS_ONLY_IN_CITIES );
GenerateDirectionInfos( gWorldSectorX, gWorldSectorY, &ubDirNumber, pusMoveDir, FALSE, TRUE );
for( unsigned ubIndex = 0; ubIndex < ubDirNumber; ubIndex++ )
{
@@ -788,7 +787,6 @@ BOOLEAN PrepareEnemyForSectorBattle()
continue;
}
// At this point we should not have added more soldiers than are in slots
AssertGT( sNumSlots, 0 );
switch( pSoldier->ubSoldierClass )
@@ -1394,6 +1392,7 @@ void AddPossiblePendingEnemiesToBattle()
if( ubStrategicInsertionCode == 255 )
{
// HEADROCK HAM 3.5: This runs into assertion errors along the map's edge! Should be fixed!
if( NumEnemiesInSector( gWorldSectorX + 1, gWorldSectorY ) )
ubStrategicInsertionCode = INSERTION_CODE_EAST;
else if( NumEnemiesInSector( gWorldSectorX - 1, gWorldSectorY ) )
@@ -1704,6 +1703,11 @@ void AddEnemiesToBattle( GROUP *pGroup, UINT8 ubStrategicInsertionCode, UINT8 ub
}
UpdateMercInSector( pSoldier, gWorldSectorX, gWorldSectorY, 0 );
}
// HEADROCK HAM 3.2: enemy reinforcements arrive with 0 APs.
if (gGameExternalOptions.ubReinforcementsFirstTurnFreeze == 1 || gGameExternalOptions.ubReinforcementsFirstTurnFreeze == 2)
{
pSoldier->bActionPoints = 0;
}
}
}
+3 -2
View File
@@ -1126,8 +1126,9 @@ BOOLEAN CheckFact( UINT16 usFact, UINT8 ubProfileID )
gubFact[usFact] = gMercProfiles[ ARNIE ].bMercStatus != MERC_IS_DEAD;
break;
case FACT_I16_BLOODCATS_KILLED:
gubFact[usFact] = (SectorInfo[ SEC_I16 ].bBloodCats == 0);
// HEADROCK HAM 3.6: No longer necessarily I16.
case FACT_BLOODCAT_LAIR_CLEANED:
gubFact[usFact] = (SectorInfo[ gubBloodcatLairSectorId ].bBloodCats == 0);
break;
case FACT_NPC_BANDAGED_TODAY:
+2 -1
View File
@@ -430,7 +430,8 @@ enum Facts
FACT_KINGPIN_NOT_IN_OFFICE,// 256
FACT_DONT_OWE_KINGPIN_MONEY,// 257
FACT_PC_MARRYING_DARYL_IS_FLO,// 258
FACT_I16_BLOODCATS_KILLED,// 259
// HEADROCK HAM 3.6: Renamed this. It is no longer necessarily at I16.
FACT_BLOODCAT_LAIR_CLEANED,// 259
FACT_NPC_COWERING = 261,
+11 -20
View File
@@ -52,8 +52,7 @@ void GetNumberOfEnemiesInFiveSectors( INT16 sSectorX, INT16 sSectorY, UINT8 *pub
if ( ( GetTownIdForSector( sSectorX, sSectorY ) == OMERTA )&&( gGameOptions.ubDifficultyLevel != DIF_LEVEL_INSANE ) ) //Madd: skip Omerta //Lal: but not on insane ;-)
return;
GenerateDirectionInfos( sSectorX, sSectorY, &ubDirNumber, pusMoveDir,
( GetTownIdForSector( sSectorX, sSectorY ) != BLANK_SECTOR ? TRUE : FALSE ), TRUE, IS_ONLY_IN_CITIES );
GenerateDirectionInfos( sSectorX, sSectorY, &ubDirNumber, pusMoveDir, FALSE, TRUE );
for( ubIndex = 0; ubIndex < ubDirNumber; ubIndex++ )
{
@@ -104,8 +103,7 @@ BOOLEAN IsGroupInARightSectorToReinforce( GROUP *pGroup, INT16 sSectorX, INT16 s
if( !gGameExternalOptions.gfAllowReinforcements )
return FALSE;
GenerateDirectionInfos( sSectorX, sSectorY, &ubDirNumber, pusMoveDir,
( GetTownIdForSector( sSectorX, sSectorY ) != BLANK_SECTOR ? TRUE : FALSE ), TRUE, IS_ONLY_IN_CITIES );
GenerateDirectionInfos( sSectorX, sSectorY, &ubDirNumber, pusMoveDir, FALSE, TRUE );
for( ubIndex = 0; ubIndex < ubDirNumber; ubIndex++ )
if( pGroup->ubSectorX == SECTORX( pusMoveDir[ ubIndex ][ 0 ] ) && pGroup->ubSectorY == SECTORY( pusMoveDir[ ubIndex ][ 0 ] ) )
@@ -120,8 +118,7 @@ UINT8 GetAdjacentSectors( UINT8 pSectors[4], INT16 sSectorX, INT16 sSectorY )
UINT8 ubDirNumber = 0, ubIndex;
UINT8 ubCounter = 0;
GenerateDirectionInfos( sSectorX, sSectorY, &ubDirNumber, pusMoveDir,
( GetTownIdForSector( sSectorX, sSectorY ) != BLANK_SECTOR ? TRUE : FALSE ), TRUE, IS_ONLY_IN_CITIES );
GenerateDirectionInfos( sSectorX, sSectorY, &ubDirNumber, pusMoveDir, FALSE, TRUE );
for( ubIndex = 0; ubIndex < ubDirNumber; ubIndex++ )
pSectors[ ubCounter++ ] = (UINT8)pusMoveDir[ ubIndex ][ 0 ];
@@ -140,8 +137,7 @@ UINT8 CountAllMilitiaInFiveSectors(INT16 sMapX, INT16 sMapY)
if( !gGameExternalOptions.gfAllowReinforcements )
return ubResult;
GenerateDirectionInfos( sMapX, sMapY, &ubDirNumber, pusMoveDir,
( GetTownIdForSector( sMapX, sMapY ) != BLANK_SECTOR ? TRUE : FALSE ), TRUE, IS_ONLY_IN_CITIES );
GenerateDirectionInfos( sMapX, sMapY, &ubDirNumber, pusMoveDir, FALSE, TRUE );
for( ubIndex = 0; ubIndex < ubDirNumber; ubIndex++ )
ubResult += CountAllMilitiaInSector( SECTORX( pusMoveDir[ ubIndex ][ 0 ] ), SECTORY( pusMoveDir[ ubIndex ][ 0 ] ) );
@@ -161,8 +157,7 @@ UINT8 MilitiaInFiveSectorsOfRank( INT16 sMapX, INT16 sMapY, UINT8 ubRank )
if( !gGameExternalOptions.gfAllowReinforcements )
return ubResult;
GenerateDirectionInfos( sMapX, sMapY, &ubDirNumber, pusMoveDir,
( GetTownIdForSector( sMapX, sMapY ) != BLANK_SECTOR ? TRUE : FALSE ), TRUE, IS_ONLY_IN_CITIES );
GenerateDirectionInfos( sMapX, sMapY, &ubDirNumber, pusMoveDir, FALSE, TRUE );
for( ubIndex = 0; ubIndex < ubDirNumber; ubIndex++ )
ubResult += MilitiaInSectorOfRank( SECTORX( pusMoveDir[ ubIndex ][ 0 ] ), SECTORY( pusMoveDir[ ubIndex ][ 0 ] ), ubRank );
@@ -179,12 +174,11 @@ BOOLEAN ARMoveBestMilitiaManFromAdjacentSector(INT16 sMapX, INT16 sMapY)
if( !gGameExternalOptions.gfAllowReinforcements )
return FALSE;
if( CountAllMilitiaInSector( sMapX, sMapY ) >= gGameExternalOptions.guiMaxMilitiaSquadSize ||
if( CountAllMilitiaInSector( sMapX, sMapY ) >= gGameExternalOptions.iMaxMilitiaPerSector ||
CountAllMilitiaInFiveSectors( sMapX, sMapY ) - CountAllMilitiaInSector( sMapX, sMapY ) == 0 )
return FALSE;
GenerateDirectionInfos( sMapX, sMapY, &ubDirNumber, pusMoveDir,
( GetTownIdForSector( sMapX, sMapY ) != BLANK_SECTOR ? TRUE : FALSE ), TRUE, IS_ONLY_IN_CITIES );
GenerateDirectionInfos( sMapX, sMapY, &ubDirNumber, pusMoveDir, FALSE, TRUE );
ubRandom = Random( ubDirNumber );
@@ -209,8 +203,7 @@ BOOLEAN ARRemoveMilitiaMan( INT16 sMapX, INT16 sMapY, UINT8 ubRank )
if( !gGameExternalOptions.gfAllowReinforcements )
return FALSE;
GenerateDirectionInfos( sMapX, sMapY, &ubDirNumber, pusMoveDir,
( GetTownIdForSector( sMapX, sMapY ) != BLANK_SECTOR ? TRUE : FALSE ), TRUE, IS_ONLY_IN_CITIES );
GenerateDirectionInfos( sMapX, sMapY, &ubDirNumber, pusMoveDir, FALSE, TRUE );
for( ; ; )
{
@@ -256,8 +249,7 @@ UINT8 DoReinforcementAsPendingEnemy( INT16 sMapX, INT16 sMapY )
pThisSector = &SectorInfo[ SECTOR( sMapX, sMapY ) ];
GenerateDirectionInfos( sMapX, sMapY, &ubDirNumber, pusMoveDir,
( GetTownIdForSector( sMapX, sMapY ) != BLANK_SECTOR ? TRUE : FALSE ), TRUE, IS_ONLY_IN_CITIES );
GenerateDirectionInfos( sMapX, sMapY, &ubDirNumber, pusMoveDir, FALSE, TRUE );
for( ubIndex = 0; ubIndex < ubDirNumber; ubIndex++ )
{
@@ -328,7 +320,7 @@ UINT8 NumFreeMilitiaSlots()
if( !pSoldier->bActive )
ubNumFreeSlots++;
}
return max( 0 , ubNumFreeSlots - ( gGameExternalOptions.ubGameMaximumNumberOfRebels - gGameExternalOptions.guiMaxMilitiaSquadSize ) );
return max( 0 , ubNumFreeSlots - ( gGameExternalOptions.ubGameMaximumNumberOfRebels - gGameExternalOptions.iMaxMilitiaPerSector ) );
}
UINT8 DoReinforcementAsPendingMilitia( INT16 sMapX, INT16 sMapY, UINT8 *pubRank )
@@ -342,8 +334,7 @@ UINT8 DoReinforcementAsPendingMilitia( INT16 sMapX, INT16 sMapY, UINT8 *pubRank
// pThisSector = &SectorInfo[ SECTOR( sMapX, sMapY ) ];
GenerateDirectionInfos( sMapX, sMapY, &ubDirNumber, pusMoveDir,
( GetTownIdForSector( sMapX, sMapY ) != BLANK_SECTOR ? TRUE : FALSE ), TRUE, IS_ONLY_IN_CITIES );
GenerateDirectionInfos( sMapX, sMapY, &ubDirNumber, pusMoveDir, FALSE, TRUE );
if( CountAllMilitiaInFiveSectors( sMapX, sMapY ) - CountAllMilitiaInSector( sMapX, sMapY ) == 0 )
{
+6 -1
View File
@@ -3704,6 +3704,9 @@ BOOLEAN LoadStrategicAI( HWFILE hFile )
}
if( ubSAIVersion < 18 )
{ //adjust down the number of bloodcats based on difficulty in the two special bloodcat levels
// HEADROCK HAM 3.6: Run the Init function instead.
InitBloodCatSectors();
/*
switch( gGameOptions.ubDifficultyLevel )
{
case DIF_LEVEL_EASY: //50%
@@ -3729,7 +3732,7 @@ BOOLEAN LoadStrategicAI( HWFILE hFile )
SectorInfo[ SEC_I16 ].bBloodCats = 39;
SectorInfo[ SEC_N5 ].bBloodCats = 37;
break;
}
}*/
}
if( ubSAIVersion < 19 )
{
@@ -3753,6 +3756,8 @@ BOOLEAN LoadStrategicAI( HWFILE hFile )
}
if( ubSAIVersion < 22 )
{ //adjust down the number of bloodcats based on difficulty in the two special bloodcat levels
// HEADROCK HAM 3.6: Run the Init function instead.
InitBloodCatSectors();
switch( gGameOptions.ubDifficultyLevel )
{
case DIF_LEVEL_EASY: //50%
+14 -1
View File
@@ -42,6 +42,10 @@
#include "Quests.h"
// HEADROCK HAM B1: Additional Include for Dynamic Roaming Restrictions
#include "MilitiaSquads.h"
// HEADROCK HAM 3.6: Additional include for Facility Operating Deby
#include "Facilities.h"
// HEADROCK HAM 3.6: And another include, for militia upkeep costs.
#include "Town Militia.h"
#endif
@@ -513,10 +517,19 @@ void MercDailyUpdate()
// rebuild list for mapscreen
ReBuildCharactersList( );
// HEADROCK HAM B1: Run a function to redefine Roaming Militia Restrictions.
if (gGameExternalOptions.bDynamicRestrictRoaming)
if (gGameExternalOptions.fDynamicRestrictRoaming)
{
AdjustRoamingRestrictions();
}
// HEADROCK HAM 3.6: Pay debt for operating Facilities today. If can't be paid, apply loyalty hit.
if (giTotalOwedForFacilityOperationsToday)
{
HandleDailyPaymentFacilityDebt();
}
// HEADROCK HAM 3.6: Pay for militia upkeep
HandleMilitiaUpkeepPayment();
}
/*
+38 -7
View File
@@ -21,6 +21,7 @@
#include "Strategic AI.h"
#include "Campaign Types.h"
#include "history.h"
#include "Facilities.h"
#endif
@@ -202,12 +203,27 @@ void InitializeMines( void )
// Alma mine can't run out for quest-related reasons (see Ian)
} while (gMineStatus[ubDepletedMineIndex].fEmpty || (ubDepletedMineIndex == MINE_ALMA));
// HEADROCK HAM 3.1: We can now select which mine runs out, or disable mine shutdown.
if (gGameExternalOptions.fManuallySelectMineShutdown)
{
// Make sure selection isn't 0 (no mine runs out) or invalid (San Mona, Alma)
if (gGameExternalOptions.ubWhichMineRunsOut > 0 &&
gGameExternalOptions.ubWhichMineRunsOut < MAX_NUMBER_OF_MINES &&
gGameExternalOptions.ubWhichMineRunsOut-1 != MINE_SAN_MONA &&
gGameExternalOptions.ubWhichMineRunsOut-1 != MINE_ALMA )
{
// Set depleted mine index.
ubDepletedMineIndex = (gGameExternalOptions.ubWhichMineRunsOut-1);
}
}
for( ubMineIndex = 0; ubMineIndex < MAX_NUMBER_OF_MINES; ubMineIndex++ )
{
pMineStatus = &(gMineStatus[ ubMineIndex ]);
if (ubMineIndex == ubDepletedMineIndex)
// HEADROCK HAM 3.1: We can disable mine shutdown, so make sure the settings aren't telling us to do so.
if (!(gGameExternalOptions.fManuallySelectMineShutdown && gGameExternalOptions.ubWhichMineRunsOut == 0) &&
(ubMineIndex == ubDepletedMineIndex))
{
if ( ubDepletedMineIndex == MINE_DRASSEN )
{
@@ -343,7 +359,7 @@ UINT32 GetMaxPeriodicRemovalFromMine( INT8 bMineIndex )
}
// HEADROCK HAM B1: Affected by external INI option.
return(( gMineStatus[ bMineIndex ].uiMaxRemovalRate * gGameExternalOptions.iMineIncomePercentage ) / 100);
return(( gMineStatus[ bMineIndex ].uiMaxRemovalRate * gGameExternalOptions.usMineIncomePercentage ) / 100);
}
@@ -370,7 +386,7 @@ UINT32 GetMaxDailyRemovalFromMine( INT8 bMineIndex )
uiAmtExtracted = gMineStatus[ bMineIndex ].uiRemainingOreSupply;
}
// HEADROCK HAM B1: Affected by external INI option.
uiAmtExtracted = (uiAmtExtracted * gGameExternalOptions.iMineIncomePercentage) / 100;
uiAmtExtracted = (uiAmtExtracted * gGameExternalOptions.usMineIncomePercentage) / 100;
return(uiAmtExtracted);
}
@@ -660,15 +676,22 @@ void HandleIncomeFromMines( void )
{
INT32 iIncome = 0;
INT8 bCounter = 0;
// HEADROCK HAM 3.6: Modifier from Facilities
INT32 iFacilityModifier = 0;
// mine each mine, check if we own it and such
for( bCounter = 0; bCounter < MAX_NUMBER_OF_MINES; bCounter++ )
{
if (bCounter)
{
// HEADROCK HAM 3.6: Add facility modifier as a percentage
iFacilityModifier = 100 + MineIncomeModifierFromFacility( bCounter );
}
// mine this mine
iIncome += MineAMine( bCounter );
iIncome += (MineAMine( bCounter ) * iFacilityModifier) / 100;
}
// HEADROCK HAM B1: Affected by external INI Option.
iIncome = (iIncome * gGameExternalOptions.iMineIncomePercentage) / 100;
iIncome = (iIncome * gGameExternalOptions.usMineIncomePercentage) / 100;
if( iIncome )
{
AddTransactionToPlayersBook( DEPOSIT_FROM_SILVER_MINE, 0, GetWorldTotalMin( ), iIncome );
@@ -681,6 +704,8 @@ UINT32 PredictDailyIncomeFromAMine( INT8 bMineIndex )
// predict income from this mine, estimate assumes mining situation will not change during next 4 income periods
// (miner loyalty, % town controlled, monster infestation level, and current max removal rate may all in fact change)
UINT32 uiAmtExtracted = 0;
// HEADROCK HAM 3.6: Facilities can now modify income
INT32 iFacilityModifier = 0;
if(PlayerControlsMine(bMineIndex))
{
@@ -693,10 +718,16 @@ UINT32 PredictDailyIncomeFromAMine( INT8 bMineIndex )
// yes reduce to value of mine
uiAmtExtracted = gMineStatus[ bMineIndex ].uiRemainingOreSupply;
}
if (bMineIndex)
{
// HEADROCK HAM 3.6: Facility modifier applied as a percentage
iFacilityModifier = 100 + MineIncomeModifierFromFacility( bMineIndex );
uiAmtExtracted = (uiAmtExtracted * iFacilityModifier) / 100;
}
}
// HEADROCK HAM B1: Affected by external INI Option.
return( ( uiAmtExtracted * gGameExternalOptions.iMineIncomePercentage ) / 100 ) ;
return( ( uiAmtExtracted * gGameExternalOptions.usMineIncomePercentage ) / 100 ) ;
}
@@ -727,7 +758,7 @@ INT32 CalcMaxPlayerIncomeFromMines( void )
iTotal += (MINE_PRODUCTION_NUMBER_OF_PERIODS * gMineStatus[bCounter].uiMaxRemovalRate);
}
// HEADROCK HAM B1: Affected by external INI Option.
iTotal = (iTotal * gGameExternalOptions.iMineIncomePercentage) / 100;
iTotal = (iTotal * gGameExternalOptions.usMineIncomePercentage) / 100;
return( iTotal );
}
+85 -37
View File
@@ -1554,6 +1554,10 @@ void AwardExperienceForTravelling( GROUP * pGroup )
void AddCorpsesToBloodcatLair( INT16 sSectorX, INT16 sSectorY )
{
// HEADROCK HAM 3.6: Note, lair location externalized, but may cause issues because the GridNos here are
// hardcoded... Maybe there will be a better way to solve this in the future, with externalized GridNos.
// At the moment, no changes.
ROTTING_CORPSE_DEFINITION Corpse;
INT16 sXPos, sYPos;
@@ -1884,12 +1888,14 @@ void GroupArrivedAtSector( UINT8 ubGroupID, BOOLEAN fCheckForBattle, BOOLEAN fNe
if( pGroup->pPlayerList->pSoldier->bAssignment < ON_DUTY )
{
// squad
ScreenMsg( FONT_MCOLOR_DKRED, MSG_INTERFACE, pMessageStrings[ MSG_ARRIVE ], pAssignmentStrings[ pGroup->pPlayerList->pSoldier->bAssignment ], pMapVertIndex[ pGroup->pPlayerList->pSoldier->sSectorY ], pMapHortIndex[ pGroup->pPlayerList->pSoldier->sSectorX ]);
// HEADROCK HAM 3.6: Messages are no longer yellow by default.
ScreenMsg( FONT_MCOLOR_LTGREEN, MSG_INTERFACE, pMessageStrings[ MSG_ARRIVE ], pAssignmentStrings[ pGroup->pPlayerList->pSoldier->bAssignment ], pMapVertIndex[ pGroup->pPlayerList->pSoldier->sSectorY ], pMapHortIndex[ pGroup->pPlayerList->pSoldier->sSectorX ]);
}
else
{
// a loner
ScreenMsg( FONT_MCOLOR_DKRED, MSG_INTERFACE, pMessageStrings[ MSG_ARRIVE ], pGroup->pPlayerList->pSoldier->name, pMapVertIndex[ pGroup->pPlayerList->pSoldier->sSectorY ], pMapHortIndex[ pGroup->pPlayerList->pSoldier->sSectorX ] );
// HEADROCK HAM 3.6: Messages are no longer yellow by default.
ScreenMsg( FONT_MCOLOR_LTGREEN, MSG_INTERFACE, pMessageStrings[ MSG_ARRIVE ], pGroup->pPlayerList->pSoldier->name, pMapVertIndex[ pGroup->pPlayerList->pSoldier->sSectorY ], pMapHortIndex[ pGroup->pPlayerList->pSoldier->sSectorX ] );
}
}
}
@@ -1978,7 +1984,8 @@ void GroupArrivedAtSector( UINT8 ubGroupID, BOOLEAN fCheckForBattle, BOOLEAN fNe
// don't print any messages when arriving underground, there's no delay involved
if ( GroupAtFinalDestination( pGroup ) && ( pGroup->ubSectorZ == 0 ) && !fNeverLeft )
{
ScreenMsg( FONT_MCOLOR_DKRED, MSG_INTERFACE, pMessageStrings[ MSG_ARRIVE ], pVehicleStrings[ pVehicleList[ iVehId ].ubVehicleType ], pMapVertIndex[ pGroup->ubSectorY ], pMapHortIndex[ pGroup->ubSectorX ] );
// HEADROCK HAM 3.6: Messages are no longer yellow by default.
ScreenMsg( FONT_MCOLOR_LTGREEN, MSG_INTERFACE, pMessageStrings[ MSG_ARRIVE ], pVehicleStrings[ pVehicleList[ iVehId ].ubVehicleType ], pMapVertIndex[ pGroup->ubSectorY ], pMapHortIndex[ pGroup->ubSectorX ] );
}
}
}
@@ -1997,7 +2004,8 @@ void GroupArrivedAtSector( UINT8 ubGroupID, BOOLEAN fCheckForBattle, BOOLEAN fNe
if ( !pGroup->fVehicle || !IsGroupTheHelicopterGroup( pGroup ) )
{
// ATE: Add a few corpse to the bloodcat lair...
if ( SECTOR( pGroup->ubSectorX, pGroup->ubSectorY ) == SEC_I16 && fFirstTimeInSector )
// HEADROCK: No longer hardcoded to I16
if ( SECTOR( pGroup->ubSectorX, pGroup->ubSectorY ) == gubBloodcatLairSectorId && fFirstTimeInSector )
{
AddCorpsesToBloodcatLair( pGroup->ubSectorX, pGroup->ubSectorY );
}
@@ -4708,13 +4716,20 @@ void RandomizePatrolGroupLocation( GROUP *pGroup )
//roll the dice to see if this will become an ambush random encounter.
BOOLEAN TestForBloodcatAmbush( GROUP *pGroup )
{
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HEADROCK HAM 3.6: Ambush locations, min/max strength and chance of ambush have all been externalized to XML.
SECTORINFO *pSector;
INT32 iHoursElapsed;
UINT8 ubSectorID;
UINT8 ubChance;
INT8 bDifficultyMaxCats;
INT8 bProgressMaxCats;
UINT8 ubDifficulty = gGameOptions.ubDifficultyLevel-1; // For use by Placements Array. Novice = 0 instead of 1.
UINT8 ubRange;
UINT8 ubRandomCats;
INT8 bNumMercMaxCats;
UINT8 PlacementType; // 0 = Ambush site. 1 = Static placement. 2 = Lair.
UINT8 ubMinBloodcats; // XML minimum.
UINT8 ubMaxBloodcats; // XML maximum.
BOOLEAN fAlreadyAmbushed = FALSE;
if( pGroup->ubSectorZ )
@@ -4725,17 +4740,24 @@ BOOLEAN TestForBloodcatAmbush( GROUP *pGroup )
ubSectorID = (UINT8)SECTOR( pGroup->ubSectorX, pGroup->ubSectorY );
pSector = &SectorInfo[ ubSectorID ];
ubChance = 5 * gGameOptions.ubDifficultyLevel;
// Read chance from XML data, based on difficulty.
ubChance = gBloodcatPlacements[ ubSectorID ][ ubDifficulty ].ubAmbushChance;
iHoursElapsed = __max(0,(GetWorldTotalMin() - pSector->uiTimeCurrentSectorWasLastLoaded) / 60);
// Decrease chance to 0% if sector has been visited this hour. Every hour after that, increase the chance by 1%
// until it reaches the default value again.
ubChance = (UINT8)__min((INT32)ubChance, iHoursElapsed);
ubChance = __max(0,ubChance);
iHoursElapsed = (GetWorldTotalMin() - pSector->uiTimeCurrentSectorWasLastLoaded) / 60;
if( ubSectorID == SEC_N5 || ubSectorID == SEC_I16 )
{ //These are special maps -- we use all placements.
if( pSector->bBloodCats == -1 )
{
pSector->bBloodCats = pSector->bBloodCatPlacements;
}
else if( pSector->bBloodCats > 0 && pSector->bBloodCats < pSector->bBloodCatPlacements )
{ //Slowly have them recuperate if we haven't been here for a long time. The population will
// Determine what type of placement this is.
PlacementType = gBloodcatPlacements[ ubSectorID ][0].PlacementType;
// At lair?
if( PlacementType == BLOODCAT_PLACEMENT_LAIR )
{
// Bloodcats still exist here, but aren't at the optimal number?
if( pSector->bBloodCats > 0 && pSector->bBloodCats < pSector->bBloodCatPlacements )
{
//Slowly have them recuperate if we haven't been here for a long time. The population will
//come back up to the maximum if left long enough.
INT32 iBloodCatDiff;
iBloodCatDiff = pSector->bBloodCatPlacements - pSector->bBloodCats;
@@ -4743,55 +4765,80 @@ BOOLEAN TestForBloodcatAmbush( GROUP *pGroup )
}
//Once 0, the bloodcats will never recupe.
}
else if( pSector->bBloodCats == -1 )
{ //If we haven't been ambushed by bloodcats yet...
if( gfAutoAmbush || PreChance( ubChance ) )
// At ambush sector?
else if( PlacementType == BLOODCAT_PLACEMENT_AMBUSH )
{
//If there's any chance of ambush in this sector, and we beat that chance...
if( ubChance && (gfAutoAmbush || PreChance( ubChance )) )
{
//randomly choose from 5-8, 7-10, 9-12 bloodcats based on easy, normal, and hard, respectively
bDifficultyMaxCats = (INT8)( Random( 4 ) + gGameOptions.ubDifficultyLevel*2 + 3 );
//bDifficultyMaxCats = (INT8)( Random( 4 ) + gGameOptions.ubDifficultyLevel*2 + 3 );
//maximum of 3 bloodcats or 1 for every 6%, 5%, 4% progress based on easy, normal, and hard, respectively
bProgressMaxCats = (INT8)max( CurrentPlayerProgressPercentage() / (7 - gGameOptions.ubDifficultyLevel), 3 );
//make sure bloodcats don't outnumber mercs by a factor greater than 2
bNumMercMaxCats = (INT8)(PlayerMercsInSector( pGroup->ubSectorX, pGroup->ubSectorY, pGroup->ubSectorZ ) * 2);
//bProgressMaxCats = (INT8)max( CurrentPlayerProgressPercentage() / (7 - gGameOptions.ubDifficultyLevel), 3 );
//choose the lowest number of cats calculated by difficulty and progress.
pSector->bBloodCats = (INT8)min( bDifficultyMaxCats, bProgressMaxCats );
//pSector->bBloodCats = (INT8)min( bDifficultyMaxCats, bProgressMaxCats );
///////////////////////////////////////////////////////////////////////////////////////////////////////
// HEADROCK HAM 3.6: Minimum and Maximum are now modder-defined, so pick a random number between them.
// Read Min/Max from XML
ubMaxBloodcats = gBloodcatPlacements[ ubSectorID ][ ubDifficulty ].ubMaxBloodcats;
ubMinBloodcats = gBloodcatPlacements[ ubSectorID ][ ubDifficulty ].ubMinBloodcats;
// Find range between Min and Max
ubRange = ubMaxBloodcats-ubMinBloodcats;
// Adjust range based on current progress.
ubRange = __max(0,( ubRange * CurrentPlayerProgressPercentage() ) / 100);
// Randomize "extra" bloodcats
ubRandomCats = PreRandom(ubRange+1);
// Add "extra" bloodcats to minimum value
ubRandomCats += ubMinBloodcats;
// SET NUMBER OF CATS THAT WILL APPEAR
pSector->bBloodCats = ubRandomCats;
if( gGameOptions.ubDifficultyLevel < DIF_LEVEL_HARD )
{ //if not hard difficulty, ensure cats never outnumber mercs by a factor of 2 (min 3 bloodcats)
{
//At NOVICE/EXPERIENCED difficulty, ensure cats never outnumber mercs by a factor of more than 2.
bNumMercMaxCats = (INT8)(PlayerMercsInSector( pGroup->ubSectorX, pGroup->ubSectorY, pGroup->ubSectorZ ) * 2);
pSector->bBloodCats = (INT8)min( pSector->bBloodCats, bNumMercMaxCats );
pSector->bBloodCats = (INT8)max( pSector->bBloodCats, 3 );
//pSector->bBloodCats = (INT8)max( pSector->bBloodCats, 3 );
}
//ensure that there aren't more bloodcats than placements
pSector->bBloodCats = (INT8)min( pSector->bBloodCats, pSector->bBloodCatPlacements );
// Once again, make absolutely sure we're still within XML-set limits
pSector->bBloodCats = (INT8)min( pSector->bBloodCats, ubMaxBloodcats);
pSector->bBloodCats = (INT8)max( pSector->bBloodCats, ubMinBloodcats);
}
}
else if( ubSectorID != SEC_I16 )
{
if( !gfAutoAmbush && PreChance( 95 ) )
{ //already ambushed here. But 5% chance of getting ambushed again!
else
{
// Chance was 0.
fAlreadyAmbushed = TRUE;
}
}
if( !fAlreadyAmbushed && ubSectorID != SEC_N5 && pSector->bBloodCats > 0 &&
// An ambush is occuring?
if( !fAlreadyAmbushed && PlacementType != BLOODCAT_PLACEMENT_STATIC && pSector->bBloodCats > 0 &&
!pGroup->fVehicle && !NumEnemiesInSector( pGroup->ubSectorX, pGroup->ubSectorY ) )
{
if( ubSectorID != SEC_I16 || !gubFact[ FACT_PLAYER_KNOWS_ABOUT_BLOODCAT_LAIR ] )
// Wilderness ambush, or the player has unwittingly entered the lair?
if( PlacementType == BLOODCAT_PLACEMENT_AMBUSH || !gubFact[ FACT_PLAYER_KNOWS_ABOUT_BLOODCAT_LAIR ] )
{
// Ambush occurs.
gubEnemyEncounterCode = BLOODCAT_AMBUSH_CODE;
}
else
{
// Player knowingly enters lair.
gubEnemyEncounterCode = ENTERING_BLOODCAT_LAIR_CODE;
}
return TRUE;
}
else
{
// No special bloodcat encounter. This ALWAYS happens in STATIC PLACEMENT sectors.
gubEnemyEncounterCode = NO_ENCOUNTER_CODE;
return FALSE;
}
@@ -4808,7 +4855,8 @@ void NotifyPlayerOfBloodcatBattle( UINT8 ubSectorX, UINT8 ubSectorY )
}
else if( gubEnemyEncounterCode == ENTERING_BLOODCAT_LAIR_CODE )
{
wcscpy( str, pMapErrorString[ 13 ] );
GetSectorIDString( ubSectorX, ubSectorY, 0, zTempString, FALSE );
swprintf( str, pMapErrorString[ 13 ], zTempString );
}
if( guiCurrentScreen == MAP_SCREEN )
+24 -1
View File
@@ -35,6 +35,8 @@
#include "Strategic Status.h"
// HEADROCK HAM B1: Added include for Dynamic Roaming Militia
#include "MilitiaSquads.h"
// HEADROCK HAM 3.6: Include for Facility Debt
#include "Facilities.h"
#endif
// the max loyalty rating for any given town
@@ -1817,7 +1819,7 @@ void CheckIfEntireTownHasBeenLiberated( INT8 bTownId, INT16 sSectorX, INT16 sSec
UpdateLastDayOfPlayerActivity( ( UINT16 ) ( GetWorldDay() + 2 ) );
}
// HEADROCK HAM B1: Run a function to redefine Roaming Militia Restrictions on city capture.
if (gGameExternalOptions.bDynamicRestrictRoaming)
if (gGameExternalOptions.fDynamicRestrictRoaming)
{
AdjustRoamingRestrictions();
}
@@ -1994,3 +1996,24 @@ void MaximizeLoyaltyForDeidrannaKilled(void)
SetTownLoyalty(bTownId, 100);
}
}
// HEADROCK HAM 3.6: A loyalty hit based on outstanding debt for facility use.
void HandleFacilityDebtLoyaltyHit( void )
{
// Loyalty hit is 1% per $1000 dollars owed.
INT32 iLoyaltyHit = giTotalOwedForFacilityOperationsToday;
if (giTotalOwedForFacilityOperationsToday > 500)
{
// But no less than 1%, if $500 are owed.
iLoyaltyHit = __max(500,iLoyaltyHit);
}
if (iLoyaltyHit > 1)
{
DecrementTownLoyaltyEverywhere( iLoyaltyHit );
}
}
+3
View File
@@ -204,4 +204,7 @@ void HandleLoyaltyImplicationsOfMercRetreat( INT8 bRetreatCode, INT16 sSectorX,
void MaximizeLoyaltyForDeidrannaKilled( void );
// HEADROCK HAM 3.6: Loyalty hit for owing too much money on facility work
void HandleFacilityDebtLoyaltyHit( void );
#endif
+32
View File
@@ -296,6 +296,10 @@
RelativePath=".\Creature Spreading.h"
>
</File>
<File
RelativePath=".\Facilities.h"
>
</File>
<File
RelativePath=".\Game Clock.h"
>
@@ -470,6 +474,10 @@
RelativePath=".\Creature Spreading.cpp"
>
</File>
<File
RelativePath=".\Facilities.cpp"
>
</File>
<File
RelativePath=".\Game Clock.cpp"
>
@@ -626,14 +634,38 @@
RelativePath=".\XML_Army.cpp"
>
</File>
<File
RelativePath=".\XML_Bloodcats.cpp"
>
</File>
<File
RelativePath=".\XML_DynamicRestrictions.cpp"
>
</File>
<File
RelativePath=".\XML_ExtraItems.cpp"
>
</File>
<File
RelativePath=".\XML_Facilities.cpp"
>
</File>
<File
RelativePath=".\XML_FacilityTypes.cpp"
>
</File>
<File
RelativePath=".\XML_Roaming.cpp"
>
</File>
<File
RelativePath=".\XML_SectorNames.cpp"
>
</File>
<File
RelativePath=".\XML_UniformColors.cpp"
>
</File>
</Filter>
</Files>
<Globals>
+36 -4
View File
@@ -295,6 +295,10 @@
RelativePath="Creature Spreading.h"
>
</File>
<File
RelativePath=".\Facilities.h"
>
</File>
<File
RelativePath="Game Clock.h"
>
@@ -467,6 +471,10 @@
RelativePath="Creature Spreading.cpp"
>
</File>
<File
RelativePath=".\Facilities.cpp"
>
</File>
<File
RelativePath="Game Clock.cpp"
>
@@ -623,15 +631,39 @@
RelativePath="XML_Army.cpp"
>
</File>
<File
RelativePath=".\XML_Bloodcats.cpp"
>
</File>
<File
RelativePath=".\XML_DynamicRestrictions.cpp"
>
</File>
<File
RelativePath=".\XML_ExtraItems.cpp"
>
</File>
<File
RelativePath=".\XML_Facilities.cpp"
>
</File>
<File
RelativePath=".\XML_FacilityTypes.cpp"
>
</File>
<File
RelativePath="XML_Roaming.cpp"
>
</File>
<File
RelativePath=".\XML_SectorNames.cpp"
>
</File>
<File
RelativePath=".\XML_UniformColors.cpp"
>
</File>
</Filter>
<File
RelativePath=".\XML_ExtraItems.cpp"
>
</File>
</Files>
<Globals>
</Globals>
+854 -144
View File
File diff suppressed because it is too large Load Diff
+32 -1
View File
@@ -39,6 +39,11 @@ UINT8 CheckOneMilitiaForPromotion(INT16 sMapX, INT16 sMapY, UINT8 ubCurrentRank,
void BuildMilitiaPromotionsString( STR16 str );
// HEADROCK HAM 3.3: Function to determine best leadership for militia training in a given sector.
// Is used for both town and mobile militia.
// HEADROCK HAM 3.6: Argument for Mobile/Town Militia training
UINT8 FindBestMilitiaTrainingLeadershipInSector ( INT16 sMapX, INT16 sMapY, INT8 usMapZ, UINT8 ubMilitiaType );
// call this if the player attacks his own militia
void HandleMilitiaDefections(INT16 sMapX, INT16 sMapY);
@@ -70,7 +75,8 @@ BOOLEAN IsSAMSiteFullOfMilitia( INT16 sSectorX, INT16 sSectorY, INT8 iMilitiaTyp
void HandleContinueOfTownTraining( void );
// handle completion of assignment byt his soldier too and inform the player
void HandleCompletionOfTownTrainingByGroupWithTrainer( SOLDIERTYPE *pTrainer );
// HEADROCK HAM 3.6: Added argument for Mobile Militia training.
void HandleCompletionOfTownTrainingByGroupWithTrainer( SOLDIERTYPE *pTrainer, UINT8 ubMilitiaType );
// clear the list of training completed sectors
void ClearSectorListForCompletedTrainingOfMilitia( void );
@@ -78,4 +84,29 @@ void ClearSectorListForCompletedTrainingOfMilitia( void );
BOOLEAN MilitiaTrainingAllowedInSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ );
BOOLEAN MilitiaTrainingAllowedInTown( INT8 bTownId );
// HEADROCK HAM 3.6: Function to calculate Militia and Mobile Militia training squad size.
UINT8 CalcNumMilitiaTrained(UINT8 ubBestLeadership, BOOLEAN fMobile);
// HEADROCK HAM 3.6: Total upkeep costs for YESTERDAY at midnight. Saved to savegames.
extern UINT32 guiTotalUpkeepForMilitia;
// HEADROCK HAM 3.6: Daily check for upkeep of all militia
void HandleMilitiaUpkeepPayment( void );
// Type to hold number of militia in each sector.
typedef struct MILITIA_LIST_TYPE
{
UINT8 ubSectorId;
UINT8 ubNumTownGreens;
UINT8 ubNumTownRegulars;
UINT8 ubNumTownElites;
UINT8 ubNumMobileGreens;
UINT8 ubNumMobileRegulars;
UINT8 ubNumMobileElites;
} MILITIA_LIST_TYPE;
// HEADROCK HAM 3.6: Calculate upkeep costs for militia
UINT32 CalcMilitiaUpkeep( void );
#endif
+343
View File
@@ -0,0 +1,343 @@
#ifdef PRECOMPILEDHEADERS
#include "Strategic All.h"
#include "XML.h"
#else
#include "builddefines.h"
#include <stdio.h>
#include "XML.h"
#include "expat.h"
#include "string.h"
#include "Campaign Types.h"
#include "FileMan.h"
#include "MemMan.h"
#include "Debug Control.h"
#include "mapscreen.h"
#endif
#define MAX_CHAR_DATA_LENGTH 500
// This array stores all XML-read placement data. There are four arrays for each sector, one array for each difficulty
// level. Please note that the Placement Type is only stored in array 0 (gBloodcatPlacements[x][0].PlacementType). It
// is not possible to have different placement types at different difficulty levels. Yet.
BLOODCATPLACEMENT gBloodcatPlacements[256][4];
// Location of the Bloodcat Lair. There can be only one, as there's a quest that relies on its location. This is a
// sectorID, 0-255.
UINT8 gubBloodcatLairSectorId;
typedef enum
{
BLOODCAT_ELEMENT_NONE = 0,
BLOODCAT_ELEMENT_PLACEMENTS,
BLOODCAT_ELEMENT_SECTOR,
BLOODCAT_ELEMENT,
BLOODCAT_ELEMENT_DIFFICULTY,
BLOODCAT_ELEMENT_DIFFICULTY_DATA,
} BLOODCAT_PARSE_STAGE;
typedef struct
{
BLOODCAT_PARSE_STAGE curElement;
CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1];
UINT8 sCurSectorX;
UINT8 sCurSectorY;
BLOODCATPLACEMENT CurPlacement[4];
UINT8 ubCurDifficulty;
UINT32 currentDepth;
UINT32 maxReadDepth;
} BloodcatsParseData;
static void XMLCALL
BloodcatsStartElementHandle(void *userData, const XML_Char *name, const char **atts)
{
BloodcatsParseData * pData = (BloodcatsParseData *) userData;
if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element?
{
if(strcmp(name, "BLOODCAT_PLACEMENTS") == 0 && pData->curElement == BLOODCAT_ELEMENT_NONE)
{
pData->curElement = BLOODCAT_ELEMENT_PLACEMENTS;
pData->maxReadDepth++; //we are not skipping this element
// Initiate Array by setting first character to 0.
for (UINT16 x = 0; x < 256; x++)
{
for (UINT16 y = 0; y < 4; y++)
{
gBloodcatPlacements[x][y].ubFactionAffiliation = 0;
gBloodcatPlacements[x][y].fRespawn = 0;
gBloodcatPlacements[x][y].PlacementType = 0;
gBloodcatPlacements[x][y].ubAmbushChance = 0;
gBloodcatPlacements[x][y].ubMaxBloodcats = 0;
gBloodcatPlacements[x][y].ubMinBloodcats = 0;
}
}
}
else if(strcmp(name, "SECTOR") == 0 && pData->curElement == BLOODCAT_ELEMENT_PLACEMENTS)
{
pData->curElement = BLOODCAT_ELEMENT_SECTOR;
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == BLOODCAT_ELEMENT_SECTOR &&
(strcmp(name, "SectorGrid") == 0 ||
strcmp(name, "ubPlacementType") == 0) )
{
pData->curElement = BLOODCAT_ELEMENT;
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == BLOODCAT_ELEMENT_SECTOR &&
strcmp(name, "NOVICE") == 0)
{
pData->curElement = BLOODCAT_ELEMENT_DIFFICULTY;
pData->ubCurDifficulty = 0;
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == BLOODCAT_ELEMENT_SECTOR &&
strcmp(name, "EXPERIENCED") == 0)
{
pData->curElement = BLOODCAT_ELEMENT_DIFFICULTY;
pData->ubCurDifficulty = 1;
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == BLOODCAT_ELEMENT_SECTOR &&
strcmp(name, "EXPERT") == 0)
{
pData->curElement = BLOODCAT_ELEMENT_DIFFICULTY;
pData->ubCurDifficulty = 2;
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == BLOODCAT_ELEMENT_SECTOR &&
strcmp(name, "INSANE") == 0)
{
pData->curElement = BLOODCAT_ELEMENT_DIFFICULTY;
pData->ubCurDifficulty = 3;
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == BLOODCAT_ELEMENT_DIFFICULTY &&
(strcmp(name, "ubMinBloodcats") == 0 ||
strcmp(name, "ubMaxBloodcats") == 0 ||
strcmp(name, "ubAmbushChance") == 0 ||
strcmp(name, "ubFactionAffiliation") == 0 ||
strcmp(name, "fRespawn") == 0 ))
{
pData->curElement = BLOODCAT_ELEMENT_DIFFICULTY_DATA;
pData->maxReadDepth++; //we are not skipping this element
}
pData->szCharData[0] = '\0';
}
pData->currentDepth++;
}
static void XMLCALL
BloodcatsCharacterDataHandle(void *userData, const XML_Char *str, int len)
{
BloodcatsParseData * pData = (BloodcatsParseData *) 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
BloodcatsEndElementHandle(void *userData, const XML_Char *name)
{
BloodcatsParseData * pData = (BloodcatsParseData *)userData;
if(pData->currentDepth <= pData->maxReadDepth) //we're at the end of an element that we've been reading
{
if(strcmp(name, "BLOODCAT_PLACEMENTS") == 0)
{
pData->curElement = BLOODCAT_ELEMENT_NONE;
}
else if(strcmp(name, "SECTOR") == 0)
{
pData->curElement = BLOODCAT_ELEMENT_PLACEMENTS;
UINT8 ubSectorId = SECTOR(pData->sCurSectorX, pData->sCurSectorY);
if (ubSectorId >= 0 && ubSectorId < 256)
{
// Set placement type for this sector. Only first array has this set, as it is not difficulty-dependent.
gBloodcatPlacements[ ubSectorId ][0].PlacementType = pData->CurPlacement[0].PlacementType;
for (UINT8 x = 0; x < 4; x++)
{
if (pData->CurPlacement[0].PlacementType == 0)
{
// Ambush placement. Bloodcats will appear in this sector randomly.
gBloodcatPlacements[ ubSectorId ][x].ubMinBloodcats = pData->CurPlacement[x].ubMinBloodcats;
gBloodcatPlacements[ ubSectorId ][x].ubMaxBloodcats = pData->CurPlacement[x].ubMaxBloodcats;
gBloodcatPlacements[ ubSectorId ][x].ubAmbushChance = pData->CurPlacement[x].ubAmbushChance;
gBloodcatPlacements[ ubSectorId ][x].ubFactionAffiliation = 0;
gBloodcatPlacements[ ubSectorId ][x].fRespawn = 0;
}
else if (pData->CurPlacement[0].PlacementType == 1)
{
// Static placement. Bloodcats always appear here, but never respawn, and may be unaggressive
// to enemies.
gBloodcatPlacements[ ubSectorId ][x].ubMinBloodcats = 0;
gBloodcatPlacements[ ubSectorId ][x].ubMaxBloodcats = pData->CurPlacement[x].ubMaxBloodcats;
gBloodcatPlacements[ ubSectorId ][x].ubAmbushChance = 0;
gBloodcatPlacements[ ubSectorId ][x].ubFactionAffiliation = pData->CurPlacement[x].ubFactionAffiliation;
gBloodcatPlacements[ ubSectorId ][x].fRespawn = 0;
}
else if (pData->CurPlacement[0].PlacementType == 2)
{
// Lair sector. There can be only one, and it is affected by the Quest. Bloodcats can regenerate
// their numbers here over time.
gBloodcatPlacements[ ubSectorId ][x].ubMinBloodcats = 0;
gBloodcatPlacements[ ubSectorId ][x].ubMaxBloodcats = pData->CurPlacement[x].ubMaxBloodcats;
gBloodcatPlacements[ ubSectorId ][x].ubAmbushChance = 0;
gBloodcatPlacements[ ubSectorId ][x].ubFactionAffiliation = 0;
gBloodcatPlacements[ ubSectorId ][x].fRespawn = pData->CurPlacement[x].fRespawn;
}
}
}
}
else if(strcmp(name, "SectorGrid") == 0 )
{
UINT8 x, y;
pData->curElement = BLOODCAT_ELEMENT_SECTOR;
y = (UINT8)pData->szCharData[0] & 0x1F;
x = (UINT8)atol(&pData->szCharData[1]);
if ( x > 0 && x <= 16 && y > 0 && y <= 16 )
{
pData->sCurSectorX = x;
pData->sCurSectorY = y;
}
THROWIFFALSE( (SECTOR(x,y) >= 0 && SECTOR(x,y) < 256) , L"Illegal sector number in BloodcatPlacements.XML" );
}
else if(strcmp(name, "ubPlacementType") == 0 )
{
pData->curElement = BLOODCAT_ELEMENT_SECTOR;
// Only set for first array (Difficulty Irrelevant)
pData->CurPlacement[0].PlacementType = (UINT8) atol(pData->szCharData);
}
else if(strcmp(name, "NOVICE") == 0 )
{
// Just return to sector data.
pData->curElement = BLOODCAT_ELEMENT_SECTOR;
}
else if(strcmp(name, "EXPERIENCED") == 0 )
{
// Just return to sector data.
pData->curElement = BLOODCAT_ELEMENT_SECTOR;
}
else if(strcmp(name, "EXPERT") == 0 )
{
// Just return to sector data.
pData->curElement = BLOODCAT_ELEMENT_SECTOR;
}
else if(strcmp(name, "INSANE") == 0 )
{
// Just return to sector data.
pData->curElement = BLOODCAT_ELEMENT_SECTOR;
}
else if(strcmp(name, "ubMinBloodcats") == 0 )
{
pData->curElement = BLOODCAT_ELEMENT_DIFFICULTY;
pData->CurPlacement[pData->ubCurDifficulty].ubMinBloodcats = (UINT8) atol(pData->szCharData);
}
else if(strcmp(name, "ubMaxBloodcats") == 0 )
{
pData->curElement = BLOODCAT_ELEMENT_DIFFICULTY;
pData->CurPlacement[pData->ubCurDifficulty].ubMaxBloodcats = (UINT8) atol(pData->szCharData);
}
else if(strcmp(name, "ubAmbushChance") == 0 )
{
pData->curElement = BLOODCAT_ELEMENT_DIFFICULTY;
pData->CurPlacement[pData->ubCurDifficulty].ubAmbushChance = (UINT8) atol(pData->szCharData);
}
else if(strcmp(name, "ubFactionAffiliation") == 0 )
{
pData->curElement = BLOODCAT_ELEMENT_DIFFICULTY;
pData->CurPlacement[pData->ubCurDifficulty].ubFactionAffiliation = (UINT8) atol(pData->szCharData);
}
else if(strcmp(name, "fRespawn") == 0 )
{
pData->curElement = BLOODCAT_ELEMENT_DIFFICULTY;
pData->CurPlacement[pData->ubCurDifficulty].fRespawn = (UINT8) atol(pData->szCharData);
}
pData->maxReadDepth--;
}
pData->currentDepth--;
}
BOOLEAN ReadInBloodcatPlacements(STR fileName)
{
HWFILE hFile;
UINT32 uiBytesRead;
UINT32 uiFSize;
CHAR8 * lpcBuffer;
XML_Parser parser = XML_ParserCreate(NULL);
BloodcatsParseData pData;
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, BloodcatsStartElementHandle, BloodcatsEndElementHandle);
XML_SetCharacterDataHandler(parser, BloodcatsCharacterDataHandle);
memset(&pData,0,sizeof(pData));
XML_SetUserData(parser, &pData);
if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE))
{
CHAR8 errorBuf[511];
sprintf(errorBuf, "XML Parser Error in BloodcatPlacements.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;
}
+223
View File
@@ -0,0 +1,223 @@
///////////////////////////////////////////////////////////////////////////////
// HEADROCK HAM 3.4: Dynamic Roaming Restrictions XMLization
//
// This is a new part of the Dynamic Roaming Restrictions system. It reads in
// data about sectors to "un-restrict", and the towns that must be liberated
// for them to be unrestricted. There can be several unrestriction conditions
// for each sector, and only one of the conditions must be true for the sector
// to become allowed.
//
///////////////////////////////////////////////////////////////////////////////
#ifdef PRECOMPILEDHEADERS
#include "Tactical All.h"
#else
#include "sgp.h"
#include "Debug Control.h"
#include "expat.h"
#include "gamesettings.h"
#include "XML.h"
#include "FileMan.h"
#include "campaign types.h"
#include "militiasquads.h"
#include "mapscreen.h"
#endif
// HEADROCK HAM 3.4: Stores restriction data from XML, including required cities for each sector to be allowed.
extern DYNAMICRESTRICTIONS gDynamicRestrictions[5001];
struct
{
PARSE_STAGE curElement;
CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1];
INT16 sCurSectorX;
INT16 sCurSectorY;
UINT32 uiReqTownFlags;
UINT32 maxArraySize;
UINT32 curIndex;
UINT32 currentDepth;
UINT32 maxReadDepth;
}
typedef dynamicroamingParseData;
static void XMLCALL
dynamicroamingStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts)
{
dynamicroamingParseData * pData = (dynamicroamingParseData *)userData;
if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element?
{
if(strcmp(name, "DYNAMICROAMING") == 0 && pData->curElement == ELEMENT_NONE)
{
// Set all sector IDs to -1 ("unused")
for (UINT16 cnt=0; cnt<5001; cnt++)
{
gDynamicRestrictions[cnt].bSectorID = -1;
}
pData->curElement = ELEMENT_LIST;
pData->maxReadDepth++; //we are not skipping this element
}
else if(strcmp(name, "RESTRICTION") == 0 && pData->curElement == ELEMENT_LIST)
{
pData->curElement = ELEMENT;
pData->uiReqTownFlags = 0;
//DebugMsg(TOPIC_JA2, DBG_LEVEL_3,"MergeStartElementHandle: setting memory for curMerge");
pData->maxReadDepth++; //we are not skipping this element
//pData->curIndex++;
}
else if(pData->curElement == ELEMENT &&
(strcmp(name, "SectorGrid") == 0 ||
strcmp(name, "ReqTown") == 0 ))
{
pData->curElement = ELEMENT_PROPERTY;
pData->maxReadDepth++; //we are not skipping this element
}
pData->szCharData[0] = '\0';
}
pData->currentDepth++;
}
static void XMLCALL
dynamicroamingCharacterDataHandle(void *userData, const XML_Char *str, int len)
{
dynamicroamingParseData * pData = (dynamicroamingParseData *)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
dynamicroamingEndElementHandle(void *userData, const XML_Char *name)
{
dynamicroamingParseData * pData = (dynamicroamingParseData *)userData;
if(pData->currentDepth <= pData->maxReadDepth) //we're at the end of an element that we've been reading
{
if(strcmp(name, "DYNAMICROAMING") == 0)
{
pData->curElement = ELEMENT_NONE;
}
else if(strcmp(name, "RESTRICTION") == 0)
{
pData->curElement = ELEMENT_LIST;
if (SECTOR(pData->sCurSectorX, pData->sCurSectorY) >= 0 && SECTOR(pData->sCurSectorX, pData->sCurSectorY) < 256)
{
pData->curIndex++;
gDynamicRestrictions[pData->curIndex].bSectorID = SECTOR(pData->sCurSectorX,pData->sCurSectorY);
gDynamicRestrictions[pData->curIndex].uiReqTownFlags |= pData->uiReqTownFlags;
}
}
else if(strcmp(name, "SectorGrid") == 0 )
{
UINT8 x, y;
pData->curElement = ELEMENT;
y = (UINT8)pData->szCharData[0] & 0x1F;
x = (UINT8)atol(&pData->szCharData[1]);
if ( x > 0 && x <= 16 && y > 0 && y <= 16 )
{
pData->sCurSectorX = x;
pData->sCurSectorY = y;
}
}
else if(strcmp(name, "ReqTown") == 0 )
{
if ((UINT8) atol(pData->szCharData) > 0 && (UINT8) atol(pData->szCharData) < NUM_TOWNS )
{
pData->curElement = ELEMENT;
pData->uiReqTownFlags |= (1 << ((UINT8) atol(pData->szCharData) - 1));
}
else
{
pData->uiReqTownFlags = 0;
}
}
pData->maxReadDepth--;
}
pData->currentDepth--;
}
BOOLEAN ReadInDynamicRoamingRestrictions(STR fileName)
{
HWFILE hFile;
UINT32 uiBytesRead;
UINT32 uiFSize;
CHAR8 * lpcBuffer;
XML_Parser parser = XML_ParserCreate(NULL);
dynamicroamingParseData pData;
DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading DynamicRestrictions.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, dynamicroamingStartElementHandle, dynamicroamingEndElementHandle);
XML_SetCharacterDataHandler(parser, dynamicroamingCharacterDataHandle);
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 DynamicRestrictions.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 );
}
+217
View File
@@ -0,0 +1,217 @@
///////////////////////////////////////////////////////////////////////////////
// HEADROCK HAM 3.5: Facility Location Externalization
//
// This file reads from an XML called "Facilities.XML". That file contains
// the locations of all facilities such as the "Gun Range", "Industrial",
// "Prison", etcetera. The data is written DIRECTLY into the global SectorInfo
// array, replacing a hardcoded system.
//
///////////////////////////////////////////////////////////////////////////////
#ifdef PRECOMPILEDHEADERS
#include "Tactical All.h"
#else
#include "sgp.h"
#include "Debug Control.h"
#include "expat.h"
#include "gamesettings.h"
#include "XML.h"
#include "FileMan.h"
#include "Campaign Types.h"
#endif
FACILITYLOCATIONS gFacilityLocations[256][MAX_NUM_FACILITY_TYPES];
UINT16 NUM_FACILITIES;
struct
{
PARSE_STAGE curElement;
CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1];
INT16 sCurSectorX;
INT16 sCurSectorY;
UINT8 ubCurFacilityType;
UINT8 ubHidden;
UINT32 maxArraySize;
UINT32 curIndex;
UINT32 currentDepth;
UINT32 maxReadDepth;
}
typedef facilityParseData;
static void XMLCALL
facilityStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts)
{
facilityParseData * pData = (facilityParseData *)userData;
if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element?
{
if(strcmp(name, "SECTORFACILITIES") == 0 && pData->curElement == ELEMENT_NONE)
{
pData->curElement = ELEMENT_LIST;
pData->maxReadDepth++; //we are not skipping this element
}
else if(strcmp(name, "FACILITY") == 0 && pData->curElement == ELEMENT_LIST)
{
pData->curElement = ELEMENT;
//DebugMsg(TOPIC_JA2, DBG_LEVEL_3,"MergeStartElementHandle: setting memory for curMerge");
pData->maxReadDepth++; //we are not skipping this element
//pData->curIndex++;
}
else if(pData->curElement == ELEMENT &&
(strcmp(name, "SectorGrid") == 0 ||
strcmp(name, "FacilityType") == 0 ||
strcmp(name, "ubHidden") == 0
))
{
pData->curElement = ELEMENT_PROPERTY;
pData->maxReadDepth++; //we are not skipping this element
}
pData->szCharData[0] = '\0';
}
pData->currentDepth++;
}
static void XMLCALL
facilityCharacterDataHandle(void *userData, const XML_Char *str, int len)
{
facilityParseData * pData = (facilityParseData *)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
facilityEndElementHandle(void *userData, const XML_Char *name)
{
facilityParseData * pData = (facilityParseData *)userData;
if(pData->currentDepth <= pData->maxReadDepth) //we're at the end of an element that we've been reading
{
if(strcmp(name, "SECTORFACILITIES") == 0)
{
pData->curElement = ELEMENT_NONE;
NUM_FACILITIES = pData->curIndex;
}
else if(strcmp(name, "FACILITY") == 0)
{
pData->curIndex++;
pData->curElement = ELEMENT_LIST;
if (pData->ubCurFacilityType != 0)
{
gFacilityLocations[SECTOR(pData->sCurSectorX,pData->sCurSectorY)][pData->ubCurFacilityType].fFacilityHere = TRUE;
gFacilityLocations[SECTOR(pData->sCurSectorX,pData->sCurSectorY)][pData->ubCurFacilityType].ubHidden = pData->ubHidden;
}
}
else if(strcmp(name, "SectorGrid") == 0 )
{
UINT8 x, y;
pData->curElement = ELEMENT;
y = (UINT8)pData->szCharData[0] & 0x1F;
x = (UINT8)atol(&pData->szCharData[1]);
if ( x > 0 && x <= 16 && y > 0 && y <= 16 )
{
pData->sCurSectorX = x;
pData->sCurSectorY = y;
}
}
else if(strcmp(name, "FacilityType") == 0 )
{
pData->curElement = ELEMENT;
pData->ubCurFacilityType = (UINT8) atol(pData->szCharData);
}
else if(strcmp(name, "ubHidden") == 0 )
{
pData->curElement = ELEMENT;
pData->ubHidden = (BOOLEAN) atol(pData->szCharData);
}
pData->maxReadDepth--;
}
pData->currentDepth--;
}
BOOLEAN ReadInSectorFacilities(STR fileName)
{
HWFILE hFile;
UINT32 uiBytesRead;
UINT32 uiFSize;
CHAR8 * lpcBuffer;
XML_Parser parser = XML_ParserCreate(NULL);
facilityParseData pData;
DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading Facilities.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, facilityStartElementHandle, facilityEndElementHandle);
XML_SetCharacterDataHandler(parser, facilityCharacterDataHandle);
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 Facilities.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 );
}
File diff suppressed because it is too large Load Diff
-1
View File
@@ -18,7 +18,6 @@
extern INT32 iRestrictedSectorArraySize;
extern UINT32 gRestrictMilitia[256];
typedef enum
{
ROAMING_ELEMENT_NONE = 0,
+232
View File
@@ -0,0 +1,232 @@
#ifdef PRECOMPILEDHEADERS
#include "Strategic All.h"
#include "XML.h"
#else
#include "builddefines.h"
#include <stdio.h>
#include "XML.h"
#include "expat.h"
#include "string.h"
#include "Campaign Types.h"
#include "FileMan.h"
#include "MemMan.h"
#include "Debug Control.h"
#include "mapscreen.h"
#endif
#define MAX_CHAR_DATA_LENGTH 500
// Four different sector names, used at different times.
extern CHAR16 gzSectorNames[256][4][MAX_SECTOR_NAME_LENGTH];
typedef enum
{
SECTORNAME_ELEMENT_NONE = 0,
SECTORNAME_ELEMENT_SECTOR_NAMES,
SECTORNAME_ELEMENT_SECTOR,
SECTORNAME_ELEMENT,
} SECTORNAME_PARSE_STAGE;
typedef struct
{
SECTORNAME_PARSE_STAGE curElement;
CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1];
UINT8 sCurSectorX;
UINT8 sCurSectorY;
CHAR16 szCurUnexploredName[MAX_SECTOR_NAME_LENGTH];
CHAR16 szCurDetailedUnexploredName[MAX_SECTOR_NAME_LENGTH];
CHAR16 szCurExploredName[MAX_SECTOR_NAME_LENGTH];
CHAR16 szCurDetailedExploredName[MAX_SECTOR_NAME_LENGTH];
UINT32 currentDepth;
UINT32 maxReadDepth;
} SectorNameParseData;
static void XMLCALL
SectorNameStartElementHandle(void *userData, const XML_Char *name, const char **atts)
{
SectorNameParseData * pData = (SectorNameParseData *) userData;
if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element?
{
if(strcmp(name, "SECTOR_NAMES") == 0 && pData->curElement == SECTORNAME_ELEMENT_NONE)
{
pData->curElement = SECTORNAME_ELEMENT_SECTOR_NAMES;
pData->maxReadDepth++; //we are not skipping this element
// Initiate Array by setting first character to 0.
for (UINT16 x = 0; x < 256; x++)
{
gzSectorNames[x][0][0]=0;
gzSectorNames[x][1][0]=0;
gzSectorNames[x][2][0]=0;
gzSectorNames[x][3][0]=0;
}
}
else if(strcmp(name, "SECTOR") == 0 && pData->curElement == SECTORNAME_ELEMENT_SECTOR_NAMES)
{
pData->curElement = SECTORNAME_ELEMENT_SECTOR;
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == SECTORNAME_ELEMENT_SECTOR &&
(strcmp(name, "SectorGrid") == 0 ||
strcmp(name, "szUnexploredName") == 0 ||
strcmp(name, "szDetailedUnexploredName") == 0 ||
strcmp(name, "szExploredName") == 0 ||
strcmp(name, "szDetailedExploredName") == 0 ))
{
pData->curElement = SECTORNAME_ELEMENT;
pData->maxReadDepth++; //we are not skipping this element
}
pData->szCharData[0] = '\0';
}
pData->currentDepth++;
}
static void XMLCALL
SectorNameCharacterDataHandle(void *userData, const XML_Char *str, int len)
{
SectorNameParseData * pData = (SectorNameParseData *) 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
SectorNameEndElementHandle(void *userData, const XML_Char *name)
{
SectorNameParseData * pData = (SectorNameParseData *)userData;
if(pData->currentDepth <= pData->maxReadDepth) //we're at the end of an element that we've been reading
{
if(strcmp(name, "SECTOR_NAMES") == 0)
{
pData->curElement = SECTORNAME_ELEMENT_NONE;
}
else if(strcmp(name, "SECTOR") == 0)
{
pData->curElement = SECTORNAME_ELEMENT_SECTOR_NAMES;
UINT8 ubSectorId = SECTOR(pData->sCurSectorX, pData->sCurSectorY);
if (ubSectorId >= 0 && ubSectorId < 256)
{
wcscpy(gzSectorNames[ubSectorId][0], pData->szCurUnexploredName);
wcscpy(gzSectorNames[ubSectorId][1], pData->szCurDetailedUnexploredName);
wcscpy(gzSectorNames[ubSectorId][2], pData->szCurExploredName);
wcscpy(gzSectorNames[ubSectorId][3], pData->szCurDetailedExploredName);
}
}
else if(strcmp(name, "SectorGrid") == 0 )
{
UINT8 x, y;
pData->curElement = SECTORNAME_ELEMENT_SECTOR;
y = (UINT8)pData->szCharData[0] & 0x1F;
x = (UINT8)atol(&pData->szCharData[1]);
if ( x > 0 && x <= 16 && y > 0 && y <= 16 )
{
pData->sCurSectorX = x;
pData->sCurSectorY = y;
}
}
else if(strcmp(name, "szUnexploredName") == 0 )
{
pData->curElement = SECTORNAME_ELEMENT_SECTOR;
MultiByteToWideChar( CP_UTF8, 0, pData->szCharData, -1, pData->szCurUnexploredName, sizeof(pData->szCurUnexploredName)/sizeof(pData->szCurUnexploredName[0]) );
pData->szCurUnexploredName[sizeof(pData->szCurUnexploredName)/sizeof(pData->szCurUnexploredName[0]) - 1] = '\0';
}
else if(strcmp(name, "szDetailedUnexploredName") == 0 )
{
pData->curElement = SECTORNAME_ELEMENT_SECTOR;
MultiByteToWideChar( CP_UTF8, 0, pData->szCharData, -1, pData->szCurDetailedUnexploredName, sizeof(pData->szCurDetailedUnexploredName)/sizeof(pData->szCurDetailedUnexploredName[0]) );
pData->szCurDetailedUnexploredName[sizeof(pData->szCurDetailedUnexploredName)/sizeof(pData->szCurDetailedUnexploredName[0]) - 1] = '\0';
}
else if(strcmp(name, "szExploredName") == 0 )
{
pData->curElement = SECTORNAME_ELEMENT_SECTOR;
MultiByteToWideChar( CP_UTF8, 0, pData->szCharData, -1, pData->szCurExploredName, sizeof(pData->szCurExploredName)/sizeof(pData->szCurExploredName[0]) );
pData->szCurExploredName[sizeof(pData->szCurExploredName)/sizeof(pData->szCurExploredName[0]) - 1] = '\0';
}
else if(strcmp(name, "szDetailedExploredName") == 0 )
{
pData->curElement = SECTORNAME_ELEMENT_SECTOR;
MultiByteToWideChar( CP_UTF8, 0, pData->szCharData, -1, pData->szCurDetailedExploredName, sizeof(pData->szCurDetailedExploredName)/sizeof(pData->szCurDetailedExploredName[0]) );
pData->szCurDetailedExploredName[sizeof(pData->szCurDetailedExploredName)/sizeof(pData->szCurDetailedExploredName[0]) - 1] = '\0';
}
pData->maxReadDepth--;
}
pData->currentDepth--;
}
BOOLEAN ReadInSectorNames(STR fileName)
{
HWFILE hFile;
UINT32 uiBytesRead;
UINT32 uiFSize;
CHAR8 * lpcBuffer;
XML_Parser parser = XML_ParserCreate(NULL);
SectorNameParseData pData;
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, SectorNameStartElementHandle, SectorNameEndElementHandle);
XML_SetCharacterDataHandler(parser, SectorNameCharacterDataHandle);
memset(&pData,0,sizeof(pData));
XML_SetUserData(parser, &pData);
if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE))
{
CHAR8 errorBuf[511];
sprintf(errorBuf, "XML Parser Error in SectorNames.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;
}
+260
View File
@@ -0,0 +1,260 @@
////////////////////////////////////////////////////////////
//
// HEADROCK HAM 3.6:
//
// This code reads an XML called "UniformColors.XML", which tells the program which colors to use for
// "standard" uniforms, including randomly-generated enemies and militia (for now).
//
//////////////////////////////////////////////////////////////
#ifdef PRECOMPILEDHEADERS
#include "Strategic All.h"
#include "XML.h"
#else
#include "builddefines.h"
#include <stdio.h>
#include "XML.h"
#include "expat.h"
#include "string.h"
#include "Campaign Types.h"
#include "FileMan.h"
#include "MemMan.h"
#include "Debug Control.h"
#include "mapscreen.h"
#endif
#define MAX_CHAR_DATA_LENGTH 500
// Error strings for this XML reader
STR16 szUniformErrorStrings[]=
{
L"ENEMY_ADMIN",
L"ENEMY_TROOP",
L"ENEMY_ELITE",
L"MILITIA_ROOKIE",
L"MILITIA_REGULAR",
L"MILITIA_ELITE",
};
// Array to hold uniform data
UNIFORMCOLORS gUniformColors[NUM_UNIFORMS];
typedef enum
{
UNIFORM_ELEMENT_NONE = 0,
UNIFORM_ELEMENT_LIST,
UNIFORM_ELEMENT,
UNIFORM_ELEMENT_DATA,
} UNIFORM_PARSE_STAGE;
typedef struct
{
UNIFORM_PARSE_STAGE curElement;
CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1];
UINT8 sCurUniform;
PaletteRepID szCurVest;
PaletteRepID szCurPants;
UINT32 currentDepth;
UINT32 maxReadDepth;
} UniformParseData;
// Array for flags making sure that we have ALL uniform data defined.
BOOLEAN UniformDataFound[NUM_UNIFORMS];
static void XMLCALL
UniformStartElementHandle(void *userData, const XML_Char *name, const char **atts)
{
UniformParseData * pData = (UniformParseData *) userData;
if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element?
{
if(strcmp(name, "UNIFORMS") == 0 && pData->curElement == UNIFORM_ELEMENT_NONE)
{
pData->curElement = UNIFORM_ELEMENT_LIST;
pData->maxReadDepth++; //we are not skipping this element
for (UINT8 cnt = 0; cnt < NUM_UNIFORMS; cnt++)
{
// reset array
UniformDataFound[cnt] = FALSE;
}
}
else if(pData->curElement == UNIFORM_ELEMENT_LIST &&
(strcmp(name, "ENEMY_ADMIN") == 0 ||
strcmp(name, "ENEMY_TROOP") == 0 ||
strcmp(name, "ENEMY_ELITE") == 0 ||
strcmp(name, "MILITIA_ROOKIE") == 0 ||
strcmp(name, "MILITIA_REGULAR") == 0 ||
strcmp(name, "MILITIA_ELITE") == 0 ) )
{
if (strcmp(name, "ENEMY_ADMIN") == 0)
{
pData->sCurUniform = UNIFORM_ENEMY_ADMIN;
}
else if (strcmp(name, "ENEMY_TROOP") == 0)
{
pData->sCurUniform = UNIFORM_ENEMY_TROOP;
}
else if (strcmp(name, "ENEMY_ELITE") == 0)
{
pData->sCurUniform = UNIFORM_ENEMY_ELITE;
}
else if (strcmp(name, "MILITIA_ROOKIE") == 0)
{
pData->sCurUniform = UNIFORM_MILITIA_ROOKIE;
}
else if (strcmp(name, "MILITIA_REGULAR") == 0)
{
pData->sCurUniform = UNIFORM_MILITIA_REGULAR;
}
else if (strcmp(name, "MILITIA_ELITE") == 0)
{
pData->sCurUniform = UNIFORM_MILITIA_ELITE;
}
pData->curElement = UNIFORM_ELEMENT;
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == UNIFORM_ELEMENT &&
(strcmp(name, "Vest") == 0 ||
strcmp(name, "Pants") == 0 ))
{
pData->curElement = UNIFORM_ELEMENT_DATA;
pData->maxReadDepth++; //we are not skipping this element
}
pData->szCharData[0] = '\0';
}
pData->currentDepth++;
}
static void XMLCALL
UniformCharacterDataHandle(void *userData, const XML_Char *str, int len)
{
UniformParseData * pData = (UniformParseData *) 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
UniformEndElementHandle(void *userData, const XML_Char *name)
{
UniformParseData * pData = (UniformParseData *)userData;
if(pData->currentDepth <= pData->maxReadDepth) //we're at the end of an element that we've been reading
{
if(strcmp(name, "UNIFORMS") == 0)
{
// All entries are mandatory. Exception thrown if an entry was not found
for (UINT8 cnt = 0; cnt < NUM_UNIFORMS; cnt++)
{
if (!UniformDataFound[cnt])
{
CHAR16 sString[256];
swprintf( sString, L"Error in UniformColors.XML: Uniform color for %s not found or not properly defined!", szUniformErrorStrings[ cnt ] );
THROWEXCEPTION( sString );
}
}
pData->curElement = UNIFORM_ELEMENT_NONE;
}
else if(strcmp(name, "ENEMY_ADMIN") == 0 ||
strcmp(name, "ENEMY_TROOP") == 0 ||
strcmp(name, "ENEMY_ELITE") == 0 ||
strcmp(name, "MILITIA_ROOKIE") == 0 ||
strcmp(name, "MILITIA_REGULAR") == 0 ||
strcmp(name, "MILITIA_ELITE") == 0 )
{
pData->curElement = UNIFORM_ELEMENT_LIST;
if (pData->sCurUniform >= UNIFORM_ENEMY_ADMIN && pData->sCurUniform < NUM_UNIFORMS )
{
memcpy( &(gUniformColors[pData->sCurUniform].pants), &(pData->szCurPants), sizeof(PaletteRepID) );
memcpy( &(gUniformColors[pData->sCurUniform].vest), &(pData->szCurVest), sizeof(PaletteRepID) );
UniformDataFound[pData->sCurUniform] = TRUE;
}
}
else if(strcmp(name, "Vest") == 0 )
{
pData->curElement = UNIFORM_ELEMENT;
strcpy(pData->szCurVest, pData->szCharData);
}
else if(strcmp(name, "Pants") == 0 )
{
pData->curElement = UNIFORM_ELEMENT;
strcpy(pData->szCurPants, pData->szCharData);
}
pData->maxReadDepth--;
}
pData->currentDepth--;
}
BOOLEAN ReadInUniforms(STR fileName)
{
HWFILE hFile;
UINT32 uiBytesRead;
UINT32 uiFSize;
CHAR8 * lpcBuffer;
XML_Parser parser = XML_ParserCreate(NULL);
UniformParseData pData;
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, UniformStartElementHandle, UniformEndElementHandle);
XML_SetCharacterDataHandler(parser, UniformCharacterDataHandle);
memset(&pData,0,sizeof(pData));
XML_SetUserData(parser, &pData);
if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE))
{
CHAR8 errorBuf[511];
sprintf(errorBuf, "XML Parser Error in UniformColors.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;
}
+329 -11
View File
@@ -111,6 +111,8 @@
#include "Strategic Status.h"
#include "Soldier Create.h"
#include "Animation Control.h"
// HEADROCK HAM 3.6: Include facilities for assignment display
#include "Facilities.h"
#endif
#include "connect.h" //hayden
@@ -905,6 +907,9 @@ void CreateContractBox( SOLDIERTYPE *pCharacter );
void CreateAssignmentsBox( void );
void CreateTrainingBox( void );
void CreateMercRemoveAssignBox( void );
// HEADROCK HAM 3.6: Facility box, Sub-menu
void CreateFacilityBox( void );
void CreateFacilityAssignmentBox( void );
void DetermineWhichAssignmentMenusCanBeShown( void );
void DetermineWhichMilitiaControlMenusCanBeShown( void ); //lal
@@ -2837,16 +2842,29 @@ void DrawCharacterInfo(INT16 sCharNumber)
// second assignment line
// HEADROCK HAM 3.6: Operating a facility?
if (pSoldier->sFacilityTypeOperated != -1)
{
UINT8 ubFacilityType = (UINT8)pSoldier->sFacilityTypeOperated;
// Print sector ID string
GetShortSectorString( pSoldier->sSectorX, pSoldier->sSectorY, sString );
wcscat( sString, L": " );
wcscat( sString, gFacilityTypes[ubFacilityType].szFacilityShortName );
//wcscpy(sString, gFacilityTypes[ pSoldier->sFacilityTypeOperated ].szFacilityName);
}
// train self / teammate / by other ?
if( ( pSoldier->bAssignment == TRAIN_SELF ) || ( pSoldier->bAssignment == TRAIN_TEAMMATE ) || ( pSoldier->bAssignment == TRAIN_BY_OTHER ) )
else if( ( pSoldier->bAssignment == TRAIN_SELF ) || ( pSoldier->bAssignment == TRAIN_TEAMMATE ) || ( pSoldier->bAssignment == TRAIN_BY_OTHER ) )
{
wcscpy(sString, pAttributeMenuStrings[pSoldier->bTrainStat]);
}
// train town?
else if( pSoldier->bAssignment == TRAIN_TOWN )
// HEADROCK HAM 3.6: Draw for Mobile Trainers as well.
else if( pSoldier->bAssignment == TRAIN_TOWN || pSoldier->bAssignment == TRAIN_MOBILE )
{
wcscpy(sString,pTownNames[GetTownIdForSector( pSoldier->sSectorX, pSoldier->sSectorY ) ] );
}
// repairing?
else if( pSoldier->bAssignment == REPAIR )
{
@@ -3127,6 +3145,136 @@ void DisplayCharacterInfo( void )
// set font buffer
SetFontDestBuffer( guiSAVEBUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
// 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 STRATEGIC info pages. Another section is in Interface Panels.cpp and draws TACTICAL 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] )
{
SOLDIERTYPE *pSoldier = MercPtrs[ gCharactersList[bSelectedInfoChar].usSolID ];
UINT8 *pDestBuf;
UINT32 uiDestPitchBYTES = 0;
SGPRect ClipRect;
UINT8 ubBarWidth = 0;
UINT16 usColor = Get16BPPColor( FROMRGB( gGameExternalOptions.ubStatProgressBarsRed, gGameExternalOptions.ubStatProgressBarsGreen, gGameExternalOptions.ubStatProgressBarsBlue ) );
//pDestBuf = LockVideoSurface( FRAME_BUFFER, &uiDestPitchBYTES );
pDestBuf = LockVideoSurface( guiSAVEBUFFER, &uiDestPitchBYTES );
// AGI
if (gMercProfiles[ pSoldier->ubProfile ].sAgilityGain)
{
ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sAgilityGain+1)) / SubpointsPerPoint(AGILAMT,0);
ClipRect.iTop = (AGL_Y-1);
ClipRect.iBottom = (AGL_Y-1) + STAT_HEI;
ClipRect.iLeft = AGL_X;
ClipRect.iRight = AGL_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// DEX
if (gMercProfiles[ pSoldier->ubProfile ].sDexterityGain)
{
ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sDexterityGain+1)) / SubpointsPerPoint(DEXTAMT,0);
ClipRect.iTop = (DEX_Y-1);
ClipRect.iBottom = (DEX_Y-1) + STAT_HEI;
ClipRect.iLeft = DEX_X;
ClipRect.iRight = DEX_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// STR
if (gMercProfiles[ pSoldier->ubProfile ].sStrengthGain)
{
ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sStrengthGain+1)) / SubpointsPerPoint(STRAMT,0);
ClipRect.iTop = (STR_Y-1);
ClipRect.iBottom = (STR_Y-1) + STAT_HEI;
ClipRect.iLeft = STR_X;
ClipRect.iRight = STR_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// WIS
if (gMercProfiles[ pSoldier->ubProfile ].sWisdomGain)
{
ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sWisdomGain+1)) / SubpointsPerPoint(WISDOMAMT,0);
ClipRect.iTop = (WIS_Y-1);
ClipRect.iBottom = (WIS_Y-1) + STAT_HEI;
ClipRect.iLeft = WIS_X;
ClipRect.iRight = WIS_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// MRK
if (gMercProfiles[ pSoldier->ubProfile ].sMarksmanshipGain)
{
ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sMarksmanshipGain+1)) / SubpointsPerPoint(MARKAMT,0);
ClipRect.iTop = (MRK_Y-1);
ClipRect.iBottom = (MRK_Y-1) + STAT_HEI;
ClipRect.iLeft = MRK_X;
ClipRect.iRight = MRK_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// LDR
if (gMercProfiles[ pSoldier->ubProfile ].sLeadershipGain)
{
ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sLeadershipGain+1)) / SubpointsPerPoint(LDRAMT,0);
ClipRect.iTop = (LDR_Y-1);
ClipRect.iBottom = (LDR_Y-1) + STAT_HEI;
ClipRect.iLeft = LDR_X;
ClipRect.iRight = LDR_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// MECH
if (gMercProfiles[ pSoldier->ubProfile ].sMechanicGain)
{
ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sMechanicGain+1)) / SubpointsPerPoint(MECHANAMT,0);
ClipRect.iTop = (MEC_Y-1);
ClipRect.iBottom = (MEC_Y-1) + STAT_HEI;
ClipRect.iLeft = MEC_X;
ClipRect.iRight = MEC_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// EXPLO
if (gMercProfiles[ pSoldier->ubProfile ].sExplosivesGain)
{
ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sExplosivesGain+1)) / SubpointsPerPoint(EXPLODEAMT,0);
ClipRect.iTop = (EXP_Y-1);
ClipRect.iBottom = (EXP_Y-1) + STAT_HEI;
ClipRect.iLeft = EXP_X;
ClipRect.iRight = EXP_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// MED
if (gMercProfiles[ pSoldier->ubProfile ].sMedicalGain)
{
ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sMedicalGain+1)) / SubpointsPerPoint(MEDICALAMT,0);
ClipRect.iTop = (MED_Y-1);
ClipRect.iBottom = (MED_Y-1) + STAT_HEI;
ClipRect.iLeft = MED_X;
ClipRect.iRight = MED_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// EXPLEVEL
if (gMercProfiles[ pSoldier->ubProfile ].sExpLevelGain)
{
ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sExpLevelGain+1)) / SubpointsPerPoint(EXPERAMT, pSoldier->stats.bExpLevel);
ClipRect.iTop = (LVL_Y-1);
ClipRect.iBottom = (LVL_Y-1) + STAT_HEI;
ClipRect.iLeft = LVL_X;
ClipRect.iRight = LVL_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
UnLockVideoSurface( guiSAVEBUFFER );
}
// draw character info and face
DrawCharacterInfo( bSelectedInfoChar );
@@ -4428,12 +4576,16 @@ UINT32 MapScreenHandle(void)
InitPreviousPaths();
// HEADROCK HAM 3.6: Init coordinates for new variable-sized message window
InitMapScreenInterfaceBottomCoords();
// if arrival sector is invalid, reset to A9
if ( ( gsMercArriveSectorX < 1 ) || ( gsMercArriveSectorY < 1 ) ||
( gsMercArriveSectorX > 16 ) || ( gsMercArriveSectorY > 16 ) )
{
gsMercArriveSectorX = 9;
gsMercArriveSectorY = 1;
// HEADROCK HAM 3.5: Externalized coordinates
gsMercArriveSectorX = gGameExternalOptions.ubDefaultArrivalSectorX;
gsMercArriveSectorY = gGameExternalOptions.ubDefaultArrivalSectorY;
}
gfInConfirmMapMoveMode = FALSE;
@@ -4702,7 +4854,8 @@ UINT32 MapScreenHandle(void)
if( AnyMercsHired( ) == FALSE )
{
// select starting sector (A9 - Omerta)
ChangeSelectedMapSector( startingX, startingY, startingZ );
// HEADROCK HAM 3.5: Externalized!
ChangeSelectedMapSector( gGameExternalOptions.ubDefaultArrivalSectorX, gGameExternalOptions.ubDefaultArrivalSectorY, startingZ );
}
else if( ( gWorldSectorX > 0 ) && ( gWorldSectorY > 0 ) && ( gbWorldSectorZ != -1 ) )
{
@@ -4714,7 +4867,8 @@ UINT32 MapScreenHandle(void)
// only select A9 - Omerta IF there is no current selection, otherwise leave it as is
if ( ( sSelMapX == 0 ) || ( sSelMapY == 0 ) || ( iCurrentMapSectorZ == -1 ) )
{
ChangeSelectedMapSector( startingX, startingY, startingZ );
// HEADROCK HAM 3.5: Externalized!
ChangeSelectedMapSector( gGameExternalOptions.ubDefaultArrivalSectorX, gGameExternalOptions.ubDefaultArrivalSectorY, startingZ );
}
}
@@ -5261,7 +5415,8 @@ UINT32 MapScreenHandle(void)
// handle display of inventory pop up
HandleDisplayOfItemPopUpForSector( startingX, startingY, startingZ );
// HEADROCK HAM 3.5: Externalize!
HandleDisplayOfItemPopUpForSector( gGameExternalOptions.ubDefaultArrivalSectorX, gGameExternalOptions.ubDefaultArrivalSectorY, startingZ );
// Display Framerate
DisplayFrameRate( );
@@ -5311,7 +5466,9 @@ UINT32 MapScreenHandle(void)
fCharacterInfoPanelDirty=TRUE;
fMapPanelDirty = TRUE;
fMapScreenBottomDirty = TRUE;
fTeamPanelDirty = TRUE;
fEndShowInventoryFlag = FALSE;
}
@@ -5702,6 +5859,8 @@ void DrawAssignment(INT16 sCharNumber, INT16 sRowIndex, INT32 iFont)
FindFontCenterCoordinates((short)ASSIGN_X + 1, (short)(usVehicleY+(sRowIndex*Y_SIZE)), (short)ASSIGN_WIDTH, (short)Y_SIZE, sString, (long)iFont, &usX, &usY);
}
SOLDIERTYPE *pSoldier = MercPtrs[ gCharactersList[ sCharNumber ].usSolID ];
if( fFlashAssignDone == TRUE )
{
if( Menptr[gCharactersList[sCharNumber].usSolID].flags.fDoneAssignmentAndNothingToDoFlag )
@@ -5710,6 +5869,97 @@ void DrawAssignment(INT16 sCharNumber, INT16 sRowIndex, INT32 iFont)
}
}
if ( gGameSettings.fOptions[TOPTION_STAT_PROGRESS_BARS] &&
(pSoldier->bAssignment >= TRAIN_SELF ||
pSoldier->bAssignment <= TRAIN_BY_OTHER ) &&
pSoldier->bAssignment != TRAIN_TEAMMATE )
{
// HEADROCK HAM 3.6: Draw militia training progress bar
UINT32 uiDestBuffer;
UINT8 *pDestBuf;
UINT32 uiDestPitchBYTES = 0;
SGPRect ClipRect;
UINT8 ubBarWidth;
UINT16 usColor = Get16BPPColor( FROMRGB( gGameExternalOptions.ubStatProgressBarsRed, gGameExternalOptions.ubStatProgressBarsGreen, gGameExternalOptions.ubStatProgressBarsBlue ) );
if( ( fShowAssignmentMenu == TRUE ) && ( fTeamPanelDirty == FALSE ) )
{
uiDestBuffer = FRAME_BUFFER;
}
else
{
uiDestBuffer = guiSAVEBUFFER;
}
pDestBuf = LockVideoSurface( uiDestBuffer, &uiDestPitchBYTES );
UINT8 ubProgress;
UINT16 usMaxProgress;
UINT8 sMapX = (UINT8)pSoldier->sSectorX;
UINT8 sMapY = (UINT8)pSoldier->sSectorY;
if ( pSoldier->bAssignment == TRAIN_TOWN )
{
ubProgress = SectorInfo[SECTOR(sMapX, sMapY)].ubMilitiaTrainingPercentDone;
usMaxProgress = 100;
}
else if ( pSoldier->bAssignment == TRAIN_MOBILE )
{
ubProgress = SectorInfo[SECTOR(sMapX, sMapY)].ubMobileMilitiaTrainingPercentDone;
usMaxProgress = 100;
}
else if ( pSoldier->bAssignment == TRAIN_SELF ||
pSoldier->bAssignment == TRAIN_BY_OTHER )
{
switch (pSoldier->bTrainStat)
{
case STRENGTH:
ubProgress = gMercProfiles[ pSoldier->ubProfile ].sStrengthGain+1;
usMaxProgress = gGameExternalOptions.usStrengthSubpointsToImprove;
break;
case AGILITY:
ubProgress = gMercProfiles[ pSoldier->ubProfile ].sAgilityGain+1;
usMaxProgress = gGameExternalOptions.usAgilitySubpointsToImprove;
break;
case DEXTERITY:
ubProgress = gMercProfiles[ pSoldier->ubProfile ].sDexterityGain+1;
usMaxProgress = gGameExternalOptions.usDexteritySubpointsToImprove;
break;
case HEALTH:
ubProgress = gMercProfiles[ pSoldier->ubProfile ].sLifeGain+1;
usMaxProgress = gGameExternalOptions.usHealthSubpointsToImprove;
break;
case MARKSMANSHIP:
ubProgress = gMercProfiles[ pSoldier->ubProfile ].sMarksmanshipGain+1;
usMaxProgress = gGameExternalOptions.usMarksmanshipSubpointsToImprove;
break;
case LEADERSHIP:
ubProgress = gMercProfiles[ pSoldier->ubProfile ].sLeadershipGain+1;
usMaxProgress = gGameExternalOptions.usLeadershipSubpointsToImprove;
break;
case MECHANICAL:
ubProgress = gMercProfiles[ pSoldier->ubProfile ].sMechanicGain+1;
usMaxProgress = gGameExternalOptions.usMechanicalSubpointsToImprove;
break;
case MEDICAL:
ubProgress = gMercProfiles[ pSoldier->ubProfile ].sMedicalGain+1;
usMaxProgress = gGameExternalOptions.usMedicalSubpointsToImprove;
break;
case EXPLOSIVE_ASSIGN:
ubProgress = gMercProfiles[ pSoldier->ubProfile ].sExplosivesGain+1;
usMaxProgress = gGameExternalOptions.usExplosivesSubpointsToImprove;
break;
}
}
ubBarWidth = (ASSIGN_WIDTH * ubProgress) / usMaxProgress;
ClipRect.iTop = (usY+(Y_OFFSET*sRowIndex+1))-1;
ClipRect.iBottom = ClipRect.iTop + Y_SIZE;
ClipRect.iLeft = ASSIGN_X+2;
ClipRect.iRight = ASSIGN_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
UnLockVideoSurface( uiDestBuffer );
}
//RestoreExternBackgroundRect(ASSIGN_X-2, ((UINT16)(usY+(Y_OFFSET*sRowIndex+1))), ASSIGN_WIDTH+2, Y_SIZE);
DrawString(sString, (UINT16)usX, ((UINT16)(usY+(Y_OFFSET*sRowIndex+1))), iFont);
}
@@ -6438,6 +6688,12 @@ void GetMapKeyboardInput( UINT32 *puiNewEvent )
fShowAttributeMenu = FALSE;
fMapPanelDirty = TRUE;
}
// stop showing current assignment box
if( fShowFacilityAssignmentMenu == TRUE )
{
fShowFacilityAssignmentMenu = FALSE;
fMapPanelDirty = TRUE;
}
else if( fShowTrainingMenu == TRUE )
{
fShowTrainingMenu = FALSE;
@@ -6450,6 +6706,11 @@ void GetMapKeyboardInput( UINT32 *puiNewEvent )
{
fShowRepairMenu = FALSE;
}
// HEADROCK HAM 3.6: Facility Menu
else if( fShowFacilityMenu == TRUE )
{
fShowFacilityMenu = FALSE;
}
else
{
fShowAssignmentMenu = FALSE;
@@ -10695,6 +10956,12 @@ void RenderMapRegionBackground( void )
ForceUpDateOfBox( ghAttributeBox );
}
// HEADROCK HAM 3.6: Force re-render due to Facility box
if ( ghFacilityAssignmentBox != 1 )
{
ForceUpDateOfBox( ghFacilityAssignmentBox );
}
if ( ghTownMineBox != - 1 )
{
// force update of town mine info boxes
@@ -14970,13 +15237,18 @@ void HandlePostAutoresolveMessages()
void GetMapscreenMercAssignmentString( SOLDIERTYPE *pSoldier, CHAR16 sString[] )
{
if( pSoldier->bAssignment != VEHICLE )
if ( pSoldier->bAssignment == VEHICLE )
{
wcscpy(sString, pAssignmentStrings[ pSoldier->bAssignment ] );
wcscpy( sString, pShortVehicleStrings[ pVehicleList[ pSoldier->iVehicleId ].ubVehicleType ] );
}
else
{
wcscpy( sString, pShortVehicleStrings[ pVehicleList[ pSoldier->iVehicleId ].ubVehicleType ] );
wcscpy(sString, pAssignmentStrings[ pSoldier->bAssignment ] );
}
// If soldier is working at a facility, add an asterisk.
if (pSoldier->sFacilityTypeOperated != -1)
{
wcscat(sString, L"*");
}
}
@@ -15433,6 +15705,7 @@ void RequestToggleMercInventoryPanel( void )
else
{
// Headrock. New line forces InvBottom rerender when the inventory is opened and closed.
fEndShowInventoryFlag = TRUE;
RenderMapScreenInterfaceBottom ( TRUE );
SetRegionFastHelpText( &gCharInfoHandRegion, pMiscMapScreenMouseRegionHelpText[ 0 ] );
}
@@ -15549,3 +15822,48 @@ void MapscreenMarkButtonsDirty()
}
}
}
// HEADROCK HAM 3.6: Get a total of all merc salaries. Used for the new Daily Expenses display.
INT32 GetTotalContractExpenses ( void )
{
if (gGameExternalOptions.ubIncludeContractsInExpenses == 0)
{
// Contract costs are excluded.
return (0);
}
UINT8 ubCounter = 0;
SOLDIERTYPE *pSoldier;
INT32 iTotalCost = 0;
while(gCharactersList[ubCounter].fValid)
{
pSoldier = MercPtrs[ gCharactersList[ ubCounter ].usSolID ];
// salary
if( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__AIM_MERC )
{
if (gGameExternalOptions.ubIncludeContractsInExpenses == 2)
{
// daily rate
if( pSoldier->bTypeOfLastContract == CONTRACT_EXTEND_2_WEEK )
{
iTotalCost += ( gMercProfiles[ pSoldier->ubProfile ].uiBiWeeklySalary / 14 );
}
if( pSoldier->bTypeOfLastContract == CONTRACT_EXTEND_1_WEEK )
{
iTotalCost += ( gMercProfiles[ pSoldier->ubProfile ].uiWeeklySalary / 7 );
}
else
{
iTotalCost += gMercProfiles[ pSoldier->ubProfile ].sSalary;
}
}
}
else
{
iTotalCost += gMercProfiles[ pSoldier->ubProfile ].sSalary;
}
ubCounter++;
}
return (iTotalCost);
}
+4
View File
@@ -9,6 +9,7 @@
#define MAP_WORLD_Y 18
#define MAX_TOWN_NAME_LENGHT 32
#define MAX_SECTOR_NAME_LENGTH 128
#define MAX_TOWNS 50 //13 //50
#define MAX_TOWN_SECTORS 260 //40 //260
@@ -93,4 +94,7 @@ BOOLEAN InitializeInvPanelCoordsOld( );
BOOLEAN InitializeInvPanelCoordsNew( );
BOOLEAN InitializeInvPanelCoordsVehicle( );
// HEADROCK HAM 3.6: Calculate daily cost for all mercs who have one.
INT32 GetTotalContractExpenses ( void );
#endif
+194 -91
View File
@@ -296,6 +296,9 @@ STR8 pHortStrings[]={
"17",
};
// HEADROCK HAM 3.6: Array to hold user-defined sector names
CHAR16 gzSectorNames[256][4][MAX_SECTOR_NAME_LENGTH];
BOOLEAN ReadInStrategicMapSectorTownNames(STR fileName, BOOLEAN localizedVersion);
void DoneFadeOutAdjacentSector( void );
@@ -1616,8 +1619,9 @@ void InitializeSAMSites( void )
{
UINT32 cnt;
// move the landing zone over to Omerta
gsMercArriveSectorX = 9;
gsMercArriveSectorY = 1;
// HEADROCK HAM 3.5: Externalized coordinates
gsMercArriveSectorX = gGameExternalOptions.ubDefaultArrivalSectorX;
gsMercArriveSectorY = gGameExternalOptions.ubDefaultArrivalSectorY;
// all SAM sites start game in perfect working condition
for ( cnt = 0; cnt < NUMBER_OF_SAMS; cnt++ )
@@ -3009,109 +3013,179 @@ void GetSectorIDString( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ , STR16 zS
}
else
{
bTownNameID = StrategicMap[ CALCULATE_STRATEGIC_INDEX( sSectorX, sSectorY ) ].bNameId;
ubSectorID = (UINT8)SECTOR( sSectorX, sSectorY );
AssertGE(ubSectorID, 0);
AssertLT(ubSectorID,256);
pSector = &SectorInfo[ ubSectorID ];
ubLandType = pSector->ubTraversability[ 4 ];
swprintf( zString, L"%c%d: ", 'A' + sSectorY - 1, sSectorX );
if ( bTownNameID == BLANK_SECTOR )
////////////////////////////////////
// Read and verify XML sector names
BOOLEAN fSectorHasXMLNames = TRUE;
CHAR16 zUnexplored[MAX_SECTOR_NAME_LENGTH];
CHAR16 zDetailedUnexplored[MAX_SECTOR_NAME_LENGTH];
CHAR16 zExplored[MAX_SECTOR_NAME_LENGTH];
CHAR16 zDetailedExplored[MAX_SECTOR_NAME_LENGTH];
wcscpy( zUnexplored, gzSectorNames[ ubSectorID ][0] );
wcscpy( zDetailedUnexplored, gzSectorNames[ ubSectorID ][1] );
wcscpy( zExplored, gzSectorNames[ ubSectorID ][2] );
wcscpy( zDetailedExplored, gzSectorNames[ ubSectorID ][3] );
if (zUnexplored[0] == 0 || zDetailedUnexplored[0] == 0 || zExplored[0] == 0 || zDetailedExplored[0] == 0)
{
// OK, build string id like J11
// are we dealing with the unfound towns?
switch( ubSectorID )
fSectorHasXMLNames = FALSE;
}
if (fSectorHasXMLNames)
{
// HEADROCK HAM 3.6: The program can now read custom names from XML for all above-ground sectors.
// In the event that a specific name or set of names is missing, the program generates a default
// name as it always has.
// I've also updated the SAM Site sectors to rely on SamSite.XML data.
BOOLEAN fVisited = (SectorInfo[ ubSectorID ].uiFlags & SF_ALREADY_VISITED);
BOOLEAN fSAMSiteKnown = FALSE;
// Test for known SAM Site at this location
for (UINT16 x=0; x < MAX_NUMBER_OF_SAMS; x++)
{
case SEC_D2: //Chitzena SAM
if( !fSamSiteFound[ SAM_SITE_ONE ] )
wcscat( zString, pLandTypeStrings[ TROPICS ] );
else if( fDetailed )
wcscat( zString, pLandTypeStrings[ TROPICS_SAM_SITE ] );
else
wcscat( zString, pLandTypeStrings[ SAM_SITE ] );
break;
case SEC_D15: //Drassen SAM
if( !fSamSiteFound[ SAM_SITE_TWO ] )
wcscat( zString, pLandTypeStrings[ SPARSE ] );
else if( fDetailed )
wcscat( zString, pLandTypeStrings[ SPARSE_SAM_SITE ] );
else
wcscat( zString, pLandTypeStrings[ SAM_SITE ] );
break;
case SEC_I8: //Cambria SAM
if( !fSamSiteFound[ SAM_SITE_THREE ] )
wcscat( zString, pLandTypeStrings[ SAND ] );
else if( fDetailed )
wcscat( zString, pLandTypeStrings[ SAND_SAM_SITE ] );
else
wcscat( zString, pLandTypeStrings[ SAM_SITE ] );
break;
default:
wcscat( zString, pLandTypeStrings[ ubLandType ] );
break;
if ( pSamList[x] == ubSectorID )
{
if ( fSamSiteFound[ x ] )
{
fSAMSiteKnown = TRUE;
}
}
}
if (fVisited || fSAMSiteKnown)
{
if (fDetailed)
{
wcscat( zString, zDetailedExplored );
}
else
{
wcscat( zString, zExplored);
}
}
else
{
if (fDetailed)
{
wcscat( zString, zDetailedUnexplored);
}
else
{
wcscat( zString, zUnexplored );
}
}
}
else
{
switch( ubSectorID )
// Default JA2 Name selection
if ( bTownNameID == BLANK_SECTOR )
{
case SEC_B13:
if( fDetailed )
wcscat( zString, pLandTypeStrings[ DRASSEN_AIRPORT_SITE ] );
else
wcscat( zString, pTownNames[ DRASSEN ] );
break;
case SEC_F8:
if( fDetailed )
wcscat( zString, pLandTypeStrings[ CAMBRIA_HOSPITAL_SITE ] );
else
wcscat( zString, pTownNames[ CAMBRIA ] );
break;
case SEC_J9: //Tixa
if( !fFoundTixa )
wcscat( zString, pLandTypeStrings[ SAND ] );
else
wcscat( zString, pTownNames[ TIXA ] );
break;
case SEC_K4: //Orta
if( !fFoundOrta )
wcscat( zString, pLandTypeStrings[ SWAMP ] );
else
wcscat( zString, pTownNames[ ORTA ] );
break;
case SEC_N3:
if( fDetailed )
wcscat( zString, pLandTypeStrings[ MEDUNA_AIRPORT_SITE ] );
else
wcscat( zString, pTownNames[ MEDUNA ] );
break;
default:
if( ubSectorID == SEC_N4 && fSamSiteFound[ SAM_SITE_FOUR ] )
{ //Meduna's SAM site
if( fDetailed )
wcscat( zString, pLandTypeStrings[ MEDUNA_SAM_SITE ] );
// OK, build string id like J11
// are we dealing with the unfound towns?
switch( ubSectorID )
{
case SEC_D2: //Chitzena SAM
if( !fSamSiteFound[ SAM_SITE_ONE ] )
wcscat( zString, pLandTypeStrings[ TROPICS ] );
else if( fDetailed )
wcscat( zString, pLandTypeStrings[ TROPICS_SAM_SITE ] );
else
wcscat( zString, pLandTypeStrings[ SAM_SITE ] );
}
else
{ //All other towns that are known since beginning of the game.
wcscat( zString, pTownNames[ bTownNameID ] );
break;
case SEC_D15: //Drassen SAM
if( !fSamSiteFound[ SAM_SITE_TWO ] )
wcscat( zString, pLandTypeStrings[ SPARSE ] );
else if( fDetailed )
wcscat( zString, pLandTypeStrings[ SPARSE_SAM_SITE ] );
else
wcscat( zString, pLandTypeStrings[ SAM_SITE ] );
break;
case SEC_I8: //Cambria SAM
if( !fSamSiteFound[ SAM_SITE_THREE ] )
wcscat( zString, pLandTypeStrings[ SAND ] );
else if( fDetailed )
wcscat( zString, pLandTypeStrings[ SAND_SAM_SITE ] );
else
wcscat( zString, pLandTypeStrings[ SAM_SITE ] );
break;
default:
wcscat( zString, pLandTypeStrings[ ubLandType ] );
break;
}
}
else
{
switch( ubSectorID )
{
case SEC_B13:
if( fDetailed )
{
switch( ubSectorID )
{ //Append the word, "mine" for town sectors containing a mine.
case SEC_B2:
case SEC_D4:
case SEC_D13:
case SEC_H3:
case SEC_H8:
case SEC_I14:
wcscat( zString, L" " ); //space
wcscat( zString, pwMineStrings[ 0 ] ); //then "Mine"
break;
wcscat( zString, pLandTypeStrings[ DRASSEN_AIRPORT_SITE ] );
else
wcscat( zString, pTownNames[ DRASSEN ] );
break;
case SEC_F8:
if( fDetailed )
wcscat( zString, pLandTypeStrings[ CAMBRIA_HOSPITAL_SITE ] );
else
wcscat( zString, pTownNames[ CAMBRIA ] );
break;
case SEC_J9: //Tixa
if( !fFoundTixa )
wcscat( zString, pLandTypeStrings[ SAND ] );
else
wcscat( zString, pTownNames[ TIXA ] );
break;
case SEC_K4: //Orta
if( !fFoundOrta )
wcscat( zString, pLandTypeStrings[ SWAMP ] );
else
wcscat( zString, pTownNames[ ORTA ] );
break;
case SEC_N3:
if( fDetailed )
wcscat( zString, pLandTypeStrings[ MEDUNA_AIRPORT_SITE ] );
else
wcscat( zString, pTownNames[ MEDUNA ] );
break;
default:
if( ubSectorID == SEC_N4 && fSamSiteFound[ SAM_SITE_FOUR ] )
{ //Meduna's SAM site
if( fDetailed )
wcscat( zString, pLandTypeStrings[ MEDUNA_SAM_SITE ] );
else
wcscat( zString, pLandTypeStrings[ SAM_SITE ] );
}
else
{ //All other towns that are known since beginning of the game.
wcscat( zString, pTownNames[ bTownNameID ] );
if( fDetailed )
{
switch( ubSectorID )
{ //Append the word, "mine" for town sectors containing a mine.
case SEC_B2:
case SEC_D4:
case SEC_D13:
case SEC_H3:
case SEC_H8:
case SEC_I14:
wcscat( zString, L" " ); //space
wcscat( zString, pwMineStrings[ 0 ] ); //then "Mine"
break;
}
}
}
}
break;
break;
}
}
}
}
@@ -4605,8 +4679,26 @@ void UpdateAirspaceControl( void )
GetSectorIDString( gsMercArriveSectorX, gsMercArriveSectorY, 0, sMsgSubString1, FALSE );
// move the landing zone over to Omerta
gsMercArriveSectorX = 9;
gsMercArriveSectorY = 1;
// HEADROCK HAM 3.5: Externalized coordinates
if ( StrategicMap[ CALCULATE_STRATEGIC_INDEX( gGameExternalOptions.ubDefaultArrivalSectorX, gGameExternalOptions.ubDefaultArrivalSectorY ) ].fEnemyAirControlled == FALSE )
{
gsMercArriveSectorX = gGameExternalOptions.ubDefaultArrivalSectorX;
gsMercArriveSectorY = gGameExternalOptions.ubDefaultArrivalSectorY;
}
else
{
for (UINT8 ubSectorX = 1; ubSectorX <= 16; ubSectorX++)
{
for (UINT8 ubSectorY = 1; ubSectorY <=16; ubSectorY++)
{
if ( StrategicMap[ CALCULATE_STRATEGIC_INDEX( ubSectorX, ubSectorY ) ].fEnemyAirControlled == FALSE )
{
gsMercArriveSectorX = ubSectorX;
gsMercArriveSectorY = ubSectorY;
}
}
}
}
// get the name of the new sector
GetSectorIDString( gsMercArriveSectorX, gsMercArriveSectorY, 0, sMsgSubString2, FALSE );
@@ -4615,7 +4707,11 @@ void UpdateAirspaceControl( void )
swprintf( sMsgString, pBullseyeStrings[ 4 ], sMsgSubString1, sMsgSubString2 );
// confirm the change with overlay message
DoScreenIndependantMessageBox( sMsgString, MSG_BOX_FLAG_OK, NULL );
// HEADROCK HAM 3.5: If we do this during SaveLoad, the message box prevents loading the game at all!
if (guiCurrentScreen != SAVE_LOAD_SCREEN)
{
DoScreenIndependantMessageBox( sMsgString, MSG_BOX_FLAG_OK, NULL );
}
// update position of bullseye
fMapPanelDirty = TRUE;
@@ -4627,6 +4723,7 @@ void UpdateAirspaceControl( void )
// ARM: airspace control now affects refueling site availability, so update that too with every change!
UpdateRefuelSiteAvailability( );
}
@@ -5524,6 +5621,12 @@ void HandleSlayDailyEvent( void )
BOOLEAN IsSectorDesert( INT16 sSectorX, INT16 sSectorY )
{
// HEADROCK HAM 3.5: Fix for assertion errors associated with rain checks.
if (sSectorX <= 0 || sSectorY <=0 || sSectorX > 16 || sSectorY > 16)
{
return( FALSE );
}
if ( SectorInfo[ SECTOR(sSectorX, sSectorY) ].ubTraversability[ THROUGH_STRATEGIC_MOVE ] == SAND )
{
// desert
@@ -5669,7 +5772,7 @@ BOOLEAN CheckAndHandleUnloadingOfCurrentWorld()
return FALSE;
}
if( gTacticalStatus.fDidGameJustStart && gWorldSectorX == 9 && gWorldSectorY == 1 && !gbWorldSectorZ )
if( gTacticalStatus.fDidGameJustStart && gWorldSectorX == gGameExternalOptions.ubDefaultArrivalSectorX && gWorldSectorY == gGameExternalOptions.ubDefaultArrivalSectorY && !gbWorldSectorZ )
{
return FALSE;
}
+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

Some files were not shown because too many files have changed in this diff Show More