Added Headrock's HAM 2.8

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@2650 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Wanne
2009-04-01 12:20:30 +00:00
parent 5f9261273a
commit 335747c3ff
48 changed files with 3439 additions and 406 deletions
+138
View File
@@ -812,6 +812,144 @@ void LoadGameExternalOptions()
// WANNE: Always use prof.dat??
gGameExternalOptions.fAlwaysUseProfDat = iniReader.ReadBoolean("JA2 Gameplay Settings", "ALWAYS_USE_PROF_DAT", FALSE);
// HEADROCK HAM B1: Set % of mine income, where 100% = normal
gGameExternalOptions.iMineIncomePercentage = iniReader.ReadInteger("JA2 HAM Settings","MINE_INCOME_PERCENTAGE",0);
// HEADROCK HAM B2.4: Set a threshold at 1% - otherwise game crashes on asserting mine income.
// Can anyone have a look at circumventing the income check? I don't want to cause any damage...
gGameExternalOptions.iMineIncomePercentage = __max(gGameExternalOptions.iMineIncomePercentage, 1);
// HEADROCK HAM B1: Set minimum and maximum CTH
gGameExternalOptions.iMaximumCTH = iniReader.ReadInteger("JA2 HAM Settings","MAXIMUM_POSSIBLE_CTH",0);
gGameExternalOptions.iMinimumCTH = iniReader.ReadInteger("JA2 HAM Settings","MINIMUM_POSSIBLE_CTH",0);
// 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",0);
// HEADROCK HAM B1: Allow restricted militia to move through visited sectors?
gGameExternalOptions.bUnrestrictVisited = iniReader.ReadBoolean("JA2 HAM Settings","ALLOW_RESTRICTED_MILITIA_THROUGH_VISITED_SECTORS",0);
gGameExternalOptions.bDynamicRestrictRoaming = iniReader.ReadBoolean("JA2 HAM Settings","ALLOW_DYNAMIC_RESTRICTED_ROAMING",0);
// 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",0);
// 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",100);
// HEADROCK HAM B2: MAXIMUM number of APs that can be lost to suppression in a given turn (0=unlimited)
gGameExternalOptions.iMaxSuppressionAPLossPerTurn = iniReader.ReadInteger("JA2 HAM Settings","MAX_SUPPRESSION_AP_LOSS_PER_TURN",8);
// HEADROCK HAM B2: MAXIMUM number of APs that can be lost to suppression in a given attack (0=unlimited)
gGameExternalOptions.iMaxSuppressionAPLossPerAttack = iniReader.ReadInteger("JA2 HAM Settings","MAX_SUPPRESSION_AP_LOSS_PER_ATTACK",8);
// HEADROCK HAM B2: Rigid limit to which a soldier's APs can drop due to suppression fire. (0=unlimited)
gGameExternalOptions.iMinAPLimitFromSuppression = iniReader.ReadInteger("JA2 HAM Settings","MIN_LIMIT_SUPPRESSION_AP_LOSS",0);
// HEADROCK HAM B2: Suppression Shock ON/OFF
gGameExternalOptions.fSuppressionShock = iniReader.ReadBoolean("JA2 HAM Settings","SUPPRESSION_SHOCK",FALSE);
// HEADROCK HAM B2: Suppression Shock effectiveness (percentage, 100 = "normal", 0 = deactivated. Range 0-65535)
gGameExternalOptions.iSuppressionShockEffectiveness = iniReader.ReadInteger("JA2 HAM Settings","SUPPRESSION_SHOCK_EFFECTIVENESS",100);
// 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);
// 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);
// HEADROCK HAM B2.4: How many APs must be lost due to suppression for every 1 point of morale lost?
gGameExternalOptions.iAPLostPerMoraleDrop = iniReader.ReadInteger("JA2 HAM Settings","AP_LOST_PER_MORALE_DROP",2);
// 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);
// 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);
// 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);
// HEADROCK HAM B2.6: Increased aiming costs?
gGameExternalOptions.fIncreasedAimingCost = iniReader.ReadBoolean("JA2 HAM Settings","INCREASED_AIM_COST", FALSE);
// HEADROCK HAM B2.6: Dynamically determine Max-Aiming based also on weapon, bipod, etc?
gGameExternalOptions.fDynamicAimingTime = iniReader.ReadBoolean("JA2 HAM Settings","DYNAMIC_AIM_LIMITS", FALSE);
// HEADROCK HAM B2.6: Controls how much effect target movement has on aiming
//gGameExternalOptions.iMovementEffectOnAiming = iniReader.ReadFloat("JA2 HAM Settings","MOVEMENT_EFFECT_ON_AIMING", 1.5);
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);
// 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);
// 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);
// 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));
// 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);
// 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));
// 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", 100));
// 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", 100));
gGameExternalOptions.usMaxTargetCoweringPenalty = __max(1,iniReader.ReadInteger("JA2 HAM Settings","MAX_TARGET_COWERING_PENALTY", 100));
// 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: 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);
// 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);
// 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);
}
INT16 DynamicAdjustAPConstants(INT16 iniReadValue, INT16 iniDefaultValue, BOOLEAN reverse)
+135 -1
View File
@@ -486,7 +486,141 @@ BOOLEAN gbBulletTracer;
INT32 fEnhancedDescriptionBox;
// WANNE: Always use "prof.dat".
BOOLEAN fAlwaysUseProfDat;
BOOLEAN fAlwaysUseProfDat;
// HEADROCK HAM B1: Global modifier for mine income (0 is automatically turned to 1 to avoid divide-by-zero.)
INT16 iMineIncomePercentage;
// HEADROCK HAM B1: Allows changing the maximum CTH possible, for any attack 0-100
UINT8 iMaximumCTH;
// HEADROCK HAM B1: Allows changing the minimum CTH possible, for any attack 0-100
UINT8 iMinimumCTH;
// HEADROCK HAM B1: Allows reducing the chance of scoring a hit fractionally, if CTH = Minimum CTH
UINT8 iMinimumCTHDivisor;
// HEADROCK HAM B1: Allows Restricted Roaming Militia to move through previously visited sectors, even if restricted.
BOOLEAN bUnrestrictVisited;
// 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;
// HEADROCK HAM B2.1: This controls how effective suppression is, by increasing the number of ubSuppressionPoints accumulated by combatants (percentage);
INT16 iSuppressionEffectiveness;
// HEADROCK HAM B2: MAXIMUM number of APs that can be lost to suppression in a given turn (0=unlimited)
UINT8 iMaxSuppressionAPLossPerTurn;
// HEADROCK HAM B2: MAXIMUM number of APs that can be lost to suppression in a given attack (0=unlimited)
UINT8 iMaxSuppressionAPLossPerAttack;
// HEADROCK HAM B2: Rigid limit to which a soldier's APs can drop due to suppression fire. (0=unlimited)
INT8 iMinAPLimitFromSuppression;
// HEADROCK HAM B2: Suppression Shock ON/OFF
BOOLEAN fSuppressionShock;
// HEADROCK HAM B2: Suppression Shock effectiveness (percentage, 100 = "normal", 0 = deactivated. Range 0-65535)
UINT16 iSuppressionShockEffectiveness;
// HEADROCK HAM B2.1: CTH penalty given by a "Cowering" target to any enemy shooter.
INT8 iAimPenaltyPerTargetShock;
// HEADROCK HAM B2.3: It is now possible for "cowering" to increase a target's suppression.
UINT16 iCowerEffectOnSuppression;
// HEADROCK HAM B2.4: How many APs must be lost due to suppression for every 1 point of morale lost?
UINT8 iAPLostPerMoraleDrop;
// 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;
// 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;
// HEADROCK HAM B2.5: Realistic tracers - CTH increased by this amount whenever a tracer is fired. 0 = off.
INT16 iCTHBumpPerTracer;
// HEADROCK HAM B2.6: Increased aiming costs?
BOOLEAN fIncreasedAimingCost;
// HEADROCK HAM B2.6: Dynamically determine Max-Aiming based also on weapon, bipod, etc?
BOOLEAN fDynamicAimingTime;
// HEADROCK HAM B2.6: Controls how much effect target movement has on aiming
FLOAT iMovementEffectOnAiming;
// HEADROCK HAM B2.6: Autofire Bullets/5AP modifier
INT16 iAutofireBulletsPer5APModifier;
// 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;
// HEADROCK HAM B2.6/2/1: Toggle new Burst/Auto CTH bars: 0=neither, 1=both, 2=Burst, 3=Auto
UINT8 iNewCTHBars;
// 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;
// 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;
// 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;
UINT8 ubCoweringPenaltyDivisorCrouchedTorso;
UINT8 ubCoweringPenaltyDivisorCrouchedLegs;
// 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.
UINT16 usMinRangeForFullCoweringPenalty;
// HEADROCK HAM B2.8: Absolute maximum CTH penalty from target/shooter cowering
UINT16 usMaxShooterCoweringPenalty;
UINT16 usMaxTargetCoweringPenalty;
// HEADROCK HAM B2.8: If this is turned on, Militia will drop their equipment similar to enemies, IF killed by non-player character.
UINT8 ubMilitiaDropEquipment;
// 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.
UINT8 ubSmartTrainingSleep;
// 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.
UINT8 ubSmartTrainingWake;
// 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;
} GAME_EXTERNAL_OPTIONS;
+7
View File
@@ -105,6 +105,8 @@
#include "Assignments.h"
#include "Interface Items.h"
#include "Shopkeeper Interface.h"
// HEADROCK HAM B1: Additional Include for HAM
#include "MilitiaSquads.h"
#endif
#include "BobbyR.h"
@@ -4401,6 +4403,11 @@ BOOLEAN LoadSavedGame( int ubSavedGameID )
// fix squads
CheckSquadMovementGroups();
// HEADROCK HAM B1: Re-Adjust Dynamic Roaming Militia restrictions
if (gGameExternalOptions.bDynamicRestrictRoaming)
{
AdjustRoamingRestrictions();
}
//The above function LightSetBaseLevel adjusts ALL the level node light values including the merc node,
//we must reset the values
+419 -24
View File
@@ -105,10 +105,12 @@ enum {
REPAIR_BIG_POCKETS,
REPAIR_MED_POCKETS,
REPAIR_SML_POCKETS,
REPAIR_LBE_GEAR, // HEADROCK HAM B2.8: New pass type for fixing LBEs only
NUM_REPAIR_PASS_TYPES,
};
#define FINAL_REPAIR_PASS REPAIR_SML_POCKETS
// HEADROCK HAM B2.8: Changed LBEs to be the final pass
#define FINAL_REPAIR_PASS REPAIR_LBE_GEAR
/* CHRISL: bSlot[xx] array declaration needs to reflect largest number of inventory locations. New inventory
@@ -128,6 +130,7 @@ REPAIR_PASS_SLOTS_TYPE gRepairPassSlotList[ NUM_REPAIR_PASS_TYPES ] =
{ /* big pockets */ 4, 7, BIGPOCK1POS, BIGPOCK2POS, BIGPOCK3POS, BIGPOCK4POS, BIGPOCK5POS, BIGPOCK6POS, BIGPOCK7POS, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ /* med pockets */ 0, 4, MEDPOCK1POS, MEDPOCK2POS, MEDPOCK3POS, MEDPOCK4POS, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ /* sml pockets */ 8, 30, SMALLPOCK1POS, SMALLPOCK2POS, SMALLPOCK3POS, SMALLPOCK4POS, SMALLPOCK5POS, SMALLPOCK6POS, SMALLPOCK7POS, SMALLPOCK8POS, SMALLPOCK9POS, SMALLPOCK10POS, SMALLPOCK11POS, SMALLPOCK12POS, SMALLPOCK13POS, SMALLPOCK14POS, SMALLPOCK15POS, SMALLPOCK16POS, SMALLPOCK17POS, SMALLPOCK18POS, SMALLPOCK19POS, SMALLPOCK20POS, SMALLPOCK21POS, SMALLPOCK22POS, SMALLPOCK23POS, SMALLPOCK24POS, SMALLPOCK25POS, SMALLPOCK26POS, SMALLPOCK27POS, SMALLPOCK28POS, SMALLPOCK29POS, SMALLPOCK30POS },
{ /* HEADROCK HAM B2.8: LBE Slot pass */ 0, 5, VESTPOCKPOS, LTHIGHPOCKPOS, RTHIGHPOCKPOS, CPACKPOCKPOS, BPACKPOCKPOS, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
};
extern STR16 sRepairsDoneString[];
@@ -3298,18 +3301,42 @@ void HandleRepairBySoldier( SOLDIERTYPE *pSoldier )
fAnyOfSoldiersOwnItemsWereFixed = UnjamGunsOnSoldier( pSoldier, pSoldier, &ubRepairPtsLeft );
// repair items on self
for( bLoop = 0; bLoop < 2; bLoop++ )
// HEADROCK HAM B2.8: Experimental feature: Fixes LBEs last, as they don't actually require repairs.
for( bLoop = 0; bLoop < 4; bLoop++ )
{
if ( bLoop == 0 )
{
bLoopStart = SECONDHANDPOS;
// HEADROCK: New loop stage only checks second hand, to avoid LBEs.
bLoopEnd = SECONDHANDPOS;
}
else if ( bLoop == 1 )
{
// HEADROCK: Second check is for armor and headgear only.
bLoopStart = HELMETPOS;
bLoopEnd = HEAD2POS;
}
else if ( bLoop == 2 )
{
// HEADROCK: Loop stage altered to run through inventory only
bLoopStart = UsingNewInventorySystem() == false ? BIGPOCKSTART : GUNSLINGPOCKPOS;
// CHRISL: Changed to dynamically determine max inventory locations.
bLoopEnd = (NUM_INV_SLOTS - 1);
}
else
else if ( bLoop == 3 )
{
bLoopStart = HELMETPOS;
bLoopEnd = UsingNewInventorySystem() == false ? HEAD2POS : BPACKPOCKPOS;
if (UsingNewInventorySystem() == true)
{
// HEADROCK: Last loop fixes LBEs
bLoopStart = VESTPOCKPOS;
bLoopEnd = BPACKPOCKPOS;
}
else
{
// HEADROCK: In OIV, simply check everything again.
bLoopStart = SECONDHANDPOS;
bLoopEnd = (NUM_INV_SLOTS - 1);
}
}
// now repair objects running from left hand to small pocket
@@ -3317,10 +3344,12 @@ void HandleRepairBySoldier( SOLDIERTYPE *pSoldier )
{
//CHRISL: These two conditions allow us to repair LBE pocket items at the same time as worn armor, while
// still letting us repair the item in our offhand first.
if(UsingNewInventorySystem() == true && bLoop == 0 && bPocket>SECONDHANDPOS && bPocket<GUNSLINGPOCKPOS)
continue;
if(UsingNewInventorySystem() == true && bLoop == 1 && bPocket==SECONDHANDPOS)
continue;
// HEADROCK HAM B2.8: No longer necessary, as I've artificially added new stages for this. LBE
// pockets are now repaired LAST.
//if(UsingNewInventorySystem() == true && bLoop == 0 && bPocket>SECONDHANDPOS && bPocket<GUNSLINGPOCKPOS)
// continue;
//if(UsingNewInventorySystem() == true && bLoop == 1 && bPocket==SECONDHANDPOS)
// continue;
pObj = &(pSoldier->inv[ bPocket ]);
if ( RepairObject( pSoldier, pSoldier, pObj, &ubRepairPtsLeft ) )
@@ -3693,7 +3722,17 @@ void HandleTrainingInSector( INT16 sMapX, INT16 sMapY, INT8 bZ )
}
// now finally train the grunt
TrainSoldierWithPts( pStudent, sTotalTrainingPts );
// HEADROCK HAM B2.8: A new trainer/student synch system allows students to rest while
// their trainer is asleep. If this happens, the student should not train on their own!
if (gGameExternalOptions.ubSmartTrainingRest == 0 || gGameExternalOptions.ubSmartTrainingRest == 2)
{
TrainSoldierWithPts( pStudent, sTotalTrainingPts );
}
else if ( pTrainer != NULL )
{
// This only occurs if at least one trainer is awake.
TrainSoldierWithPts( pStudent, sTotalTrainingPts );
}
}
}
}
@@ -5587,13 +5626,17 @@ void MakeSureToolKitIsInHand( SOLDIERTYPE *pSoldier )
{
if( Item[pSoldier->inv[ bPocket ].usItem].toolkit )
{
// If the second hand is empty, swap item in first hand there
if (pSoldier->inv[HANDPOS].exists() &&
!pSoldier->inv[SECONDHANDPOS].exists() &&
CanItemFitInPosition(pSoldier, &pSoldier->inv[SECONDHANDPOS], HANDPOS, FALSE)) {
SwapObjs( pSoldier, HANDPOS, SECONDHANDPOS, TRUE );
}
if(!CanItemFitInPosition(pSoldier, &pSoldier->inv[HANDPOS], bPocket, FALSE))
// HEADROCK HAM B2.8: These new conditions will create a bias for swapping an item out of
// our hand.
//If the second hand is free, the item will go to the SECONDHANDPOS while the toolkit
// goes into the HANDPOS
if( Item[pSoldier->inv[HANDPOS].usItem].usItemClass & (IC_WEAPON | IC_PUNCH) && !pSoldier->inv[SECONDHANDPOS].exists())
SwapObjs(pSoldier, HANDPOS, SECONDHANDPOS, TRUE);
// Else, if the gun sling slot is free, and the item can go there, it will.
else if(UsingNewInventorySystem() && !pSoldier->inv[GUNSLINGPOCKPOS].exists() && CanItemFitInPosition(pSoldier, &pSoldier->inv[HANDPOS], GUNSLINGPOCKPOS, FALSE))
SwapObjs(pSoldier, HANDPOS, GUNSLINGPOCKPOS, TRUE);
else if(!CanItemFitInPosition(pSoldier, &pSoldier->inv[HANDPOS], bPocket, FALSE))
SwapObjs(pSoldier, HANDPOS, SECONDHANDPOS, TRUE);
SwapObjs( pSoldier, HANDPOS, bPocket, TRUE );
break;
@@ -5623,13 +5666,17 @@ BOOLEAN MakeSureMedKitIsInHand( SOLDIERTYPE *pSoldier )
if ( Item[pSoldier->inv[ bPocket ].usItem].medicalkit )
{
fCharacterInfoPanelDirty = TRUE;
// If the second hand is empty, swap item in first hand there
if (pSoldier->inv[HANDPOS].exists() &&
!pSoldier->inv[SECONDHANDPOS].exists() &&
CanItemFitInPosition(pSoldier, &pSoldier->inv[SECONDHANDPOS], HANDPOS, FALSE)) {
SwapObjs( pSoldier, HANDPOS, SECONDHANDPOS, TRUE );
}
if(!CanItemFitInPosition(pSoldier, &pSoldier->inv[HANDPOS], bPocket, FALSE))
// HEADROCK HAM B2.8: These new conditions will create a bias for swapping an item out of
// our hand.
//If the second hand is free, the item will go to the SECONDHANDPOS while the medikit
// goes into the HANDPOS
if( Item[pSoldier->inv[HANDPOS].usItem].usItemClass & (IC_WEAPON | IC_PUNCH) && !pSoldier->inv[SECONDHANDPOS].exists())
SwapObjs(pSoldier, HANDPOS, SECONDHANDPOS, TRUE);
// Else, if the gun sling slot is free, and the item can go there, it will.
else if(UsingNewInventorySystem() && !pSoldier->inv[GUNSLINGPOCKPOS].exists() && CanItemFitInPosition(pSoldier, &pSoldier->inv[HANDPOS], GUNSLINGPOCKPOS, FALSE))
SwapObjs(pSoldier, HANDPOS, GUNSLINGPOCKPOS, TRUE);
else if(!CanItemFitInPosition(pSoldier, &pSoldier->inv[HANDPOS], bPocket, FALSE))
SwapObjs(pSoldier, HANDPOS, SECONDHANDPOS, TRUE);
SwapObjs( pSoldier, HANDPOS, bPocket, TRUE );
return(TRUE);
@@ -11719,9 +11766,357 @@ BOOLEAN UnjamGunsOnSoldier( SOLDIERTYPE *pOwnerSoldier, SOLDIERTYPE *pRepairSold
return ( fAnyGunsWereUnjammed );
}
// HEADROCK HAM B2.8: A set of functions to synchronize sleeping periods of trainers and trainees
BOOLEAN SetTrainerSleepWhenTraineesSleep( SOLDIERTYPE *pThisTrainee)
{
UINT16 sMapX = pThisTrainee->sSectorX;
UINT16 sMapY = pThisTrainee->sSectorY;
UINT16 sMapZ = pThisTrainee->sZLevel;
UINT8 bStat = pThisTrainee->bTrainStat;
INT32 iCounter, iNumberOnTeam;
SOLDIERTYPE * pOtherTrainee;
SOLDIERTYPE * pTrainer;
BOOLEAN fAllTraineesAsleep = TRUE;
BOOLEAN fTrainersSentToSleep = FALSE;
if (pThisTrainee->bAssignment != TRAIN_BY_OTHER)
{
// Shouldn't happen...
return (FALSE);
}
iNumberOnTeam =gTacticalStatus.Team[ OUR_TEAM ].bLastID;
// Check to see if all other trainees of the same stat are also asleep
for( iCounter = 0; iCounter < iNumberOnTeam; iCounter++ )
{
pOtherTrainee = &Menptr[ iCounter ];
if (pOtherTrainee->bAssignment == TRAIN_BY_OTHER && pOtherTrainee->bTrainStat == pThisTrainee->bTrainStat &&
pOtherTrainee->sSectorX == sMapX && pOtherTrainee->sSectorY == sMapY && pOtherTrainee->sZLevel == sMapZ &&
pOtherTrainee->bActive && !pOtherTrainee->flags.fMercAsleep )
{
// Trainee is present and awake. Flag is reset to false.
fAllTraineesAsleep = FALSE;
}
}
// If they are all asleep
if (fAllTraineesAsleep)
{
// Look for trainers of that stat, in the same sector
for( iCounter = 0; iCounter < iNumberOnTeam; iCounter++ )
{
pTrainer = &Menptr[ iCounter ];
if (pTrainer->bAssignment == TRAIN_TEAMMATE && pTrainer->bTrainStat == pThisTrainee->bTrainStat &&
pTrainer->sSectorX == sMapX && pTrainer->sSectorY == sMapY && pTrainer->sZLevel == sMapZ &&
pTrainer->bActive && !pTrainer->flags.fMercAsleep )
{
// Trainer will go to sleep
if( SetMercAsleep( pTrainer, FALSE ) )
{
if( gGameSettings.fOptions[ TOPTION_SLEEPWAKE_NOTIFICATION ] )
{
// tell player about it
AddSoldierToWaitingListQueue( pTrainer );
}
// seems unnecessary now? ARM
pTrainer->bOldAssignment = pTrainer->bAssignment;
fTrainersSentToSleep = TRUE;
}
}
}
if (fTrainersSentToSleep)
{
return(TRUE);
}
else
{
return(FALSE);
}
}
else
{
return(FALSE);
}
}
BOOLEAN SetTraineesSleepWhenTrainerSleeps( SOLDIERTYPE *pTrainer)
{
UINT16 sMapX = pTrainer->sSectorX;
UINT16 sMapY = pTrainer->sSectorY;
UINT16 sMapZ = pTrainer->sZLevel;
UINT8 bStat = pTrainer->bTrainStat;
INT32 iCounter, iNumberOnTeam;
BOOLEAN fTraineesSentToSleep = FALSE;
SOLDIERTYPE * pTrainee;
if (pTrainer->bAssignment != TRAIN_TEAMMATE)
{
// Shouldn't happen...
return(FALSE);
}
iNumberOnTeam =gTacticalStatus.Team[ OUR_TEAM ].bLastID;
for( iCounter = 0; iCounter < iNumberOnTeam; iCounter++ )
{
pTrainee = &Menptr[ iCounter ];
if (pTrainee->bAssignment == TRAIN_BY_OTHER && pTrainee->bTrainStat == pTrainer->bTrainStat &&
pTrainee->sSectorX == sMapX && pTrainee->sSectorY == sMapY && pTrainee->sZLevel == sMapZ &&
pTrainee->bActive && !pTrainee->flags.fMercAsleep )
{
// Trainee will go to sleep
if( SetMercAsleep( pTrainee, FALSE ) )
{
if( gGameSettings.fOptions[ TOPTION_SLEEPWAKE_NOTIFICATION ] )
{
// tell player about it
AddSoldierToWaitingListQueue( pTrainee );
}
// seems unnecessary now? ARM
pTrainee->bOldAssignment = pTrainee->bAssignment;
fTraineesSentToSleep = TRUE;
}
}
}
if (fTraineesSentToSleep)
{
return(TRUE);
}
else
{
return(FALSE);
}
}
BOOLEAN SetTrainerWakeWhenTraineesWake( SOLDIERTYPE *pThisTrainee)
{
UINT16 sMapX = pThisTrainee->sSectorX;
UINT16 sMapY = pThisTrainee->sSectorY;
UINT16 sMapZ = pThisTrainee->sZLevel;
UINT8 bStat = pThisTrainee->bTrainStat;
INT32 iCounter, iNumberOnTeam;
SOLDIERTYPE * pOtherTrainee;
SOLDIERTYPE * pTrainer;
BOOLEAN fAllTraineesAwake = TRUE;
BOOLEAN fTrainersWokenUp = FALSE;
if (pThisTrainee->bAssignment != TRAIN_BY_OTHER)
{
// Shouldn't happen...
return (FALSE);
}
iNumberOnTeam =gTacticalStatus.Team[ OUR_TEAM ].bLastID;
// Check to see if all other trainees of the same stat are also asleep
for( iCounter = 0; iCounter < iNumberOnTeam; iCounter++ )
{
pOtherTrainee = &Menptr[ iCounter ];
if (pOtherTrainee->bAssignment == TRAIN_BY_OTHER && pOtherTrainee->bTrainStat == pThisTrainee->bTrainStat &&
pOtherTrainee->sSectorX == sMapX && pOtherTrainee->sSectorY == sMapY && pOtherTrainee->sZLevel == sMapZ &&
pOtherTrainee->bActive && pOtherTrainee->flags.fMercAsleep )
{
// Trainee is present and asleep. Flag is reset to FALSE.
fAllTraineesAwake = FALSE;
}
}
// If they are all awake
if (fAllTraineesAwake)
{
// Look for trainers of that stat, in the same sector
for( iCounter = 0; iCounter < iNumberOnTeam; iCounter++ )
{
pTrainer = &Menptr[ iCounter ];
if (pTrainer->bAssignment == TRAIN_TEAMMATE && pTrainer->bTrainStat == pThisTrainee->bTrainStat &&
pTrainer->sSectorX == sMapX && pTrainer->sSectorY == sMapY && pTrainer->sZLevel == sMapZ &&
pTrainer->bActive && pTrainer->flags.fMercAsleep )
{
// Trainer will wake up
if( SetMercAwake( pTrainer, FALSE, FALSE ) )
{
if( gGameSettings.fOptions[ TOPTION_SLEEPWAKE_NOTIFICATION ] )
{
// tell player about it
AddSoldierToWaitingListQueue( pTrainer );
}
// seems unnecessary now? ARM
pTrainer->bOldAssignment = pTrainer->bAssignment;
fTrainersWokenUp = TRUE;
}
}
}
if (fTrainersWokenUp)
{
return(TRUE);
}
else
{
return(FALSE);
}
}
else
{
return(FALSE);
}
}
BOOLEAN SetTraineesWakeWhenTrainerWakes( SOLDIERTYPE *pTrainer)
{
UINT16 sMapX = pTrainer->sSectorX;
UINT16 sMapY = pTrainer->sSectorY;
UINT16 sMapZ = pTrainer->sZLevel;
UINT8 bStat = pTrainer->bTrainStat;
INT32 iCounter, iNumberOnTeam;
BOOLEAN fTraineesWokenUp = FALSE;
SOLDIERTYPE * pTrainee;
if (pTrainer->bAssignment != TRAIN_TEAMMATE)
{
// Shouldn't happen...
return(FALSE);
}
iNumberOnTeam =gTacticalStatus.Team[ OUR_TEAM ].bLastID;
for( iCounter = 0; iCounter < iNumberOnTeam; iCounter++ )
{
pTrainee = &Menptr[ iCounter ];
if (pTrainee->bAssignment == TRAIN_BY_OTHER && pTrainee->bTrainStat == pTrainer->bTrainStat &&
pTrainee->sSectorX == sMapX && pTrainee->sSectorY == sMapY && pTrainee->sZLevel == sMapZ &&
pTrainee->bActive && pTrainee->flags.fMercAsleep )
{
// Trainee will wake up
if( SetMercAwake( pTrainee, FALSE, FALSE ) )
{
if( gGameSettings.fOptions[ TOPTION_SLEEPWAKE_NOTIFICATION ] )
{
// tell player about it
AddSoldierToWaitingListQueue( pTrainee );
}
// seems unnecessary now? ARM
pTrainee->bOldAssignment = pTrainee->bAssignment;
fTraineesWokenUp = TRUE;
}
}
}
if (fTraineesWokenUp)
{
return(TRUE);
}
else
{
return(FALSE);
}
}
void HandleTrainingSleepSynchronize( SOLDIERTYPE *pSoldier )
{
// HEADROCK HAM B2.8: Trainees will now go to sleep if the trainer goes to sleep.
if ((gGameExternalOptions.ubSmartTrainingSleep == 1 || gGameExternalOptions.ubSmartTrainingSleep == 2) && pSoldier->bAssignment == TRAIN_TEAMMATE)
{
SetTraineesSleepWhenTrainerSleeps( pSoldier );
}
// HEADROCK HAM B2.8: If this is a trainee, and all other trainees are already asleep, put all trainers to sleep as well.
if ( (gGameExternalOptions.ubSmartTrainingSleep == 1 || gGameExternalOptions.ubSmartTrainingSleep == 3 ) && pSoldier->bAssignment == TRAIN_BY_OTHER)
{
SetTrainerSleepWhenTraineesSleep( pSoldier );
}
}
void HandleTrainingWakeSynchronize( SOLDIERTYPE *pSoldier )
{
// HEADROCK HAM B2.8: Trainees will now go to sleep if the trainer goes to sleep.
if ((gGameExternalOptions.ubSmartTrainingWake == 1 || gGameExternalOptions.ubSmartTrainingWake == 2) && pSoldier->bAssignment == TRAIN_TEAMMATE)
{
SetTraineesWakeWhenTrainerWakes( pSoldier );
}
// HEADROCK HAM B2.8: If this is a trainee, and all other trainees are already asleep, put all trainers to sleep as well.
if ( (gGameExternalOptions.ubSmartTrainingWake == 1 || gGameExternalOptions.ubSmartTrainingWake == 3 ) && pSoldier->bAssignment == TRAIN_BY_OTHER)
{
SetTrainerWakeWhenTraineesWake( pSoldier );
}
}
BOOLEAN FindAnyAwakeTrainers( SOLDIERTYPE *pTrainee )
{
UINT16 sMapX = pTrainee->sSectorX;
UINT16 sMapY = pTrainee->sSectorY;
UINT16 sMapZ = pTrainee->sZLevel;
UINT8 bStat = pTrainee->bTrainStat;
INT32 iCounter, iNumberOnTeam;
BOOLEAN fAllTrainersAsleep = TRUE;
SOLDIERTYPE * pTrainer;
if (pTrainee->bAssignment != TRAIN_BY_OTHER)
{
// Shouldn't happen...
return(FALSE);
}
iNumberOnTeam =gTacticalStatus.Team[ OUR_TEAM ].bLastID;
for( iCounter = 0; iCounter < iNumberOnTeam; iCounter++ )
{
pTrainer = &Menptr[ iCounter ];
if (pTrainer->bAssignment == TRAIN_TEAMMATE && pTrainer->bTrainStat == pTrainee->bTrainStat &&
pTrainer->sSectorX == sMapX && pTrainer->sSectorY == sMapY && pTrainer->sZLevel == sMapZ &&
pTrainer->bActive && !pTrainer->flags.fMercAsleep )
{
fAllTrainersAsleep = FALSE;
}
}
return(fAllTrainersAsleep);
}
BOOLEAN FindAnyAwakeTrainees( SOLDIERTYPE *pTrainer )
{
UINT16 sMapX = pTrainer->sSectorX;
UINT16 sMapY = pTrainer->sSectorY;
UINT16 sMapZ = pTrainer->sZLevel;
UINT8 bStat = pTrainer->bTrainStat;
INT32 iCounter, iNumberOnTeam;
BOOLEAN fAllTraineesAsleep = TRUE;
SOLDIERTYPE * pTrainee;
if (pTrainer->bAssignment != TRAIN_TEAMMATE)
{
// Shouldn't happen...
return(FALSE);
}
iNumberOnTeam =gTacticalStatus.Team[ OUR_TEAM ].bLastID;
for( iCounter = 0; iCounter < iNumberOnTeam; iCounter++ )
{
pTrainee = &Menptr[ iCounter ];
if (pTrainee->bAssignment == TRAIN_BY_OTHER && pTrainee->bTrainStat == pTrainer->bTrainStat &&
pTrainee->sSectorX == sMapX && pTrainee->sSectorY == sMapY && pTrainee->sZLevel == sMapZ &&
pTrainee->bActive && !pTrainee->flags.fMercAsleep )
{
fAllTraineesAsleep = FALSE;
}
}
return(fAllTraineesAsleep);
}
+9
View File
@@ -324,6 +324,15 @@ void UnEscortEPC( SOLDIERTYPE *pSoldier );
SOLDIERTYPE *AnyDoctorWhoCanHealThisPatient( SOLDIERTYPE *pPatient, BOOLEAN fThisHour );
// HEADROCK HAM B2.8: A set of functions to synchronize sleeping periods of trainers and trainees
BOOLEAN SetTrainerSleepWhenTraineesSleep( SOLDIERTYPE *pTrainee);
BOOLEAN SetTraineesSleepWhenTrainerSleeps( SOLDIERTYPE *pTrainer );
BOOLEAN SetTrainerWakeWhenTraineesWake( SOLDIERTYPE *pTrainee );
BOOLEAN SetTraineesWakeWhenTrainerWakes( SOLDIERTYPE *pTrainer );
void HandleTrainingSleepSynchronize( SOLDIERTYPE *pSoldier );
void HandleTrainingWakeSynchronize( SOLDIERTYPE *pSoldier );
BOOLEAN FindAnyAwakeTrainers( SOLDIERTYPE *pTrainee );
BOOLEAN FindAnyAwakeTrainees( SOLDIERTYPE *pTrainer );
#endif
+2 -2
View File
@@ -4007,7 +4007,7 @@ void AttackTarget( SOLDIERCELL *pAttacker, SOLDIERCELL *pTarget )
pAttacker->uiFlags |= CELL_FIREDATTARGET | CELL_DIRTY;
if( pAttacker->usAttack < 950 )
usAttack = (UINT16)(pAttacker->usAttack + PreRandom(2000 - pAttacker->usAttack ));
usAttack = (UINT16)(pAttacker->usAttack + PreRandom((INT16)(gGameExternalOptions.iAutoResolveLuckFactor*1000.0) - pAttacker->usAttack ));
else
usAttack = (UINT16)(950 + PreRandom( 50 ));
if( pTarget->uiFlags & CELL_RETREATING && !(pAttacker->uiFlags & CELL_FEMALECREATURE) )
@@ -4016,7 +4016,7 @@ void AttackTarget( SOLDIERCELL *pAttacker, SOLDIERCELL *pTarget )
usAttack = usAttack * 7 / 10;
}
if( pTarget->usDefence < 950 )
usDefence = (UINT16)(pTarget->usDefence + PreRandom(2000 - pTarget->usDefence ));
usDefence = (UINT16)(pTarget->usDefence + PreRandom((INT16)(gGameExternalOptions.iAutoResolveLuckFactor*1000.0) - pTarget->usDefence ));
else
usDefence = (UINT16)(950 + PreRandom( 50 ));
if( pAttacker->uiFlags & CELL_FEMALECREATURE )
+760 -65
View File
@@ -66,6 +66,10 @@
INT32 iRestrictedSectorArraySize;
UINT32 gRestrictMilitia[256];
// HEADROCK HAM B1: Alternate array keeps track of dynamically unrestricted sectors
BOOLEAN gDynamicRestrictMilitia[ 256 ];
// HEADROCK HAM B1: Function that dynamically unrestricts sectors as we take over towns.
extern void AdjustRoamingRestrictions();
UINT8 gpAttackDirs[5][4]; // 0. Green Militia 1. Regular Militia 2. Elite Militia 3. Insertion code
UINT8 guiDirNumber = 0;
@@ -143,9 +147,41 @@ void GenerateMilitiaSquad(INT16 sMapX, INT16 sMapY, INT16 sTMapX, INT16 sTMapY )
{
SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR( sMapX, sMapY ) ] );
StrategicAddMilitiaToSector( sTMapX, sTMapY, GREEN_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ GREEN_MILITIA ] / gGameExternalOptions.guiDivOfOriginalMilitia);
StrategicAddMilitiaToSector( sTMapX, sTMapY, REGULAR_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] / gGameExternalOptions.guiDivOfOriginalMilitia);
StrategicAddMilitiaToSector( sTMapX, sTMapY, ELITE_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ ELITE_MILITIA ] / gGameExternalOptions.guiDivOfOriginalMilitia);
//HEADROCK HAM B2.7: Track the number of militia at the source.
UINT16 bTotalMilitiaAtSource = pSectorInfo->ubNumberOfCivsAtLevel[ GREEN_MILITIA ] + pSectorInfo->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] + pSectorInfo->ubNumberOfCivsAtLevel[ ELITE_MILITIA ];
UINT8 bTargetGreen, bTargetRegular, bTargetElite;
UINT8 bUpgradePoints;
if (gGameExternalOptions.fDiverseRoamingMilitiaGroups)
{
bTargetRegular = __max(1,bTotalMilitiaAtSource / (gGameExternalOptions.guiDivOfOriginalMilitia * 4));
bTargetElite = __max(1,bTotalMilitiaAtSource / (gGameExternalOptions.guiDivOfOriginalMilitia * 4));
bTargetGreen = (bTotalMilitiaAtSource / gGameExternalOptions.guiDivOfOriginalMilitia) - (bTargetRegular + bTargetElite);
pSectorInfo = &( SectorInfo[ SECTOR( sTMapX, sTMapY ) ] );
// Continue if we're dealing with a full group that isn't full of veterans
if ( CountMilitia(pSectorInfo) >= gGameExternalOptions.guiMaxMilitiaSquadSize && pSectorInfo->ubNumberOfCivsAtLevel[ELITE_MILITIA] < CountMilitia(pSectorInfo) )
{
bUpgradePoints = bTargetGreen + (bTargetRegular * 2);
bTargetElite += __min(bTargetRegular, pSectorInfo->ubNumberOfCivsAtLevel[REGULAR_MILITIA]);
bUpgradePoints -= (__min(bTargetRegular, pSectorInfo->ubNumberOfCivsAtLevel[REGULAR_MILITIA]))*2;
bTargetRegular = bUpgradePoints;
bTargetGreen = 0;
}
// HEADROCK HAM B2.7: Create 1/2 green, 1/4 regular, 1/4 elite.
StrategicAddMilitiaToSector( sTMapX, sTMapY, GREEN_MILITIA, bTargetGreen);
StrategicAddMilitiaToSector( sTMapX, sTMapY, REGULAR_MILITIA, bTargetRegular);
StrategicAddMilitiaToSector( sTMapX, sTMapY, ELITE_MILITIA, bTargetElite);
}
else
{
StrategicAddMilitiaToSector( sTMapX, sTMapY, GREEN_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ GREEN_MILITIA ] / gGameExternalOptions.guiDivOfOriginalMilitia);
StrategicAddMilitiaToSector( sTMapX, sTMapY, REGULAR_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] / gGameExternalOptions.guiDivOfOriginalMilitia);
StrategicAddMilitiaToSector( sTMapX, sTMapY, ELITE_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ ELITE_MILITIA ] / gGameExternalOptions.guiDivOfOriginalMilitia);
}
pSectorInfo = &( SectorInfo[ SECTOR( sTMapX, sTMapY ) ] );
@@ -178,13 +214,145 @@ void MoveMilitiaSquad(INT16 sMapX, INT16 sMapY, INT16 sTMapX, INT16 sTMapY, BOOL
SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR( sMapX, sMapY ) ] );
SECTORINFO *pTSectorInfo = &( SectorInfo[ SECTOR( sTMapX, sTMapY ) ] );
StrategicAddMilitiaToSector( sTMapX, sTMapY, GREEN_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ GREEN_MILITIA ] );
StrategicAddMilitiaToSector( sTMapX, sTMapY, REGULAR_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] );
StrategicAddMilitiaToSector( sTMapX, sTMapY, ELITE_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ ELITE_MILITIA ] );
UINT8 bGreensSourceTeam = 0, bGreensDestTeam = 0;
UINT8 bRegularsSourceTeam = 0, bRegularsDestTeam = 0;
UINT8 bElitesSourceTeam = 0, bElitesDestTeam = 0;
UINT8 bTotalGreens = 0, bTotalRegulars = 0, bTotalElites = 0;
UINT8 bTotalGreensPercent = 0, bTotalRegularsPercent = 0, bTotalElitesPercent = 0;
INT8 bNewSourceGroupSize = 0, bNewDestGroupSize = 0, bGroupSizeRatio = 0;
StrategicRemoveMilitiaFromSector( sMapX, sMapY, GREEN_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ GREEN_MILITIA ] );
StrategicRemoveMilitiaFromSector( sMapX, sMapY, REGULAR_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] );
StrategicRemoveMilitiaFromSector( sMapX, sMapY, ELITE_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ ELITE_MILITIA ] );
// HEADROCK HAM B2.8
// There are now several methods of militia join-up.
if (PreRandom(100) < gGameExternalOptions.ubRoamingMilitiaSpreadsOutChance)
{
// Militia will attempt to spread out, averaging the size and composition of both groups.
if ( CountMilitia(pSectorInfo) && CountMilitia(pTSectorInfo) )
{
bGreensSourceTeam = pSectorInfo->ubNumberOfCivsAtLevel[ GREEN_MILITIA ];
bGreensDestTeam = pTSectorInfo->ubNumberOfCivsAtLevel[ GREEN_MILITIA ];
bRegularsSourceTeam = pSectorInfo->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ];
bRegularsDestTeam = pTSectorInfo->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ];
bElitesSourceTeam = pSectorInfo->ubNumberOfCivsAtLevel[ ELITE_MILITIA ];
bElitesDestTeam = pTSectorInfo->ubNumberOfCivsAtLevel[ ELITE_MILITIA ];
bTotalGreens = bGreensSourceTeam + bGreensDestTeam;
bTotalRegulars = bRegularsSourceTeam + bRegularsDestTeam;
bTotalElites = bElitesSourceTeam + bElitesDestTeam;
// Source team gets half of each group, rounded down
bGreensSourceTeam = bTotalGreens / 2;
bRegularsSourceTeam = bTotalRegulars / 2;
bElitesSourceTeam = bTotalElites / 2;
// Destination team gets half of each group, rounded up
bGreensDestTeam = bTotalGreens - bGreensSourceTeam;
bRegularsDestTeam = bTotalRegulars - bRegularsSourceTeam;
bElitesDestTeam = bTotalElites - bElitesSourceTeam;
// Erase ALL militia from both locations.
StrategicRemoveMilitiaFromSector( sMapX, sMapY, GREEN_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ GREEN_MILITIA ] );
StrategicRemoveMilitiaFromSector( sMapX, sMapY, REGULAR_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] );
StrategicRemoveMilitiaFromSector( sMapX, sMapY, ELITE_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ ELITE_MILITIA ] );
StrategicRemoveMilitiaFromSector( sTMapX, sTMapY, GREEN_MILITIA, pTSectorInfo->ubNumberOfCivsAtLevel[ GREEN_MILITIA ] );
StrategicRemoveMilitiaFromSector( sTMapX, sTMapY, REGULAR_MILITIA, pTSectorInfo->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] );
StrategicRemoveMilitiaFromSector( sTMapX, sTMapY, ELITE_MILITIA, pTSectorInfo->ubNumberOfCivsAtLevel[ ELITE_MILITIA ] );
// Add new militia.
StrategicAddMilitiaToSector( sMapX, sMapY, GREEN_MILITIA, bGreensSourceTeam );
StrategicAddMilitiaToSector( sMapX, sMapY, REGULAR_MILITIA, bRegularsSourceTeam );
StrategicAddMilitiaToSector( sMapX, sMapY, ELITE_MILITIA, bElitesSourceTeam );
StrategicAddMilitiaToSector( sTMapX, sTMapY, GREEN_MILITIA, bGreensDestTeam );
StrategicAddMilitiaToSector( sTMapX, sTMapY, REGULAR_MILITIA, bRegularsDestTeam );
StrategicAddMilitiaToSector( sTMapX, sTMapY, ELITE_MILITIA, bElitesDestTeam );
}
else
{
StrategicAddMilitiaToSector( sTMapX, sTMapY, GREEN_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ GREEN_MILITIA ] );
StrategicAddMilitiaToSector( sTMapX, sTMapY, REGULAR_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] );
StrategicAddMilitiaToSector( sTMapX, sTMapY, ELITE_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ ELITE_MILITIA ] );
StrategicRemoveMilitiaFromSector( sMapX, sMapY, GREEN_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ GREEN_MILITIA ] );
StrategicRemoveMilitiaFromSector( sMapX, sMapY, REGULAR_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] );
StrategicRemoveMilitiaFromSector( sMapX, sMapY, ELITE_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ ELITE_MILITIA ] );
}
}
else
{
if ( gGameExternalOptions.fDiverseRoamingMilitiaGroups )
{
// Diverse Militia Join-up: Destination team gets as many troops as possible, but both teams
// keep an averaged green-regular-elite ratio.
bNewDestGroupSize = __min((CountMilitia(pTSectorInfo) + CountMilitia(pSectorInfo)), (UINT8)gGameExternalOptions.guiMaxMilitiaSquadSize);
bNewSourceGroupSize = __max(0,(CountMilitia(pTSectorInfo) + CountMilitia(pSectorInfo)) - gGameExternalOptions.guiMaxMilitiaSquadSize);
// If there are still going to be two teams after the transfer
if ( bNewSourceGroupSize > 0 )
{
bGreensSourceTeam = pSectorInfo->ubNumberOfCivsAtLevel[ GREEN_MILITIA ];
bGreensDestTeam = pTSectorInfo->ubNumberOfCivsAtLevel[ GREEN_MILITIA ];
bRegularsSourceTeam = pSectorInfo->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ];
bRegularsDestTeam = pTSectorInfo->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ];
bElitesSourceTeam = pSectorInfo->ubNumberOfCivsAtLevel[ ELITE_MILITIA ];
bElitesDestTeam = pTSectorInfo->ubNumberOfCivsAtLevel[ ELITE_MILITIA ];
bTotalGreens = bGreensSourceTeam + bGreensDestTeam;
bTotalRegulars = bRegularsSourceTeam + bRegularsDestTeam;
bTotalElites = bElitesSourceTeam + bElitesDestTeam;
bGroupSizeRatio = __max(1,(bNewDestGroupSize / bNewSourceGroupSize));
// Destination team gets the majority of troops (based on the ratios),
// but will always leave at least 1 troop of each type (if available) for the source team
bGreensDestTeam = __min(__min(bTotalGreens, ((bTotalGreens * bGroupSizeRatio) / (bGroupSizeRatio + 1) +1) ), __max(0,bTotalGreens-1));
bRegularsDestTeam = __min(__min(bTotalRegulars, ((bTotalRegulars * bGroupSizeRatio) / (bGroupSizeRatio + 1) +1) ), __max(0,bTotalRegulars-1));
bElitesDestTeam = __min(__min(bTotalElites, ((bTotalElites * bGroupSizeRatio) / (bGroupSizeRatio + 1) +1) ), __max(0,bTotalElites-1));
// Source team gets the remainder (no less than one troop of each type, if available)
bGreensSourceTeam = bTotalGreens - bGreensDestTeam;
bRegularsSourceTeam = bTotalRegulars - bRegularsDestTeam;
bElitesSourceTeam = bTotalElites - bElitesDestTeam;
// Erase ALL militia from both locations.
StrategicRemoveMilitiaFromSector( sMapX, sMapY, GREEN_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ GREEN_MILITIA ] );
StrategicRemoveMilitiaFromSector( sMapX, sMapY, REGULAR_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] );
StrategicRemoveMilitiaFromSector( sMapX, sMapY, ELITE_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ ELITE_MILITIA ] );
StrategicRemoveMilitiaFromSector( sTMapX, sTMapY, GREEN_MILITIA, pTSectorInfo->ubNumberOfCivsAtLevel[ GREEN_MILITIA ] );
StrategicRemoveMilitiaFromSector( sTMapX, sTMapY, REGULAR_MILITIA, pTSectorInfo->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] );
StrategicRemoveMilitiaFromSector( sTMapX, sTMapY, ELITE_MILITIA, pTSectorInfo->ubNumberOfCivsAtLevel[ ELITE_MILITIA ] );
// Add new militia.
StrategicAddMilitiaToSector( sMapX, sMapY, GREEN_MILITIA, bGreensSourceTeam );
StrategicAddMilitiaToSector( sMapX, sMapY, REGULAR_MILITIA, bRegularsSourceTeam );
StrategicAddMilitiaToSector( sMapX, sMapY, ELITE_MILITIA, bElitesSourceTeam );
StrategicAddMilitiaToSector( sTMapX, sTMapY, GREEN_MILITIA, bGreensDestTeam );
StrategicAddMilitiaToSector( sTMapX, sTMapY, REGULAR_MILITIA, bRegularsDestTeam );
StrategicAddMilitiaToSector( sTMapX, sTMapY, ELITE_MILITIA, bElitesDestTeam );
}
else
{
// Move all militia from source to destination.
StrategicAddMilitiaToSector( sTMapX, sTMapY, GREEN_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ GREEN_MILITIA ] );
StrategicAddMilitiaToSector( sTMapX, sTMapY, REGULAR_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] );
StrategicAddMilitiaToSector( sTMapX, sTMapY, ELITE_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ ELITE_MILITIA ] );
StrategicRemoveMilitiaFromSector( sMapX, sMapY, GREEN_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ GREEN_MILITIA ] );
StrategicRemoveMilitiaFromSector( sMapX, sMapY, REGULAR_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] );
StrategicRemoveMilitiaFromSector( sMapX, sMapY, ELITE_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ ELITE_MILITIA ] );
}
}
else
{
// normal join-up. Destination group gets all the best militia. Source team gets the leftovers.
StrategicAddMilitiaToSector( sTMapX, sTMapY, GREEN_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ GREEN_MILITIA ] );
StrategicAddMilitiaToSector( sTMapX, sTMapY, REGULAR_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] );
StrategicAddMilitiaToSector( sTMapX, sTMapY, ELITE_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ ELITE_MILITIA ] );
StrategicRemoveMilitiaFromSector( sMapX, sMapY, GREEN_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ GREEN_MILITIA ] );
StrategicRemoveMilitiaFromSector( sMapX, sMapY, REGULAR_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] );
StrategicRemoveMilitiaFromSector( sMapX, sMapY, ELITE_MILITIA, pSectorInfo->ubNumberOfCivsAtLevel[ ELITE_MILITIA ] );
}
}
while( !fAlternativeMax && CountMilitia(pTSectorInfo) > gGameExternalOptions.guiMaxMilitiaSquadSize ||
fAlternativeMax && CountMilitia(pTSectorInfo) > gGameExternalOptions.guiMaxMilitiaSquadSizeBattle )
@@ -362,12 +530,40 @@ UINT16 CountDirectionRating( INT16 sMapX, INT16 sMapY, UINT8 uiDir )
BOOLEAN CheckStandardConditionsForDirection( INT16 sSMapX, INT16 sSMapY, INT16 sMapX, INT16 sMapY, BOOLEAN fWithCities, BOOLEAN fForBattle, BOOLEAN fOnlyCitySectors )
{
UINT8 uiTravab = GetTraversability( SECTOR( sSMapX , sSMapY ) , SECTOR( sMapX, sMapY ) );
BOOLEAN fTargetCityAllowsRoaming;
if( uiTravab == GROUNDBARRIER || uiTravab == EDGEOFWORLD ) return FALSE;
if( !fForBattle && gfMSBattle && NumEnemiesInSector( sMapX, sMapY ) ) return FALSE;
return (GetTownIdForSector( sMapX, sMapY ) == BLANK_SECTOR || fWithCities) && !IsThisSectorASAMSector( sMapX, sMapY , 0 ) &&
// HEADROCK HAM B2.7 : This allows roaming militia to move into Minor City sectors, if liberated at least
// once before
if (GetTownIdForSector( sMapX, sMapY ) == BLANK_SECTOR)
{
fTargetCityAllowsRoaming = TRUE;
}
else
{
if (gGameExternalOptions.fAllowMilitiaMoveThroughMinorCities)
{
if ( SectorInfo[SECTOR( sMapX, sMapY )].fSurfaceWasEverPlayerControlled )
{
fTargetCityAllowsRoaming = ( !gfMilitiaAllowedInTown[GetTownIdForSector( sMapX, sMapY )] );
}
else
{
fTargetCityAllowsRoaming = FALSE;
}
}
else
{
fTargetCityAllowsRoaming = FALSE;
}
}
//return (GetTownIdForSector( sMapX, sMapY ) == BLANK_SECTOR || fWithCities) && !IsThisSectorASAMSector( sMapX, sMapY , 0 ) &&
// (GetTownIdForSector( sMapX, sMapY ) != BLANK_SECTOR || !fOnlyCitySectors);// &&
return (fTargetCityAllowsRoaming || fWithCities) && !IsThisSectorASAMSector( sMapX, sMapY , 0 ) &&
(GetTownIdForSector( sMapX, sMapY ) != BLANK_SECTOR || !fOnlyCitySectors);// &&
// ( !NumEnemiesInSector( sMapX, sMapY ) || GetEnemyGroupIdInSector(sMapX, sMapY ) || fForBattle ) &&
// ( fForBattle || CountAllMilitiaInSector( sMapX, sMapY ) < gGameExternalOptions.guiMaxMilitiaSquadSize || PlayerMercsInSector( sMapX, sMapY, 0 ) )
@@ -482,6 +678,7 @@ void UpdateMilitiaSquads(INT16 sMapX, INT16 sMapY )
UINT8 x;//,y;
SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR( sMapX, sMapY ) ] );
UINT8 uiMilitiaCount;
BOOLEAN fSourceCityAllowsRoaming;
// If we don't want roaming militia
@@ -521,9 +718,14 @@ void UpdateMilitiaSquads(INT16 sMapX, INT16 sMapY )
}
}
// HEADROCK HAM B2.7: If INI flag is set, allow militia to move out of Minor City sectors (Orta, Tixa, San Mona, etc).
if (gGameExternalOptions.fAllowMilitiaMoveThroughMinorCities)
fSourceCityAllowsRoaming = ( !gfMilitiaAllowedInTown[GetTownIdForSector( sMapX, sMapY )] );
else
fSourceCityAllowsRoaming = ( GetTownIdForSector( sMapX, sMapY ) == BLANK_SECTOR );
// moving squad, if it is not a SAM site
if( ( GetTownIdForSector( sMapX, sMapY ) == BLANK_SECTOR ) && (!IsThisSectorASAMSector( sMapX, sMapY, 0 )) )
if( ( fSourceCityAllowsRoaming ) && (!IsThisSectorASAMSector( sMapX, sMapY, 0 )) )
{
if( !PlayerMercsInSector_MSE( (UINT8)sMapX, (UINT8)sMapY, FALSE ) ) // and there's no player's mercs in the sector
{
@@ -559,13 +761,74 @@ void UpdateMilitiaSquads(INT16 sMapX, INT16 sMapY )
//Kaiden: if Restricted Sectors List option is turned on,
// militia can't move to any sectors in the list.
// Unless they are following a group of mercs.
///////////////////////////////////////////////////////////////////
// HEADROCK HAM B1: Restrict roamers by XML as normal, but also
// allow them to move through visited sectors.
// Also, there's an option now to use dynamic restriction. The
// AdjustRoamingRestrictions() function is used to dynamically
// define which sectors are restricted, based on city conquest.
///////////////////////////////////////////////////////////////////
if (gGameExternalOptions.gflimitedRoaming)
for (INT32 i=0;i<iRestrictedSectorArraySize; ++i)
{
// Is militia allowed to move through visited sectors?
if (gGameExternalOptions.bUnrestrictVisited)
{
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("RestrictedSectors, %d", gRestrictMilitia[i]));
if(pMoveDir[iRandomRes][0] == gRestrictMilitia[i])
return;
// Scan each sector restricted in the XML.
for (INT32 i=0;i<iRestrictedSectorArraySize; ++i)
{
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("RestrictedSectors, %d", gRestrictMilitia[i]));
// If sector isn't explored yet
if ( SectorInfo[ pMoveDir[iRandomRes][0] ].fSurfaceWasEverPlayerControlled == 0 )
{
// Is militia allowed to move through dynamically defined sectors?
if (gGameExternalOptions.bDynamicRestrictRoaming)
{
// Is destination allowed by Dynamic Array?
if( !gDynamicRestrictMilitia[pMoveDir[iRandomRes][0]] )
{
return;
}
}
// Militia limited to XMLized sectors
else
{
// Is destination allowed by XML?
if(pMoveDir[iRandomRes][0] == gRestrictMilitia[i] )
{
return;
}
}
}
}
}
// Militia must adhere to restrictions, regardless of visited sectors
else
{
for (INT32 i=0;i<iRestrictedSectorArraySize; ++i)
{
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("RestrictedSectors, %d", gRestrictMilitia[i]));
// Is militia allowed to move through dynamically defined sectors?
if (gGameExternalOptions.bDynamicRestrictRoaming)
{
// Is destination allowed by Dynamic Array?
if( !gDynamicRestrictMilitia[pMoveDir[iRandomRes][0]] )
{
return;
}
}
// Militia limited to XMLized sectors
else
{
// Is destination allowed by XML?
if(pMoveDir[iRandomRes][0] == gRestrictMilitia[i] )
{
return;
}
}
}
}
}
// WDS bug fix for moving militia
int targetX = SECTORX( pMoveDir[ iRandomRes ][0] );
@@ -622,6 +885,11 @@ void CreateMilitiaSquads(INT16 sMapX, INT16 sMapY )
UINT8 x;//,y;
SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR( sMapX, sMapY ) ] );
UINT8 uiMilitiaCount;
// HEADROCK HAM B2.7: New values:
UINT16 iCounter;
BOOLEAN fFoundValidSector;
UINT16 bTownId;
INT16 sCurrentX, sCurrentY;
// If we're not allowing roaming groups,
@@ -649,68 +917,139 @@ void CreateMilitiaSquads(INT16 sMapX, INT16 sMapY )
// Create new Militia Squad
if( GetTownIdForSector( sMapX, sMapY ) != BLANK_SECTOR )
bTownId = GetTownIdForSector( sMapX, sMapY );
if( bTownId != BLANK_SECTOR )
{
fFoundValidSector = FALSE;
// Check all sectors adjacent to the training sector itself.
GenerateDirectionInfosWithCapacityCheck( sMapX, sMapY, &uiDirNumber, pMoveDir, FALSE, FALSE, FALSE );
if(uiDirNumber)// && Random(100) < CHANCE_TO_GENERATE_A_SQUAD)
{
GenerateDirectionInfos( sMapX, sMapY, &uiDirNumber, pMoveDir, FALSE, FALSE, FALSE );
for( x = 1; x < uiDirNumber ; ++x )pMoveDir[x][1] += pMoveDir[x-1][1];
if(uiDirNumber)// && Random(100) < CHANCE_TO_GENERATE_A_SQUAD)
{
for( x = 1; x < uiDirNumber ; ++x )pMoveDir[x][1] += pMoveDir[x-1][1];
iRandomRes = Random( pMoveDir[ uiDirNumber - 1 ][1] );
iRandomRes = Random( pMoveDir[ uiDirNumber - 1 ][1] );
for( x = 0; x < uiDirNumber; ++x)
if( iRandomRes < pMoveDir[x][1] )
{
iRandomRes = x;
break;
}
// shouldn't be!
if(iRandomRes >= uiDirNumber)iRandomRes = 0;
//ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%ld,%ld:Dir count %ld, Rand %ld. Go to %ld,%ld", sMapX, sMapY, uiDirNumber, iRandomRes, SECTORX( pMoveDir[ iRandomRes ][0] ), SECTORY( pMoveDir[ iRandomRes ][0] ));
GenerateMilitiaSquad( sMapX, sMapY, SECTORX( pMoveDir[ iRandomRes ][0] ), SECTORY( pMoveDir[ iRandomRes ][0] ) );
AddToBlockMoveList( SECTORX( pMoveDir[ iRandomRes ][0] ), SECTORY( pMoveDir[ iRandomRes ][0] ) );
if( NumEnemiesInSector( SECTORX( pMoveDir[ iRandomRes ][0] ), SECTORY( pMoveDir[ iRandomRes ][0] ) ) && CountAllMilitiaInSector( SECTORX( pMoveDir[ iRandomRes ][0] ), SECTORY( pMoveDir[ iRandomRes ][0] ) ) )
for( x = 0; x < uiDirNumber; ++x)
if( iRandomRes < pMoveDir[x][1] )
{
/* GROUP* pEnemyGroup = GetGroup( GetEnemyGroupIdInSector( SECTORX( pMoveDir[ iRandomRes ][0] ), SECTORY( pMoveDir[ iRandomRes ][0] ) ) );
if(pEnemyGroup && pEnemyGroup->ubGroupID)
{
//ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Attacking from %ld,%ld to %ld,%ld - enemy's group id %ld", sMapX, sMapY, SECTORX( pMoveDir[ iRandomRes ][0] ), SECTORY( pMoveDir[ iRandomRes ][0], pEnemyGroup->ubGroupID ));
//ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Arrival 1, Arrival 2");
pEnemyGroup->ubPrevX = sMapX;
pEnemyGroup->ubPrevY = sMapY;
pEnemyGroup->ubNextX = SECTORX( pMoveDir[ iRandomRes ][0] );
pEnemyGroup->ubNextY = SECTORY( pMoveDir[ iRandomRes ][0] );
*/
gfMSBattle = TRUE;
// GroupArrivedAtSector( pEnemyGroup->ubGroupID , TRUE, FALSE );
EnterAutoResolveMode( SECTORX( pMoveDir[ iRandomRes ][0] ), SECTORY( pMoveDir[ iRandomRes ][0] ) );
// }
iRandomRes = x;
break;
}
// shouldn't be!
if(iRandomRes >= uiDirNumber)iRandomRes = 0;
//ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%ld,%ld:Dir count %ld, Rand %ld. Go to %ld,%ld", sMapX, sMapY, uiDirNumber, iRandomRes, SECTORX( pMoveDir[ iRandomRes ][0] ), SECTORY( pMoveDir[ iRandomRes ][0] ));
GenerateMilitiaSquad( sMapX, sMapY, SECTORX( pMoveDir[ iRandomRes ][0] ), SECTORY( pMoveDir[ iRandomRes ][0] ) );
fFoundValidSector = TRUE;
AddToBlockMoveList( SECTORX( pMoveDir[ iRandomRes ][0] ), SECTORY( pMoveDir[ iRandomRes ][0] ) );
if( NumEnemiesInSector( SECTORX( pMoveDir[ iRandomRes ][0] ), SECTORY( pMoveDir[ iRandomRes ][0] ) ) && CountAllMilitiaInSector( SECTORX( pMoveDir[ iRandomRes ][0] ), SECTORY( pMoveDir[ iRandomRes ][0] ) ) )
{
/* GROUP* pEnemyGroup = GetGroup( GetEnemyGroupIdInSector( SECTORX( pMoveDir[ iRandomRes ][0] ), SECTORY( pMoveDir[ iRandomRes ][0] ) ) );
if(pEnemyGroup && pEnemyGroup->ubGroupID)
{
//ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Attacking from %ld,%ld to %ld,%ld - enemy's group id %ld", sMapX, sMapY, SECTORX( pMoveDir[ iRandomRes ][0] ), SECTORY( pMoveDir[ iRandomRes ][0], pEnemyGroup->ubGroupID ));
//ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Arrival 1, Arrival 2");
pEnemyGroup->ubPrevX = sMapX;
pEnemyGroup->ubPrevY = sMapY;
pEnemyGroup->ubNextX = SECTORX( pMoveDir[ iRandomRes ][0] );
pEnemyGroup->ubNextY = SECTORY( pMoveDir[ iRandomRes ][0] );
*/
gfMSBattle = TRUE;
// GroupArrivedAtSector( pEnemyGroup->ubGroupID , TRUE, FALSE );
EnterAutoResolveMode( SECTORX( pMoveDir[ iRandomRes ][0] ), SECTORY( pMoveDir[ iRandomRes ][0] ) );
// }
}
else return;
}
// HEADROCK HAM B2.7: Smarter check - looks at each city sector, and checks if there's room around that
// sector to place militia. Also relies on whether the sector has full militia before generating more.
// This section only runs if the program has failed to find suitable sectors around the "home" sector
// (where militia is being trained).
iCounter = 0;
if (gGameExternalOptions.fSmartRoamingMilitiaGenerator)
{
while( pTownNamesList[ iCounter ] != 0 && fFoundValidSector == FALSE )
{
if( pTownNamesList[ iCounter] == bTownId )
{
sCurrentX = GET_X_FROM_STRATEGIC_INDEX( pTownLocationsList[ iCounter ] );
sCurrentY = GET_Y_FROM_STRATEGIC_INDEX( pTownLocationsList[ iCounter ] );
// if sector has enemies or hasn't already been taken at least once, then
if ( !SectorInfo[ SECTOR(sCurrentX, sCurrentY) ].fSurfaceWasEverPlayerControlled || NumEnemiesInSector( sCurrentX, sCurrentY ) > 0 )
{
// skip the rest. Generate no militia from this sector.
iCounter++;
continue;
}
GenerateDirectionInfosWithCapacityCheck( sCurrentX, sCurrentY, &uiDirNumber, pMoveDir, FALSE, TRUE, FALSE );
if(uiDirNumber)// && Random(100) < CHANCE_TO_GENERATE_A_SQUAD)
{
for( x = 1; x < uiDirNumber ; ++x )pMoveDir[x][1] += pMoveDir[x-1][1];
iRandomRes = Random( pMoveDir[ uiDirNumber - 1 ][1] );
for( x = 0; x < uiDirNumber; ++x)
if( iRandomRes < pMoveDir[x][1] )
{
iRandomRes = x;
break;
}
// shouldn't be!
if(iRandomRes >= uiDirNumber)iRandomRes = 0;
//ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%ld,%ld:Dir count %ld, Rand %ld. Go to %ld,%ld", sMapX, sMapY, uiDirNumber, iRandomRes, SECTORX( pMoveDir[ iRandomRes ][0] ), SECTORY( pMoveDir[ iRandomRes ][0] ));
GenerateMilitiaSquad( sCurrentX, sCurrentY, SECTORX( pMoveDir[ iRandomRes ][0] ), SECTORY( pMoveDir[ iRandomRes ][0] ) );
fFoundValidSector = TRUE;
AddToBlockMoveList( SECTORX( pMoveDir[ iRandomRes ][0] ), SECTORY( pMoveDir[ iRandomRes ][0] ) );
if( NumEnemiesInSector( SECTORX( pMoveDir[ iRandomRes ][0] ), SECTORY( pMoveDir[ iRandomRes ][0] ) ) && CountAllMilitiaInSector( SECTORX( pMoveDir[ iRandomRes ][0] ), SECTORY( pMoveDir[ iRandomRes ][0] ) ) )
{
/* GROUP* pEnemyGroup = GetGroup( GetEnemyGroupIdInSector( SECTORX( pMoveDir[ iRandomRes ][0] ), SECTORY( pMoveDir[ iRandomRes ][0] ) ) );
if(pEnemyGroup && pEnemyGroup->ubGroupID)
{
//ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Attacking from %ld,%ld to %ld,%ld - enemy's group id %ld", sMapX, sMapY, SECTORX( pMoveDir[ iRandomRes ][0] ), SECTORY( pMoveDir[ iRandomRes ][0], pEnemyGroup->ubGroupID ));
//ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Arrival 1, Arrival 2");
pEnemyGroup->ubPrevX = sMapX;
pEnemyGroup->ubPrevY = sMapY;
pEnemyGroup->ubNextX = SECTORX( pMoveDir[ iRandomRes ][0] );
pEnemyGroup->ubNextY = SECTORY( pMoveDir[ iRandomRes ][0] );
*/
gfMSBattle = TRUE;
// GroupArrivedAtSector( pEnemyGroup->ubGroupID , TRUE, FALSE );
EnterAutoResolveMode( SECTORX( pMoveDir[ iRandomRes ][0] ), SECTORY( pMoveDir[ iRandomRes ][0] ) );
// }
}
}
}
iCounter++;
}
}
}
return;
}
extern BOOLEAN gfMSResetMilitia;
void DoMilitiaHelpFromAdjacentSectors( INT16 sMapX, INT16 sMapY )
@@ -837,3 +1176,359 @@ void MilitiaFollowPlayer( INT16 sMapX, INT16 sMapY, INT16 sDMapX, INT16 sDMapY )
MoveMilitiaSquad( sMapX, sMapY, sDMapX, sDMapY, FALSE );
}
// HEADROCK (HAM): New function to alter Restricted Roaming based on the recent capture of new towns. The area
// around the town will be unrestricted, as well as some road sectors leading away from the town.
// This function runs during sector conquest checks, and only if an entire town has been conquered. It also
// runs at day end, as well as on load/save.
void AdjustRoamingRestrictions()
{
if (!gGameExternalOptions.bDynamicRestrictRoaming)
return;
// to do: Add something to clean up the entire array before setting the flags...
if ( IsTownUnderCompleteControlByPlayer(DRASSEN) )
{
// DRASSEN OUTSKIRTS
gDynamicRestrictMilitia[SECTOR(12,1)] = true;
gDynamicRestrictMilitia[SECTOR(13,1)] = true;
gDynamicRestrictMilitia[SECTOR(14,1)] = true;
gDynamicRestrictMilitia[SECTOR(12,2)] = true;
gDynamicRestrictMilitia[SECTOR(14,2)] = true;
gDynamicRestrictMilitia[SECTOR(12,3)] = true;
gDynamicRestrictMilitia[SECTOR(14,3)] = true;
gDynamicRestrictMilitia[SECTOR(12,4)] = true;
gDynamicRestrictMilitia[SECTOR(14,4)] = true;
gDynamicRestrictMilitia[SECTOR(12,5)] = true;
gDynamicRestrictMilitia[SECTOR(13,5)] = true;
gDynamicRestrictMilitia[SECTOR(14,5)] = true;
// SAM SITE DEFENSE
gDynamicRestrictMilitia[SECTOR(15,5)] = true;
// ROAD WEST TO OMERTA
gDynamicRestrictMilitia[SECTOR(9,2)] = true;
gDynamicRestrictMilitia[SECTOR(10,2)] = true;
gDynamicRestrictMilitia[SECTOR(11,2)] = true;
// ROAD SOUTH TO ALMA
gDynamicRestrictMilitia[SECTOR(12,6)] = true;
}
if ( IsTownUnderCompleteControlByPlayer(ALMA) )
{
// ALMA OUTSKIRTS
gDynamicRestrictMilitia[SECTOR(12,7)] = true;
gDynamicRestrictMilitia[SECTOR(13,7)] = true;
gDynamicRestrictMilitia[SECTOR(14,7)] = true;
gDynamicRestrictMilitia[SECTOR(15,7)] = true;
gDynamicRestrictMilitia[SECTOR(12,8)] = true;
gDynamicRestrictMilitia[SECTOR(15,8)] = true;
gDynamicRestrictMilitia[SECTOR(12,9)] = true;
gDynamicRestrictMilitia[SECTOR(15,9)] = true;
gDynamicRestrictMilitia[SECTOR(12,10)] = true;
gDynamicRestrictMilitia[SECTOR(13,10)] = true;
gDynamicRestrictMilitia[SECTOR(14,10)] = true;
gDynamicRestrictMilitia[SECTOR(15,10)] = true;
// ROAD SOUTH
gDynamicRestrictMilitia[SECTOR(14,11)] = true;
}
if ( IsTownUnderCompleteControlByPlayer(CHITZENA) )
{
// CHITZENA OUTSKIRTS
gDynamicRestrictMilitia[SECTOR(1,1)] = true;
gDynamicRestrictMilitia[SECTOR(3,1)] = true;
gDynamicRestrictMilitia[SECTOR(1,2)] = true;
gDynamicRestrictMilitia[SECTOR(3,2)] = true;
gDynamicRestrictMilitia[SECTOR(1,3)] = true;
gDynamicRestrictMilitia[SECTOR(2,3)] = true;
gDynamicRestrictMilitia[SECTOR(3,3)] = true;
// SAM SITE DEFENSE / ROAD SOUTH
gDynamicRestrictMilitia[SECTOR(3,4)] = true;
gDynamicRestrictMilitia[SECTOR(3,5)] = true;
}
if ( IsTownUnderCompleteControlByPlayer(CAMBRIA) )
{
// CAMBRIA OUTSKIRTS
gDynamicRestrictMilitia[SECTOR(7,5)] = true;
gDynamicRestrictMilitia[SECTOR(8,5)] = true;
gDynamicRestrictMilitia[SECTOR(9,5)] = true;
gDynamicRestrictMilitia[SECTOR(10,5)] = true;
gDynamicRestrictMilitia[SECTOR(7,6)] = true;
gDynamicRestrictMilitia[SECTOR(10,6)] = true;
gDynamicRestrictMilitia[SECTOR(7,7)] = true;
gDynamicRestrictMilitia[SECTOR(10,7)] = true;
gDynamicRestrictMilitia[SECTOR(7,8)] = true;
gDynamicRestrictMilitia[SECTOR(9,8)] = true;
gDynamicRestrictMilitia[SECTOR(10,8)] = true;
// SAM SITE DEFENSE
gDynamicRestrictMilitia[SECTOR(7,9)] = true;
gDynamicRestrictMilitia[SECTOR(9,9)] = true;
// ROAD TO OMERTA
gDynamicRestrictMilitia[SECTOR(9,2)] = true;
gDynamicRestrictMilitia[SECTOR(9,3)] = true;
gDynamicRestrictMilitia[SECTOR(9,4)] = true;
// CROSSROADS WEST
gDynamicRestrictMilitia[SECTOR(6,7)] = true;
// ROAD TO ALMA
gDynamicRestrictMilitia[SECTOR(11,7)] = true;
}
if ( IsTownUnderCompleteControlByPlayer(BALIME) )
{
// BALIME OUTSKIRTS
gDynamicRestrictMilitia[SECTOR(10,11)] = true;
gDynamicRestrictMilitia[SECTOR(11,11)] = true;
gDynamicRestrictMilitia[SECTOR(12,11)] = true;
gDynamicRestrictMilitia[SECTOR(13,11)] = true;
gDynamicRestrictMilitia[SECTOR(10,12)] = true;
gDynamicRestrictMilitia[SECTOR(13,12)] = true;
gDynamicRestrictMilitia[SECTOR(10,13)] = true;
gDynamicRestrictMilitia[SECTOR(13,13)] = true;
// WEST ROAD
gDynamicRestrictMilitia[SECTOR(6,11)] = true;
gDynamicRestrictMilitia[SECTOR(7,11)] = true;
gDynamicRestrictMilitia[SECTOR(8,11)] = true;
gDynamicRestrictMilitia[SECTOR(9,11)] = true;
// SOUTH ROAD
gDynamicRestrictMilitia[SECTOR(8,14)] = true;
gDynamicRestrictMilitia[SECTOR(9,14)] = true;
gDynamicRestrictMilitia[SECTOR(10,14)] = true;
}
if ( IsTownUnderCompleteControlByPlayer(GRUMM) )
{
// GRUMM OUTSKIRTS
gDynamicRestrictMilitia[SECTOR(1,6)] = true;
gDynamicRestrictMilitia[SECTOR(2,6)] = true;
gDynamicRestrictMilitia[SECTOR(3,6)] = true;
gDynamicRestrictMilitia[SECTOR(3,7)] = true;
gDynamicRestrictMilitia[SECTOR(4,7)] = true;
gDynamicRestrictMilitia[SECTOR(4,8)] = true;
gDynamicRestrictMilitia[SECTOR(3,9)] = true;
gDynamicRestrictMilitia[SECTOR(4,9)] = true;
// ROAD NORTH
gDynamicRestrictMilitia[SECTOR(3,5)] = true;
gDynamicRestrictMilitia[SECTOR(3,4)] = true;
// ROAD EAST
gDynamicRestrictMilitia[SECTOR(5,7)] = true;
gDynamicRestrictMilitia[SECTOR(6,7)] = true;
// ROAD SOUTH
gDynamicRestrictMilitia[SECTOR(2,10)] = true;
gDynamicRestrictMilitia[SECTOR(3,10)] = true;
gDynamicRestrictMilitia[SECTOR(2,11)] = true;
}
if ( IsTownUnderCompleteControlByPlayer(DRASSEN) && IsTownUnderCompleteControlByPlayer(CHITZENA) )
{
// ROAD EAST OF SAN-MONA
gDynamicRestrictMilitia[SECTOR(7,3)] = true;
gDynamicRestrictMilitia[SECTOR(8,3)] = true;
gDynamicRestrictMilitia[SECTOR(9,3)] = true;
// SAN MONA
gDynamicRestrictMilitia[SECTOR(5,3)] = true;
gDynamicRestrictMilitia[SECTOR(6,3)] = true;
gDynamicRestrictMilitia[SECTOR(4,4)] = true;
gDynamicRestrictMilitia[SECTOR(5,4)] = true;
}
if ( IsTownUnderCompleteControlByPlayer(CAMBRIA) && ( IsTownUnderCompleteControlByPlayer(CHITZENA) || IsTownUnderCompleteControlByPlayer(DRASSEN) ) )
{
// ROAD TO SAN MONA
gDynamicRestrictMilitia[SECTOR(7,3)] = true;
gDynamicRestrictMilitia[SECTOR(8,3)] = true;
gDynamicRestrictMilitia[SECTOR(9,3)] = true;
}
if ( IsTownUnderCompleteControlByPlayer(CAMBRIA) && ( IsTownUnderCompleteControlByPlayer(DRASSEN) || IsTownUnderCompleteControlByPlayer(CHITZENA) || IsTownUnderCompleteControlByPlayer(GRUMM) ) )
{
// ROAD SOUTH-EAST OF SAN MONA
gDynamicRestrictMilitia[SECTOR(6,4)] = true;
gDynamicRestrictMilitia[SECTOR(7,4)] = true;
// SAN MONA
gDynamicRestrictMilitia[SECTOR(5,3)] = true;
gDynamicRestrictMilitia[SECTOR(6,3)] = true;
gDynamicRestrictMilitia[SECTOR(4,4)] = true;
gDynamicRestrictMilitia[SECTOR(5,4)] = true;
}
if ( IsTownUnderCompleteControlByPlayer(ALMA) && ( IsTownUnderCompleteControlByPlayer(DRASSEN) || IsTownUnderCompleteControlByPlayer(CAMBRIA) ) )
{
// ROAD WEST OF ALMA
gDynamicRestrictMilitia[SECTOR(11,7)] = true;
}
if ( IsTownUnderCompleteControlByPlayer(CHITZENA) && ( IsTownUnderCompleteControlByPlayer(DRASSEN) || IsTownUnderCompleteControlByPlayer(CAMBRIA) || IsTownUnderCompleteControlByPlayer(GRUMM) ) )
{
// SAN MONA
gDynamicRestrictMilitia[SECTOR(5,3)] = true;
gDynamicRestrictMilitia[SECTOR(6,3)] = true;
gDynamicRestrictMilitia[SECTOR(4,4)] = true;
gDynamicRestrictMilitia[SECTOR(5,4)] = true;
// ROAD TO SAN MONA
gDynamicRestrictMilitia[SECTOR(7,3)] = true;
gDynamicRestrictMilitia[SECTOR(8,3)] = true;
gDynamicRestrictMilitia[SECTOR(9,3)] = true;
}
if ( IsTownUnderCompleteControlByPlayer(CAMBRIA) && IsTownUnderCompleteControlByPlayer(ALMA) )
{
// ROAD EAST OF CAMBRIA
gDynamicRestrictMilitia[SECTOR(11,7)] = true;
}
if ( IsTownUnderCompleteControlByPlayer(CAMBRIA) && ( IsTownUnderCompleteControlByPlayer(BALIME) || IsTownUnderCompleteControlByPlayer(GRUMM) || IsTownUnderCompleteControlByPlayer(ALMA) ) )
{
// UPGRADED SAM-SITE DEFENSE FOR CAMBRIA
gDynamicRestrictMilitia[SECTOR(7,10)] = true;
gDynamicRestrictMilitia[SECTOR(8,10)] = true;
gDynamicRestrictMilitia[SECTOR(9,10)] = true; // Tixa. Won't be accessible unless Minor Cities are allowed.
}
if ( IsTownUnderCompleteControlByPlayer(CAMBRIA) && IsTownUnderCompleteControlByPlayer(GRUMM) )
{
// ESTONI
gDynamicRestrictMilitia[SECTOR(6,8)] = true;
// ESTONI MOUNTAIN GATE
gDynamicRestrictMilitia[SECTOR(6,9)] = true;
// SOUTHEAST ROAD TO SAN MONA
gDynamicRestrictMilitia[SECTOR(6,4)] = true;
gDynamicRestrictMilitia[SECTOR(7,4)] = true;
}
if ( IsTownUnderCompleteControlByPlayer(BALIME) && IsTownUnderCompleteControlByPlayer(GRUMM) && IsTownUnderCompleteControlByPlayer(CAMBRIA) )
{
// GRUMM-CAMBRIA-BALIME ROAD
gDynamicRestrictMilitia[SECTOR(6,10)] = true;
}
// CONTROL ALL TOWNS?
if ( IsTownUnderCompleteControlByPlayer(BALIME) && IsTownUnderCompleteControlByPlayer(CAMBRIA) && IsTownUnderCompleteControlByPlayer(CHITZENA) && IsTownUnderCompleteControlByPlayer(DRASSEN) && IsTownUnderCompleteControlByPlayer(ALMA) && IsTownUnderCompleteControlByPlayer(GRUMM) )
{
// ROADS TO MEDUNA
gDynamicRestrictMilitia[SECTOR(6,12)] = true;
gDynamicRestrictMilitia[SECTOR(7,14)] = true;
gDynamicRestrictMilitia[SECTOR(2,12)] = true;
// MEDUNA OUTSKIRTS
gDynamicRestrictMilitia[SECTOR(2,13)] = true;
gDynamicRestrictMilitia[SECTOR(3,13)] = true;
gDynamicRestrictMilitia[SECTOR(4,13)] = true;
gDynamicRestrictMilitia[SECTOR(5,13)] = true;
gDynamicRestrictMilitia[SECTOR(6,13)] = true;
gDynamicRestrictMilitia[SECTOR(6,14)] = true;
}
}
// HEADROCK HAM B2.7: This is a copy of an existing function that generates possible movement directions for militia.
// Due to the widespread use of that function, I've decided to make a new one that calculates directions
// when generating militia. This function checks for available space at the target location. It won't count green
// or regular militia in this total, as they will be replaced by higher grade militia when added.
void GenerateDirectionInfosWithCapacityCheck( INT16 sMapX, INT16 sMapY, UINT8* uiDirNumber, UINT16 pMoveDir[4][3], BOOLEAN fWithCities, BOOLEAN fForBattle, BOOLEAN fOnlyCitySectors )
{
SECTORINFO *pSectorInfo;
*uiDirNumber = 0;
#ifdef DEBUG_SHOW_RATINGS
if( DEBUG_RATINGS_CONDITION )ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%ld,%ld-------------------", sMapX, sMapY );
#endif
pSectorInfo = &( SectorInfo[ SECTOR( sMapX, sMapY - 1 ) ] );
if(CheckStandardConditionsForDirection( sMapX, sMapY, sMapX, sMapY - 1, fWithCities, fForBattle, fOnlyCitySectors ) &&
pSectorInfo->ubNumberOfCivsAtLevel[ ELITE_MILITIA ] < gGameExternalOptions.iMaxMilitiaPerSector )
{
pMoveDir[ *uiDirNumber ][0] = SECTOR( sMapX, sMapY - 1 );
if( fForBattle )
pMoveDir[ *uiDirNumber ][1] = 0;
else
pMoveDir[ *uiDirNumber ][1] = CountDirectionRating( sMapX, sMapY, DIR_NORTH );
pMoveDir[ *uiDirNumber ][2] = INSERTION_CODE_NORTH;
#ifdef DEBUG_SHOW_RATINGS
if( DEBUG_RATINGS_CONDITION )ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Priority of north direction - %ld", pMoveDir[ *uiDirNumber ][1]);
#endif
++(*uiDirNumber);
}
pSectorInfo = &( SectorInfo[ SECTOR( sMapX - 1, sMapY ) ] );
if(CheckStandardConditionsForDirection( sMapX, sMapY, sMapX - 1, sMapY, fWithCities, fForBattle, fOnlyCitySectors ) &&
pSectorInfo->ubNumberOfCivsAtLevel[ ELITE_MILITIA ] < gGameExternalOptions.iMaxMilitiaPerSector)
{
pMoveDir[ *uiDirNumber ][0] = SECTOR( sMapX - 1, sMapY );
if( fForBattle )
pMoveDir[ *uiDirNumber ][1] = 0;
else
pMoveDir[ *uiDirNumber ][1] = CountDirectionRating( sMapX, sMapY, DIR_WEST );
pMoveDir[ *uiDirNumber ][2] = INSERTION_CODE_WEST;
#ifdef DEBUG_SHOW_RATINGS
if( DEBUG_RATINGS_CONDITION )ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Priority of west direction - %ld", pMoveDir[ *uiDirNumber ][1]);
#endif
++(*uiDirNumber);
}
pSectorInfo = &( SectorInfo[ SECTOR( sMapX , sMapY + 1 ) ] );
if(CheckStandardConditionsForDirection( sMapX, sMapY, sMapX, sMapY + 1, fWithCities, fForBattle, fOnlyCitySectors ) &&
pSectorInfo->ubNumberOfCivsAtLevel[ ELITE_MILITIA ] < gGameExternalOptions.iMaxMilitiaPerSector )
{
pMoveDir[ *uiDirNumber ][0] = SECTOR( sMapX, sMapY + 1 );
if( fForBattle )
pMoveDir[ *uiDirNumber ][1] = 0;
else
pMoveDir[ *uiDirNumber ][1] = CountDirectionRating( sMapX, sMapY, DIR_SOUTH );
pMoveDir[ *uiDirNumber ][2] = INSERTION_CODE_SOUTH;
#ifdef DEBUG_SHOW_RATINGS
if( DEBUG_RATINGS_CONDITION )ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Priority of south direction - %ld", pMoveDir[ *uiDirNumber ][1]);
#endif
++(*uiDirNumber);
}
pSectorInfo = &( SectorInfo[ SECTOR( sMapX + 1 , sMapY ) ] );
if(CheckStandardConditionsForDirection( sMapX, sMapY, sMapX + 1, sMapY, fWithCities, fForBattle, fOnlyCitySectors ) &&
pSectorInfo->ubNumberOfCivsAtLevel[ ELITE_MILITIA ] < gGameExternalOptions.iMaxMilitiaPerSector )
{
pMoveDir[ *uiDirNumber ][0] = SECTOR( sMapX + 1, sMapY );
if( fForBattle )
pMoveDir[ *uiDirNumber ][1] = 0;
else
pMoveDir[ *uiDirNumber ][1] = CountDirectionRating( sMapX, sMapY, DIR_EAST );
pMoveDir[ *uiDirNumber ][2] = INSERTION_CODE_EAST;
#ifdef DEBUG_SHOW_RATINGS
if( DEBUG_RATINGS_CONDITION )ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Priority of east direction - %ld", pMoveDir[ *uiDirNumber ][1]);
#endif
++(*uiDirNumber);
}
}
+12
View File
@@ -22,4 +22,16 @@ void GenerateDirectionInfos( INT16 sMapX, INT16 sMapY, UINT8* uiDirNumber, UINT1
BOOLEAN MoveOneBestMilitiaMan(INT16 sMapX, INT16 sMapY, INT16 sTMapX, INT16 sTMapY);
void MilitiaFollowPlayer( INT16 sMapX, INT16 sMapY, INT16 sDMapX, INT16 sDMapY );
// HEADROCK HAM B1: Changes the allowed militia sectors
extern void AdjustRoamingRestrictions();
// HEADROCK HAM B1: Alternate array keeps track of dynamically unrestricted sectors
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 );
// 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 );
#endif
+7
View File
@@ -40,6 +40,8 @@
#include "finances.h"
#include "GameSettings.h"
#include "Quests.h"
// HEADROCK HAM B1: Additional Include for Dynamic Roaming Restrictions
#include "MilitiaSquads.h"
#endif
@@ -510,6 +512,11 @@ void MercDailyUpdate()
// rebuild list for mapscreen
ReBuildCharactersList( );
// HEADROCK HAM B1: Run a function to redefine Roaming Militia Restrictions.
if (gGameExternalOptions.bDynamicRestrictRoaming)
{
AdjustRoamingRestrictions();
}
}
/*
+10 -2
View File
@@ -342,7 +342,8 @@ UINT32 GetMaxPeriodicRemovalFromMine( INT8 bMineIndex )
return ( 0 );
}
return( gMineStatus[ bMineIndex ].uiMaxRemovalRate );
// HEADROCK HAM B1: Affected by external INI option.
return(( gMineStatus[ bMineIndex ].uiMaxRemovalRate * gGameExternalOptions.iMineIncomePercentage ) / 100);
}
@@ -368,6 +369,8 @@ UINT32 GetMaxDailyRemovalFromMine( INT8 bMineIndex )
// yes, reduce to value of mine
uiAmtExtracted = gMineStatus[ bMineIndex ].uiRemainingOreSupply;
}
// HEADROCK HAM B1: Affected by external INI option.
uiAmtExtracted = (uiAmtExtracted * gGameExternalOptions.iMineIncomePercentage) / 100;
return(uiAmtExtracted);
}
@@ -664,6 +667,8 @@ void HandleIncomeFromMines( void )
// mine this mine
iIncome += MineAMine( bCounter );
}
// HEADROCK HAM B1: Affected by external INI Option.
iIncome = (iIncome * gGameExternalOptions.iMineIncomePercentage) / 100;
if( iIncome )
{
AddTransactionToPlayersBook( DEPOSIT_FROM_SILVER_MINE, 0, GetWorldTotalMin( ), iIncome );
@@ -690,7 +695,8 @@ UINT32 PredictDailyIncomeFromAMine( INT8 bMineIndex )
}
}
return( uiAmtExtracted );
// HEADROCK HAM B1: Affected by external INI Option.
return( ( uiAmtExtracted * gGameExternalOptions.iMineIncomePercentage ) / 100 ) ;
}
@@ -720,6 +726,8 @@ INT32 CalcMaxPlayerIncomeFromMines( void )
// add up the total
iTotal += (MINE_PRODUCTION_NUMBER_OF_PERIODS * gMineStatus[bCounter].uiMaxRemovalRate);
}
// HEADROCK HAM B1: Affected by external INI Option.
iTotal = (iTotal * gGameExternalOptions.iMineIncomePercentage) / 100;
return( iTotal );
}
+7
View File
@@ -33,6 +33,8 @@
#include "history.h"
#include "meanwhile.h"
#include "Strategic Status.h"
// HEADROCK HAM B1: Added include for Dynamic Roaming Militia
#include "MilitiaSquads.h"
#endif
// the max loyalty rating for any given town
@@ -1814,6 +1816,11 @@ 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)
{
AdjustRoamingRestrictions();
}
// set flag even for towns where you can't train militia, useful for knowing Orta/Tixa were previously controlled
gTownLoyalty[ bTownId ].fLiberatedAlready = TRUE;
+239 -23
View File
@@ -653,6 +653,8 @@ extern BOOLEAN gfDeductPoints;
extern void CleanUpStack( OBJECTTYPE * pObj, OBJECTTYPE * pCursorObj );
extern void SwapGoggles(SOLDIERTYPE *pTeamSoldier);
// HEADROCK HAM B2.8: Function to switch team's goggles uniformly
extern void SwapGogglesUniformly(SOLDIERTYPE *pTeamSoldier, BOOLEAN fToNightVision);
UINT32 guiCHARLIST;
UINT32 guiCHARINFO;
@@ -1038,7 +1040,8 @@ void CheckForInventoryModeCancellation();
void ChangeMapScreenMaskCursor( UINT16 usCursor );
void CancelOrShortenPlottedPath( void );
BOOLEAN HandleCtrlOrShiftInTeamPanel( INT8 bCharNumber );
// HEADROCK HAM B2.8: Added argument to enable multi-selecting entire squads
BOOLEAN HandleCtrlOrShiftInTeamPanel( INT8 bCharNumber, BOOLEAN fFromRightClickAssignments );
INT32 GetContractExpiryTime( SOLDIERTYPE *pSoldier );
@@ -9674,7 +9677,8 @@ void TeamListInfoRegionBtnCallBack(MOUSE_REGION *pRegion, INT32 iReason )
if( gCharactersList[ iValue ].fValid == TRUE )
{
if ( HandleCtrlOrShiftInTeamPanel( ( INT8 ) iValue ) )
// HEADROCK HAM B2.8: Added argument for multi-select entire squads
if ( HandleCtrlOrShiftInTeamPanel( ( INT8 ) iValue , FALSE ))
{
return;
}
@@ -9824,7 +9828,8 @@ void TeamListAssignmentRegionBtnCallBack(MOUSE_REGION *pRegion, INT32 iReason )
if( gCharactersList[ iValue ].fValid == TRUE )
{
if ( HandleCtrlOrShiftInTeamPanel( ( INT8 ) iValue ) )
// HEADROCK HAM B2.8: Added argument for multi-select entire squads
if ( HandleCtrlOrShiftInTeamPanel( ( INT8 ) iValue , FALSE ))
{
return;
}
@@ -9892,8 +9897,87 @@ void TeamListAssignmentRegionBtnCallBack(MOUSE_REGION *pRegion, INT32 iReason )
if (iReason & MSYS_CALLBACK_REASON_RBUTTON_UP)
{
// HEADROCK HAM B2.8: Added argument for multi-select entire squads
if ( HandleCtrlOrShiftInTeamPanel( ( INT8 ) iValue, TRUE ))
{
return;
}
// reset selected characters
ResetAllSelectedCharacterModes( );
// HEADROCK HAM B2.8: Right mouse button selects entire squad, if clicked on a squad-assigned character.
// set to new info character...make sure is valid
if( IsMapScreenHelpTextUp() )
{
// stop mapscreen text
StopMapScreenHelpText( );
return;
}
if( gCharactersList[ iValue ].fValid == TRUE )
{
ChangeSelectedInfoChar( ( INT8 ) iValue, TRUE );
pSoldier = &Menptr[ gCharactersList[ iValue ].usSolID ];
// highlight
giDestHighLine = -1;
// reset character
bSelectedAssignChar = -1;
bSelectedDestChar = -1;
bSelectedContractChar = -1;
fPlotForHelicopter = FALSE;
// if not dead or POW, select his sector
if( ( pSoldier->stats.bLife > 0 ) && ( pSoldier->bAssignment != ASSIGNMENT_POW ) )
{
ChangeSelectedMapSector( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ );
}
// Select all characters in squad
INT16 iCounter;
for( iCounter = 0; iCounter < CODE_MAXIMUM_NUMBER_OF_PLAYER_SLOTS; iCounter++ )
{
if( gCharactersList[ iCounter ].fValid == TRUE )
{
// if not already selected
if( fSelectedListOfMercsForMapScreen[ iCounter ] == FALSE )
{
pSoldier = &( Menptr[ gCharactersList[ iCounter ].usSolID ] );
// if on a squad or in a vehicle
if ( ( pSoldier->bAssignment < ON_DUTY ) || ( pSoldier->bAssignment == VEHICLE ) )
{
// and a member of that squad or vehicle is selected
if ( AnyMercInSameSquadOrVehicleIsSelected( pSoldier ) )
{
// then also select this guy
SetEntryInSelectedCharacterList( ( INT8 ) iCounter );
}
}
}
}
}
// unhilight contract line
giContractHighLine = -1;
// can't assign highlight line
giAssignHighLine = -1;
// dirty team and map regions
fTeamPanelDirty = TRUE;
fMapPanelDirty = TRUE;
//fMapScreenBottomDirty = TRUE;
gfRenderPBInterface = TRUE;
}
else
{
// reset selected characters
ResetAllSelectedCharacterModes( );
}
}
}
@@ -9980,7 +10064,8 @@ void TeamListDestinationRegionBtnCallBack(MOUSE_REGION *pRegion, INT32 iReason )
if( gCharactersList[ iValue ].fValid == TRUE )
{
if ( HandleCtrlOrShiftInTeamPanel( ( INT8 ) iValue ) )
// HEADROCK HAM B2.8: Added argument for multi-select entire squads
if ( HandleCtrlOrShiftInTeamPanel( ( INT8 ) iValue , FALSE ))
{
return;
}
@@ -10153,7 +10238,8 @@ void TeamListSleepRegionBtnCallBack( MOUSE_REGION *pRegion, INT32 iReason )
if( ( gCharactersList[ iValue ].fValid == TRUE ) )
{
if ( HandleCtrlOrShiftInTeamPanel( ( INT8 ) iValue ) )
// HEADROCK HAM B2.8: Added argument for multi-select entire squads
if ( HandleCtrlOrShiftInTeamPanel( ( INT8 ) iValue , FALSE ))
{
return;
}
@@ -10171,6 +10257,8 @@ void TeamListSleepRegionBtnCallBack( MOUSE_REGION *pRegion, INT32 iReason )
// try to wake him up
if( SetMercAwake( pSoldier, TRUE, FALSE ) )
{
// HEADROCK HAM B2.8: New feature wakes all trainees/trainers automatically
HandleTrainingWakeSynchronize( pSoldier );
// propagate
HandleSelectedMercsBeingPutAsleep( TRUE, TRUE );
return;
@@ -10185,6 +10273,8 @@ void TeamListSleepRegionBtnCallBack( MOUSE_REGION *pRegion, INT32 iReason )
// try to put him to sleep
if( SetMercAsleep( pSoldier, TRUE ) )
{
// HEADROCK HAM B2.8: New feature sends all trainees/trainers to sleep automatically
HandleTrainingSleepSynchronize( pSoldier );
// propagate
HandleSelectedMercsBeingPutAsleep( FALSE, TRUE );
return;
@@ -13853,34 +13943,160 @@ void CancelOrShortenPlottedPath( void )
}
BOOLEAN HandleCtrlOrShiftInTeamPanel( INT8 bCharNumber )
BOOLEAN HandleCtrlOrShiftInTeamPanel( INT8 bCharNumber, BOOLEAN fFromRightClickAssignments )
{
// check if shift or ctrl held down, if so, set values in list
if (_KeyDown(CTRL))
// HEADROCK HAM B2.8: New condition based on new argument.
if (fFromRightClickAssignments)
{
ToggleEntryInSelectedList( bCharNumber );
if ( _KeyDown(CTRL) || _KeyDown(SHIFT) )
{
if ( fSelectedListOfMercsForMapScreen[ bCharNumber ] == FALSE )
{
SetEntryInSelectedCharacterList( bCharNumber );
fTeamPanelDirty = TRUE;
fCharacterInfoPanelDirty = TRUE;
INT16 iCounter;
return( TRUE);
for( iCounter = 0; iCounter < CODE_MAXIMUM_NUMBER_OF_PLAYER_SLOTS; iCounter++ )
{
if( gCharactersList[ iCounter ].fValid == TRUE )
{
// if not already selected
if( fSelectedListOfMercsForMapScreen[ iCounter ] == FALSE )
{
SOLDIERTYPE * pSelected = &( Menptr[ gCharactersList[ bCharNumber ].usSolID ] );
SOLDIERTYPE * pSoldier = &( Menptr[ gCharactersList[ iCounter ].usSolID ] );
// if on a squad, or in a vehicle, or IS a vehicle
if ( pSoldier->bAssignment == VEHICLE )
{
// and a member of that squad or vehicle is selected, or we are a vehicle
if ( pSoldier->iVehicleId == pSelected->iVehicleId ||
(pSelected->flags.uiStatusFlags & SOLDIER_VEHICLE && pSoldier->iVehicleId == pSelected->bVehicleID ) ||
(pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE && pSelected->iVehicleId == pSoldier->bVehicleID ) )
{
// then also select this guy
SetEntryInSelectedCharacterList( ( INT8 ) iCounter );
}
}
else if ( pSoldier->bAssignment == pSelected->bAssignment &&
(pSoldier->bAssignment == TRAIN_TEAMMATE || pSoldier->bAssignment == TRAIN_BY_OTHER) &&
pSoldier->sSectorX == pSelected->sSectorX &&
pSoldier->sSectorY == pSelected->sSectorY &&
pSoldier->sZLevel == pSelected->sZLevel )
{
// make sure only trainers/trainees of the same stat are selected together.
if (pSoldier->bTrainStat == pSelected->bTrainStat)
{
SetEntryInSelectedCharacterList( ( INT8 ) iCounter );
}
}
else if ( pSoldier->bAssignment == pSelected->bAssignment &&
pSoldier->sSectorX == pSelected->sSectorX &&
pSoldier->sSectorY == pSelected->sSectorY &&
pSoldier->sZLevel == pSelected->sZLevel )
{
SetEntryInSelectedCharacterList( ( INT8 ) iCounter );
}
}
}
}
}
else
{
// Deselect entire group
ResetEntryForSelectedList( bCharNumber );
INT16 iCounter;
for( iCounter = 0; iCounter < CODE_MAXIMUM_NUMBER_OF_PLAYER_SLOTS; iCounter++ )
{
if( gCharactersList[ iCounter ].fValid == TRUE )
{
// if not already selected
if( fSelectedListOfMercsForMapScreen[ iCounter ] == TRUE )
{
SOLDIERTYPE * pSelected = &( Menptr[ gCharactersList[ bCharNumber ].usSolID ] );
SOLDIERTYPE * pSoldier = &( Menptr[ gCharactersList[ iCounter ].usSolID ] );
// if on a squad, or in a vehicle, or IS a vehicle
if ( pSoldier->bAssignment == VEHICLE )
{
// and a member of that squad or vehicle is selected, or we are a vehicle
if ( pSoldier->iVehicleId == pSelected->iVehicleId ||
(pSelected->flags.uiStatusFlags & SOLDIER_VEHICLE && pSoldier->iVehicleId == pSelected->bVehicleID ) ||
(pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE && pSelected->iVehicleId == pSoldier->bVehicleID ) )
{
// then also select this guy
ResetEntryForSelectedList( ( INT8 ) iCounter );
}
}
else if ( pSoldier->bAssignment == pSelected->bAssignment &&
(pSoldier->bAssignment == TRAIN_TEAMMATE || pSoldier->bAssignment == TRAIN_BY_OTHER) &&
pSoldier->sSectorX == pSelected->sSectorX &&
pSoldier->sSectorY == pSelected->sSectorY &&
pSoldier->sZLevel == pSelected->sZLevel )
{
// make sure only trainers/trainees of the same stat are selected together.
if (pSoldier->bTrainStat == pSelected->bTrainStat)
{
ResetEntryForSelectedList( ( INT8 ) iCounter );
}
}
else if ( pSoldier->bAssignment == pSelected->bAssignment &&
pSoldier->sSectorX == pSelected->sSectorX &&
pSoldier->sSectorY == pSelected->sSectorY &&
pSoldier->sZLevel == pSelected->sZLevel )
{
ResetEntryForSelectedList( ( INT8 ) iCounter );
}
}
}
}
}
fTeamPanelDirty = TRUE;
fCharacterInfoPanelDirty = TRUE;
return(TRUE);
}
return (FALSE);
}
else if( _KeyDown(SHIFT) )
else
{
// build a list from the bSelectedInfoChar To here, reset everyone
//empty the list
ResetSelectedListForMapScreen( );
// rebuild the list
BuildSelectedListFromAToB( bSelectedInfoChar, bCharNumber );
// check if shift or ctrl held down, if so, set values in list
if (_KeyDown(CTRL))
{
ToggleEntryInSelectedList( bCharNumber );
fTeamPanelDirty = TRUE;
fCharacterInfoPanelDirty = TRUE;
fTeamPanelDirty = TRUE;
fCharacterInfoPanelDirty = TRUE;
return( TRUE );
return( TRUE);
}
else if( _KeyDown(SHIFT) )
{
// build a list from the bSelectedInfoChar To here, reset everyone
//empty the list
ResetSelectedListForMapScreen( );
// rebuild the list
BuildSelectedListFromAToB( bSelectedInfoChar, bCharNumber );
fTeamPanelDirty = TRUE;
fCharacterInfoPanelDirty = TRUE;
return( TRUE );
}
return( FALSE );
}
return( FALSE );
}
+3
View File
@@ -13,6 +13,9 @@
#define MAX_TOWNS 50 //13 //50
#define MAX_TOWN_SECTORS 260 //40 //260
// HEADROCK HAM B2.7: Moved here from Strategicmap.cpp to allow use by MilitiaSquads.cpp
extern BOOLEAN gfMilitiaAllowedInTown [ MAX_TOWNS ];
// Sector name identifiers
enum Towns
{
+4
View File
@@ -69,6 +69,10 @@ typedef struct
UINT16 ubItemStatus;
UINT16 fromItem;
INT32 flash;
// HEADROCK HAM B2.5: Experimental bullet tracer info. If the new tracer system is activated, this flag tells
// the bullet animation functions to create a lightpath for this bullet. This means now all bullets in a tracer
// magazine will cause a lightshow (that's the intended result).
BOOLEAN fTracer;
} BULLET;
extern UINT32 guiNumBullets;
+103 -25
View File
@@ -73,7 +73,11 @@ STR16 wDebugStatStrings[]={
// local prototypes
UINT8 CalcImportantSectorControl( void );
// HEADROCK HAM B1: New function to calculate how many important sectors there are in the game at all.
UINT8 CalcTotalImportantSectors( void );
UINT16 CountSurfaceSectorsVisited( void );
// HAEDROCK HAM B1: New function to calculate how many sectors CAN be visited, on the surface.
UINT16 TotalVisitableSurfaceSectors( void );
@@ -1076,30 +1080,58 @@ UINT16 SubpointsPerPoint(UINT8 ubStat, INT8 bExpLevel)
{
UINT16 usSubpointsPerPoint;
UINT16 HEALTH_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.ubHealthSubpointsToImprove;
UINT16 STRENGTH_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.ubStrengthSubpointsToImprove;
UINT16 DEXTERITY_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.ubDexteritySubpointsToImprove;
UINT16 AGILITY_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.ubAgilitySubpointsToImprove;
UINT16 WISDOM_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.ubWisdomSubpointsToImprove;
UINT16 MARKSMANSHIP_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.ubMarksmanshipSubpointsToImprove;
UINT16 MEDICAL_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.ubMedicalSubpointsToImprove;
UINT16 MECHANICAL_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.ubMechanicalSubpointsToImprove;
UINT16 LEADERSHIP_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.ubLeadershipSubpointsToImprove;
UINT16 EXPLOSIVES_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.ubExplosivesSubpointsToImprove;
UINT16 LEVEL_SUBPOINTS_TO_IMPROVE = gGameExternalOptions.ubLevelSubpointsToImprove;
// figure out how many subpoints this type of stat needs to change
switch (ubStat)
{
// Attributes
case HEALTHAMT:
usSubpointsPerPoint = HEALTH_SUBPOINTS_TO_IMPROVE;
break;
case AGILAMT:
usSubpointsPerPoint = AGILITY_SUBPOINTS_TO_IMPROVE;
break;
case DEXTAMT:
usSubpointsPerPoint = DEXTERITY_SUBPOINTS_TO_IMPROVE;
break;
case WISDOMAMT:
case STRAMT:
// attributes
usSubpointsPerPoint = ATTRIBS_SUBPOINTS_TO_IMPROVE;
break;
usSubpointsPerPoint = WISDOM_SUBPOINTS_TO_IMPROVE;
break;
case STRAMT:
usSubpointsPerPoint = STRENGTH_SUBPOINTS_TO_IMPROVE;
break;
// Skills
case MEDICALAMT:
usSubpointsPerPoint = MEDICAL_SUBPOINTS_TO_IMPROVE;
break;
case EXPLODEAMT:
usSubpointsPerPoint = EXPLOSIVES_SUBPOINTS_TO_IMPROVE;
break;
case MECHANAMT:
usSubpointsPerPoint = MECHANICAL_SUBPOINTS_TO_IMPROVE;
break;
case MARKAMT:
case LDRAMT:
// skills
usSubpointsPerPoint = SKILLS_SUBPOINTS_TO_IMPROVE;
break;
usSubpointsPerPoint = MARKSMANSHIP_SUBPOINTS_TO_IMPROVE;
break;
case LDRAMT:
usSubpointsPerPoint = LEADERSHIP_SUBPOINTS_TO_IMPROVE;
break;
// Experience
case EXPERAMT:
usSubpointsPerPoint = LEVEL_SUBPOINTS_TO_IMPROVE * bExpLevel;
break;
usSubpointsPerPoint = LEVEL_SUBPOINTS_TO_IMPROVE * bExpLevel;
break;
default:
// BETA message
@@ -1267,7 +1299,7 @@ UINT8 CurrentPlayerProgressPercentage(void)
{
UINT32 uiCurrentIncome;
UINT32 uiPossibleIncome;
UINT8 ubCurrentProgress = gGameExternalOptions.ubGameProgressIncrement;
UINT8 ubCurrentProgress;
UINT8 ubKillsPerPoint;
UINT16 usKillsProgress;
UINT16 usControlProgress;
@@ -1332,7 +1364,12 @@ UINT8 CurrentPlayerProgressPercentage(void)
// 19 sectors in mining towns + 3 wilderness SAMs each count double. Balime & Meduna are extra and not required
usControlProgress = CalcImportantSectorControl();
// HEADROCK HAM B1: Changed the next line, adding a call to a new function. This allows the weight of Sector
// Control to be altered in JA2_OPTIONS.INI (Previously damaged the game's progress if set over 25... So I've
// made this MOD-Friendly :D )
// BTW, Balime and Meduna _ARE_ required. The function doesn't differentiate! Such carelessness. Tsk tsk tsk.
usControlProgress = gGameExternalOptions.ubGameProgressPortionControl * CalcImportantSectorControl() / CalcTotalImportantSectors();
if (usControlProgress > gGameExternalOptions.ubGameProgressPortionControl)
{
usControlProgress = gGameExternalOptions.ubGameProgressPortionControl;
@@ -1343,21 +1380,14 @@ UINT8 CurrentPlayerProgressPercentage(void)
// WDS: Adding more ways to progress in the game
// Get a ratio of sectors visited to the total number of sectors
usVisitProgress = CountSurfaceSectorsVisited() * gGameExternalOptions.ubGameProgressPortionVisited / ((MAP_WORLD_X - 2) * (MAP_WORLD_Y - 2) - 56 /* note: should be calculated */);
// HEADROCK HAM B1: Fixed this so it doesn't count sectors that can't be visited. Allows progress to go to
// 100 even if the map has some unvisitable sectors (heh, doesn't it always?)
usVisitProgress = CountSurfaceSectorsVisited() * gGameExternalOptions.ubGameProgressPortionVisited / TotalVisitableSurfaceSectors();
// add visit progress
// add control progress
ubCurrentProgress += usVisitProgress;
// Add increment to progress
ubCurrentProgress += gGameExternalOptions.ubGameProgressIncrement;
if (ubCurrentProgress < gGameExternalOptions.ubGameProgressMinimum)
return gGameExternalOptions.ubGameProgressMinimum;
if (ubCurrentProgress < 100)
return ubCurrentProgress;
else
return 100;
return(ubCurrentProgress);
}
@@ -1607,6 +1637,36 @@ UINT8 CalcImportantSectorControl( void )
return( ubSectorControlPts );
}
// HEADROCK HAM B1: function to calculate how many "important sectors" there actually are in the game. This is
// used to fix the weight of strategic control importance on game progress, which was until now not really
// moddable.
UINT8 CalcTotalImportantSectors( void )
{
UINT8 ubMapX, ubMapY;
UINT8 ubSectorControlPts = 0;
for ( ubMapX = 1; ubMapX < MAP_WORLD_X - 1; ubMapX++ )
{
for ( ubMapY = 1; ubMapY < MAP_WORLD_Y - 1; ubMapY++ )
{
// towns where militia can be trained and SAM sites are important sectors
if ( MilitiaTrainingAllowedInSector( ubMapX, ubMapY, 0 ) )
{
ubSectorControlPts++;
// SAM sites count double - they have no income, but have significant air control value
if ( IsThisSectorASAMSector( ubMapX, ubMapY, 0 ) )
{
ubSectorControlPts++;
}
}
}
}
return( ubSectorControlPts );
}
// WDS: Adding more ways to progress in the game
// Count how many surface sectors the player has visited
@@ -1627,6 +1687,24 @@ UINT16 CountSurfaceSectorsVisited( void )
return( ubSectorsVisited );
}
// HEADROCK: Count number of VISITABLE sectors
UINT16 TotalVisitableSurfaceSectors( void )
{
UINT8 ubMapX, ubMapY;
UINT16 ubVisitableSectors = 0;
for ( ubMapX = 1; ubMapX < MAP_WORLD_X - 1; ubMapX++ )
{
for ( ubMapY = 1; ubMapY < MAP_WORLD_Y - 1; ubMapY++ )
{
if( SectorInfo[ SECTOR(ubMapX,ubMapY) ].ubTraversability[ THROUGH_STRATEGIC_MOVE ] != GROUNDBARRIER && SectorInfo[ SECTOR(ubMapX,ubMapY) ].ubTraversability[ THROUGH_STRATEGIC_MOVE ] != EDGEOFWORLD )
++ubVisitableSectors;
}
}
return( ubVisitableSectors );
}
void MERCMercWentUpALevelSendEmail( UINT8 ubMercMercIdValue )
{
+7 -3
View File
@@ -25,9 +25,13 @@
#define MAX_STAT_VALUE 100 // for stats and skills
#define MAXEXPLEVEL 10 // maximum merc experience level
#define SKILLS_SUBPOINTS_TO_IMPROVE 25
#define ATTRIBS_SUBPOINTS_TO_IMPROVE 50
#define LEVEL_SUBPOINTS_TO_IMPROVE 350 // per current level! (Can't go over 6500, 10x must fit in USHORT!)
// HEADROCK HAM B2.7 : Externalizing these (changed from #define)
//#define SKILLS_SUBPOINTS_TO_IMPROVE 25
//#define ATTRIBS_SUBPOINTS_TO_IMPROVE 50
//#define LEVEL_SUBPOINTS_TO_IMPROVE 350 // per current level! (Can't go over 6500, 10x must fit in USHORT!)
extern UINT16 SKILLS_SUBPOINTS_TO_IMPROVE;
extern UINT16 ATTRIBS_SUBPOINTS_TO_IMPROVE;
extern UINT16 LEVEL_SUBPOINTS_TO_IMPROVE;
#define WORKIMPROVERATE 2 // increase to make working mercs improve more
#define TRAINIMPROVERATE 2 // increase to make training mercs improve more
+8 -1
View File
@@ -30,6 +30,8 @@
#include "Text.h"
#include "strategicmap.h"
#include "Render Fun.h"
// HEADROCK HAM B2.7: Allow calling a CTH approximation function for the CTH display ("F" key)
#include "UI Cursors.h"
#endif
@@ -635,7 +637,12 @@ void DisplayRangeToTarget( SOLDIERTYPE *pSoldier, INT16 sTargetGridNo )
//AXP 30.03.2007: Fix CtH calculation for first shot after changing aim level (roof/ground)
INT8 bTempTargetLevel = pSoldier->bTargetLevel;
pSoldier->bTargetLevel = (INT8)gsInterfaceLevel;
uiHitChance = CalcChanceToHitGun( pSoldier, sTargetGridNo, (pSoldier->aiData.bShownAimTime ), pSoldier->bAimShotLocation );
uiHitChance = CalcChanceToHitGun( pSoldier, sTargetGridNo, (INT8)(pSoldier->aiData.bShownAimTime ), pSoldier->bAimShotLocation );
// HEADROCK HAM B2.7: CTH approximation?
if (gGameExternalOptions.fApproximateCTH)
{
uiHitChance = ChanceToHitApproximation( pSoldier, uiHitChance );
}
pSoldier->bTargetLevel = bTempTargetLevel;
swprintf( zOutputString, zNewTacticalMessages[ TCTL_MSG__GUN_RANGE_AND_CTH ], Weapon[ pSoldier->inv[HANDPOS].usItem ].usRange / 10, uiHitChance );
+7 -1
View File
@@ -230,7 +230,11 @@ INT16 gsTreeRevealYPos;
// taken out of header to remove multiple symbol definitions (jonathanl)
BOOLEAN gfUICtHBar;
UINT8 gbCtH;
// HEADROCK HAM B1/2: Created an array to hold CTH of different bullets for Burst/Auto CTH Bar.
UINT8 gbCtH[ 10 ];
UINT8 gbCtHBurstCount;
// HEADROCK HAM B2: This value tracks whether Autofire mode is selected. This value may be redundant... not sure.
BOOLEAN gbCtHAutoFire;
UINT16 gsTotalBulletCount;
UINT16 gsBulletCount;
BOOLEAN gTintBulletCounts;
@@ -514,6 +518,8 @@ UINT32 HandleTacticalUI( void )
gTintBulletCounts = FALSE;
gfUIAutofireBulletCount = FALSE;
gfUICtHBar = FALSE;
// HEADROCK HAM B2: tells the cursor-drawing function to draw two CTH bars (for autofire).
gbCtHAutoFire = FALSE;
// Set old event value
guiOldEvent = uiNewEvent = guiCurrentEvent;
+5 -1
View File
@@ -220,7 +220,11 @@ extern BOOLEAN gTintBulletCounts;
extern BOOLEAN gfUIAutofireBulletCount;
extern BOOLEAN gfUICtHBar;
extern UINT8 gbCtH;
// HEADROCK HAM B1/2: Multiple-bullet CTH bar array (replaces old single integer)
extern UINT8 gbCtH[ 10 ];
extern UINT8 gbCtHBurstCount;
// HEADROCK HAM B2: Track autofire on/off
extern BOOLEAN gbCtHAutoFire;
extern CHAR16 gzIntTileLocation[ 20 ];
extern BOOLEAN gfUIIntTileLocation;
+2 -1
View File
@@ -2241,7 +2241,8 @@ else
// only enemy soldiers use auto-drop system!
// don't use the auto-drop system in auto-resolve: player won't see what's being used & enemies will often win & keep'em
if ( SOLDIER_CLASS_ENEMY( bSoldierClass ) && !IsAutoResolveActive() )
// HEADROCK HAM B2.8: Militia now drop all their equipment... IF not killed by player (see TurnSoldierIntoCorpse() )
if ( (SOLDIER_CLASS_ENEMY( bSoldierClass ) || ( gGameExternalOptions.ubMilitiaDropEquipment > 0 && SOLDIER_CLASS_MILITIA( bSoldierClass ) )) && !IsAutoResolveActive() )
{
// SPECIAL handling for weapons: we'll always drop a weapon type that has never been dropped before
for( i = 0; i < pp->Inv.size(); i++ )
+90
View File
@@ -7102,6 +7102,9 @@ INT16 GetBurstToHitBonus( OBJECTTYPE * pObj, BOOLEAN fProneStance )
bonus += Item[pObj->usItem].bipod;
bonus += BonusReduceMore( Item[pObj->usItem].bursttohitbonus, (*pObj)[0]->data.objectStatus );
// HEADROCK HAM B2.5: A certain setting in the New Tracer System can turn auto/burst penalties off
// entirely, to make up for "Tracer Bump".
if ( gGameExternalOptions.iRealisticTracers != 1 )
bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].bursttohitbonus ;
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
@@ -7228,6 +7231,10 @@ INT16 GetAutoToHitBonus( OBJECTTYPE * pObj, BOOLEAN fProneStance )
bonus += BonusReduceMore( Item[pObj->usItem].autofiretohitbonus, (*pObj)[0]->data.objectStatus );
// HEADROCK HAM B2.5: This external setting determines whether autofire penalty is affected by
// tracer ammo. At setting "1", it is disabled. This goes hand in hand with a new tracer effect that
// "bumps" CTH up after firing a tracer bullet.
if ( gGameExternalOptions.iRealisticTracers != 1 )
bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].autofiretohitbonus ;
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
@@ -8491,6 +8498,88 @@ UINT8 AllowedAimingLevels(SOLDIERTYPE * pSoldier)
float iScopeBonus = 0;
BOOLEAN allowed = TRUE;
// HEADROCK HAM B2.6: Dynamic aiming level restrictions based on gun type and attachments.
if ( gGameExternalOptions.fDynamicAimingTime )
{
UINT16 weaponRange;
UINT8 weaponType, maxAimForType, maxAimWithoutBipod;
BOOLEAN fTwoHanded, fUsingBipod;
// Read weapon data
fTwoHanded = Item[pSoldier->inv[pSoldier->ubAttackingHand].usItem].twohanded;
weaponRange = Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].usRange + GetRangeBonus(&pSoldier->inv[pSoldier->ubAttackingHand]);
weaponType = Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].ubWeaponType;
fUsingBipod = FALSE;
maxAimWithoutBipod = 4;
// Define basic (no attachments), and absolute maximums
if (weaponType == GUN_PISTOL || weaponType == GUN_M_PISTOL || (weaponType == GUN_SMG && fTwoHanded == 0) || fTwoHanded == 0)
{
maxAimForType = 2;
aimLevels = 1;
maxAimWithoutBipod = 2;
}
else if (weaponType == GUN_SHOTGUN || weaponType == GUN_LMG || (weaponType == GUN_SMG && fTwoHanded == 1))
{
maxAimForType = 3;
aimLevels = 2;
maxAimWithoutBipod = 3;
}
else if ((weaponType == GUN_AS_RIFLE || weaponType == GUN_RIFLE || weaponType == GUN_SN_RIFLE) && weaponRange <= 500)
{
maxAimForType = 4;
aimLevels = 2;
maxAimWithoutBipod = 3;
}
else if ((weaponType == GUN_AS_RIFLE || weaponType == GUN_RIFLE || weaponType == GUN_SN_RIFLE) && weaponRange > 500)
{
maxAimForType = 8;
aimLevels = 3;
maxAimWithoutBipod = 4;
}
else
{
return 4;
}
// Determine whether a bipod is being used (prone)
if (GetBipodBonus(&pSoldier->inv[pSoldier->ubAttackingHand])>0 && gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE )
{
fUsingBipod = TRUE;
}
iScopeBonus = ( (float)gGameExternalOptions.ubStraightSightRange * GetMinRangeForAimBonus(&pSoldier->inv[pSoldier->ubAttackingHand]) / 100 );
if ( iScopeBonus >= ( (float)gGameExternalOptions.ubStraightSightRange * 0.6) ) // >= 60% of sight range (~9 tiles by default)
{
aimLevels = (UINT8)((float)aimLevels * (float)2);
}
else if ( iScopeBonus >= ( (float)gGameExternalOptions.ubStraightSightRange * 0.3) ) // >= 30% of sight range (~4 tiles by default)
{
aimLevels = (UINT8)((float)(aimLevels+1) * (float)1.5);
}
// Smaller scopes increase by one.
else if ( iScopeBonus > 0 )
{
aimLevels++;
}
// Make sure not over maximum allowed for weapon type.
if (aimLevels > maxAimForType)
{
aimLevels = maxAimForType;
}
// Make sure not over maximum allowed without a bipod.
if (!fUsingBipod)
{
aimLevels = __min(aimLevels, maxAimWithoutBipod);
}
}
else // JA2 1.13 Basic aiming restrictions (8 levels for 10x scope, 6 levels for 7x scope)
{
if ( gGameSettings.fOptions[TOPTION_AIM_LEVEL_RESTRICTION] && Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].ubWeaponType != GUN_RIFLE && Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].ubWeaponType != GUN_SN_RIFLE )
allowed = FALSE;
@@ -8506,6 +8595,7 @@ UINT8 AllowedAimingLevels(SOLDIERTYPE * pSoldier)
if ( iScopeBonus >= ( (float)gGameExternalOptions.ubStraightSightRange * 0.6) ) // >= 60% of sight range (~9 tiles by default)
{
aimLevels += 2;
}
}
}
+46 -2
View File
@@ -3669,6 +3669,24 @@ INT8 FireBulletGivenTarget( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOA
usBulletFlags |= BULLET_FLAG_FLAME;
ubSpreadIndex = 2;
}
// HEADROCK HAM B2.5: Set tracer effect on/off for individual bullets in a Tracer Magazine, as part of the
// New Tracer System.
else if (gGameExternalOptions.iRealisticTracers > 0 && gGameExternalOptions.iNumBulletsPerTracer > 0 && (pFirer->bDoAutofire > 0 || pFirer->bDoBurst > 0)
&& AmmoTypes[ pFirer->inv[pFirer->ubAttackingHand][0]->data.gun.ubGunAmmoType ].tracerEffect )
{
UINT16 iBulletsLeft, iBulletsPerTracer;
iBulletsPerTracer = gGameExternalOptions.iNumBulletsPerTracer;
iBulletsLeft = pFirer->inv[pFirer->ubAttackingHand][0]->data.gun.ubGunShotsLeft + pFirer->bDoBurst;
if ((((iBulletsLeft - (pFirer->bDoBurst - 1)) / iBulletsPerTracer) - ((iBulletsLeft - pFirer->bDoBurst) / iBulletsPerTracer)) == 1)
{
fTracer = TRUE;
}
else
{
fTracer = FALSE;
}
}
else if ( AmmoTypes[ pFirer->inv[pFirer->ubAttackingHand][0]->data.gun.ubGunAmmoType ].tracerEffect && (pFirer->bDoBurst || gGameSettings.fOptions[ TOPTION_TRACERS_FOR_SINGLE_FIRE ]) )
{
//usBulletFlags |= BULLET_FLAG_TRACER;
@@ -3817,6 +3835,26 @@ INT8 FireBulletGivenTarget( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOA
// this distance limit only applies in a "hard" sense to fake bullets for chance-to-get-through,
// but is used for determining structure hits by the regular code
pBullet->iDistanceLimit = iDistance;
// HEADROCK HAM BETA2.5: New method for signifying whether a bullet is a tracer or not, using an individual
// bullet structure flag. Hehehehe, I think this is kind of reverting to old code, isn't it?
if (gGameExternalOptions.iRealisticTracers > 0 && gGameExternalOptions.iNumBulletsPerTracer > 0 && (pFirer->bDoAutofire > 0 || pFirer->bDoBurst > 0)
&& AmmoTypes[ pFirer->inv[pFirer->ubAttackingHand][0]->data.gun.ubGunAmmoType ].tracerEffect )
{
UINT16 iBulletsLeft, iBulletsPerTracer;
iBulletsPerTracer = gGameExternalOptions.iNumBulletsPerTracer;
iBulletsLeft = pFirer->inv[pFirer->ubAttackingHand][0]->data.gun.ubGunShotsLeft + pFirer->bDoBurst;
// Is this specific bullet a tracer? - based on how many tracers there are per regular bullets in
// a tracer magazine (INI-settable).
if ((((iBulletsLeft - (pFirer->bDoBurst - 1)) / iBulletsPerTracer) - ((iBulletsLeft - pFirer->bDoBurst) / iBulletsPerTracer)) == 1)
{
pBullet->fTracer = TRUE;
}
else
{
pBullet->fTracer = FALSE;
}
}
if (fFake)
{
bCTGT = FireBullet( pFirer, pBullet, TRUE );
@@ -4366,7 +4404,10 @@ void MoveBullet( INT32 iBullet )
}
}
if (( pBullet->usFlags & ( BULLET_FLAG_MISSILE | BULLET_FLAG_SMALL_MISSILE | BULLET_FLAG_TANK_CANNON | BULLET_FLAG_FLAME | BULLET_FLAG_CREATURE_SPIT /*| BULLET_FLAG_TRACER*/ ) ) || fTracer == TRUE)
// HEADROCK HAM B2.5: Changed condition to read fTracer flag directly from bullet's struct.
// This is for the New Tracer System.
if (( pBullet->usFlags & ( BULLET_FLAG_MISSILE | BULLET_FLAG_SMALL_MISSILE | BULLET_FLAG_TANK_CANNON | BULLET_FLAG_FLAME | BULLET_FLAG_CREATURE_SPIT /*| BULLET_FLAG_TRACER*/ ) )
|| ((gGameExternalOptions.iRealisticTracers > 0 && gGameExternalOptions.iNumBulletsPerTracer > 0 && pBullet->fTracer == TRUE) || (gGameExternalOptions.iRealisticTracers == 0 && fTracer == TRUE)))
{
INT8 bStepsPerMove = STEPS_FOR_BULLET_MOVE_TRAILS;
@@ -4653,7 +4694,10 @@ void MoveBullet( INT32 iBullet )
pBullet->iCurrCubesZ = CONVERT_HEIGHTUNITS_TO_INDEX( FIXEDPT_TO_INT32( pBullet->qCurrZ ) );
pBullet->iLoop++;
if (( pBullet->usFlags & ( BULLET_FLAG_MISSILE | BULLET_FLAG_SMALL_MISSILE | BULLET_FLAG_TANK_CANNON | BULLET_FLAG_FLAME | BULLET_FLAG_CREATURE_SPIT /*| BULLET_FLAG_TRACER */) ) || fTracer == TRUE)
// HEADROCK HAM B2.5: Changed condition to read fTracer flag directly from bullet's struct.
// This is for the New Tracer System.
if (( pBullet->usFlags & ( BULLET_FLAG_MISSILE | BULLET_FLAG_SMALL_MISSILE | BULLET_FLAG_TANK_CANNON | BULLET_FLAG_FLAME | BULLET_FLAG_CREATURE_SPIT /*| BULLET_FLAG_TRACER */) )
|| ((gGameExternalOptions.iRealisticTracers > 0 && gGameExternalOptions.iNumBulletsPerTracer > 0 && pBullet->fTracer == TRUE) || (gGameExternalOptions.iRealisticTracers == 0 && fTracer == TRUE)))
{
INT8 bStepsPerMove = STEPS_FOR_BULLET_MOVE_TRAILS;
+158 -15
View File
@@ -7206,12 +7206,24 @@ INT8 CalcSuppressionTolerance( SOLDIERTYPE * pSoldier )
void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
{
///////////////////////////////////////////////////////////////////////////////
//
// HEADROCK HAM B2: This entire function has been completely revamped.
//
///////////////////////////////////////////////////////////////////////////////
// External options.
UINT8 MAX_APS_SUPPRESSED = gGameExternalOptions.iMaxSuppressionAPLossPerAttack;
UINT8 MAX_APS_SUPPRESSED_TOTAL = gGameExternalOptions.iMaxSuppressionAPLossPerTurn;
INT8 SUPPRESSION_AP_LIMIT = gGameExternalOptions.iMinAPLimitFromSuppression;
INT8 MAXIMUM_SUPPRESSION_SHOCK = gGameExternalOptions.iMaxSuppressionShock;
INT8 bTolerance;
INT16 sClosestOpponent, sClosestOppLoc;
UINT8 ubPointsLost, ubTotalPointsLost, ubNewStance;
UINT32 uiLoop;
UINT8 ubLoop2;
UINT16 uiLoop3;
// Flag to determine if the target is cowering (if allowed)
BOOLEAN fCower;
SOLDIERTYPE * pSoldier;
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
@@ -7226,7 +7238,14 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: figure out aps lost"));
// multiply by 2, add 1 and divide by 2 to round off to nearest whole number
ubPointsLost = (UINT8)( (FLOAT)((pSoldier->ubSuppressionPoints * APBPConstants[AP_SUPPRESSION_MOD]) / (bTolerance + 6)) * 2 + 1 ) / 2;
// HEADROCK: Note that suppression points accumulate by bullets flying near the character. It includes
// friendly fire at a certain distance. Also note that it may be reset either each attack or each turn
// (based on new INI settings), which has a small effect on how suppression builds up (but nothing
// major).
ubPointsLost = ( ( (pSoldier->ubSuppressionPoints * APBPConstants[AP_SUPPRESSION_MOD]) / (bTolerance + 6) ) * 2 + 1 ) / 2;
// HEADROCK HAM Beta 2.2: SuppressionEffectiveness acts as a percentage for the number of lost APs.
ubPointsLost = ( ubPointsLost * gGameExternalOptions.iSuppressionEffectiveness ) / 100;
// reduce loss of APs based on stance
// ATE: Taken out because we can possibly supress ourselves...
@@ -7243,37 +7262,125 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
//}
// cap the # of APs we can lose
if (ubPointsLost > APBPConstants[AP_MAX_SUPPRESSED])
// HEADROCK HAM B2: This now reads an external value. 0 means no limit.
if (MAX_APS_SUPPRESSED > 0)
{
ubPointsLost = (UINT8)APBPConstants[AP_MAX_SUPPRESSED];
if (ubPointsLost > APBPConstants[AP_MAX_SUPPRESSED])
{
ubPointsLost = APBPConstants[AP_MAX_SUPPRESSED];
}
}
// HEADROCK HAM B2: This makes sure that we never lose more APs than we're allowed per turn,
if (MAX_APS_SUPPRESSED_TOTAL > 0)
{
if (pSoldier->ubAPsLostToSuppression + ubPointsLost > MAX_APS_SUPPRESSED_TOTAL)
{
ubPointsLost = MAX_APS_SUPPRESSED_TOTAL - pSoldier->ubAPsLostToSuppression;
}
}
// Keeps a number for later reference
ubTotalPointsLost = ubPointsLost;
// Subtract off the APs lost before this point to find out how many points are lost now
// Make sure we're suffering extra AP loss at all. If the number of APs we're supposed to lose now
// is equal/higher to the number of APs we've already lost, it means we haven't actually gained any
// suppression. This is very important, as this function runs EVERY TIME an attack, ANY attack, ends.
// If the soldier hasn't suffered suppression since the last time this check ran, we'll hit the
// "continue" command. Note that with a certain INI setting, this value is reset after each attack
// or after each turn, but overall the function acts the same in both cases.
if (pSoldier->ubAPsLostToSuppression >= ubPointsLost)
{
continue;
}
// APs actually lost will be the difference between the potential loss and the APs we've already lost
// so far. Would theoretically equal 0 if we haven't suffered sufficient extra suppression this turn to
// cause any AP loss, but then we would've already hit the "continue" command, above.
ubPointsLost -= pSoldier->ubAPsLostToSuppression;
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: check for morale effects"));
// morale modifier
if (ubTotalPointsLost / 2 > pSoldier->ubAPsLostToSuppression / 2)
// HEADROCK HAM B2: This nifty little bit gives suppression an "extra kick". Soldiers affected by
// suppression (I.E. lost APs) will also suffer from SHOCK. This is similar to getting shot but
// without the health/stamina loss - the soldier will lose 5% CTH for every point of shock they suffer.
// Shock is sliced in half at the start of every turn. Also note that shock may cause "cowering", and
// may also reduce any attacker's aim as well!
if (gGameExternalOptions.fSuppressionShock)
{
//CHRISL: This should dynamically adjust the number of times we run the morale loop based on AP_MAXIMUM
uiLoop3 = (((ubTotalPointsLost / 2) - (pSoldier->ubAPsLostToSuppression / 2)) * APBPConstants[AP_MAXIMUM]) / 100;
for ( ubLoop2 = 0; ubLoop2 < uiLoop3; ubLoop2++ )
if (ubPointsLost > 0)
{
// Experienced and/or high-morale soldiers suffer less shock than others.
INT8 bShockValue, bShockLimit;
bShockLimit = MAXIMUM_SUPPRESSION_SHOCK - bTolerance;
// the amount of shock received depends mainly on how many APs we've lost. 8 here is arbitrary,
// as the shock loss can later be adjusted by the external modifier below.
bShockValue = (bShockLimit * ubPointsLost) / 8;
if (bShockValue < 0)
bShockValue = 0;
if (bShockLimit < 0)
bShockLimit = 0;
// use external value to determine how effective SHOCK really is.
bShockValue = (bShockValue * gGameExternalOptions.iSuppressionShockEffectiveness) / 100;
// Make sure total shock doesn't go TOO high. Maximum is around 30 (for a CTH effect of -150!),
// including previous shock from suppression and/or wounds. The Maximum is mitigated by
// the character's experience and morale. The shock value can bump above that level
// momentarily, for particularily lousy characters, rendering them practically incapable of firing
// back effectively... But of course, it is halved once the character starts his next turn, so
// shock at turnstart will usually be no higher than 15.
if ( pSoldier->aiData.bShock + bShockValue <= bShockLimit )
{
// Shock limit not yet breached. Add shock to character.
pSoldier->aiData.bShock += bShockValue;
}
else if ( pSoldier->aiData.bShock < bShockLimit ) // Shock limit will be breached.
{
// Original shock was lower than the limit, so add extra shock and breach the limit.
pSoldier->aiData.bShock += bShockValue;
}
// Else, original shock was already over the limit. No more shock is added.
}
}
// HEADROCK: Untrained characters won't react well to being fired at (they'll keep standing), but if
// Suppression Shock is activated, they may dive and "COWER" anyway. For this to happen, they must first
// make a check to see if they are in enough shock to cower.
fCower = false;
if ( gGameExternalOptions.fSuppressionShock && gGameExternalOptions.iAimPenaltyPerTargetShock > 0 )
{
if (pSoldier->aiData.bShock >= bTolerance)
{ fCower = true; }
}
// HEADROCK HAM B2: If enemy cowers in fear, let the player know.
if (fCower)
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113HAMMessage[0], pSoldier->name );
// If cowering, increase suppression effectiveness by external percentage
if (gGameExternalOptions.iCowerEffectOnSuppression > 0)
ubPointsLost = (ubPointsLost * gGameExternalOptions.iCowerEffectOnSuppression) / 100;
}
// morale modifier
// For every 2 APs lost, subtract morale by a certain value.
// HEADROCK: Modified - now externalized to INI.
if (gGameExternalOptions.iAPLostPerMoraleDrop > 0 && ubPointsLost > 0)
{
for ( ubLoop2 = 0; ubLoop2 < (ubPointsLost / gGameExternalOptions.iAPLostPerMoraleDrop); ubLoop2++ )
{
HandleMoraleEvent( pSoldier, MORALE_SUPPRESSED, pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ );
}
}
ubPointsLost -= pSoldier->ubAPsLostToSuppression;
ubNewStance = 0;
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: check for reaction"));
// merc may get to react
if ( pSoldier->ubSuppressionPoints >= ( 130 / (6 + bTolerance) ) )
// Headrock: apply suppression effectiveness percentage to this value.
if ( (pSoldier->ubSuppressionPoints * gGameExternalOptions.iSuppressionEffectiveness) / 100 >= ( 130 / (6 + bTolerance) ) || fCower )
{
// merc gets to use APs to react!
switch (gAnimControl[ pSoldier->usAnimState ].ubEndHeight)
@@ -7285,7 +7392,8 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
if (ubTotalPointsLost >= APBPConstants[AP_PRONE] && IsValidStance( pSoldier, ANIM_PRONE ) )
{
sClosestOpponent = ClosestKnownOpponent( pSoldier, &sClosestOppLoc, NULL );
if (sClosestOpponent == NOWHERE || SpacesAway( pSoldier->sGridNo, sClosestOppLoc ) > 8)
// HEADROCK: Added cowering.
if (sClosestOpponent == NOWHERE || SpacesAway( pSoldier->sGridNo, sClosestOppLoc ) > 8 || fCower)
{
if (ubPointsLost < APBPConstants[AP_PRONE])
{
@@ -7311,7 +7419,8 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
else if (ubTotalPointsLost >= (APBPConstants[AP_CROUCH] + APBPConstants[AP_PRONE]) && ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_PRONE ) && IsValidStance( pSoldier, ANIM_PRONE ) )
{
sClosestOpponent = ClosestKnownOpponent( pSoldier, &sClosestOppLoc, NULL );
if ( sClosestOpponent == NOWHERE || SpacesAway( pSoldier->sGridNo, sClosestOppLoc ) > 8 )
// HEADROCK: Added cowering.
if ( sClosestOpponent == NOWHERE || SpacesAway( pSoldier->sGridNo, sClosestOppLoc ) > 8 ||fCower )
{
if ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND )
{
@@ -7341,7 +7450,18 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: reduce action points"));
// Reduce action points!
pSoldier->bActionPoints -= ubPointsLost;
// HEADROCK HAM Beta 2.2: Enforce a minimum limit via INI.
if (pSoldier->bActionPoints - ubPointsLost < gGameExternalOptions.iMinAPLimitFromSuppression )
{
pSoldier->bActionPoints = gGameExternalOptions.iMinAPLimitFromSuppression;
}
else
{
pSoldier->bActionPoints -= ubPointsLost;
}
// Remember how many APs were lost. This prevents us from losing more and more APs without receiving
// extra suppression. Note that a specific HAM setting will reset this value after every attack,
// but also resets ubSuppressionPoints.
pSoldier->ubAPsLostToSuppression = ubTotalPointsLost;
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: check for quote"));
@@ -7404,6 +7524,18 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
pSoldier->flags.fDontChargeAPsForStanceChange = TRUE;
}
// HEADROCK HAM B2: Optional fix for suppression. This clears up the value that measures suppression
// accumulated so far. Previously, the value was NEVER cleared, which means that a character could
// only be suppressed ONCE in the game (unless they die or get deleted).
// With the setting at "2", these two values are cleared every turn. Therefore, suppression doesn't
// accumulate at all, only its effects are cumulative. In the end, it functions almost the same as
// clearing every turn, but I added this as an alternative.
if (gGameExternalOptions.iClearSuppression == 2)
{
pSoldier->ubAPsLostToSuppression = 0;
pSoldier->ubSuppressionPoints = 0;
}
} // end of examining one soldier
} // end of loop
@@ -7988,6 +8120,17 @@ SOLDIERTYPE *InternalReduceAttackBusyCount( )
pSoldier->flags.fGettingHit = FALSE;
}
// HEADROCK HAM B2: Optional fix for suppression. This clears up the value that measures suppression
// accumulated so far. Previously, the value was NEVER cleared, which means that a character could
// only be suppressed ONCE in the game (unless they die or get deleted).
// With the setting at "2", these two values are cleared every turn. Therefore, suppression doesn't
// accumulate at all, only its effects are cumulative. In the end, it functions almost the same as
// clearing every turn, but I added this as an alternative.
if (gGameExternalOptions.iClearSuppression == 2)
{
pSoldier->ubAPsLostToSuppression = 0;
pSoldier->ubSuppressionPoints = 0;
}
if (pSoldier->ubAttackerID != NOBODY )
{
if (pSoldier->ubPreviousAttackerID != pSoldier->ubAttackerID)
+2
View File
@@ -316,6 +316,8 @@ void ResetAllMercSpeeds( );
BOOLEAN HandleGotoNewGridNo( SOLDIERTYPE *pSoldier, BOOLEAN *pfKeepMoving, BOOLEAN fInitialMove, UINT16 usAnimState );
SOLDIERTYPE * ReduceAttackBusyCount( );
// HEADROCK HAM B2.6: Made this public so it can be used elsewhere.
INT8 CalcSuppressionTolerance( SOLDIERTYPE * pSoldier );
void CommonEnterCombatModeCode( );
+37 -1
View File
@@ -1122,7 +1122,43 @@ INT16 CalcTotalAPsToAttack( SOLDIERTYPE *pSoldier, INT16 sGridNo, UINT8 ubAddTur
}
else
{
sAPCost += (bAimTime*APBPConstants[AP_CLICK_AIM]);
if (gGameExternalOptions.fIncreasedAimingCost )
{
// HEADROCK HAM B2.6: Changed the number of APs to attack when aiming.
if (bAimTime > 0)
{
// Add 1/2 ready cost (rounded up) for getting the sights up to the eye
sAPCost += ((Weapon[ usItemNum ].ubReadyTime * (100 - GetPercentReadyTimeAPReduction(&pSoldier->inv[HANDPOS])) / 100) + 1) / 2;
// Add regular aim time for the first 4 aiming actions.
sAPCost += __min(bAimTime,4);
// If the weapon has a scope, and the target is within eligible range for scope use
if ( IsScoped(&pSoldier->inv[HANDPOS])
&& GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sGridNo ) >= GetMinRangeForAimBonus(&pSoldier->inv[HANDPOS]) )
{
// Add time to adjust eye to scope
if (bAimTime > 0)
{
sAPCost += 1;
}
// Add 2 APs for each aiming point between 5 and 6
if (bAimTime > 4)
{
sAPCost += __min(((bAimTime - 4) * 2), 4);
}
// Add 3 APs for each aiming point beyond 6.
if (bAimTime > 6)
{
sAPCost += (bAimTime - 6) * 3;
}
}
}
}
else
{
sAPCost += bAimTime;
}
}
}
+11 -3
View File
@@ -932,9 +932,12 @@ BOOLEAN TurnSoldierIntoCorpse( SOLDIERTYPE *pSoldier, BOOLEAN fRemoveMerc, BOOLE
if ( !(Item[ pObj->usItem ].defaultundroppable ) )
{
ReduceAmmoDroppedByNonPlayerSoldiers( pSoldier, cnt );
//if this soldier was an enemy
// Kaiden: Added from UB's reveal all items after combat feature!
if( pSoldier->bTeam == ENEMY_TEAM )
//if this soldier was an enemy
// Kaiden: Added from UB's reveal all items after combat feature!
// HEADROCK HAM B2.8: Now also reveals equipment dropped by militia, if requirement is met.
if( pSoldier->bTeam == ENEMY_TEAM ||
( gGameExternalOptions.ubMilitiaDropEquipment == 2 && pSoldier->bTeam == MILITIA_TEAM ) ||
( gGameExternalOptions.ubMilitiaDropEquipment == 1 && pSoldier->bTeam == MILITIA_TEAM && Menptr[ pSoldier->ubAttackerID ].bTeam != OUR_TEAM ))
{
//add a flag to the item so when all enemies are killed, we can run through and reveal all the enemies items
usItemFlags |= WORLD_ITEM_DROPPED_FROM_ENEMY;
@@ -946,7 +949,12 @@ BOOLEAN TurnSoldierIntoCorpse( SOLDIERTYPE *pSoldier, BOOLEAN fRemoveMerc, BOOLE
}
}
// HEADROCK HAM B2.8: Militia will drop items only if allowed.
if (!(gGameExternalOptions.ubMilitiaDropEquipment == 0 && pSoldier->bTeam == MILITIA_TEAM ) &&
!(gGameExternalOptions.ubMilitiaDropEquipment == 1 && pSoldier->bTeam == MILITIA_TEAM && Menptr[ pSoldier->ubAttackerID ].bTeam == OUR_TEAM ))
{
AddItemToPool( pSoldier->sGridNo, pObj, bVisible , pSoldier->pathing.bLevel, usItemFlags, -1 );
}
}
}
}
+12 -2
View File
@@ -1849,8 +1849,9 @@ INT16 SOLDIERTYPE::CalcActionPoints( void )
ubPoints = DynamicAdjustAPConstants(ubPoints, ubPoints);
// If resulting APs are below our permitted minimum, raise them to it!
if (ubPoints < APBPConstants[AP_MINIMUM])
ubPoints = APBPConstants[AP_MINIMUM];
// HEADROCK: Enforce new minimums due to suppression. I should've done this neater though.
if (ubPoints < gGameExternalOptions.iMinAPLimitFromSuppression)
ubPoints = gGameExternalOptions.iMinAPLimitFromSuppression;
// make sure action points doesn't exceed the permitted maximum
ubMaxAPs = gubMaxActionPoints[ this->ubBodyType ];
@@ -6688,6 +6689,15 @@ void SOLDIERTYPE::EVENT_BeginMercTurn( BOOLEAN fFromRealTime, INT32 iRealTimeCou
this->usQuoteSaidExtFlags &= ( ~SOLDIER_QUOTE_SAID_EXT_CLOSE_CALL );
this->bNumHitsThisTurn = 0;
this->ubSuppressionPoints = 0;
// HEADROCK HAM B2: Optional fix for suppression. This clears up the value that measures suppression
// accumulated so far. Previously, the value was NEVER cleared, which means that a character could
// only be suppressed ONCE in the game (unless they die or get deleted). There's really no reason to
// keep this in an IF statement though, as it should, by all rights, erase itself each turn at the very
// least to avoid the once-in-a-lifetime suppression problem.
if (gGameExternalOptions.iClearSuppression == 1)
{
this->ubAPsLostToSuppression = 0;
}
this->flags.fCloseCall = FALSE;
this->ubMovementNoiseHeard = 0;
+274 -121
View File
@@ -192,6 +192,8 @@ extern INT16 ITEMDESC_START_Y;
//Little functions called by keyboard input
void SwapGoggles(SOLDIERTYPE *pTeamSoldier);
// HEADROCK HAM B2.8: Function to switch team's goggles uniformly
void SwapGogglesUniformly(SOLDIERTYPE *pTeamSoldier, BOOLEAN fToNightVision);
void SeperateItems();
void StackAndSort( BOOLEAN fRestrictToAmmo );
void CreateRandomItem();
@@ -3315,10 +3317,43 @@ void GetKeyboardInput( UINT32 *puiNewEvent )
case 'N':
SOLDIERTYPE *pTeamSoldier;
INT8 bLoop;
for (bLoop=gTacticalStatus.Team[gbPlayerNum].bFirstID, pTeamSoldier=MercPtrs[bLoop]; bLoop <= gTacticalStatus.Team[gbPlayerNum].bLastID; bLoop++, pTeamSoldier++)
BOOLEAN fToNightVision;
// HEADROCK HAM B2.8: Added call for CTRL-SHIFT-N to switch all soldiers to day/night.
if ( fCtrl )
{
if ( OK_CONTROLLABLE_MERC( pTeamSoldier ) && pTeamSoldier->bAssignment == CurrentSquad( ) && !AM_A_ROBOT( pTeamSoldier ) ) {
SwapGoggles(pTeamSoldier);
for (bLoop=gTacticalStatus.Team[gbPlayerNum].bFirstID, pTeamSoldier=MercPtrs[bLoop]; bLoop <= gTacticalStatus.Team[gbPlayerNum].bLastID; bLoop++, pTeamSoldier++)
{
if ( OK_CONTROLLABLE_MERC( pTeamSoldier ) && pTeamSoldier->bAssignment == CurrentSquad( ) && !AM_A_ROBOT( pTeamSoldier ) )
{
if ( pTeamSoldier->inv[HEAD1POS].exists() || pTeamSoldier->inv[HEAD2POS].exists() )
{
fToNightVision = ( Item[pTeamSoldier->inv[HEAD1POS].usItem].brightlightvisionrangebonus > 0 || Item[pTeamSoldier->inv[HEAD2POS].usItem].brightlightvisionrangebonus > 0 );
break;
}
if ( bLoop == gTacticalStatus.Team[gbPlayerNum].bLastID )
{
// Default to night or day based on game hour
fToNightVision = NightTime();
}
}
}
for (bLoop=gTacticalStatus.Team[gbPlayerNum].bFirstID, pTeamSoldier=MercPtrs[bLoop]; bLoop <= gTacticalStatus.Team[gbPlayerNum].bLastID; bLoop++, pTeamSoldier++)
{
if ( OK_CONTROLLABLE_MERC( pTeamSoldier ) && pTeamSoldier->bAssignment == CurrentSquad( ) && !AM_A_ROBOT( pTeamSoldier ) )
{
SwapGogglesUniformly(pTeamSoldier, fToNightVision);
}
}
}
else // Shift-N
{
for (bLoop=gTacticalStatus.Team[gbPlayerNum].bFirstID, pTeamSoldier=MercPtrs[bLoop]; bLoop <= gTacticalStatus.Team[gbPlayerNum].bLastID; bLoop++, pTeamSoldier++)
{
if ( OK_CONTROLLABLE_MERC( pTeamSoldier ) && pTeamSoldier->bAssignment == CurrentSquad( ) && !AM_A_ROBOT( pTeamSoldier ) )
{
SwapGoggles(pTeamSoldier);
}
}
}
break;
@@ -5638,81 +5673,186 @@ void SwapGoggles(SOLDIERTYPE *pTeamSoldier)
/* CHRISL - Adjusted this option to allow the game to search through Helmet attachments
as well as inventory positions.
*/
// WDS - Smart goggle switching
// NOTE: Investigate using GetItemVisionRangeBonus from Items.cpp???
if (gGameExternalOptions.smartGoggleSwitch) {
// Look through the head slots and find any sort of goggle or an empty spot
int slotToUse = -1;
for (int headSlot = HEAD1POS; headSlot <= HEAD2POS; ++headSlot) {
if ( (Item[pTeamSoldier->inv[headSlot].usItem].brightlightvisionrangebonus > 0) ) {
slotToUse = headSlot;
break;
} else if ( (Item[pTeamSoldier->inv[headSlot].usItem].nightvisionrangebonus > 0) ) {
slotToUse = headSlot;
break;
} else if (pTeamSoldier->inv[headSlot].exists() == false) {
slotToUse = headSlot;
OBJECTTYPE * pObj;
OBJECTTYPE * pGoggles = NULL;
INT8 bSlot1;
int bestBonus;
bool itemFound = false;
//CHRISL: Before doing anything, we should look at both head slots to see if either slot has some sort of goggles
for(bSlot1 = HEAD1POS; bSlot1 <= HEAD2POS; bSlot1++)
{
if(Item[pTeamSoldier->inv[bSlot1].usItem].brightlightvisionrangebonus > 0)
itemFound = true;
if(Item[pTeamSoldier->inv[bSlot1].usItem].nightvisionrangebonus > 0)
itemFound = true;
}
//2 head slots
for (bSlot1 = HEAD1POS; bSlot1 <= HEAD2POS; bSlot1++)
{
// if wearing sungoggles
if ( Item[pTeamSoldier->inv[bSlot1].usItem].brightlightvisionrangebonus > 0 )
{
itemFound = true;
bestBonus = 0;
pGoggles = FindNightGogglesInInv( pTeamSoldier );
//search for better goggles on the helmet
if (pGoggles)
{
bestBonus = Item[pGoggles->usItem].nightvisionrangebonus;
}
}
if (slotToUse == -1) {
// No place to swap in a new goggle, give up
return;
}
// Find the best goggles for the current time of day anywhere in inventory
OBJECTTYPE * pGoggles = 0;
if (DayTime()) {
pGoggles = FindSunGogglesInInv( pTeamSoldier, TRUE );
} else {
pGoggles = FindNightGogglesInInv( pTeamSoldier, TRUE );
}
if (pGoggles) {
// Now either swap or equip the best one that was found
if (pTeamSoldier->inv[slotToUse].exists()) {
SwapObjs( pTeamSoldier, slotToUse, pGoggles, TRUE );
} else {
pGoggles->MoveThisObjectTo(pTeamSoldier->inv[slotToUse], 1, pTeamSoldier, slotToUse);
}
} else {
// No goggles to equip, should the current ones be unequiped?
if (pTeamSoldier->inv[slotToUse].exists()) {
if ((DayTime() && (Item[pTeamSoldier->inv[slotToUse].usItem].nightvisionrangebonus > 0)) ||
(!DayTime() && (Item[pTeamSoldier->inv[slotToUse].usItem].brightlightvisionrangebonus > 0))) {
// It's day and we're wearing night goggles (or vice-versa), find a place to stash them
if (pTeamSoldier->inv[ HELMETPOS ].exists()) {
if (pTeamSoldier->inv[ HELMETPOS ].AttachObject( NULL, &pTeamSoldier->inv[slotToUse] )) {
// It worked!
} else {
// Try dumping it anywhere in inventory because it doesn't attach to the helmet
}
} else {
// Try dumping it anywhere in inventory given there's no helemt
//search helmet and vest
for(UINT8 gear = HELMETPOS; gear <= VESTPOS; gear++)
{
pObj = &(pTeamSoldier->inv[gear]);
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
{
if ( Item[ iter->usItem ].nightvisionrangebonus > bestBonus && Item[ iter->usItem ].usItemClass == IC_FACE )
{
pGoggles = &(*iter);
bestBonus = Item[ iter->usItem ].nightvisionrangebonus;
}
}
}
}
} else {
// Normal goggle switching
OBJECTTYPE * pObj;
OBJECTTYPE * pGoggles = NULL;
INT8 bSlot1;
int bestBonus;
bool itemFound = false;
//CHRISL: Before doing anything, we should look at both head slots to see if either slot has some sort of goggles
for (bSlot1 = HEAD1POS; bSlot1 <= HEAD2POS; bSlot1++) {
if ((Item[pTeamSoldier->inv[bSlot1].usItem].brightlightvisionrangebonus > 0) ||
(Item[pTeamSoldier->inv[bSlot1].usItem].nightvisionrangebonus > 0))
itemFound = true;
}
//2 head slots
for (bSlot1 = HEAD1POS; bSlot1 <= HEAD2POS; bSlot1++)
{
// if wearing sungoggles
if ( (Item[pTeamSoldier->inv[bSlot1].usItem].brightlightvisionrangebonus > 0) )
if ( pGoggles )
{
SwapObjs( pTeamSoldier, bSlot1, pGoggles, TRUE );
break;
}
// HEADROCK HAM B2.8: If no goggles were found to switch to, the character will remove what they're
// wearing, to avoid situations where a character refuses to remove the wrong set of goggles and
// thus suffers a penalty.
else
{
// Remove sungoggles.
PlaceInAnyPocket(pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE);
break;
}
}
// else if wearing NVGs
else if(Item[pTeamSoldier->inv[bSlot1].usItem].nightvisionrangebonus > 0)
{
itemFound = true;
bestBonus = 0;
pGoggles = FindSunGogglesInInv( pTeamSoldier );
//search for better goggles on the helmet
if (pGoggles)
{
bestBonus = Item[pGoggles->usItem].brightlightvisionrangebonus;
}
//search helmet and vest
for(UINT8 gear = HELMETPOS; gear <= VESTPOS; gear++)
{
pObj = &(pTeamSoldier->inv[gear]);
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
{
if ( Item[ iter->usItem ].brightlightvisionrangebonus > bestBonus && Item[ iter->usItem ].usItemClass == IC_FACE )
{
pGoggles = &(*iter);
bestBonus = Item[ iter->usItem ].brightlightvisionrangebonus;
}
}
}
if ( pGoggles )
{
SwapObjs( pTeamSoldier, bSlot1, pGoggles, TRUE );
break;
}
// HEADROCK HAM B2.8: If no goggles were found to switch to, the character will remove what they're
// wearing, to avoid situations where a character refuses to remove the wrong set of goggles and
// thus suffers a penalty.
else
{
// Remove nightgoggles.
PlaceInAnyPocket(pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE);
break;
}
}
// else if not wearing anything and no goggles found
else if(itemFound == false && pTeamSoldier->inv[bSlot1].exists() == false)
{
bestBonus = 0;
// search helmet and vest for goggles of some kind
for(UINT8 gear = HELMETPOS; gear <= VESTPOS; gear++)
{
pObj = &(pTeamSoldier->inv[gear]);
for(attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
{
if(DayTime() == TRUE && Item[iter->usItem].brightlightvisionrangebonus > bestBonus && Item[iter->usItem].usItemClass == IC_FACE)
{
pGoggles = &(*iter);
bestBonus = Item[iter->usItem].brightlightvisionrangebonus;
}
else if(NightTime() == TRUE && Item[iter->usItem].nightvisionrangebonus > bestBonus && Item[iter->usItem].usItemClass == IC_FACE)
{
pGoggles = &(*iter);
bestBonus = Item[iter->usItem].nightvisionrangebonus;
}
}
if(pGoggles)
{
pGoggles->MoveThisObjectTo(pTeamSoldier->inv[bSlot1], 1, pTeamSoldier, bSlot1);
pObj->RemoveAttachment(pGoggles);
break;
}
}
if(pTeamSoldier->inv[bSlot1].exists() == false)
{
if(DayTime() == TRUE)
pGoggles = FindSunGogglesInInv( pTeamSoldier );
else
pGoggles = FindNightGogglesInInv( pTeamSoldier );
if(pGoggles)
{
SwapObjs( pTeamSoldier, bSlot1, pGoggles, TRUE );
break;
}
}
else
{
break;
}
}
}
fCharacterInfoPanelDirty = TRUE;
fTeamPanelDirty = TRUE;
fInterfacePanelDirty = DIRTYLEVEL2;
pTeamSoldier->DeleteSoldierLight( );
pTeamSoldier->PositionSoldierLight( );
}
// HEADROCK HAM B2.8: This function does the same as SwapGoggles, with a twist. It changes all worn goggles in the
// team uniformly, so that everyone is wearing either nightvision or dayvision, regardless of what they were wearing
// before. The check is based on the headgear of the first character in the group (he'll switch, and everyone else
// will switch to match him.
void SwapGogglesUniformly(SOLDIERTYPE *pTeamSoldier, BOOLEAN fToNightVision)
{
/* CHRISL - Adjusted this option to allow the game to search through Helmet attachments
as well as inventory positions.
*/
OBJECTTYPE * pObj;
OBJECTTYPE * pGoggles = NULL;
INT8 bSlot1;
int bestBonus;
bool itemFound = false;
//CHRISL: Before doing anything, we should look at both head slots to see if either slot has some sort of goggles
for(bSlot1 = HEAD1POS; bSlot1 <= HEAD2POS; bSlot1++)
{
if(Item[pTeamSoldier->inv[bSlot1].usItem].brightlightvisionrangebonus > 0)
itemFound = true;
if(Item[pTeamSoldier->inv[bSlot1].usItem].nightvisionrangebonus > 0)
itemFound = true;
}
//2 head slots
for (bSlot1 = HEAD1POS; bSlot1 <= HEAD2POS; bSlot1++)
{
// if wearing sungoggles
if ( Item[pTeamSoldier->inv[bSlot1].usItem].brightlightvisionrangebonus > 0 )
{
if (fToNightVision == TRUE) // Only if we want to switch to nightvision!
{
itemFound = true;
bestBonus = 0;
pGoggles = FindNightGogglesInInv( pTeamSoldier );
//search for better goggles on the helmet
@@ -5738,10 +5878,20 @@ void SwapGoggles(SOLDIERTYPE *pTeamSoldier)
SwapObjs( pTeamSoldier, bSlot1, pGoggles, TRUE );
break;
}
else if (Item[pTeamSoldier->inv[bSlot1].usItem].nightvisionrangebonus <= 0)
{
// Remove sungoggles.
PlaceInAnyPocket(pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE);
break;
}
}
// else if wearing NVGs
else if(Item[pTeamSoldier->inv[bSlot1].usItem].nightvisionrangebonus > 0 )
}
// else if wearing NVGs
else if(Item[pTeamSoldier->inv[bSlot1].usItem].nightvisionrangebonus > 0)
{
if (fToNightVision == FALSE) // Only if we want to switch to dayvision!
{
itemFound = true;
bestBonus = 0;
pGoggles = FindSunGogglesInInv( pTeamSoldier );
//search for better goggles on the helmet
@@ -5767,57 +5917,60 @@ void SwapGoggles(SOLDIERTYPE *pTeamSoldier)
SwapObjs( pTeamSoldier, bSlot1, pGoggles, TRUE );
break;
}
}
// else if not wearing anything and no goggles found
else if(itemFound == false && pTeamSoldier->inv[bSlot1].exists() == false)
{
bestBonus = 0;
// search helmet and vest for goggles of some kind
for(UINT8 gear = HELMETPOS; gear <= VESTPOS; gear++)
{
pObj = &(pTeamSoldier->inv[gear]);
for(attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
{
if(DayTime() == TRUE && Item[iter->usItem].brightlightvisionrangebonus > bestBonus && Item[iter->usItem].usItemClass == IC_FACE)
{
pGoggles = &(*iter);
bestBonus = Item[iter->usItem].brightlightvisionrangebonus;
}
else if(NightTime() == TRUE && Item[iter->usItem].nightvisionrangebonus > bestBonus && Item[iter->usItem].usItemClass == IC_FACE)
{
pGoggles = &(*iter);
bestBonus = Item[iter->usItem].nightvisionrangebonus;
}
}
if(pGoggles)
{
pGoggles->MoveThisObjectTo(pTeamSoldier->inv[bSlot1], 1, pTeamSoldier, bSlot1);
pObj->RemoveAttachment(pGoggles);
break;
}
}
if(pTeamSoldier->inv[bSlot1].exists() == false)
{
if(DayTime() == TRUE)
pGoggles = FindSunGogglesInInv( pTeamSoldier );
else
pGoggles = FindNightGogglesInInv( pTeamSoldier );
if(pGoggles)
{
SwapObjs( pTeamSoldier, bSlot1, pGoggles, TRUE );
break;
}
}
else
else if (Item[pTeamSoldier->inv[bSlot1].usItem].brightlightvisionrangebonus <= 0)
{
// Remove nightgoggles.
PlaceInAnyPocket(pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE);
break;
}
}
}
// else if not wearing anything and no goggles found
else if(itemFound == false && pTeamSoldier->inv[bSlot1].exists() == false)
{
bestBonus = 0;
// search helmet and vest for goggles of some kind
for(UINT8 gear = HELMETPOS; gear <= VESTPOS; gear++)
{
pObj = &(pTeamSoldier->inv[gear]);
for(attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
{
if(fToNightVision == FALSE && Item[iter->usItem].brightlightvisionrangebonus > bestBonus && Item[iter->usItem].usItemClass == IC_FACE)
{
pGoggles = &(*iter);
bestBonus = Item[iter->usItem].brightlightvisionrangebonus;
}
else if(fToNightVision == TRUE && Item[iter->usItem].nightvisionrangebonus > bestBonus && Item[iter->usItem].usItemClass == IC_FACE)
{
pGoggles = &(*iter);
bestBonus = Item[iter->usItem].nightvisionrangebonus;
}
}
if(pGoggles)
{
pGoggles->MoveThisObjectTo(pTeamSoldier->inv[bSlot1], 1, pTeamSoldier, bSlot1);
pObj->RemoveAttachment(pGoggles);
break;
}
}
if(pTeamSoldier->inv[bSlot1].exists() == false)
{
if(fToNightVision == FALSE)
pGoggles = FindSunGogglesInInv( pTeamSoldier );
else
pGoggles = FindNightGogglesInInv( pTeamSoldier );
if(pGoggles)
{
SwapObjs( pTeamSoldier, bSlot1, pGoggles, TRUE );
break;
}
}
else
{
break;
}
}
}
fCharacterInfoPanelDirty = TRUE;
fTeamPanelDirty = TRUE;
fInterfacePanelDirty = DIRTYLEVEL2;
@@ -5963,4 +6116,4 @@ void StackAndSort( BOOLEAN fRestrictToAmmo )
//HandleAllReachAbleItemsInTheSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, pImpButtonText[11] );
}
}
}
+231 -14
View File
@@ -575,19 +575,123 @@ UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT16 sMapPos, BOOLEAN
{
usCursor = ACTION_TARGETCONFIRMBURST_UICURSOR;
// HEADROCK HAM B1: Burst cursor now shows multiple CTH bars (one for each bullet)
// and also a Targetted Bodypart indicator.
if(pSoldier->bDoAutofire == 0 && gGameSettings.fOptions[ TOPTION_CTH_CURSOR ])
{
//AXP 29.03.2007: Rooftop CtH fix. See below.
INT8 bTempTargetLevel = pSoldier->bTargetLevel;
pSoldier->bTargetLevel = (INT8) gsInterfaceLevel;
if (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 2)
{
// Burst mode only
OBJECTTYPE * pInHand;
pInHand = &(pSoldier->inv[pSoldier->ubAttackingHand]);
// Burst size
gbCtHBurstCount = GetShotsPerBurst(pInHand);
UINT8 i, saveDoBurst;
// Save original burst value (should be 1 always, before the burst has been fired, but
// this is just a failsafe
saveDoBurst = pSoldier->bDoBurst;
UINT32 uiHitChance;
uiHitChance = CalcChanceToHitGun( pSoldier, sMapPos, 0, pSoldier->bAimShotLocation );
// For each bullet in the burst
for (i=0;i<gbCtHBurstCount;i++)
{
//AXP 29.03.2007: Rooftop CtH fix. See below.
INT8 bTempTargetLevel = pSoldier->bTargetLevel;
pSoldier->bTargetLevel = (INT8) gsInterfaceLevel;
pSoldier->bTargetLevel = bTempTargetLevel;
// Calculate hit chance (using the current bDoBurst for burst-penalty calculations)
UINT32 uiHitChance;
uiHitChance = CalcChanceToHitGun( pSoldier, sMapPos, 0, pSoldier->bAimShotLocation );
// HEADROCK HAM B2.7: CTH approximation?
if (gGameExternalOptions.fApproximateCTH)
{
uiHitChance = ChanceToHitApproximation( pSoldier, uiHitChance );
}
gfUICtHBar = TRUE;
gbCtH = (gbCtH+uiHitChance)/2;
pSoldier->bTargetLevel = bTempTargetLevel;
// Put result (burst CTH) into the array
gbCtH[i] = (gbCtH[i]+uiHitChance)/2;
// Increase burst size, so that the next time we run CalcChanceToHitGun we'll get a lower
// result, based on our Burst Penalty
pSoldier->bDoBurst++;
}
// Reset original burst status
pSoldier->bDoBurst = saveDoBurst;
// Activate CTH bar display
gfUICtHBar = TRUE;
}
else // One "BASE CTH" bar, JA2 1.13 vanilla
{
//AXP 29.03.2007: Rooftop CtH fix. See below.
INT8 bTempTargetLevel = pSoldier->bTargetLevel;
pSoldier->bTargetLevel = (INT8) gsInterfaceLevel;
UINT32 uiHitChance;
uiHitChance = CalcChanceToHitGun( pSoldier, sMapPos, 0, pSoldier->bAimShotLocation );
// HEADROCK HAM B2.7: CTH approximation?
if (gGameExternalOptions.fApproximateCTH)
{
uiHitChance = ChanceToHitApproximation( pSoldier, uiHitChance );
}
pSoldier->bTargetLevel = bTempTargetLevel;
gfUICtHBar = TRUE;
gbCtH[0] = (gbCtH[0]+uiHitChance)/2;
gbCtHBurstCount = 1;
}
}
// HEADROCK HAM B2: Now autofire will show both its starting CTH and the CTH of the last
// bullet in the volley.
else if(pSoldier->bDoAutofire > 0 && gGameSettings.fOptions[ TOPTION_CTH_CURSOR ])
{
if (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 3)
{
gbCtHBurstCount = 1;
//AXP 29.03.2007: Rooftop CtH fix. See below.
INT8 bTempTargetLevel = pSoldier->bTargetLevel;
pSoldier->bTargetLevel = (INT8) gsInterfaceLevel;
UINT32 uiHitChance;
// Calculate CTH for the first bullet
uiHitChance = CalcChanceToHitGun( pSoldier, sMapPos, 0, pSoldier->bAimShotLocation );
// HEADROCK HAM B2.7: CTH approximation?
if (gGameExternalOptions.fApproximateCTH)
{
uiHitChance = ChanceToHitApproximation( pSoldier, uiHitChance );
}
// CTH for the first bullet is entered into this array, and later displayed
gbCtH[0] = (gbCtH[0]+uiHitChance)/2;
// Fool the CTH formula into thinking we're already firing the last bullet in the volley,
// by artificially altering bDoBurst (which tracks actual burst progression). The CTH formula
// calculates Auto Penalty based on bDoBurst - (Autopen * (bDoBurst-1), basically).
UINT8 saveDoBurst = pSoldier->bDoBurst;
pSoldier->bDoBurst = pSoldier->bDoAutofire;
uiHitChance = CalcChanceToHitGun( pSoldier, sMapPos, 0, pSoldier->bAimShotLocation );
// HEADROCK HAM B2.7: CTH approximation?
if (gGameExternalOptions.fApproximateCTH)
{
uiHitChance = ChanceToHitApproximation( pSoldier, uiHitChance );
}
pSoldier->bTargetLevel = bTempTargetLevel;
// Return Burst State to original value
pSoldier->bDoBurst = saveDoBurst;
// CTH for the last bullet is entered into this array and later displayed.
gbCtH[1] = (gbCtH[1]+uiHitChance)/2;
// Flag to tell the program to draw two CTH bars.
gbCtHAutoFire = TRUE;
gfUICtHBar = TRUE;
}
}
}
}
@@ -603,11 +707,17 @@ UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT16 sMapPos, BOOLEAN
UINT32 uiHitChance;
uiHitChance = CalcChanceToHitGun( pSoldier, sMapPos, (INT8)(pSoldier->aiData.bShownAimTime ), pSoldier->bAimShotLocation );
// HEADROCK HAM B2.7: CTH approximation?
if (gGameExternalOptions.fApproximateCTH)
{
uiHitChance = ChanceToHitApproximation( pSoldier, uiHitChance );
}
pSoldier->bTargetLevel = bTempTargetLevel;
gfUICtHBar = TRUE;
gbCtH = (gbCtH+uiHitChance)/2;
gbCtHBurstCount = 1;
gbCtH[0] = (gbCtH[0]+uiHitChance)/2;
}
switchVal = pSoldier->aiData.bShownAimTime;
@@ -1283,8 +1393,10 @@ void DetermineCursorBodyLocation( UINT8 ubSoldierID, BOOLEAN fDisplay, BOOLEAN f
}
}
if ( fDisplay && !pSoldier->bDoBurst)
// HEADROCK HAM B2: Now shows targetted bodypart for ALL firing modes. Note that the external toggle is not
// taken into account yet.
// if ( fDisplay && !pSoldier->bDoAutofire )
if ( fDisplay )
{
if ( gfUIFullTargetFound )
{
@@ -1296,7 +1408,14 @@ void DetermineCursorBodyLocation( UINT8 ubSoldierID, BOOLEAN fDisplay, BOOLEAN f
wcscpy( gzLocation, TacticalStr[ CROW_HIT_LOCATION_STR ] );
gfUIBodyHitLocation = TRUE;
if ( !pSoldier->bDoBurst )
gfUIBodyHitLocation = TRUE;
// HEADROCK: This'll toggle whether the bodypart targetting indicator shows up in the burst/auto
// CTH cursors.
else if ( pSoldier->bDoBurst && !pSoldier->bDoAutofire && (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 2) )
gfUIBodyHitLocation = TRUE;
else if ( pSoldier->bDoBurst && pSoldier->bDoAutofire && (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 3) )
gfUIBodyHitLocation = TRUE;
return;
}
@@ -1318,16 +1437,37 @@ void DetermineCursorBodyLocation( UINT8 ubSoldierID, BOOLEAN fDisplay, BOOLEAN f
{
wcscpy( gzLocation, TacticalStr[ HEAD_HIT_LOCATION_STR ] );
}
gfUIBodyHitLocation = TRUE;
if ( !pSoldier->bDoBurst )
gfUIBodyHitLocation = TRUE;
// HEADROCK: This'll toggle whether the bodypart targetting indicator shows up in the burst/auto
// CTH cursors.
else if ( pSoldier->bDoBurst && !pSoldier->bDoAutofire && (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 2) )
gfUIBodyHitLocation = TRUE;
else if ( pSoldier->bDoBurst && pSoldier->bDoAutofire && (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 3) )
gfUIBodyHitLocation = TRUE;
break;
case AIM_SHOT_TORSO:
wcscpy( gzLocation, TacticalStr[ TORSO_HIT_LOCATION_STR ] );
gfUIBodyHitLocation = TRUE;
if ( !pSoldier->bDoBurst )
gfUIBodyHitLocation = TRUE;
// HEADROCK: This'll toggle whether the bodypart targetting indicator shows up in the burst/auto
// CTH cursors.
else if ( pSoldier->bDoBurst && !pSoldier->bDoAutofire && (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 2) )
gfUIBodyHitLocation = TRUE;
else if ( pSoldier->bDoBurst && pSoldier->bDoAutofire && (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 3) )
gfUIBodyHitLocation = TRUE;
break;
case AIM_SHOT_LEGS:
wcscpy( gzLocation, TacticalStr[ LEGS_HIT_LOCATION_STR ] );
if ( !pSoldier->bDoBurst )
gfUIBodyHitLocation = TRUE;
// HEADROCK: This'll toggle whether the bodypart targetting indicator shows up in the burst/auto
// CTH cursors.
else if ( pSoldier->bDoBurst && !pSoldier->bDoAutofire && (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 2) )
gfUIBodyHitLocation = TRUE;
else if ( pSoldier->bDoBurst && pSoldier->bDoAutofire && (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 3) )
gfUIBodyHitLocation = TRUE;
break;
}
@@ -2384,3 +2524,80 @@ void HandleUICursorRTFeedback( SOLDIERTYPE *pSoldier )
}
}
// HEADROCK HAM B2.7: This function gives us an "approximate" CTH bar, that doesn't show the exact value of
// CTH unless the character is well-trained. The worse trained a character is, the wilder the speculation.
UINT32 ChanceToHitApproximation( SOLDIERTYPE * pSoldier, UINT32 uiChance )
{
UINT16 bExpLevel = pSoldier->stats.bExpLevel;
UINT16 bMarksmanship = pSoldier->stats.bMarksmanship;
UINT16 bWisdom = pSoldier->stats.bWisdom;
UINT16 iNumStages, iNumStagesBase, StageSize, SubStageSize;
UINT8 iSniper;
UINT16 uiNewChance;
UINT16 i;
if ( pSoldier->ubProfile != NO_PROFILE )
{
iSniper = NUM_SKILL_TRAITS( pSoldier, PROF_SNIPER );
}
else
{
// Dunno, but I get the strong feeling that we don't want CTH bars for non-mercs.
return(0);
}
if (uiChance == 100)
{
// Sure hit. The player needs to set Maximum_CTH to 100 for this to happen. Normally, the
// max chance is only 99.
return(100);
}
if (uiChance == 0)
{
// Sure Miss. The player needs to set Minimum_CTH to 0 for this to happen. Normally, the
// min chance is 1.
return(0);
}
uiNewChance = uiChance;
iNumStagesBase = __min(165,__max(0, ((bExpLevel * 10) - 30) + (bMarksmanship - 25) + (bWisdom - 50)));
//iNumStagesBase = __max(255, iNumStagesBase);
iNumStagesBase = __min(165, iNumStagesBase + (10 * iSniper));
iNumStagesBase = (UINT16)((float)iNumStagesBase * (float)((float)iNumStagesBase / 195.0));
// Gives a number between 2 and 51.
iNumStages = __max(2,(100 * iNumStagesBase) / 300);
// Find out how large the slices are
StageSize = 100/iNumStages;
// Correct iNumStages to match StageSize, +1 compensates for the rounding down of StageSize.
iNumStages = (100/StageSize) + 1;
// These sub-stages are used to determine which way to round the results.
SubStageSize = __max(1, StageSize / 2);
if (StageSize == 1)
// CTH assessment is perfect. No need for the rest of this function
return (uiChance);
// Jump each "stage" and see whether the CTH is within this slice of the scale
for (i=0; i<iNumStages; i++)
{
UINT16 CurrentStage = i * StageSize;
UINT16 NextStage = (i+1) * StageSize;
// Check whether the CTH should be rounded down or up.
if ( (CurrentStage <= (UINT16) uiChance) && (CurrentStage + SubStageSize > (UINT16) uiChance) )
{
return (CurrentStage);
}
else if ( (CurrentStage + SubStageSize <= (UINT16) uiChance) && (NextStage > (UINT16) uiChance))
{
return (NextStage);
}
}
// Something went wrong. Return 50, as in "God Knows"
return (50);
}
+3
View File
@@ -24,5 +24,8 @@ void HandleEndConfirmCursor( SOLDIERTYPE *pSoldier );
BOOLEAN GetMouseRecalcAndShowAPFlags( UINT32 *puiCursorFlags, BOOLEAN *pfShowAPs );
// HEADROCK HAM B2.7: This function calculates the nearest value (display purposes only)
// based on how trained the shooter is.
UINT32 ChanceToHitApproximation( SOLDIERTYPE * pSoldier, UINT32 uiChance );
#endif
+224 -27
View File
@@ -59,8 +59,9 @@ extern INT8 gbCurrentRainIntensity;
//end rain
#define MINCHANCETOHIT 1
#define MAXCHANCETOHIT 99
// HEADROCK HAM B1: Externalized both values to INI
//#define MINCHANCETOHIT 1
//#define MAXCHANCETOHIT 99
// NB this is arbitrary, chances in DG ranged from 1 in 6 to 1 in 20
#define BASIC_DEPRECIATE_CHANCE 15
@@ -105,6 +106,10 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO
BOOLEAN gfNextShotKills = FALSE;
BOOLEAN gfReportHitChances = FALSE;
// HEADROCK HAM B2.5:Using this boolean to tell the CTH formula that it is being called by UseGun(), rather than
// by other functions. This is mostly to assist the new Tracer Fire system...
BOOLEAN fCalculateCTHDuringGunfire = FALSE;
//GLOBALS
// TODO: Move strings to extern file
@@ -1683,8 +1688,10 @@ BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT16 sTargetGridNo )
}
else
{
uiHitChance = CalcChanceToHitGun( pSoldier, sTargetGridNo, pSoldier->aiData.bAimTime, pSoldier->bAimShotLocation );
fCalculateCTHDuringGunfire = TRUE;
uiHitChance = CalcChanceToHitGun( pSoldier, sTargetGridNo, pSoldier->aiData.bAimTime, pSoldier->bAimShotLocation );
}
fCalculateCTHDuringGunfire = FALSE;
//DIGICRAB: Barrel extender wear code
// Relocated from CalcChanceToHitGun
@@ -1728,10 +1735,19 @@ BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT16 sTargetGridNo )
// big penalty to hit
// WDS 07/06/2008 fix randoms
//if(uiHitChance < 30)
if(uiHitChance <= 30)
uiHitChance = MINCHANCETOHIT;
// HEADROCK: Altered formula to accept variable MINIMUM CTH.
//if(uiHitChance <= 30)
// uiHitChance = MINCHANCETOHIT;
//else
// uiHitChance -= 30;
if(uiHitChance <= (UINT16)(__max(30, gGameExternalOptions.iMinimumCTH + 30)))
{
uiHitChance = gGameExternalOptions.iMinimumCTH ;
}
else
{
uiHitChance -= 30;
}
// curse!
if ( pSoldier->bTeam == OUR_TEAM )
@@ -3552,8 +3568,9 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT16 sGridNo, INT16 ubAimTime,
if ( pSoldier->stats.bMarksmanship == 0 )
{
// always min chance
return( MINCHANCETOHIT );
// HEADROCK: (HAM) Altered to accept external arguments
// return( MINCHANCETOHIT );
return( gGameExternalOptions.iMinimumCTH );
}
// make sure the guy's actually got a weapon in his hand!
@@ -3724,7 +3741,7 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT16 sGridNo, INT16 ubAimTime,
}
// If in burst mode, deduct points for change to hit for each shot after the first
if ( pSoldier->bDoBurst > 0 && pSoldier->bDoAutofire == 0 )
if ( pSoldier->bDoBurst && pSoldier->bDoAutofire == 0 )
{
// Snap: bipod may reduce burst penalty
iPenalty = GetBurstPenalty(pInHand, gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE)
@@ -3749,6 +3766,54 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT16 sGridNo, INT16 ubAimTime,
iPenalty /= 2 * NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPS );
}
iChance -= iPenalty;
// HEADROCK HAM B2.5: One of every X bullets in a tracer magazine is a tracer round, which will
// bump the CTH up by a certain amount.
if (AmmoTypes[(*pInHand)[0]->data.gun.ubGunAmmoType].tracerEffect == 1 && gGameExternalOptions.iRealisticTracers > 0 )
{
UINT16 iBulletsLeft, iTracersFired, iBulletsPerTracer, iBulletsSinceLastTracer;
UINT8 cnt;
UINT16 iAutoPenaltySinceLastTracer;
iTracersFired = 0;
iBulletsPerTracer = gGameExternalOptions.iNumBulletsPerTracer;
// Calculate number of bullets left right before firing this bullet
if (fCalculateCTHDuringGunfire)
{
iBulletsLeft = (*pInHand)[0]->data.gun.ubGunShotsLeft + (pSoldier->bDoBurst - 1);
}
else
{
iBulletsLeft = (*pInHand)[0]->data.gun.ubGunShotsLeft;
}
iBulletsSinceLastTracer = 0;
for (cnt=0;cnt<pSoldier->bDoBurst;cnt++)
{
iBulletsSinceLastTracer++;
if ((( iBulletsLeft - (cnt - 1) ) / iBulletsPerTracer) - ((iBulletsLeft - cnt) / iBulletsPerTracer) == 1)
{
iBulletsSinceLastTracer = 0;
}
}
iTracersFired = ((iBulletsLeft+1) / iBulletsPerTracer) - (((iBulletsLeft+1) - (pSoldier->bDoBurst)) / iBulletsPerTracer);
if ( iTracersFired > 0 )
{
// Correct all autofire penalty so far
iBonus = iPenalty;
// Add Tracer Bump if previous bullet was a tracer
//if (iBulletsSinceLastTracer == 0)
iBonus += (gGameExternalOptions.iCTHBumpPerTracer * iTracersFired);
// Calculate penalty since last tracer was fired
iAutoPenaltySinceLastTracer = GetAutoPenalty(pInHand, gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE) * iBulletsSinceLastTracer;
// Add penalty to bonus.
iBonus -= iAutoPenaltySinceLastTracer;
iChance += iBonus;
}
}
}
//ADB we need to calculate the distance visible and SoldierTo...LOSTests that we want to
@@ -3866,7 +3931,22 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT16 sGridNo, INT16 ubAimTime,
// if shooter is still in shock
if (pSoldier->aiData.bShock)
iChance -= (pSoldier->aiData.bShock * AIM_PENALTY_PER_SHOCK);
{
// HEADROCK HAM B2.8: Placed a maximum here, as shock is now also used in suppression.
UINT16 usShockPenalty;
usShockPenalty = pSoldier->aiData.bShock * AIM_PENALTY_PER_SHOCK;
if (gGameExternalOptions.usMaxShooterCoweringPenalty > 0)
{
if ( usShockPenalty > gGameExternalOptions.usMaxShooterCoweringPenalty )
usShockPenalty = gGameExternalOptions.usMaxShooterCoweringPenalty;
}
if ( usShockPenalty < 1 )
usShockPenalty = 1;
iChance -= usShockPenalty;
}
// WANNE: Changed this, because RPGs are not in the calculation, only guns
//if ( Item[ usInHand ].usItemClass == IC_GUN )
@@ -3962,6 +4042,92 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT16 sGridNo, INT16 ubAimTime,
{
iSightRange = 1;
}
// HEADROCK HAM B2.1 : The TARGET's shock now also affects aiming. If the target is prone
// and in shock, they are harder to hit! This represents a target that's cowering as close
// to the ground (and as close to any possible cover, like a small dune or a fold of earth
// or anything like that).
if ( gGameExternalOptions.iAimPenaltyPerTargetShock > 0 )
{
// HEADROCK HAM B2.1 : This value determines how much penalty the target's shock-value gives the shooter.
// As of HAM B2.3: There's a maximum range at which 100% penalty is given.
// As of HAM B2.8: Target's stance and the targetted bodypart will affect the end result.
INT8 AIM_PENALTY_PER_TARGET_SHOCK;
INT16 sCoweringPenalty = 0;
UINT8 ubCoweringDivisor;
UINT16 MIN_RANGE_FOR_FULL_COWER;
UINT16 MAX_TARGET_COWERING_PENALTY;
AIM_PENALTY_PER_TARGET_SHOCK = gGameExternalOptions.iAimPenaltyPerTargetShock;
MIN_RANGE_FOR_FULL_COWER = gGameExternalOptions.usMinRangeForFullCoweringPenalty;
MAX_TARGET_COWERING_PENALTY = gGameExternalOptions.usMaxTargetCoweringPenalty;
pTarget = SimpleFindSoldier( sGridNo, pSoldier->bTargetLevel );
if (pTarget != NULL)
{
if (pTarget->aiData.bShock )
{
if (gAnimControl[ pTarget->usAnimState ].ubHeight == ANIM_PRONE)
{
ubCoweringDivisor = gGameExternalOptions.ubCoweringPenaltyDivisorProne;
sCoweringPenalty = (pTarget->aiData.bShock * AIM_PENALTY_PER_TARGET_SHOCK);
sCoweringPenalty = sCoweringPenalty / ubCoweringDivisor;
sCoweringPenalty = (sCoweringPenalty * __min(iSightRange,MIN_RANGE_FOR_FULL_COWER)) / MIN_RANGE_FOR_FULL_COWER;
if (gGameExternalOptions.usMaxTargetCoweringPenalty > 0)
{
if ( sCoweringPenalty > gGameExternalOptions.usMaxTargetCoweringPenalty )
sCoweringPenalty = gGameExternalOptions.usMaxTargetCoweringPenalty;
}
if ( sCoweringPenalty < 1 )
sCoweringPenalty = 1;
iChance -= sCoweringPenalty;
}
else if (gAnimControl[ pTarget->usAnimState ].ubHeight == ANIM_CROUCH)
{
switch ( ubAimPos )
{
case AIM_SHOT_HEAD:
ubCoweringDivisor = gGameExternalOptions.ubCoweringPenaltyDivisorCrouchedHead;
break;
case AIM_SHOT_TORSO:
case AIM_SHOT_RANDOM:
case AIM_SHOT_GLAND:
ubCoweringDivisor = gGameExternalOptions.ubCoweringPenaltyDivisorCrouchedTorso;
break;
case AIM_SHOT_LEGS:
ubCoweringDivisor = gGameExternalOptions.ubCoweringPenaltyDivisorCrouchedLegs;
break;
}
sCoweringPenalty = (pTarget->aiData.bShock * AIM_PENALTY_PER_TARGET_SHOCK);
sCoweringPenalty = sCoweringPenalty / ubCoweringDivisor;
sCoweringPenalty = (sCoweringPenalty * __min(iSightRange,MIN_RANGE_FOR_FULL_COWER)) / MIN_RANGE_FOR_FULL_COWER;
if (gGameExternalOptions.usMaxTargetCoweringPenalty > 0)
{
if ( sCoweringPenalty > gGameExternalOptions.usMaxTargetCoweringPenalty )
sCoweringPenalty = gGameExternalOptions.usMaxTargetCoweringPenalty;
}
if ( sCoweringPenalty < 1 )
sCoweringPenalty = 1;
// HEADROCK HAM B2.8.1: Added formula to make sure that cowering target penalties
// are not given when on the roof.
if (pSoldier->pathing.bLevel == pTarget->pathing.bLevel && pSoldier->pathing.bLevel > 0)
sCoweringPenalty = 0; // No cowering penalties when both are on the roof!
else if (pSoldier->pathing.bLevel < pSoldier->pathing.bLevel && gAnimControl[ pTarget->usAnimState ].ubHeight == ANIM_PRONE)
sCoweringPenalty *= 2; // Much harder to shoot at anyone cowering above you.
else if (pSoldier->pathing.bLevel > pSoldier->pathing.bLevel)
sCoweringPenalty /= 2; // Much easier to shoot at cowerers below you.
iChance -= sCoweringPenalty;
}
}
}
}
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CalcChanceToHitGun: after scope bonus - ubAimTime = %d, iSightRange = %d, iChance = %d ", ubAimTime, iSightRange, iChance));
UINT8 bLightLevel = LightTrueLevel(sGridNo, pSoldier->bTargetLevel);
@@ -4123,7 +4289,8 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT16 sGridNo, INT16 ubAimTime,
}
// penalty for amount that enemy has moved
iPenalty = __min( ((pTarget->bTilesMoved * 3) / 2), 30 );
// HEADROCK HAM B2.6: Externalized the value
iPenalty = __min( (UINT16)((float)pTarget->bTilesMoved * (float)gGameExternalOptions.iMovementEffectOnAiming), 30 );
iChance -= iPenalty;
// if target sees us, he may have a chance to dodge before the gun goes off
@@ -4235,7 +4402,12 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT16 sGridNo, INT16 ubAimTime,
}
// MAKE SURE CHANCE TO HIT IS WITHIN DEFINED LIMITS
if (iChance < MINCHANCETOHIT)
// HEADROCK: (HAM) Altered so called "Defined Limits" to accept external arguments.
// The divisor argument only works when the minimum is set to 0. It has a chance of 1 in X to
// bump the minimum back to 1, where X = the Divisor value. So a divisor value of 50 gives a 1/50
// chance of getting some actual chance to hit despite the 0 minimum. The overall total would then
// be an effective CTH of only 1/5000 (50 chances to get a 1 out of 100 CTH, hehehe)
if (iChance <= gGameExternalOptions.iMinimumCTH)
{
if ( TANK( pSoldier ) )
{
@@ -4244,14 +4416,24 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT16 sGridNo, INT16 ubAimTime,
}
else
{
iChance = MINCHANCETOHIT;
iChance = gGameExternalOptions.iMinimumCTH;
if ( gGameExternalOptions.iMinimumCTH == 0 )
{
if ( PreRandom( gGameExternalOptions.iMinimumCTHDivisor ) == (gGameExternalOptions.iMinimumCTHDivisor - 1) )
{
iChance = 1;
}
}
}
}
else
{
if (iChance > MAXCHANCETOHIT)
iChance = MAXCHANCETOHIT;
}
else
{
// HEADROCK (HAM): Externalized maximum to JA2_OPTIONS.INI
// if (iChance > MAXCHANCETOHIT)
// iChance = MAXCHANCETOHIT;
if (iChance > gGameExternalOptions.iMaximumCTH)
iChance = gGameExternalOptions.iMaximumCTH;
}
// NumMessage("ChanceToHit = ",chance);
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CalcChanceToHitGun: ichance = %d",iChance));
@@ -5305,14 +5487,19 @@ UINT32 CalcChanceHTH( SOLDIERTYPE * pAttacker,SOLDIERTYPE *pDefender, INT16 ubAi
// MAKE SURE CHANCE TO HIT IS WITHIN DEFINED LIMITS
if (iChance < MINCHANCETOHIT)
// HEADROCK: I urinate on your Defined Limits! Power Rangers, Externalize!
// Disclaimer: No offense meant, all in good fun ;)
if (iChance < gGameExternalOptions.iMinimumCTH)
{
iChance = MINCHANCETOHIT;
iChance = gGameExternalOptions.iMinimumCTH;
}
else
{
if (iChance > MAXCHANCETOHIT)
iChance = MAXCHANCETOHIT;
// HEADROCK (HAM): Externalized maximum to JA2_OPTIONS.INI
//if (iChance > MAXCHANCETOHIT)
// iChance = MAXCHANCETOHIT;
if (iChance > gGameExternalOptions.iMaximumCTH)
iChance = gGameExternalOptions.iMaximumCTH;
}
//NumMessage("ChanceToStab = ",chance);
@@ -5768,13 +5955,17 @@ UINT32 CalcThrownChanceToHit(SOLDIERTYPE *pSoldier, INT16 sGridNo, INT16 ubAimTi
// reduce iChance to hit DIRECTLY by the item's working condition
iChance = (iChance * WEAPON_STATUS_MOD(pSoldier->inv[HANDPOS][0]->data.objectStatus)) / 100;
// MAKE SURE CHANCE TO HIT IS WITHIN DEFINED LIMITS
if (iChance < MINCHANCETOHIT)
iChance = MINCHANCETOHIT;
// What's with all these defined limits? Let's think out of the box for a minute, shall we?
// HEADROCK (HAM): externalized, effective immediately.
if (iChance < gGameExternalOptions.iMinimumCTH)
iChance = gGameExternalOptions.iMinimumCTH;
else
{
if (iChance > MAXCHANCETOHIT)
iChance = MAXCHANCETOHIT;
// HEADROCK (HAM): Externalized maximum to JA2_OPTIONS.INI
//if (iChance > MAXCHANCETOHIT)
// iChance = MAXCHANCETOHIT;
if (iChance > gGameExternalOptions.iMaximumCTH)
iChance = gGameExternalOptions.iMaximumCTH;
}
@@ -5969,7 +6160,13 @@ UINT8 GetAutofireShotsPerFiveAPs( OBJECTTYPE *pObj )
{
// DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("GetAutofireShotsPerFiveAPs"));
return Weapon[ pObj->usItem ].bAutofireShotsPerFiveAP;
// HEADROCK HAM B2.6: Added overall modifier
if (Weapon[ pObj->usItem ].bAutofireShotsPerFiveAP > 0)
{
return __max((Weapon[ pObj->usItem ].bAutofireShotsPerFiveAP + gGameExternalOptions.iAutofireBulletsPer5APModifier), 0);
}
else
return 0;
}
UINT16 GetMagSize( OBJECTTYPE *pObj )
+2 -1
View File
@@ -19,7 +19,8 @@ enum WeaponMode
void HandleTacticalEffectsOfEquipmentChange( SOLDIERTYPE *pSoldier, UINT32 uiInvPos, UINT16 usOldItem, UINT16 usNewItem );
#define MAXCHANCETOHIT 99
// HEADROCK: Removed this and externalized to JA2_OPTIONS.INI as part of HAM project.
//#define MAXCHANCETOHIT 99
#define BAD_DODGE_POSITION_PENALTY 20
#define GUN_BARREL_RANGE_BONUS 100
+10 -2
View File
@@ -470,7 +470,11 @@ void AddMissileTrail( BULLET *pBullet, FIXEDPT qCurrX, FIXEDPT qCurrY, FIXEDPT q
}
}
if (fTracer == TRUE)
// HEADROCK HAM B2.5: Created new bullet flag that tells us whether this specific bullet is a tracer.
// The condition now reads that flag and creates a lightshow only for tracer bullets. This flag is only
// used if the new Tracer System is on.
//if (fTracer == TRUE)
if ((gGameExternalOptions.iRealisticTracers > 0 && gGameExternalOptions.iNumBulletsPerTracer > 0 && pBullet->fTracer == TRUE) || (gGameExternalOptions.iRealisticTracers == 0 && fTracer == TRUE))
{
if ( pBullet->iLoop < 5 )
{
@@ -517,7 +521,11 @@ void AddMissileTrail( BULLET *pBullet, FIXEDPT qCurrX, FIXEDPT qCurrY, FIXEDPT q
AniParams.sDelay = (INT16)( 100 );
}
//else if ( pBullet->usFlags & ( BULLET_FLAG_TRACER ) )
else if (fTracer == TRUE)
// HEADROCK HAM B2.5: Created new bullet flag that tells us whether this specific bullet is a tracer.
// The condition now reads that flag and creates a lightshow only for tracer bullets. This flag is only
// used if the new Tracer System is on.
// else if (fTracer == TRUE)
else if ((gGameExternalOptions.iRealisticTracers > 0 && gGameExternalOptions.iNumBulletsPerTracer > 0 && pBullet->fTracer == TRUE) || (gGameExternalOptions.iRealisticTracers == 0 && fTracer == TRUE))
{
INT16 sXPos, sYPos;
+4
View File
@@ -231,4 +231,8 @@ INT16 FindBestCoverNearTheGridNo(SOLDIERTYPE *pSoldier, INT16 sGridNo, UINT8 ubS
INT8 FindDirectionForClimbing( SOLDIERTYPE *pSoldier, INT16 sGridNo, INT8 bLevel);
// HEADROCK HAM B2.7: Functions to assist group AI
INT16 AssessTacticalSituation( INT8 bSide );
BOOLEAN TeamSeesOpponent( INT8 bSide, SOLDIERTYPE * pOpponent );
INT32 CalcStraightThreatValue( SOLDIERTYPE *pEnemy );
+233
View File
@@ -2565,3 +2565,236 @@ void AINameMessage(SOLDIERTYPE * pSoldier,const STR8 str,INT32 num)
DebugAI( tempstr );
}
#endif
/////////////////////////////////////////////////////////////////////////////////////////////////
// HEADROCK:
//
// The following function(s) are part of my half-assed attempt to have the AI analyze the tactical
// situation, by comparing (known) squad sizes, the state of all combatants, and the orders of all
// friendlies. The idea is to return a value called "TacticalSituation" which can tell a combatant
// whether he should try to undertake a smarter course of action.
/////////////////////////////////////////////////////////////////////////////////////////////////
INT16 AssessTacticalSituation( INT8 bTeam )
{
UINT16 ubFriendlyTeamTacticalValue = 0;
UINT16 ubEnemyTeamTacticalValue = 0;
UINT8 ubSoldierTacticalThreat;
INT16 ubTacticalSituation;
UINT16 cnt;
SOLDIERTYPE * pSoldier;
// begin loop through all MERCs.
for ( cnt = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; cnt <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; cnt++ )
{
pSoldier = MercPtrs[ cnt ];
ubSoldierTacticalThreat = CalcStraightThreatValue( pSoldier );
// Player-controlled Mercs are 1.5 times more threatening than AIs
if (pSoldier->flags.uiStatusFlags & SOLDIER_PC)
ubSoldierTacticalThreat = (UINT8)((float)ubSoldierTacticalThreat * 1.5);
// Assess Threat
if (bTeam == OUR_TEAM || bTeam == MILITIA_TEAM)
{
// Friendly!
ubFriendlyTeamTacticalValue += ubSoldierTacticalThreat;
}
else
{
// Enemy!
if ( TeamSeesOpponent( ENEMY_TEAM, pSoldier ) )
ubEnemyTeamTacticalValue += ubSoldierTacticalThreat;
}
}
// begin loop through all Militia.
for ( cnt = gTacticalStatus.Team[ MILITIA_TEAM ].bFirstID; cnt <= gTacticalStatus.Team[ MILITIA_TEAM ].bLastID; cnt++ )
{
pSoldier = MercPtrs[ cnt ];
ubSoldierTacticalThreat = CalcStraightThreatValue( pSoldier );
// Assess Threat
if (bTeam == OUR_TEAM || bTeam == MILITIA_TEAM)
{
// Friendly!
ubFriendlyTeamTacticalValue += ubSoldierTacticalThreat;
}
else
{
// Enemy!
if ( TeamSeesOpponent( ENEMY_TEAM, pSoldier ) )
ubEnemyTeamTacticalValue += ubSoldierTacticalThreat;
}
}
// begin loop through all Enemies.
for ( cnt = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; cnt <= gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; cnt++ )
{
pSoldier = MercPtrs[ cnt ];
ubSoldierTacticalThreat = CalcStraightThreatValue( pSoldier );
// Assess Threat
if (bTeam == ENEMY_TEAM)
{
// Friendly!
ubFriendlyTeamTacticalValue += ubSoldierTacticalThreat;
}
else
{
// Enemy!
if ( TeamSeesOpponent( OUR_TEAM, pSoldier ) || TeamSeesOpponent ( MILITIA_TEAM, pSoldier) )
ubEnemyTeamTacticalValue += ubSoldierTacticalThreat;
}
}
ubTacticalSituation = ubEnemyTeamTacticalValue - ubFriendlyTeamTacticalValue;
return (ubTacticalSituation);
}
// HEADROCK: Function to check whether a team can see the specified soldier.
BOOLEAN TeamSeesOpponent( INT8 bTeam, SOLDIERTYPE * pOpponent )
{
SOLDIERTYPE * pSoldier;
UINT16 cnt;
// This assertion can be safely removed, assuming the program does what it should. It simply checks
// whether the "opponent" is on the same team being checked. That should be avoided when calling this
// function.
Assert( pOpponent->bTeam != bTeam );
// We're checking Merc/Militia visibility
if (bTeam == OUR_TEAM || bTeam == MILITIA_TEAM )
{
for ( cnt = gTacticalStatus.Team[ MILITIA_TEAM ].bFirstID; cnt <= gTacticalStatus.Team[ MILITIA_TEAM ].bLastID; cnt++ )
{
pSoldier = MercPtrs[ cnt ];
if (pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife >= OKLIFE)
{
if (pSoldier->aiData.bOppList[ pOpponent->ubID ] == SEEN_CURRENTLY)
return ( TRUE );
}
}
for ( cnt = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; cnt <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; cnt++ )
{
pSoldier = MercPtrs[ cnt ];
if (pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife >= OKLIFE)
{
// This assertion can be safely removed, assuming the program does what it should. It simply checks
// whether the "opponent" is on the same team being checked. That should be avoided when calling this
// function.
//Assert( pOpponent->bSide != bSide );
if (pSoldier->aiData.bOppList[ pOpponent->ubID ] == SEEN_CURRENTLY)
return ( TRUE );
}
}
return ( FALSE );
}
// Check enemy visibility
else if (bTeam == ENEMY_TEAM)
{
for ( cnt = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; cnt <= gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; cnt++ )
{
pSoldier = MercPtrs[ cnt ];
if (pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife >= OKLIFE)
{
// This assertion can be safely removed, assuming the program does what it should. It simply checks
// whether the "opponent" is on the same team being checked. That should be avoided when calling this
// function.
//Assert( pOpponent->bSide != bSide );
if (pSoldier->aiData.bOppList[ pOpponent->ubID ] == SEEN_CURRENTLY)
return ( TRUE );
}
}
return ( FALSE );
}
else
return (FALSE);
}
// HEADROCK: Function to assess an enemy's threat value without "me" argument.
INT32 CalcStraightThreatValue( SOLDIERTYPE *pEnemy )
{
INT32 iThreatValue = 0;
// If man is inactive, at base, on assignment, dead, unconscious
if (!pEnemy->bActive || !pEnemy->bInSector || !pEnemy->stats.bLife )
{
// he's no threat at all, return a negative number
iThreatValue = 0;
return(iThreatValue);
}
else
{
// ADD twice the man's level (2-20)
iThreatValue += pEnemy->stats.bExpLevel;
// ADD man's total action points (10-35)
iThreatValue += pEnemy->CalcActionPoints();
// ADD 1/2 of man's current action points (4-17)
iThreatValue += (pEnemy->bActionPoints / 2);
// ADD 1/10 of man's current health (0-10)
iThreatValue += (pEnemy->stats.bLife / 10);
if (pEnemy->bAssignment < ON_DUTY )
{
// ADD 1/4 of man's protection percentage (0-25)
iThreatValue += ArmourPercent( pEnemy ) / 4;
// ADD 1/5 of man's marksmanship skill (0-20)
iThreatValue += (pEnemy->stats.bMarksmanship / 5);
if ( Item[ pEnemy->inv[HANDPOS].usItem ].usItemClass & IC_WEAPON )
{
// ADD the deadliness of the item(weapon) he's holding (0-50)
iThreatValue += Weapon[pEnemy->inv[HANDPOS].usItem].ubDeadliness;
}
}
// SUBTRACT 1/5 of man's bleeding (0-20)
iThreatValue -= (pEnemy->bBleeding / 5);
// SUBTRACT 1/10 of man's breath deficiency (0-10)
iThreatValue -= ((100 - pEnemy->bBreath) / 10);
// SUBTRACT man's current shock value
iThreatValue -= pEnemy->aiData.bShock;
}
// if this man is conscious
if (pEnemy->stats.bLife < OKLIFE)
{
// if he's still something of a threat
if (iThreatValue > 0)
{
// drastically reduce his threat value (divide by 5 to 18)
iThreatValue /= (4 + (OKLIFE - pEnemy->stats.bLife));
}
}
// threat value of any opponent can never drop below 1
if (iThreatValue < 0)
{
iThreatValue = 0;
}
return(iThreatValue);
}
+20 -4
View File
@@ -1296,7 +1296,9 @@ void CalcBestStab(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestStab, BOOLEAN fBladeAt
}
}
else
ubChanceToHit = MAXCHANCETOHIT;
// HEADROCK (HAM): Externalized maximum to JA2_OPTIONS.INI
// ubChanceToHit = MAXCHANCETOHIT;
ubChanceToHit = gGameExternalOptions.iMaximumCTH;
//NumMessage("chance to Hit = ",ubChanceToHit);
//sprintf(tempstr,"Vs. %s, at AimTime %d, ubChanceToHit = %d",ExtMen[pOpponent->ubID].name,ubAimTime,ubChanceToHit);
@@ -1473,7 +1475,9 @@ void CalcTentacleAttack(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestStab )
ubChanceToHit = (INT16) CalcChanceToStab(pSoldier,pOpponent,ubAimTime);
}
else
ubChanceToHit = MAXCHANCETOHIT;
// HEADROCK (HAM): Externalized maximum to JA2_OPTIONS.INI
// ubChanceToHit = MAXCHANCETOHIT;
ubChanceToHit = gGameExternalOptions.iMaximumCTH;
//NumMessage("chance to Hit = ",ubChanceToHit);
//sprintf(tempstr,"Vs. %s, at AimTime %d, ubChanceToHit = %d",ExtMen[pOpponent->ubID].name,ubAimTime,ubChanceToHit);
@@ -2472,8 +2476,20 @@ void CheckIfShotPossible(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN s
}
//if ( (!suppressionFire && ( (IsScoped(pObj) && GunRange(pObj) > pSoldier->MaxDistanceVisible(pBestShot->sTarget, pBestShot->bTargetLevel) ) || pSoldier->bOrders == SNIPER ) ) ||
if ( (!suppressionFire && ( (IsScoped(pObj) && GunRange(pObj) > MaxNormalDistanceVisible() ) || pSoldier->aiData.bOrders == SNIPER ) ) ||
(suppressionFire && IsGunAutofireCapable(&pSoldier->inv[pBestShot->bWeaponIn] ) && GetMagSize(pObj) > 30 && (*pObj)[0]->data.gun.ubGunShotsLeft > 20 ))
// HEADROCK HAM B2.4: Changed this again - weapons are no longer checked for larger magazine to allow suppressive fire, due to
// suppressive fire revamp.
// if ( (!suppressionFire && ( (IsScoped(pObj) && GunRange(pObj) > MaxNormalDistanceVisible() ) || pSoldier->aiData.bOrders == SNIPER ) ) ||
// (suppressionFire && IsGunAutofireCapable(&pSoldier->inv[pBestShot->bWeaponIn] ) && GetMagSize(pObj) > 30 && (*pObj)[0]->data.gun.ubGunShotsLeft > 20 ))
BOOLEAN fEnableAISuppression = FALSE;
if ( gGameExternalOptions.fIncreaseAISuppressionFire && ((!suppressionFire && ( (IsScoped(pObj) && GunRange(pObj) > MaxNormalDistanceVisible() ) || pSoldier->aiData.bOrders == SNIPER ) ) ||
(suppressionFire && IsGunAutofireCapable(&pSoldier->inv[pBestShot->bWeaponIn]))) )
fEnableAISuppression = TRUE;
else if ( !gGameExternalOptions.fIncreaseAISuppressionFire && ( (!suppressionFire && ( (IsScoped(pObj) && GunRange(pObj) > MaxNormalDistanceVisible() ) || pSoldier->aiData.bOrders == SNIPER ) ) ||
(suppressionFire && IsGunAutofireCapable(&pSoldier->inv[pBestShot->bWeaponIn] ) && GetMagSize(pObj) > 30 && (*pObj)[0]->data.gun.ubGunShotsLeft > 20 )))
fEnableAISuppression = TRUE;
if (fEnableAISuppression)
{
// get the minimum cost to attack with this item
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"CheckIfShotPossible: getting min aps");
+38 -4
View File
@@ -1950,6 +1950,8 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
BOOLEAN fCivilian = (PTR_CIVILIAN && (pSoldier->ubCivilianGroup == NON_CIV_GROUP ||
(pSoldier->aiData.bNeutral && gTacticalStatus.fCivGroupHostile[pSoldier->ubCivilianGroup] == CIV_GROUP_NEUTRAL) ||
(pSoldier->ubBodyType >= FATCIV && pSoldier->ubBodyType <= CRIPPLECIV) ) );
// HEADROCK HAM B2.7: Calculate the overall tactical situation
INT16 ubOverallTacticalSituation = AssessTacticalSituation(pSoldier->bSide);
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("DecideActionRed: soldier orders = %d",pSoldier->aiData.bOrders));
@@ -2313,7 +2315,17 @@ if(!is_networked)//hayden
CheckIfShotPossible(pSoldier,&BestShot,TRUE);
//must have a small chance to hit and the opponent must be on the ground (can't suppress guys on the roof)
if ( BestShot.ubPossible && BestShot.ubChanceToReallyHit < 50 && Menptr[BestShot.ubOpponent].pathing.bLevel == 0 && pSoldier->aiData.bOrders != SNIPER )
// HEADROCK HAM BETA2.4: Adjusted this for a random chance to suppress regardless of chance. This augments
// current revamp of suppression fire.
BOOLEAN fEnableAIAutofire = FALSE;
if ( gGameExternalOptions.fIncreaseAISuppressionFire && ( ( BestShot.ubPossible && BestShot.ubChanceToReallyHit < 50 ) || (BestShot.ubPossible && BestShot.ubChanceToReallyHit < PreRandom(100)) && Menptr[BestShot.ubOpponent].pathing.bLevel == 0 && pSoldier->aiData.bOrders != SNIPER ))
fEnableAIAutofire = TRUE;
else if ( !gGameExternalOptions.fIncreaseAISuppressionFire && ( BestShot.ubPossible && BestShot.ubChanceToReallyHit < 50 && Menptr[BestShot.ubOpponent].pathing.bLevel == 0 && pSoldier->aiData.bOrders != SNIPER ))
fEnableAIAutofire = TRUE;
if (fEnableAIAutofire)
{
// then do it!
@@ -3141,7 +3153,23 @@ if(!is_networked)//hayden
{
// only try to run if we've actually been hit recently & noticably so
// otherwise, presumably our current cover is pretty good & sufficient
if (pSoldier->aiData.bShock > 0 || fCivilian)
// HEADROCK HAM B2.6: New value here helps us change the ratio of running away due to shock. This
// is terribly important if Suppression Shock is enabled.
UINT16 bShock = 0;
if (gGameExternalOptions.fSuppressionShock)
{
// If bShock value is greater than (2*ExpLevel + MoraleModifier)*1.5, the target will flee.
bShock = pSoldier->aiData.bShock;
if (bShock <= ((float)CalcSuppressionTolerance(pSoldier)*(float)1.5))
bShock = 0;
}
else
{
bShock = pSoldier->aiData.bShock;
}
if (bShock > 0 || fCivilian)
{
// look for best place to RUN AWAY to (farthest from the closest threat)
pSoldier->aiData.usActionData = FindSpotMaxDistFromOpponents(pSoldier);
@@ -4424,7 +4452,10 @@ INT8 DecideActionBlack(SOLDIERTYPE *pSoldier)
case ATTACKSLAYONLY:iChance += 30; break;
}
if ( pSoldier->inv[BestAttack.bWeaponIn][0]->data.gun.ubGunShotsLeft > 50 )
// HEADROCK HAM B2.6: Allows control over increased enemy burstfire.
if ( gGameExternalOptions.fIncreaseAISuppressionFire && pSoldier->inv[BestAttack.bWeaponIn][0]->data.gun.ubGunShotsLeft > 10 )
iChance += 20;
else if ( !gGameExternalOptions.fIncreaseAISuppressionFire && pSoldier->inv[BestAttack.bWeaponIn][0]->data.gun.ubGunShotsLeft > 50 )
iChance += 20;
// increase chance based on proximity and difficulty of enemy
@@ -4502,7 +4533,10 @@ INT8 DecideActionBlack(SOLDIERTYPE *pSoldier)
}
if ( pSoldier->inv[BestAttack.bWeaponIn][0]->data.gun.ubGunShotsLeft > 50 )
// HEADROCK HAM B2.6: Allows control over increased enemy autofire.
if ( gGameExternalOptions.fIncreaseAISuppressionFire && pSoldier->inv[BestAttack.bWeaponIn][0]->data.gun.ubGunShotsLeft > 20 )
iChance += 30;
else if ( !gGameExternalOptions.fIncreaseAISuppressionFire && pSoldier->inv[BestAttack.bWeaponIn][0]->data.gun.ubGunShotsLeft > 50 )
iChance += 30;
if ( bInGas )
+76 -34
View File
@@ -16,6 +16,8 @@
#include "overhead.h"
#include "Cursor Control.h"
#include "Sound Control.h"
// HEADROCK HAM B2.6: included this here to allow toggling the CTH bars.
#include "GameSettings.h"
#endif
//aim
@@ -1244,10 +1246,11 @@ extern UINT16 gsCurMouseWidth;*/
void DrawMouseGraphics( )
{
// HEADROCK (HAM): Made several changes here to allow multi-shot CtH display for bursts.
UINT16 * ptrBuf;
UINT32 uiPitch;
UINT32 cnt;
UINT32 actualPct = __min(gbCtH,99);
UINT32 cnt, i;
UINT32 actualPct = __min(gbCtH[0],99);
UINT16 usCBorderTop = Get16BPPColor( FROMRGB( 155, 155, 155 ) );
UINT16 usCBorderBottom = Get16BPPColor( FROMRGB( 120, 120, 120 ) );
UINT16 usCBar = Get16BPPColor( FROMRGB( 255, 255-255*actualPct/99, 0 ) );
@@ -1255,40 +1258,67 @@ void DrawMouseGraphics( )
UINT16 usCBar2 = Get16BPPColor( FROMRGB( 180, 140-140*actualPct/99, 0 ) );
UINT16 usCBack2 = Get16BPPColor( FROMRGB( 110, 100-100*actualPct/99, 0 ) );
UINT32 barLength = __min(35,gsCurMouseWidth);
UINT32 barY = gsCurMouseOffsetY-__min(35,gsCurMouseHeight)/2;
//UINT32 barY = gsCurMouseOffsetY-__min(35,gsCurMouseHeight)/2;
UINT32 barY;
if(gfUICtHBar)
{
ptrBuf = (UINT16 *) LockMouseBuffer( &uiPitch );
uiPitch >>= 1;
// HEADROCK HAM B1/2/2.6:
// This causes the function to display two CTH bars for autofire - the CTH of the first bullet,
// and the CTH of the last bullet in the volley, stored in gbCtH[0] and [1] respectively.
if ( gbCtHAutoFire && (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 3) )
gbCtHBurstCount = 2;
else if ( gbCtHAutoFire )
gbCtHBurstCount = 0;
for(cnt = gsCurMouseOffsetX+barLength/2;cnt > gsCurMouseOffsetX-barLength/2+1;cnt--)
// Sets the initial offsets of the bars. Burst and Autofire will display them higher above the
// cursor, to avoid obscuring the target or other data.
if (gbCtHBurstCount > 1 && !gbCtHAutoFire && (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 2) )
barY = gsCurMouseOffsetY-__min(55,gsCurMouseHeight)/2;
else if (gbCtHBurstCount && gbCtHAutoFire && (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 3) )
barY = gsCurMouseOffsetY-__min(55,gsCurMouseHeight)/2;
else
barY = gsCurMouseOffsetY-__min(35,gsCurMouseHeight)/2;
for (i=0; i<gbCtHBurstCount; i++)
{
ptrBuf[cnt-1 + uiPitch*(3+barY)] = usCBorderBottom;
ptrBuf[cnt-1 + uiPitch*barY] = usCBorderTop;
actualPct = __min(gbCtH[ i ],99);
ptrBuf = (UINT16 *) LockMouseBuffer( &uiPitch );
uiPitch >>= 1;
for(cnt = gsCurMouseOffsetX+barLength/2;cnt > gsCurMouseOffsetX-barLength/2+1;cnt--)
{
ptrBuf[cnt-1 + uiPitch*(3+barY)] = usCBorderBottom;
ptrBuf[cnt-1 + uiPitch*barY] = usCBorderTop;
}
ptrBuf[gsCurMouseOffsetX+barLength/2 + uiPitch*(1+barY)] = usCBorderBottom;
ptrBuf[gsCurMouseOffsetX-barLength/2 + uiPitch*(1+barY)] = usCBorderTop;
ptrBuf[gsCurMouseOffsetX+barLength/2 + uiPitch*(2+barY)] = usCBorderBottom;
ptrBuf[gsCurMouseOffsetX-barLength/2 + uiPitch*(2+barY)] = usCBorderTop;
for(cnt = 0;cnt < (barLength-2)*actualPct/99;cnt++)
{
ptrBuf[cnt + gsCurMouseOffsetX-barLength/2+1 + uiPitch*(barY+2)] = usCBar2;
ptrBuf[cnt + gsCurMouseOffsetX-barLength/2+1 + uiPitch*(barY+1)] = usCBar;
}
for(cnt = (barLength-2)*actualPct/99;cnt < (barLength-2);cnt++)
{
ptrBuf[cnt + gsCurMouseOffsetX-barLength/2+1 + uiPitch*(barY+2)] = usCBack2;
ptrBuf[cnt + gsCurMouseOffsetX-barLength/2+1 + uiPitch*(barY+1)] = usCBack;
}
UnlockMouseBuffer();
if (gbCtHBurstCount>1)
barY = barY+5;
}
ptrBuf[gsCurMouseOffsetX+barLength/2 + uiPitch*(1+barY)] = usCBorderBottom;
ptrBuf[gsCurMouseOffsetX-barLength/2 + uiPitch*(1+barY)] = usCBorderTop;
ptrBuf[gsCurMouseOffsetX+barLength/2 + uiPitch*(2+barY)] = usCBorderBottom;
ptrBuf[gsCurMouseOffsetX-barLength/2 + uiPitch*(2+barY)] = usCBorderTop;
for(cnt = 0;cnt < (barLength-2)*actualPct/99;cnt++)
{
ptrBuf[cnt + gsCurMouseOffsetX-barLength/2+1 + uiPitch*(barY+2)] = usCBar2;
ptrBuf[cnt + gsCurMouseOffsetX-barLength/2+1 + uiPitch*(barY+1)] = usCBar;
}
for(cnt = (barLength-2)*actualPct/99;cnt < (barLength-2);cnt++)
{
ptrBuf[cnt + gsCurMouseOffsetX-barLength/2+1 + uiPitch*(barY+2)] = usCBack2;
ptrBuf[cnt + gsCurMouseOffsetX-barLength/2+1 + uiPitch*(barY+1)] = usCBack;
}
UnlockMouseBuffer();
barY = gsCurMouseOffsetY-__min(35,gsCurMouseHeight)/2;
}
}
@@ -1346,11 +1376,23 @@ void DrawMouseText( )
swprintf( pStr, L"%d", gsBulletCount );
FindFontCenterCoordinates( 0, 0, gsCurMouseWidth, gsCurMouseHeight, pStr, TINYFONT1, &sX, &sY );
mprintf( sX, sY - 10 - GetFontHeight(TINYFONT1), pStr );
// HEADROCK HAM B2: Moved bullet counter to right side (and a bit upwards) to accomodate two CTH bars.
//mprintf( sX, sY - 10 - GetFontHeight(TINYFONT1), pStr );
if (gGameExternalOptions.iNewCTHBars == 1 || gGameExternalOptions.iNewCTHBars == 3)
// New CTH Bar moves bullet count to new location.
mprintf( 46, sY - 15 - GetFontHeight(TINYFONT1), pStr );
else
// Vanilla 1.13
mprintf( sX, sY - 10 - GetFontHeight(TINYFONT1), pStr );
swprintf( pStr, L"%d", gsTotalBulletCount );
FindFontCenterCoordinates( 0, 0, gsCurMouseWidth, gsCurMouseHeight, pStr, TINYFONT1, &sX, &sY );
mprintf( sX, sY + 7 + GetFontHeight(TINYFONT1), pStr );
// HEADROCK HAM B2: Removed this. The bottom line will now display bodypart targetting, like Burst and
// Single.
if ( gGameExternalOptions.iNewCTHBars != 1 && gGameExternalOptions.iNewCTHBars != 3 )
{
swprintf( pStr, L"%d", gsTotalBulletCount );
FindFontCenterCoordinates( 0, 0, gsCurMouseWidth, gsCurMouseHeight, pStr, TINYFONT1, &sX, &sY );
mprintf( sX, sY + 7 + GetFontHeight(TINYFONT1), pStr );
}
// reset
SetFontDestBuffer( FRAME_BUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
+2
View File
@@ -1653,6 +1653,8 @@ extern STR16 New113Message[];
extern STR16 New113MERCMercMailTexts[];
extern STR16 MissingIMPSkillsDescriptions[];
// HEADROCK: HAM Messages
extern STR16 New113HAMMessage[];
enum
{
MSG113_STORM_STARTED,
+9 -3
View File
@@ -5091,9 +5091,10 @@ STR16 sRepairsDoneString[] =
L"%s修复了自己的物品。",
L"%s修复了所有人的枪和护甲。",
L"%s修复了所有人的装备。",
L"%s修复了所有人的携带物品。",
L"%s修复了所有人的携带物品。",
L"%s修复了所有人的携带物品。",
L"%s finished repairing everyone's large carried items",
L"%s finished repairing everyone's medium carried items",
L"%s finished repairing everyone's small carried items",
L"%s finished repairing everyone's LBE gear",
};
STR16 zGioDifConfirmText[]=
@@ -5406,6 +5407,11 @@ STR16 New113Message[] =
L"你得检查一下你的眼部装备",
};
STR16 New113HAMMessage[] =
{
L"%s cowers in fear!",
};
// WANNE: This are the email texts, when one of the 4 new 1.13 MERC mercs have levelled up, that Speck sends
// INFO: Do not replace the ?characters. They indicate the <B2> (-> Newline) from the edt files
STR16 New113MERCMercMailTexts[] =
+9 -3
View File
@@ -4243,9 +4243,10 @@ STR16 sRepairsDoneString[] =
L"%s is klaar met reparatie van eigen items",
L"%s is klaar met reparatie van ieders wapens en bepantering",
L"%s is klaar met reparatie van ieders uitrusting",
L"%s is klaar met reparatie van ieders vervoerde items",
L"%s is klaar met reparatie van ieders vervoerde items",
L"%s is klaar met reparatie van ieders vervoerde items",
L"%s finished repairing everyone's large carried items",
L"%s finished repairing everyone's medium carried items",
L"%s finished repairing everyone's small carried items",
L"%s finished repairing everyone's LBE gear",
};
STR16 zGioDifConfirmText[]=
@@ -4474,6 +4475,11 @@ STR16 New113Message[] =
L"You should check your goggles",
};
STR16 New113HAMMessage[] =
{
L"%s cowers in fear!",
};
// WANNE: This are the email texts, when one of the 4 new 1.13 MERC mercs have levelled up, that Speck sends
// INFO: Do not replace the ± characters. They indicate the <B2> (-> Newline) from the edt files
STR16 New113MERCMercMailTexts[] =
+10 -3
View File
@@ -4250,14 +4250,16 @@ STR16 gzCreditNameFunny[]=
L"(did items and loading screens too!)", // Joey \"Joeker\" Whelan",
};
// HEADROCK: Adjusted strings for better feedback, and added new string for LBE repair.
STR16 sRepairsDoneString[] =
{
L"%s finished repairing own items",
L"%s finished repairing everyone's guns & armor",
L"%s finished repairing everyone's equipped items",
L"%s finished repairing everyone's carried items",
L"%s finished repairing everyone's carried items",
L"%s finished repairing everyone's carried items",
L"%s finished repairing everyone's large carried items",
L"%s finished repairing everyone's medium carried items",
L"%s finished repairing everyone's small carried items",
L"%s finished repairing everyone's LBE gear",
};
STR16 zGioDifConfirmText[]=
@@ -4486,6 +4488,11 @@ STR16 New113Message[] =
L"You should check your goggles",
};
STR16 New113HAMMessage[] =
{
L"%s cowers in fear!",
};
// WANNE: This are the email texts, when one of the 4 new 1.13 MERC mercs have levelled up, that Speck sends
// INFO: Do not replace the ± characters. They indicate the <B2> (-> Newline) from the edt files
STR16 New113MERCMercMailTexts[] =
+9 -3
View File
@@ -4256,9 +4256,10 @@ STR16 sRepairsDoneString[] =
L"%s a terminé la réparation de ses objets",
L"%s a terminé la réparation des armes & protections",
L"%s a terminé la réparation des objets portés",
L"%s a terminé la réparation des objets transportés",
L"%s a terminé la réparation des objets transportés",
L"%s a terminé la réparation des objets transportés",
L"%s finished repairing everyone's large carried items",
L"%s finished repairing everyone's medium carried items",
L"%s finished repairing everyone's small carried items",
L"%s finished repairing everyone's LBE gear",
};
STR16 zGioDifConfirmText[]=
@@ -4487,6 +4488,11 @@ STR16 New113Message[] =
L"Vous devriez vérifier votre accessoire de vision",
};
STR16 New113HAMMessage[] =
{
L"%s cowers in fear!",
};
// WANNE: This are the email texts, when one of the 4 new 1.13 MERC mercs have levelled up, that Speck sends
// INFO: Do not replace the ± characters. They indicate the <B2> (-> Newline) from the edt files
STR16 New113MERCMercMailTexts[] =
+9 -3
View File
@@ -4058,9 +4058,10 @@ STR16 sRepairsDoneString[] =
L"%s hat seine eigenen Gegenstände repariert",
L"%s hat die Waffen und Rüstungen aller Teammitglieder repariert",
L"%s hat die aktivierten Gegenstände aller Teammitglieder repariert",
L"%s hat die mitgeführten Gegenstände aller Teammitglieder repariert",
L"%s hat die mitgeführten Gegenstände aller Teammitglieder repariert",
L"%s hat die mitgeführten Gegenstände aller Teammitglieder repariert",
L"%s hat die großen mitgeführten Gegenstände aller Teammitglieder repariert",
L"%s hat die mittelgroßen mitgeführten Gegenstände aller Teammitglieder repariert",
L"%s hat die kleinen mitgeführten Gegenstände aller Teammitglieder repariert",
L"%s hat die LBE-Gegenstände aller Teammitglieder repariert",
};
STR16 zGioDifConfirmText[]=
@@ -4282,6 +4283,11 @@ STR16 New113Message[] =
L"Sie sollten Ihre Brillen prüfen",
};
STR16 New113HAMMessage[] =
{
L"%s cowers in fear!",
};
// WANNE: This are the email texts, when one of the 4 new 1.13 MERC mercs have levelled up, that Speck sends
// INFO: Do not replace the ± characters. They indicate the <B2> (-> Newline) from the edt files
STR16 New113MERCMercMailTexts[] =
+9 -3
View File
@@ -4235,9 +4235,10 @@ STR16 sRepairsDoneString[] =
L"%s ha finito di riparare gli oggetti",
L"%s ha finito di riparare le armi e i giubbotti antiproiettile di tutti",
L"%s ha finito di riparare gli oggetti dell'equipaggiamento di tutti",
L"%s ha finito di riparare gli oggetti trasportati di tutti",
L"%s ha finito di riparare gli oggetti trasportati di tutti",
L"%s ha finito di riparare gli oggetti trasportati di tutti",
L"%s finished repairing everyone's large carried items",
L"%s finished repairing everyone's medium carried items",
L"%s finished repairing everyone's small carried items",
L"%s finished repairing everyone's LBE gear",
};
STR16 zGioDifConfirmText[]=
@@ -4472,6 +4473,11 @@ STR16 New113Message[] =
L"You should check your goggles",
};
STR16 New113HAMMessage[] =
{
L"%s cowers in fear!",
};
// WANNE: This are the email texts, when one of the 4 new 1.13 MERC mercs have levelled up, that Speck sends
// INFO: Do not replace the ± characters. They indicate the <B2> (-> Newline) from the edt files
STR16 New113MERCMercMailTexts[] =
+9 -3
View File
@@ -4248,9 +4248,10 @@ STR16 sRepairsDoneString[] =
L"%s skoñczy³(a) naprawiaæ w³asne wyposa¿enie",
L"%s skoñczy³(a) naprawiaæ broñ i ochraniacze wszystkich cz³onków oddzia³u",
L"%s skoñczy³(a) naprawiaæ wyposa¿enie wszystkich cz³onków oddzia³u",
L"%s skończył(a) naprawiać ekwipunek wszystkich członków oddziału",
L"%s zakończył(a) naprawę ekwipunku oddziału",
L"%s zakończył(a) naprawę ekwipunku oddziału",
L"%s finished repairing everyone's large carried items",
L"%s finished repairing everyone's medium carried items",
L"%s finished repairing everyone's small carried items",
L"%s finished repairing everyone's LBE gear",
};
STR16 zGioDifConfirmText[]=
@@ -4479,6 +4480,11 @@ STR16 New113Message[] =
L"SprawdŸ swoje gogle",
};
STR16 New113HAMMessage[] =
{
L"%s cowers in fear!",
};
// WANNE: This are the email texts, when one of the 4 new 1.13 MERC mercs have levelled up, that Speck sends
// INFO: Do not replace the ± characters. They indicate the <B2> (-> Newline) from the edt files
STR16 New113MERCMercMailTexts[] =
+9 -3
View File
@@ -4250,9 +4250,10 @@ STR16 sRepairsDoneString[] =
L"%s: çàâåðøåí ðåìîíò ëè÷íûõ âåùåé.",
L"%s: çàâåðøåí ðåìîíò âñåãî îðóæèÿ è áðîíè.",
L"%s: çàâåðøåí ðåìîíò âñåé ýêèïèðîâêè îòðÿäà.",
L"%s: ηΰβεπψεν πεμξνς βρευ βεωει, θμεώωθυρ σ ξςπδΰ.",
L"%s: ηΰβεπψεν πεμξνς βρευ βεωει, θμεώωθυρ σ ξςπδΰ.",
L"%s: ηΰβεπψεν πεμξνς βρευ βεωει, θμεώωθυρ σ ξςπδΰ.",
L"%s finished repairing everyone's large carried items",
L"%s finished repairing everyone's medium carried items",
L"%s finished repairing everyone's small carried items",
L"%s finished repairing everyone's LBE gear",
};
STR16 zGioDifConfirmText[]=
@@ -4482,6 +4483,11 @@ STR16 New113Message[] =
L"Ïðîâåðü ÷òî ñîëäàòó ìåøàåò ëó÷øå âèäåòü.", //You should check your goggles
};
STR16 New113HAMMessage[] =
{
L"%s cowers in fear!",
};
// WANNE: This are the email texts, when one of the 4 new 1.13 MERC mercs have levelled up, that Speck sends
// INFO: Do not replace the ± characters. They indicate the <B2> (-> Newline) from the edt files
STR16 New113MERCMercMailTexts[] =
+9 -3
View File
@@ -4255,9 +4255,10 @@ STR16 sRepairsDoneString[] =
L"%s finished repairing own items",
L"%s finished repairing everyone's guns & armor",
L"%s finished repairing everyone's equipped items",
L"%s finished repairing everyone's carried items",
L"%s finished repairing everyone's carried items",
L"%s finished repairing everyone's carried items",
L"%s finished repairing everyone's large carried items",
L"%s finished repairing everyone's medium carried items",
L"%s finished repairing everyone's small carried items",
L"%s finished repairing everyone's LBE gear",
};
STR16 zGioDifConfirmText[]=
@@ -4486,6 +4487,11 @@ STR16 New113Message[] =
L"You should check your goggles",
};
STR16 New113HAMMessage[] =
{
L"%s cowers in fear!",
};
// WANNE: This are the email texts, when one of the 4 new 1.13 MERC mercs have levelled up, that Speck sends
// INFO: Do not replace the ± characters. They indicate the <B2> (-> Newline) from the edt files
STR16 New113MERCMercMailTexts[] =