diff --git a/GameSettings.cpp b/GameSettings.cpp index 7825a116..f2476426 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -73,6 +73,10 @@ // anv: helicopter repair settings - enough of these to put them in own file #define HELICOPTER_SETTINGS_FILE "Helicopter_Settings.ini" +#define MORALE_SETTINGS_FILE "Morale_Settings.ini" + +#define REPUTATION_SETTINGS_FILE "Reputation_Settings.ini" + #define CD_ROOT_DIR "DATA\\" GAME_SETTINGS gGameSettings; @@ -82,6 +86,8 @@ GAME_EXTERNAL_OPTIONS gGameExternalOptions; SKILL_TRAIT_VALUES gSkillTraitValues; // SANDRO - added this one TAUNTS_SETTINGS gTauntsSettings; HELICOPTER_SETTINGS gHelicopterSettings; +MORALE_SETTINGS gMoraleSettings; +REPUTATION_SETTINGS gReputationSettings; CTH_CONSTANTS gGameCTHConstants; // HEADROCK HAM 4: CTH constants MOD_SETTINGS gModSettings; //DBrot: mod specific settings @@ -2169,12 +2175,15 @@ void LoadSkillTraitsExternalSettings() { CIniReader iniReader(STOMP_SETTINGS_FILE); - gSkillTraitValues.ubMaxNumberOfTraits = iniReader.ReadInteger("Generic Traits Settings","MAX_NUMBER_OF_TRAITS", 3, 2, 30); - gSkillTraitValues.ubNumberOfMajorTraitsAllowed = iniReader.ReadInteger("Generic Traits Settings","NUMBER_OF_MAJOR_TRAITS_ALLOWED", 2, 2, 20); + gSkillTraitValues.ubMaxNumberOfTraits = iniReader.ReadInteger("Generic Traits Settings","MAX_NUMBER_OF_TRAITS", 5, 2, 30); + gSkillTraitValues.ubNumberOfMajorTraitsAllowed = iniReader.ReadInteger("Generic Traits Settings","NUMBER_OF_MAJOR_TRAITS_ALLOWED", 3, 2, 20); + + gSkillTraitValues.ubMaxNumberOfTraitsForIMP = iniReader.ReadInteger("Generic Traits Settings","MAX_NUMBER_OF_TRAITS_FOR_IMP", 3, 2, 30); + gSkillTraitValues.ubNumberOfMajorTraitsAllowedForIMP = iniReader.ReadInteger("Generic Traits Settings","NUMBER_OF_MAJOR_TRAITS_ALLOWED_FOR_IMP", 2, 2, 20); // Allow an exception in number of traits for Special Merc? - gSkillTraitValues.fAllowSpecialMercTraitsException = iniReader.ReadBoolean("Generic Traits Settings","ALLOW_EXCEPTION_FOR_SPECIAL_MERC", TRUE); - gSkillTraitValues.ubSpecialMercID = iniReader.ReadInteger("Generic Traits Settings","SPECIAL_MERC_ID", 33, 0, 254); + //gSkillTraitValues.fAllowSpecialMercTraitsException = iniReader.ReadBoolean("Generic Traits Settings","ALLOW_EXCEPTION_FOR_SPECIAL_MERC", TRUE); + //gSkillTraitValues.ubSpecialMercID = iniReader.ReadInteger("Generic Traits Settings","SPECIAL_MERC_ID", 33, 0, 254); // Allow traits prerequisities for attributes? gSkillTraitValues.fAllowAttributePrereq = iniReader.ReadBoolean("Generic Traits Settings","SET_MINIMUM_ATTRIBUTES_FOR_TRAITS", TRUE); @@ -2443,6 +2452,16 @@ void LoadSkillTraitsExternalSettings() gSkillTraitValues.usVOMortarSignalShellRadius = iniReader.ReadInteger("Radio Operator","RADIO_OPERATOR_MORTAR_SIGNAL_SHELL_RADIUS", 2, 2, 100); gSkillTraitValues.sVOScanAssignmentBaseRange = iniReader.ReadInteger("Radio Operator","RADIO_OPERATOR_ASSIGNMENT_SCAN_BASE_RANGE", 5, 0, 20); gSkillTraitValues.sVOListeningHearingBonus = iniReader.ReadInteger("Radio Operator","RADIO_OPERATOR_LISTENING_HEARING_BONUS", 20, 0, 100); + + // anv: SNITCH + gSkillTraitValues.ubSNTBaseChance = iniReader.ReadInteger("Snitch","BASE_CHANCE", 50, 0, 100); + gSkillTraitValues.fSNTMercOpinionAboutSnitchBonusModifier = iniReader.ReadFloat("Snitch","MERC_OPINION_ABOUT_SNITCH_MODIFIER", 0.5, 0.0, 10.0); + gSkillTraitValues.fSNTSnitchOpinionAboutMercBonusModifier = iniReader.ReadFloat("Snitch","SNITCH_OPINION_ABOUT_MERC_MODIFIER", 0.2, 0.0, 10.0); + gSkillTraitValues.fSNTSnitchLeadershipBonusModifer = iniReader.ReadFloat("Snitch","SNITCH_LEADERSHIP_BONUS_MODIFIER", 0.5, 0.0, 10.0); + gSkillTraitValues.bSNTSociableMercBonus = iniReader.ReadInteger("Snitch","SOCIABLE_MERC_BONUS", 10, -100, 100); + gSkillTraitValues.bSNTLonerMercBonus = iniReader.ReadInteger("Snitch","LONER_MERC_BONUS", -10, -100, 100); + gSkillTraitValues.bSNTSameAssignmentBonus = iniReader.ReadInteger("Snitch","LONER_MERC_BONUS", -20, -100, 100); + gSkillTraitValues.bSNTMercOpinionAboutMercTreshold = iniReader.ReadInteger("Snitch","MERC_OPINION_ABOUT_MERC_TRESHOLD", -10, -25, 25); } //DBrot: Grids void LoadModSettings(){ @@ -3352,6 +3371,120 @@ void LoadHelicopterRepairRefuelSettings() gHelicopterSettings.fHelicopterTownLoyaltyCheck = iniReader.ReadBoolean("Helicopter Other Settings","HELICOPTER_TOWN_LOYALTY_CHECK", TRUE ); } +void LoadMoraleSettings() +{ + CIniReader iniReader(MORALE_SETTINGS_FILE); + + gMoraleSettings.ubDefaultMorale = iniReader.ReadInteger("General Morale Settings","DEFAULT_MORALE", 50, 0, 100); + + gMoraleSettings.bValues[MORALE_KILLED_ENEMY] = iniReader.ReadInteger("Tactical Morale Settings","MORALE_KILLED_ENEMY", 4, -100, 100); + gMoraleSettings.bValues[MORALE_SQUADMATE_DIED] = iniReader.ReadInteger("Tactical Morale Settings","MORALE_SQUADMATE_DIED", -5, -100, 100); + gMoraleSettings.bValues[MORALE_SUPPRESSED] = iniReader.ReadInteger("Tactical Morale Settings","MORALE_SUPPRESSED", -1, -100, 100); + gMoraleSettings.bValues[MORALE_AIRSTRIKE] = iniReader.ReadInteger("Tactical Morale Settings","MORALE_AIRSTRIKE", -2, -100, 100); + gMoraleSettings.bValues[MORALE_DID_LOTS_OF_DAMAGE] = iniReader.ReadInteger("Tactical Morale Settings","MORALE_DID_LOTS_OF_DAMAGE", 2, -100, 100); + gMoraleSettings.bValues[MORALE_TOOK_LOTS_OF_DAMAGE] = iniReader.ReadInteger("Tactical Morale Settings","MORALE_TOOK_LOTS_OF_DAMAGE", -3, -100, 100); + gMoraleSettings.bValues[MORALE_ALCOHOL_CRASH] = iniReader.ReadInteger("Tactical Morale Settings","MORALE_ALCOHOL_CRASH", -10, -100, 100); + gMoraleSettings.bValues[MORALE_DRUGS_CRASH] = iniReader.ReadInteger("Tactical Morale Settings","MORALE_DRUGS_CRASH", -5, -100, 100); + gMoraleSettings.bValues[MORALE_CLAUSTROPHOBE_UNDERGROUND] = iniReader.ReadInteger("Tactical Morale Settings","MORALE_CLAUSTROPHOBE_UNDERGROUND", -1, -100, 100); + gMoraleSettings.bValues[MORALE_INSECT_PHOBIC_SEES_CREATURE] = iniReader.ReadInteger("Tactical Morale Settings","MORALE_INSECT_PHOBIC_SEES_CREATURE", -5, -100, 100); + gMoraleSettings.bValues[MORALE_NERVOUS_ALONE] = iniReader.ReadInteger("Tactical Morale Settings","MORALE_NERVOUS_ALONE", -1, -100, 1000); + gMoraleSettings.bValues[MORALE_PSYCHO_UNABLE_TO_PSYCHO] = iniReader.ReadInteger("Tactical Morale Settings","MORALE_PSYCHO_UNABLE_TO_PSYCHO", -1, -100, 100); + gMoraleSettings.bValues[MORALE_MALICIOUS_HIT] = iniReader.ReadInteger("Tactical Morale Settings","MORALE_MALICIOUS_HIT", 1, -100, 100); + gMoraleSettings.bValues[MORALE_FOOD] = iniReader.ReadInteger("Tactical Morale Settings","MORALE_FOOD", 1, -100, 100); + gMoraleSettings.bValues[MORALE_GOOD_FOOD] = iniReader.ReadInteger("Tactical Morale Settings","MORALE_GOOD_FOOD", 5, -100, 100); + gMoraleSettings.bValues[MORALE_BAD_FOOD] = iniReader.ReadInteger("Tactical Morale Settings","MORALE_BAD_FOOD", -1, -100, 100); + gMoraleSettings.bValues[MORALE_LOATHSOME_FOOD] = iniReader.ReadInteger("Tactical Morale Settings","MORALE_LOATHSOME_FOOD", -5, -100, 100); + + gMoraleSettings.bValues[MORALE_KILLED_CIVILIAN] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_KILLED_CIVILIAN", -5, -100, 100); + gMoraleSettings.bValues[MORALE_BATTLE_WON] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_BATTLE_WON", 4, -100, 100); + gMoraleSettings.bValues[MORALE_RAN_AWAY] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_RAN_AWAY", -5, -100, 1000); + gMoraleSettings.bValues[MORALE_HEARD_BATTLE_WON] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_HEARD_BATTLE_WON", 2, -100, 100); + gMoraleSettings.bValues[MORALE_HEARD_BATTLE_LOST] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_HEARD_BATTLE_LOST", -2, -100, 100); + gMoraleSettings.bValues[MORALE_TOWN_LIBERATED] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_TOWN_LIBERATED", 5, -100, 100); + gMoraleSettings.bValues[MORALE_TOWN_LOST] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_TOWN_LOST", -5, -100, 100); + gMoraleSettings.bValues[MORALE_MINE_LIBERATED] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_MINE_LIBERATED", 8, -100, 1000); + gMoraleSettings.bValues[MORALE_MINE_LOST] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_MINE_LOST", -8, -100, 100); + gMoraleSettings.bValues[MORALE_SAM_SITE_LIBERATED] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_SAM_SITE_LIBERATED", 3, -100, 100); + gMoraleSettings.bValues[MORALE_SAM_SITE_LOST] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_SAM_SITE_LOST", -3, -100, 100); + gMoraleSettings.bValues[MORALE_BUDDY_DIED] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_BUDDY_DIED", -15, -100, 1000); + gMoraleSettings.bValues[MORALE_HATED_DIED] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_HATED_DIED", 5, -100, 100); + gMoraleSettings.bValues[MORALE_TEAMMATE_DIED] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_TEAMMATE_DIED", -5, -100, 100); + gMoraleSettings.bValues[MORALE_LOW_DEATHRATE] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_LOW_DEATHRATE", 5, -100, 100); + gMoraleSettings.bValues[MORALE_HIGH_DEATHRATE] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_HIGH_DEATHRATE", -5, -100, 100); + gMoraleSettings.bValues[MORALE_GREAT_MORALE] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_GREAT_MORALE", 2, -100, 1000); + gMoraleSettings.bValues[MORALE_POOR_MORALE] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_POOR_MORALE", -2, -100, 100); + gMoraleSettings.bValues[MORALE_MONSTER_QUEEN_KILLED] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_MONSTER_QUEEN_KILLED", 15, -100, 100); + gMoraleSettings.bValues[MORALE_DEIDRANNA_KILLED] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_DEIDRANNA_KILLED", 25, -100, 1000); + gMoraleSettings.bValues[MORALE_MERC_CAPTURED] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_MERC_CAPTURED", -5, -100, 100); + gMoraleSettings.bValues[MORALE_MERC_MARRIED] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_MERC_MARRIED", -5, -100, 100); + gMoraleSettings.bValues[MORALE_QUEEN_BATTLE_WON] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_QUEEN_BATTLE_WON", 8, -100, 100); + gMoraleSettings.bValues[MORALE_SEX] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_SEX", 5, -100, 100); + gMoraleSettings.bValues[MORALE_HEAT_INTOLERANT_IN_DESERT] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_HEAT_INTOLERANT_IN_DESERT",-14, -100, 100); + gMoraleSettings.bValues[MORALE_PACIFIST_GAIN_NONCOMBAT] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_PACIFIST_GAIN_NONCOMBAT", 1, -100, 1000); + gMoraleSettings.bValues[MORALE_BUDDY_FIRED] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_BUDDY_FIRED", -5, -100, 100); + gMoraleSettings.bValues[MORALE_BUDDY_FIRED_EARLY] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_BUDDY_FIRED_EARLY", -3, -100, 100); + gMoraleSettings.bValues[MORALE_BUDDY_FIRED_ON_BAD_TERMS] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_BUDDY_FIRED_ON_BAD_TERMS", -3, -100, 100); + gMoraleSettings.bValues[MORALE_BAD_EQUIPMENT] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_BAD_EQUIPMENT", -2, -100, 1000); + gMoraleSettings.bValues[MORALE_OWED_MONEY] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_OWED_MONEY", -3, -100, 100); + gMoraleSettings.bValues[MORALE_OWED_MONEY_DAYS] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_OWED_MONEY_DAYS", 3, 0, 100); + gMoraleSettings.bValues[MORALE_PLAYER_INACTIVE] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_PLAYER_INACTIVE", 3, -100, 100); + gMoraleSettings.bValues[MORALE_PLAYER_INACTIVE_DAYS] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_PLAYER_INACTIVE_DAYS", 3, 0, 100); + gMoraleSettings.bValues[MORALE_PLAYER_INACTIVE_DAYS_AGGRESSIVE_BONUS] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_PLAYER_INACTIVE_DAYS_AGGRESSIVE_BONUS", -1, -100, 100); + gMoraleSettings.bValues[MORALE_PLAYER_INACTIVE_DAYS_PACIFIST_BONUS] = iniReader.ReadInteger("Strategic Morale Settings","MORALE_PLAYER_INACTIVE_DAYS_PACIFIST_BONUS", 2, -100, 100); + + gMoraleSettings.bModifiers[MORALE_MOD_MAX] = iniReader.ReadInteger("Morale Modifiers Settings","MORALE_MOD_MAX", -1, 0, 100); + + gMoraleSettings.sDrugAndAlcoholModifiers[DRUG_EFFECT_MORALE_MOD] = iniReader.ReadInteger("Morale Modifiers Settings","DRUG_EFFECT_MORALE_MOD", 150, 0, 10000); + gMoraleSettings.sDrugAndAlcoholModifiers[ALCOHOL_EFFECT_MORALE_MOD] = iniReader.ReadInteger("Morale Modifiers Settings","ALCOHOL_EFFECT_MORALE_MOD", 160, 0, 10000); + gMoraleSettings.bModifiers[PHOBIC_LIMIT] = iniReader.ReadInteger("Morale Modifiers Settings","PHOBIC_LIMIT", 20, 0, 100); + + gMoraleSettings.bModifiers[MORALE_MODIFIER_SOCIABLE_ONE_MERC_NEARBY] = iniReader.ReadInteger("Morale Modifiers Settings","MORALE_MODIFIER_SOCIABLE_ONE_MERC_NEARBY", -2, -100, 100); + gMoraleSettings.bModifiers[MORALE_MODIFIER_SOCIABLE_NO_MERCS_NEARBY] = iniReader.ReadInteger("Morale Modifiers Settings","MORALE_MODIFIER_SOCIABLE_NO_MERCS_NEARBY", -5, -100, 100); + gMoraleSettings.bModifiers[MORALE_MODIFIER_LONER_ONE_MERC_NEARBY] = iniReader.ReadInteger("Morale Modifiers Settings","MORALE_MODIFIER_LONER_ONE_MERC_NEARBY", -2, -100, 100); + gMoraleSettings.bModifiers[MORALE_MODIFIER_LONER_MORE_MERCS_NEARBY] = iniReader.ReadInteger("Morale Modifiers Settings","MORALE_MODIFIER_LONER_MORE_MERCS_NEARBY", -5, -100, 100); + gMoraleSettings.bModifiers[MORALE_MODIFIER_OPTIMIST] = iniReader.ReadInteger("Morale Modifiers Settings","MORALE_MODIFIER_OPTIMIST", 1, -100, 1000); + gMoraleSettings.bModifiers[MORALE_MODIFIER_AGRESSIVE_VIOLENT_ACTION] = iniReader.ReadInteger("Morale Modifiers Settings","MORALE_MODIFIER_AGRESSIVE_VIOLENT_ACTION", -5, -100, 100); + gMoraleSettings.bModifiers[MORALE_MODIFIER_PACIFIST_VIOLENT_ACTION] = iniReader.ReadInteger("Morale Modifiers Settings","MORALE_MODIFIER_PACIFIST_VIOLENT_ACTION", -5, -100, 100); + gMoraleSettings.bModifiers[MORALE_MODIFIER_SHOWOFF_AROUND] = iniReader.ReadInteger("Morale Modifiers Settings","MORALE_MODIFIER_SHOWOFF_AROUND", -2, -100, 1000); + gMoraleSettings.bModifiers[MORALE_MODIFIER_DAUNTLESS_SQUADMATE_DIED] = iniReader.ReadInteger("Morale Modifiers Settings","MORALE_MODIFIER_DAUNTLESS_SQUADMATE_DIED", 3, -100, 100); + gMoraleSettings.bModifiers[MORALE_MODIFIER_DAUNTLESS_SUPPRESSED] = iniReader.ReadInteger("Morale Modifiers Settings","MORALE_MODIFIER_DAUNTLESS_SUPPRESSED", 3, -100, 100); + gMoraleSettings.bModifiers[MORALE_MODIFIER_DAUNTLESS_TOOK_LOTS_OF_DAMAGE] = iniReader.ReadInteger("Morale Modifiers Settings","MORALE_MODIFIER_DAUNTLESS_TOOK_LOTS_OF_DAMAGE", 3, -100, 100); + gMoraleSettings.bModifiers[MORALE_MODIFIER_DAUNTLESS_TEAMMATE_DIED] = iniReader.ReadInteger("Morale Modifiers Settings","MORALE_MODIFIER_DAUNTLESS_TEAMMATE_DIED", 2, -100, 100); + + gMoraleSettings.bModifiers[MORALE_MODIFIER_OT_OPTIMIST_GOOD_EVENT] = iniReader.ReadInteger("Morale Modifiers Settings","MORALE_MODIFIER_OT_OPTIMIST_GOOD_EVENT", 1, -100, 100); + gMoraleSettings.bModifiers[MORALE_MODIFIER_OT_AGGRESSIVE_GOOD_EVENT] = iniReader.ReadInteger("Morale Modifiers Settings","MORALE_MODIFIER_OT_AGGRESSIVE_GOOD_EVENT", 1, -100, 100); + gMoraleSettings.bModifiers[MORALE_MODIFIER_OT_PESSIMIST_GOOD_EVENT] = iniReader.ReadInteger("Morale Modifiers Settings","MORALE_MODIFIER_OT_PESSIMIST_GOOD_EVENT", -1, -100, 100); + gMoraleSettings.bModifiers[MORALE_MODIFIER_OT_OPTIMIST_BAD_EVENT] = iniReader.ReadInteger("Morale Modifiers Settings","MORALE_MODIFIER_OT_OPTIMIST_BAD_EVENT", 1, -100, 100); + gMoraleSettings.bModifiers[MORALE_MODIFIER_OT_PESSIMIST_BAD_EVENT] = iniReader.ReadInteger("Morale Modifiers Settings","MORALE_MODIFIER_OT_PESSIMIST_BAD_EVENT", -1, -100, 100); + gMoraleSettings.bModifiers[MORALE_MODIFIER_OT_COWARD_BAD_EVENT] = iniReader.ReadInteger("Morale Modifiers Settings","MORALE_MODIFIER_OT_COWARD_BAD_EVENT", -2, -100, 100); + + gMoraleSettings.bModifiers[MORALE_MODIFIER_MALICIOUS_HOURLY_DECAY] = iniReader.ReadInteger("Morale Modifiers Settings","MORALE_MODIFIER_MALICIOUS_HOURLY_DECAY", -1, -100, 100); +} + +void LoadReputationSettings() +{ + CIniReader iniReader(REPUTATION_SETTINGS_FILE); + + gReputationSettings.bValues[REPUTATION_LOW_DEATHRATE] = iniReader.ReadInteger("Reputation Settings","REPUTATION_LOW_DEATHRATE", 5, -100, 100); + gReputationSettings.bValues[REPUTATION_HIGH_DEATHRATE] = iniReader.ReadInteger("Reputation Settings","REPUTATION_HIGH_DEATHRATE", -5, -100, 100); + gReputationSettings.bValues[REPUTATION_GREAT_MORALE] = iniReader.ReadInteger("Reputation Settings","REPUTATION_GREAT_MORALE", 3, -100, 100); + gReputationSettings.bValues[REPUTATION_POOR_MORALE] = iniReader.ReadInteger("Reputation Settings","REPUTATION_POOR_MORALE", -3, -100, 100); + gReputationSettings.bValues[REPUTATION_BATTLE_WON] = iniReader.ReadInteger("Reputation Settings","REPUTATION_BATTLE_WON", 2, -100, 100); + gReputationSettings.bValues[REPUTATION_BATTLE_LOST] = iniReader.ReadInteger("Reputation Settings","REPUTATION_BATTLE_LOST", -2, -100, 100); + gReputationSettings.bValues[REPUTATION_TOWN_WON] = iniReader.ReadInteger("Reputation Settings","REPUTATION_TOWN_WON", 5, -100, 100); + gReputationSettings.bValues[REPUTATION_TOWN_LOST] = iniReader.ReadInteger("Reputation Settings","REPUTATION_TOWN_LOST", -5, -100, 100); + gReputationSettings.bValues[REPUTATION_SOLDIER_DIED] = iniReader.ReadInteger("Reputation Settings","REPUTATION_SOLDIER_DIED", -2, -100, 100); + gReputationSettings.bValues[REPUTATION_SOLDIER_CAPTURED] = iniReader.ReadInteger("Reputation Settings","REPUTATION_SOLDIER_CAPTURED", -1, -100, 100); + gReputationSettings.bValues[REPUTATION_KILLED_CIVILIAN] = iniReader.ReadInteger("Reputation Settings","REPUTATION_KILLED_CIVILIAN", -5, -100, 100); + gReputationSettings.bValues[REPUTATION_EARLY_FIRING] = iniReader.ReadInteger("Reputation Settings","REPUTATION_EARLY_FIRING", -3, -100, 100); + gReputationSettings.bValues[REPUTATION_KILLED_MONSTER_QUEEN] = iniReader.ReadInteger("Reputation Settings","REPUTATION_KILLED_MONSTER_QUEEN", 15, -100, 100); + gReputationSettings.bValues[REPUTATION_KILLED_DEIDRANNA] = iniReader.ReadInteger("Reputation Settings","REPUTATION_KILLED_DEIDRANNA", 25, -100, 100); + gReputationSettings.bValues[REPUTATION_MERC_COMPLAIN_EQUIPMENT] = iniReader.ReadInteger("Reputation Settings","REPUTATION_MERC_COMPLAIN_EQUIPMENT", -1, -100, 100); + gReputationSettings.bValues[REPUTATION_MERC_OWED_MONEY] = iniReader.ReadInteger("Reputation Settings","REPUTATION_MERC_OWED_MONEY", -2, -100, 100); + gReputationSettings.bValues[REPUTATION_PLAYER_IS_INACTIVE] = iniReader.ReadInteger("Reputation Settings","REPUTATION_PLAYER_IS_INACTIVE", -3, -100, 100); + gReputationSettings.bValues[REPUTATION_MERC_FIRED_ON_BAD_TERMS] = iniReader.ReadInteger("Reputation Settings","REPUTATION_MERC_FIRED_ON_BAD_TERMS", -3, -100, 100); +} + void FreeGameExternalOptions() { if (gGameExternalOptions.iaIMPSlots != NULL) // OJW - 20081129 - Fix memory leak when calling LoadGameExternalOptions twice diff --git a/GameSettings.h b/GameSettings.h index 37968359..7ffa06ca 100644 --- a/GameSettings.h +++ b/GameSettings.h @@ -2,6 +2,9 @@ #define _GAME_SETTINGS__H_ #include "Types.h" +#include "Strategic Status.h" +#include "Morale.h" + #define GAME_INI_FILE "Ja2.ini" @@ -1452,13 +1455,30 @@ typedef struct } HELICOPTER_SETTINGS; +typedef struct +{ + UINT8 ubDefaultMorale; + UINT8 ubHoursBetweenStrategicDelay; + INT8 bValues[64]; + INT8 bModifiers[32]; + INT16 sDrugAndAlcoholModifiers[2]; +} MORALE_SETTINGS; + +typedef struct +{ + INT8 bValues[32]; +} REPUTATION_SETTINGS; + typedef struct { UINT8 ubMaxNumberOfTraits; UINT8 ubNumberOfMajorTraitsAllowed; + + UINT8 ubMaxNumberOfTraitsForIMP; + UINT8 ubNumberOfMajorTraitsAllowedForIMP; - BOOLEAN fAllowSpecialMercTraitsException; - UINT8 ubSpecialMercID; + //BOOLEAN fAllowSpecialMercTraitsException; + //UINT8 ubSpecialMercID; BOOLEAN fAllowAttributePrereq; @@ -1725,6 +1745,17 @@ typedef struct INT8 sVOScanAssignmentBaseRange; INT8 sVOListeningHearingBonus; + + // SNITCH + UINT8 ubSNTBaseChance; // Base chance that snitch will inform about certain event (in percents) + FLOAT fSNTMercOpinionAboutSnitchBonusModifier; // How much chance is influenced by relation between snitch and target + FLOAT fSNTSnitchOpinionAboutMercBonusModifier; // How much chance is influenced by relation between snitch and target + FLOAT fSNTSnitchLeadershipBonusModifer; // How much chance is influenced by snitch's leadership + INT8 bSNTSociableMercBonus; // Bonus to chance if merc is sociable + INT8 bSNTLonerMercBonus; // Bonus to chance if merc is loner + INT8 bSNTSameAssignmentBonus; // Bonus to chance if snitch and merc are on the same assignment + INT8 bSNTMercOpinionAboutMercTreshold; // For reports "merc hates merc" final chance is proportional to dislike in range between treshold (0%) and -25(100%) + } SKILL_TRAIT_VALUES; // HEADROCK HAM 4: Constants used as coefficients by the various parts of the new CTH system. @@ -2140,6 +2171,10 @@ extern TAUNTS_SETTINGS gTauntsSettings; extern HELICOPTER_SETTINGS gHelicopterSettings; +extern MORALE_SETTINGS gMoraleSettings; + +extern REPUTATION_SETTINGS gReputationSettings; + // HEADROCK HAM 4: CTH constants read from a separate INI file extern CTH_CONSTANTS gGameCTHConstants; @@ -2158,6 +2193,8 @@ void LoadGameAPBPConstants(); void LoadCTHConstants(); void LoadTauntsSettings(); void LoadHelicopterRepairRefuelSettings(); +void LoadMoraleSettings(); +void LoadReputationSettings(); void FreeGameExternalOptions(); void InitGameOptions(); diff --git a/Laptop/IMP Compile Character.cpp b/Laptop/IMP Compile Character.cpp index e53d0d55..669f26fb 100644 --- a/Laptop/IMP Compile Character.cpp +++ b/Laptop/IMP Compile Character.cpp @@ -754,7 +754,7 @@ void HandleMercStatsForChangesInFace( ) if (gGameOptions.fNewTraitSystem) { - for ( UINT8 ubCnt = 0; ubCnt < gSkillTraitValues.ubMaxNumberOfTraits; ubCnt++ ) + for ( UINT8 ubCnt = 0; ubCnt < gSkillTraitValues.ubMaxNumberOfTraitsForIMP; ubCnt++ ) { gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bSkillTraits[ ubCnt ] = ( INT8 )SkillsList[ ubCnt ]; } diff --git a/Laptop/IMP Skill Trait.cpp b/Laptop/IMP Skill Trait.cpp index c977dc55..e49e8515 100644 --- a/Laptop/IMP Skill Trait.cpp +++ b/Laptop/IMP Skill Trait.cpp @@ -529,7 +529,7 @@ void HandleIMPSkillTraitAnswers( UINT32 uiSkillPressed, BOOLEAN fSecondTrait ) } else { - if ( CountNumSkillTraitsSelected( FALSE ) < gSkillTraitValues.ubNumberOfMajorTraitsAllowed && CountNumSkillTraitsSelected( FALSE ) < gSkillTraitValues.ubMaxNumberOfTraits ) + if ( CountNumSkillTraitsSelected( FALSE ) < gSkillTraitValues.ubNumberOfMajorTraitsAllowedForIMP && CountNumSkillTraitsSelected( FALSE ) < gSkillTraitValues.ubMaxNumberOfTraitsForIMP ) { // we can select next one, simply do so gfSkillTraitQuestions[ uiSkillPressed ] = TRUE; @@ -540,7 +540,7 @@ void HandleIMPSkillTraitAnswers( UINT32 uiSkillPressed, BOOLEAN fSecondTrait ) } else { - if ( gSkillTraitValues.ubNumberOfMajorTraitsAllowed == 2 ) + if ( gSkillTraitValues.ubNumberOfMajorTraitsAllowedForIMP == 2 ) { //loop through all the skill and reset them for( uiCnt=0; uiCntubWhatKindOfMercAmI == MERC_TYPE__AIM_MERC ) { ModifyPlayerReputation(REPUTATION_EARLY_FIRING); + + // piss off his buddies too + HandleBuddiesReactionToFiringMerc(pSoldier, MORALE_BUDDY_FIRED_EARLY); + } } } diff --git a/Strategic/Merc Contract.cpp b/Strategic/Merc Contract.cpp index 9860e511..a7311b2a 100644 --- a/Strategic/Merc Contract.cpp +++ b/Strategic/Merc Contract.cpp @@ -53,6 +53,7 @@ void MercDepartEquipmentBoxCallBack( UINT8 bExitValue ); BOOLEAN HandleFiredDeadMerc( SOLDIERTYPE *pSoldier ); void HandleExtendMercsContract( SOLDIERTYPE *pSoldier ); void HandleSoldierLeavingWithLowMorale( SOLDIERTYPE *pSoldier ); +void HandleBuddiesReactionToFiringMerc(SOLDIERTYPE *pFiredSoldier, INT8 bMoraleEvent ); void HandleSoldierLeavingForAnotherContract( SOLDIERTYPE *pSoldier ); //BOOLEAN SoldierWantsToDelayRenewalOfContract( SOLDIERTYPE *pSoldier ); void HandleNotifyPlayerCantAffordInsurance( void ); @@ -743,6 +744,29 @@ BOOLEAN WillMercRenew( SOLDIERTYPE *pSoldier, BOOLEAN fSayQuote ) } } +void HandleBuddiesReactionToFiringMerc(SOLDIERTYPE *pFiredSoldier, INT8 bMoraleEvent ) +{ + INT8 bMercID, bOtherID; + INT8 bLastTeamID; + SOLDIERTYPE * pSoldier; + + + bMercID = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; + bLastTeamID = gTacticalStatus.Team[ gbPlayerNum ].bLastID; + // loop through all mercs to find buddies + for ( pSoldier = MercPtrs[ bMercID ]; bMercID <= bLastTeamID; bMercID++,pSoldier++) + { + //if the merc is active, in Arulco, not POW and is a buddy + if ( WhichBuddy(pSoldier->ubProfile,pFiredSoldier->ubProfile) != (-1) && + pSoldier->bActive && pSoldier->ubProfile != NO_PROFILE && + !(pSoldier->bAssignment == IN_TRANSIT || + pSoldier->bAssignment == ASSIGNMENT_DEAD || + pSoldier->bAssignment == ASSIGNMENT_POW) ) + { + HandleMoraleEvent(pSoldier, bMoraleEvent, pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ); + } + } +} void HandleSoldierLeavingWithLowMorale( SOLDIERTYPE *pSoldier ) { @@ -751,6 +775,9 @@ void HandleSoldierLeavingWithLowMorale( SOLDIERTYPE *pSoldier ) // this will cause him give us lame excuses for a while until he gets over it // 3-6 days (but the first 1-2 days of that are spent "returning" home) gMercProfiles[ pSoldier->ubProfile ].ubDaysOfMoraleHangover = (UINT8) (3 + Random(4)); + + // piss off his buddies too + HandleBuddiesReactionToFiringMerc(pSoldier, MORALE_BUDDY_FIRED_EARLY); } } @@ -912,6 +939,9 @@ BOOLEAN StrategicRemoveMerc( SOLDIERTYPE *pSoldier ) EndCurrentContractRenewal( ); } + // anv: let buddies react + HandleBuddiesReactionToFiringMerc(pSoldier, MORALE_BUDDY_FIRED); + // ATE: Determine which HISTORY ENTRY to use... if ( pSoldier->ubLeaveHistoryCode == 0 ) { diff --git a/Strategic/Merc Contract.h b/Strategic/Merc Contract.h index 388dab03..88a0fbfb 100644 --- a/Strategic/Merc Contract.h +++ b/Strategic/Merc Contract.h @@ -61,6 +61,7 @@ BOOLEAN BeginStrategicRemoveMerc( SOLDIERTYPE *pSoldier, BOOLEAN fAddRehireButto BOOLEAN WillMercRenew( SOLDIERTYPE *pSoldier, BOOLEAN fSayQuote ); +void HandleBuddiesReactionToFiringMerc(SOLDIERTYPE *pFiredSoldier, INT8 bMoraleEvent ); void CheckIfMercGetsAnotherContract( SOLDIERTYPE *pSoldier ); void FindOutIfAnyMercAboutToLeaveIsGonnaRenew( void ); diff --git a/Strategic/Strategic Merc Handler.cpp b/Strategic/Strategic Merc Handler.cpp index 1655739e..25156bba 100644 --- a/Strategic/Strategic Merc Handler.cpp +++ b/Strategic/Strategic Merc Handler.cpp @@ -597,6 +597,9 @@ void MercDailyUpdate() // HEADROCK HAM 3.6: Pay for militia upkeep HandleMilitiaUpkeepPayment(); + + // anv: time for snitches to report + HandleSnitchCheck(); } /* @@ -877,6 +880,9 @@ void MercComplainAboutEquipment( UINT8 ubProfile ) { // Say quote! TacticalCharacterDialogue( pSoldier, QUOTE_WHINE_EQUIPMENT ); + // anv: morale hit + HandleMoraleEvent( pSoldier, MORALE_BAD_EQUIPMENT, pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ); + ModifyPlayerReputation(REPUTATION_TOWN_LOST); } } } diff --git a/Strategic/Strategic Status.cpp b/Strategic/Strategic Status.cpp index f2a7e851..8ba961e3 100644 --- a/Strategic/Strategic Status.cpp +++ b/Strategic/Strategic Status.cpp @@ -79,9 +79,9 @@ UINT8 CalcDeathRate(void) void ModifyPlayerReputation(INT8 bRepChange) { INT32 iNewBadRep; - + INT8 bRepChangeValue = gReputationSettings.bValues[bRepChange]; // subtract, so that a negative reputation change results in an increase in bad reputation - iNewBadRep = (INT32) gStrategicStatus.ubBadReputation - bRepChange; + iNewBadRep = (INT32) gStrategicStatus.ubBadReputation - bRepChangeValue; // keep within a 0-100 range (0 = Saint, 100 = Satan) iNewBadRep = __max( 0, iNewBadRep ); @@ -175,6 +175,44 @@ BOOLEAN MercThinksHisMoraleIsTooLow( SOLDIERTYPE *pSoldier ) } } +BOOLEAN MercIsOwedTooMuchMoney( UINT8 ubProfileID ) +{ + if(gMercProfiles[ ubProfileID ].iBalance >= gMercProfiles[ ubProfileID ].sSalary * gMoraleSettings.bValues[MORALE_OWED_MONEY_DAYS]) + { + return(TRUE); + } + else + { + return(FALSE); + } +} + +BOOLEAN MercThinksPlayerIsInactiveTooLong( UINT8 ubProfileID ) +{ + UINT8 ubTolerance; + ubTolerance = gMoraleSettings.bValues[MORALE_PLAYER_INACTIVE_DAYS]; + if( gMercProfiles[ubProfileID].bCharacterTrait == CHAR_TRAIT_PACIFIST ) + { + ubTolerance = max(0, ubTolerance + gMoraleSettings.bValues[MORALE_PLAYER_INACTIVE_DAYS_PACIFIST_BONUS]); + } + else if( gMercProfiles[ubProfileID].bCharacterTrait == CHAR_TRAIT_AGGRESSIVE ) + { + ubTolerance = max(0, ubTolerance + gMoraleSettings.bValues[MORALE_PLAYER_INACTIVE_DAYS_AGGRESSIVE_BONUS]); + } + if( ubTolerance == 0) + { + return(FALSE); + } + if( gStrategicStatus.ubNumberOfDaysOfInactivity >= ubTolerance ) + { + return(TRUE); + } + else + { + return(FALSE); + } +} + void UpdateLastDayOfPlayerActivity( UINT16 usDay ) { if ( usDay > gStrategicStatus.usLastDayOfPlayerActivity ) diff --git a/Strategic/Strategic Status.h b/Strategic/Strategic Status.h index 3e55094e..090ccd2e 100644 --- a/Strategic/Strategic Status.h +++ b/Strategic/Strategic Status.h @@ -18,23 +18,46 @@ class SOLDIERTYPE; #define ARMY_GUN_LEVELS 11 - +// anv: externalised, now these serve as enums below // player reputation modifiers -#define REPUTATION_LOW_DEATHRATE +5 -#define REPUTATION_HIGH_DEATHRATE -5 -#define REPUTATION_GREAT_MORALE +3 -#define REPUTATION_POOR_MORALE -3 -#define REPUTATION_BATTLE_WON +2 -#define REPUTATION_BATTLE_LOST -2 -#define REPUTATION_TOWN_WON +5 -#define REPUTATION_TOWN_LOST -5 -#define REPUTATION_SOLDIER_DIED -2 // per exp. level -#define REPUTATION_SOLDIER_CAPTURED -1 -#define REPUTATION_KILLED_CIVILIAN -5 -#define REPUTATION_EARLY_FIRING -3 -#define REPUTATION_KILLED_MONSTER_QUEEN +15 -#define REPUTATION_KILLED_DEIDRANNA +25 +//#define REPUTATION_LOW_DEATHRATE +5 +//#define REPUTATION_HIGH_DEATHRATE -5 +//#define REPUTATION_GREAT_MORALE +3 +//#define REPUTATION_POOR_MORALE -3 +//#define REPUTATION_BATTLE_WON +2 +//#define REPUTATION_BATTLE_LOST -2 +//#define REPUTATION_TOWN_WON +5 +//#define REPUTATION_TOWN_LOST -5 +//#define REPUTATION_SOLDIER_DIED -2 // per exp. level +//#define REPUTATION_SOLDIER_CAPTURED -1 +//#define REPUTATION_KILLED_CIVILIAN -5 +//#define REPUTATION_EARLY_FIRING -3 +//#define REPUTATION_KILLED_MONSTER_QUEEN +15 +//#define REPUTATION_KILLED_DEIDRANNA +25 +typedef enum +{ + REPUTATION_LOW_DEATHRATE = 0, + REPUTATION_HIGH_DEATHRATE, + REPUTATION_GREAT_MORALE, + REPUTATION_POOR_MORALE, + REPUTATION_BATTLE_WON, + REPUTATION_BATTLE_LOST, // 5 + REPUTATION_TOWN_WON, + REPUTATION_TOWN_LOST, + REPUTATION_SOLDIER_DIED, + REPUTATION_SOLDIER_CAPTURED, + REPUTATION_KILLED_CIVILIAN, // 10 + REPUTATION_EARLY_FIRING, + REPUTATION_KILLED_MONSTER_QUEEN, + REPUTATION_KILLED_DEIDRANNA, + REPUTATION_MERC_COMPLAIN_EQUIPMENT, + REPUTATION_MERC_OWED_MONEY, // 15 + REPUTATION_PLAYER_IS_INACTIVE, + REPUTATION_MERC_FIRED_ON_BAD_TERMS, + + NUM_REPUTATION_EVENTS, +} ReputationEventNames; // flags to remember whether a certain E-mail has already been sent out #define ENRICO_EMAIL_SENT_SOME_PROGRESS 0x0001 @@ -125,6 +148,8 @@ void ModifyPlayerReputation(INT8 bRepChange); BOOLEAN MercThinksDeathRateTooHigh( UINT8 ubProfileID ); BOOLEAN MercThinksBadReputationTooHigh( UINT8 ubProfileID ); BOOLEAN MercThinksHisMoraleIsTooLow( SOLDIERTYPE *pSoldier ); +BOOLEAN MercIsOwedTooMuchMoney( UINT8 ubProfileID ); +BOOLEAN MercThinksPlayerIsInactiveTooLong( UINT8 ubProfileID ); void HandleEnricoEmail(void); diff --git a/Tactical/Animation Control.h b/Tactical/Animation Control.h index a9866910..cd43d3f6 100644 --- a/Tactical/Animation Control.h +++ b/Tactical/Animation Control.h @@ -129,7 +129,7 @@ typedef struct UINT8 ubEndRoll; UINT8 ubFlags; UINT8 ubAnimHeight; - CHAR8 zSoundFile[ 30 ]; + CHAR8 zSoundFile[ 64 ]; } RANDOM_ANI_DEF; diff --git a/Tactical/Dialogue Control.cpp b/Tactical/Dialogue Control.cpp index f94fce1e..88c8011e 100644 --- a/Tactical/Dialogue Control.cpp +++ b/Tactical/Dialogue Control.cpp @@ -1318,6 +1318,20 @@ void HandleDialogue( ) } else if( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_MULTIPURPOSE ) { + // anv: handle snitch event + if( QItem->uiSpecialEventData & MULTIPURPOSE_SPECIAL_EVENT_SNITCH_DIALOGUE ) + { + gTacticalStatus.ubLastQuoteSaid = (UINT8)QItem->usQuoteNum; + gTacticalStatus.ubLastQuoteProfileNUm = (UINT8)QItem->ubCharacterNum; + // Setup face pointer + gpCurrentTalkingFace = &gFacesData[ QItem->iFaceIndex ]; + gubCurrentTalkingID = QItem->iFaceIndex; + + //ExecuteCharacterDialogue( QItem->ubCharacterNum, QItem->usQuoteNum, QItem->iFaceIndex, DIALOGUE_TACTICAL_UI, TRUE ); + + //ExecuteCharacterDialogue( QItem->ubCharacterNum, QItem->usQuoteNum, QItem->iFaceIndex, DIALOGUE_TACTICAL_UI, TRUE); + ExecuteSnitchCharacterDialogue( QItem->ubCharacterNum, QItem->usQuoteNum, QItem->iFaceIndex, QItem->bUIHandlerID, QItem->uiSpecialEventData2, QItem->uiSpecialEventData3, QItem->uiSpecialEventData4 ); + } #ifdef JA2UB //JA25 UB if ( QItem->uiSpecialEventData & MULTIPURPOSE_SPECIAL_EVENT_TEAM_MEMBERS_DONE_TALKING ) @@ -1414,6 +1428,9 @@ void HandleDialogue( ) BOOLEAN GetDialogue( UINT8 ubCharacterNum, UINT16 usQuoteNum, UINT32 iDataSize, STR16 zDialogueText, UINT32 *puiSoundID, CHAR8 *zSoundString ); +BOOLEAN SnitchDialogueReplaceMercNicksWithProperData( CHAR16 *pFinishedString, UINT8 ubTargetProfile, UINT8 ubSecondaryTargetProfile ); + +BOOLEAN GetSnitchDialogue( UINT8 ubCharacterNum, UINT16 usQuoteNum, UINT32 iDataSize, STR16 zDialogueText, UINT32 *puiSound1ID, UINT32 *puiSound2ID, UINT32 *puiSound3ID, CHAR8 zSoundFiles[][64], UINT8 ubTargetProfile, UINT8 ubSecondaryTargetProfile ); BOOLEAN DelayedTacticalCharacterDialogue( SOLDIERTYPE *pSoldier, UINT16 usQuoteNum ) { @@ -1580,6 +1597,61 @@ BOOLEAN TacticalCharacterDialogue( SOLDIERTYPE *pSoldier, UINT16 usQuoteNum ) return( CharacterDialogue( pSoldier->ubProfile, usQuoteNum, pSoldier->iFaceIndex, DIALOGUE_TACTICAL_UI, TRUE, FALSE ) ); } +BOOLEAN SnitchTacticalCharacterDialogue( SOLDIERTYPE *pSoldier, UINT16 usQuoteNum, UINT8 ubEventType, UINT8 ubTargetProfile, UINT8 ubSecondaryTargetProfile ) +{ + // Haydent + if(is_client) + { + return(FALSE); //somewhere amongst all this it causes a puase of merc movement while making the quote which throws out the movement sync between clients... : hayden. + } + if ( pSoldier->ubProfile == NO_PROFILE ) + { + return( FALSE ); + } + +#if (defined JA2UB) + //Ja25 no meanwhiles +#else + if ( AreInMeanwhile( ) ) + { + return( FALSE ); + } +#endif + if (pSoldier->stats.bLife < CONSCIOUSNESS ) + return( FALSE ); + + if (pSoldier->stats.bLife < OKLIFE && usQuoteNum != QUOTE_SERIOUSLY_WOUNDED ) + return( FALSE ); + + if ( pSoldier->flags.uiStatusFlags & SOLDIER_GASSED ) + return( FALSE ); + + if ( (AM_A_ROBOT( pSoldier )) ) + { + return( FALSE ); + } + + if( pSoldier->bAssignment == ASSIGNMENT_POW ) + { + return( FALSE ); + } + + // OK, let's check if this is the exact one we just played, if so, skip. + //if ( pSoldier->ubProfile == gTacticalStatus.ubLastQuoteProfileNUm && + // usQuoteNum == gTacticalStatus.ubLastQuoteSaid ) + //{ + // return( FALSE ); + //} + + if ( AM_AN_EPC( pSoldier ) && !(gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags & PROFILE_MISC_FLAG_FORCENPCQUOTE) ) + return( FALSE ); + + return( SnitchCharacterDialogue( pSoldier->ubProfile, usQuoteNum, pSoldier->iFaceIndex, + DIALOGUE_SPECIAL_EVENT_MULTIPURPOSE, MULTIPURPOSE_SPECIAL_EVENT_SNITCH_DIALOGUE, + ubTargetProfile, ubTargetProfile, ubSecondaryTargetProfile, + DIALOGUE_TACTICAL_UI, TRUE, FALSE ) ); +} + // This function takes a profile num, quote num, faceindex and a UI hander ID. // What it does is queues up the dialog to be ultimately loaded/displayed // FACEINDEX @@ -1693,6 +1765,44 @@ BOOLEAN CharacterDialogue( UINT8 ubCharacterNum, UINT16 usQuoteNum, INT32 iFaceI return( TRUE ); } +BOOLEAN SnitchCharacterDialogue( UINT8 ubCharacterNum, UINT16 usQuoteNum, INT32 iFaceIndex, + UINT32 uiSpecialEventFlag, UINT32 uiSpecialEventData1, UINT32 uiSpecialEventData2, + UINT32 uiSpecialEventData3, UINT32 uiSpecialEventData4, + UINT8 bUIHandlerID, BOOLEAN fFromSoldier, BOOLEAN fDelayed ) +{ + DIALOGUE_Q_STRUCT *QItem; + + // Allocate new item + QItem = (DIALOGUE_Q_STRUCT *) MemAlloc( sizeof( DIALOGUE_Q_STRUCT ) ); + memset( QItem, 0, sizeof( DIALOGUE_Q_STRUCT ) ); + + QItem->ubCharacterNum = ubCharacterNum; + QItem->usQuoteNum = usQuoteNum; + QItem->uiSpecialEventFlag = uiSpecialEventFlag; + QItem->uiSpecialEventData = uiSpecialEventData1; + QItem->uiSpecialEventData2 = uiSpecialEventData2; + QItem->uiSpecialEventData3 = uiSpecialEventData3; + QItem->uiSpecialEventData4 = uiSpecialEventData4; + QItem->iFaceIndex = iFaceIndex; + QItem->bUIHandlerID = bUIHandlerID; + QItem->iTimeStamp = GetJA2Clock( ); + QItem->fFromSoldier = fFromSoldier; + QItem->fDelayed = fDelayed; + + // check if pause already locked, if so, then don't mess with it + if( gfLockPauseState == FALSE ) + { + QItem->fPauseTime = fPausedTimeDuringQuote; + } + + fPausedTimeDuringQuote = FALSE; + + // Add to queue + ghDialogueQ = AddtoQueue( ghDialogueQ, &QItem ); + + return( TRUE ); +} + BOOLEAN SpecialCharacterDialogueEvent( UINT32 uiSpecialEventFlag, UINT32 uiSpecialEventData1, UINT32 uiSpecialEventData2, UINT32 uiSpecialEventData3, INT32 iFaceIndex, UINT8 bUIHandlerID ) { @@ -1853,6 +1963,9 @@ BOOLEAN ExecuteCharacterDialogue( UINT8 ubCharacterNum, UINT16 usQuoteNum, INT32 } } + // anv: have to do it now for single sounds + subsequentsounds.ubMaxSndCounter = 0; + // Check face index CHECKF( iFaceIndex != -1 ); @@ -1883,6 +1996,36 @@ BOOLEAN ExecuteCharacterDialogue( UINT8 ubCharacterNum, UINT16 usQuoteNum, INT32 return( TRUE ); } +BOOLEAN ExecuteSnitchCharacterDialogue( UINT8 ubCharacterNum, UINT16 usQuoteNum, INT32 iFaceIndex, UINT8 bUIHandlerID, UINT8 ubSnitchEventType, UINT8 ubSnitchTargetID, UINT8 ubSecondarySnitchTargetID ) +{ + UINT32 uiSound1ID; + UINT32 uiSound2ID; + UINT32 uiSound3ID; + //if( bUIHandlerID == DIALOGUE_SNITCH_UI ) + { + CHAR8 zSoundFiles[10][64]; + + SOLDIERTYPE *pSoldier; + pSoldier = FindSoldierByProfileID( ubCharacterNum, TRUE ); + if ( !GetSnitchDialogue( ubCharacterNum, + usQuoteNum, DIALOGUESIZE, gzQuoteStr, &uiSound1ID, &uiSound2ID, &uiSound3ID, zSoundFiles, ubSnitchTargetID, ubSecondarySnitchTargetID ) ) + { + return( FALSE ); + } + //SetFaceTalkingMultipleSounds( iFaceIndex, zSoundString1, zSoundString2, zSoundString3, gzQuoteStr, RATE_11025, 30, 1, MIDDLEPAN ); + //SetFaceTalking( iFaceIndex, zSoundString1, gzQuoteStr, RATE_11025, 30, 1, MIDDLEPAN ); + SetFaceTalkingMultipleSounds( iFaceIndex, zSoundFiles, 3, gzQuoteStr, RATE_11025, 30, 1, MIDDLEPAN ); + CreateTalkingUI( DIALOGUE_TACTICAL_UI, iFaceIndex, ubCharacterNum, pSoldier, gzQuoteStr ); + + // Set global handleer ID value, used when face desides it's done... + gbUIHandlerID = DIALOGUE_TACTICAL_UI; + + guiScreenIDUsedWhenUICreated = guiCurrentScreen; + + return( TRUE ); + } + +} void CreateTalkingUI( INT8 bUIHandlerID, INT32 iFaceIndex, UINT8 ubCharacterNum, SOLDIERTYPE *pSoldier, STR16 zQuoteStr ) { @@ -2211,6 +2354,46 @@ CHAR8 *GetDialogueDataFilename( UINT8 ubCharacterNum, UINT16 usQuoteNum, BOOLEAN return( zFileName ); } +CHAR8 *GetSnitchDialogueDataFilename( UINT8 ubCharacterNum, UINT16 usQuoteNum, BOOLEAN fWavFile, BOOLEAN fName ) +{ + static CHAR8 zFileName[164]; + static CHAR8 zFileNameExists[164]; + UINT8 ubFileNumID; + + if ( fWavFile ) + { + if ( gSoundProfileValue[ubCharacterNum].EnabledSound == TRUE ) + { + // build name of wav file (characternum + quotenum) + if(fName) + { + sprintf( zFileName,"SPEECH\\SNITCH\\NAMES\\%03d_%03d.ogg",ubCharacterNum,usQuoteNum ); + if ( !FileExists( zFileName ) ) + { + sprintf( zFileName,"SPEECH\\SNITCH\\NAMES\\%03d_%03d.wav",ubCharacterNum,usQuoteNum ); + } + } + else + { + sprintf( zFileName,"SPEECH\\SNITCH\\%03d_%03d.ogg",ubCharacterNum,usQuoteNum ); + if ( !FileExists( zFileName ) ) + { + sprintf( zFileName,"SPEECH\\SNITCH\\%03d_%03d.wav",ubCharacterNum,usQuoteNum ); + } + } + } + } + else + { + // assume EDT files are in EDT directory on HARD DRIVE + if(fName) + sprintf( zFileName,"MERCEDT\\SNITCH\\NAMES\\%03d.EDT", ubCharacterNum ); + else + sprintf( zFileName,"MERCEDT\\SNITCH\\%03d.EDT", ubCharacterNum ); + } + + return( zFileName ); +} // Used to see if the dialog text file exists BOOLEAN DialogueDataFileExistsForProfile( UINT8 ubCharacterNum, UINT16 usQuoteNum, BOOLEAN fWavFile, STR8 *ppStr ) @@ -2227,6 +2410,20 @@ BOOLEAN DialogueDataFileExistsForProfile( UINT8 ubCharacterNum, UINT16 usQuoteNu return( FileExists( pFilename ) ); } +BOOLEAN SnitchDialogueDataFileExistsForProfile( UINT8 ubCharacterNum, UINT16 usQuoteNum, BOOLEAN fWavFile, STR8 *ppStr, BOOLEAN fName ) +{ + STR8 pFilename; + + pFilename = GetSnitchDialogueDataFilename( ubCharacterNum, usQuoteNum, fWavFile, fName ); + + if ( ppStr ) + { + (*ppStr ) = pFilename; + } + + return( FileExists( pFilename ) ); +} + BOOLEAN GetDialogue( UINT8 ubCharacterNum, UINT16 usQuoteNum, UINT32 iDataSize, STR16 zDialogueText, UINT32 *puiSoundID, CHAR8 *zSoundString ) { STR8 pFilename; @@ -2297,6 +2494,190 @@ BOOLEAN GetDialogue( UINT8 ubCharacterNum, UINT16 usQuoteNum, UINT32 iDataSize, } +BOOLEAN SnitchDialogueReplaceMercNicksWithProperData( CHAR16 *pFinishedString, UINT8 ubTargetProfile, UINT8 ubSecondaryTargetProfile ) +{ + CHAR16 pTempString[ 320 ]; + INT32 iLength =0; + INT32 iCurLocInSourceString =0 ; + INT32 iLengthOfSourceString = wcslen( pFinishedString ); //Get the length of the source string + CHAR16 *pMercNickString = NULL; + CHAR16 *pOtherMercNickString = NULL; + + CHAR16 *pSubString = NULL; + BOOLEAN fReplacingMercName = TRUE; + + CHAR16 sMercNick[ 32 ] = L"$MERCNICK$"; //Will be replaced by the mercs name + CHAR16 sOtherMercNick[ 32 ] = L"$MERCNICK2$"; //Will be replaced by the mercs name + CHAR16 sSearchString[32]; + + //Copy the original string over to the temp string + wcscpy( pTempString, pFinishedString ); + + //Null out the string + pFinishedString[0] = L'\0'; + + //Keep looping through to replace all references to the keyword + while( iCurLocInSourceString < iLengthOfSourceString ) + { + iLength = 0; + pSubString = NULL; + + //Find out if the $MERCNICK$ is in the string + pMercNickString = wcsstr( &pTempString[ iCurLocInSourceString ], sMercNick ); + + //Find out if the $MERCNICK2$ is in the string + pOtherMercNickString = wcsstr( &pTempString[ iCurLocInSourceString ], sOtherMercNick ); + + if( pMercNickString != NULL && pOtherMercNickString != NULL ) + { + if( pMercNickString < pOtherMercNickString ) + { + fReplacingMercName = TRUE; + pSubString = pMercNickString; + wcscpy( sSearchString, sMercNick); + } + else + { + fReplacingMercName = FALSE; + pSubString = pOtherMercNickString; + wcscpy( sSearchString, sOtherMercNick); + } + } + else if( pMercNickString != NULL ) + { + fReplacingMercName = TRUE; + pSubString = pMercNickString; + wcscpy( sSearchString, sMercNick); + } + else if( pOtherMercNickString != NULL ) + { + fReplacingMercName = FALSE; + pSubString = pOtherMercNickString; + wcscpy( sSearchString, sOtherMercNick); + } + else + { + pSubString = NULL; + } + + // if there is a substring + if( pSubString != NULL ) + { + iLength = pSubString - &pTempString[ iCurLocInSourceString ]; + + //Copy the part of the source string up to the keyword + wcsncat( pFinishedString, &pTempString[ iCurLocInSourceString ], iLength ); + + //increment the source string counter by how far in the keyword is and by the length of the keyword + iCurLocInSourceString+= iLength + wcslen( sSearchString ); + + if( fReplacingMercName ) + { + //add the mercs name to the string + wcscat( pFinishedString, gMercProfiles[ ubTargetProfile ].zNickname ); + } + else + { + //add the mercs name to the string + wcscat( pFinishedString, gMercProfiles[ ubSecondaryTargetProfile ].zNickname ); + } + } + else + { + //add the rest of the string + wcscat( pFinishedString, &pTempString[ iCurLocInSourceString ] ); + + iCurLocInSourceString += wcslen( &pTempString[ iCurLocInSourceString ] ); + } + } + + return( TRUE ); +} + +// anv: special version of GetDialogue, message is put together from parts +BOOLEAN GetSnitchDialogue( UINT8 ubCharacterNum, UINT16 usQuoteNum, UINT32 iDataSize, STR16 zDialogueText, UINT32 *puiSound1ID, UINT32 *puiSound2ID, UINT32 *puiSound3ID, CHAR8 zSoundFiles[][64], UINT8 ubTargetProfile, UINT8 ubSecondaryTargetProfile ) +{ + STR8 pFilename1; + STR8 pFilename2; + STR8 pFilename3; + CHAR16 zDialogueTextTemp[ QUOTE_MESSAGE_SIZE ]; + BOOLEAN fTextAvailable = FALSE; + + // first things first - grab the text (if player has SUBTITLE PREFERENCE ON) + //if ( gGameSettings.fOptions[ TOPTION_SUBTITLES ] ) + { + + if ( SnitchDialogueDataFileExistsForProfile( ubCharacterNum, 0, FALSE, &pFilename1, FALSE ) ) + //SnitchDialogueDataFileExistsForProfile( ubCharacterNum, 0, FALSE, &pFilename, TRUE ) && + //SnitchDialogueDataFileExistsForProfile( ubCharacterNum, 0, FALSE, &pFilename, TRUE ) && ) + { + + LoadEncryptedDataFromFile( pFilename1, zDialogueText, usQuoteNum * iDataSize, iDataSize ); + //LoadEncryptedDataFromFile( pFilename2, zDialogueText2, ubSnitchTarget * iDataSize, iDataSize ); + //LoadEncryptedDataFromFile( pFilename3, zDialogueText3, ubSecondarySnitchTarget * iDataSize, iDataSize ); + SnitchDialogueReplaceMercNicksWithProperData( zDialogueText, ubTargetProfile, ubSecondaryTargetProfile ); + //if( ubSnitchTargetID != NOBODY ) + //{ + // wcscpy( zDialogueTextTemp, gMercProfiles[ubTargetProfile].zNickname ); + // wcscat( zDialogueTextTemp, zDialogueText ); + //} + //else + //{ + // wcscpy( zDialogueTextTemp, zDialogueText ); + //} + //if( ubSecondarySnitchTargetID != NOBODY ) + //{ + // wcscat( zDialogueTextTemp, gMercProfiles[ubSecondaryTargetProfile].zNickname ); + //} + //wcscpy( zDialogueText, zDialogueTextTemp ); + if(zDialogueText[0] == 0) + { + swprintf( zDialogueText, L"I have no text in the EDT file ( %d ) %S", usQuoteNum, pFilename1 ); + +#ifndef JA2BETAVERSION + return( FALSE ); +#endif + } + else + fTextAvailable = TRUE; + } + else + { + swprintf( zDialogueText, L"I have no text in the file ( %d ) %S", usQuoteNum , pFilename1 ); + +#ifndef JA2BETAVERSION + return( FALSE ); +#endif + } + } + + + // CHECK IF THE FILE EXISTS, IF NOT, USE DEFAULT! + //pFilename1 = GetSnitchDialogueDataFilename( ubCharacterNum, usQuoteNum, TRUE, FALSE ); + //pFilename2 = GetSnitchDialogueDataFilename( ubCharacterNum, ubSnitchTargetID, TRUE, TRUE ); + //pFilename3 = GetSnitchDialogueDataFilename( ubCharacterNum, ubSecondarySnitchTargetID, TRUE, TRUE ); + + // Copy + strcpy( zSoundFiles[0], GetSnitchDialogueDataFilename( ubCharacterNum, ubTargetProfile, TRUE, TRUE ) ); + strcpy( zSoundFiles[1], GetSnitchDialogueDataFilename( ubCharacterNum, usQuoteNum, TRUE, FALSE ) ); + strcpy( zSoundFiles[2], GetSnitchDialogueDataFilename( ubCharacterNum, ubSecondaryTargetProfile, TRUE, TRUE ) ); + + *puiSound1ID = NO_SAMPLE; + *puiSound2ID = NO_SAMPLE; + *puiSound3ID = NO_SAMPLE; + + // get speech if applicable + if ( gGameSettings.fOptions[ TOPTION_SPEECH ] ) + { + // Load it into memory! + *puiSound1ID = SoundLoadSample( zSoundFiles[0] ); + *puiSound2ID = SoundLoadSample( zSoundFiles[0] ); + *puiSound3ID = SoundLoadSample( zSoundFiles[0] ); + } + + return (*puiSound2ID != NO_SAMPLE) || fTextAvailable; +} + // Handlers for tactical UI stuff void HandleTacticalNPCTextUI( UINT8 ubCharacterNum, STR16 zQuoteStr ) { diff --git a/Tactical/Dialogue Control.h b/Tactical/Dialogue Control.h index 0408fe73..1940634a 100644 --- a/Tactical/Dialogue Control.h +++ b/Tactical/Dialogue Control.h @@ -229,7 +229,7 @@ enum DialogQuoteIDs #define DIALOGUE_SPECK_CONTACT_PAGE_UI 4 #define DIALOGUE_EXTERNAL_NPC_UI 5 #define DIALOGUE_SHOPKEEPER_UI 6 - +#define DIALOGUE_SNITCH_UI 7 // anv: special handle for snitch dialogue #define DIALOGUE_SPECIAL_EVENT_GIVE_ITEM 0x00000001 #define DIALOGUE_SPECIAL_EVENT_TRIGGER_NPC 0x00000002 @@ -278,6 +278,8 @@ enum DialogQuoteIDs #define MULTIPURPOSE_SPECIAL_EVENT_TEAM_MEMBERS_DONE_TALKING 0x00000002 #endif +#define MULTIPURPOSE_SPECIAL_EVENT_SNITCH_DIALOGUE 0x00000004 + #ifdef JA2UB enum{ JERRY_MELO_FACE = 6, @@ -340,12 +342,19 @@ BOOLEAN TacticalCharacterDialogueWithSpecialEventEx( SOLDIERTYPE *pSoldier, UINT // A higher level function used for tactical quotes BOOLEAN TacticalCharacterDialogue( SOLDIERTYPE *pSoldier, UINT16 usQuoteNum ); +BOOLEAN SnitchTacticalCharacterDialogue( SOLDIERTYPE *pSoldier, UINT16 usQuoteNum, UINT8 ubEventType, UINT8 ubTargetProfile, UINT8 ubSecondaryTargetProfile ); + // A higher level function used for tactical quotes BOOLEAN DelayedTacticalCharacterDialogue( SOLDIERTYPE *pSoldier, UINT16 usQuoteNum ); // A more general purpose function for processing quotes BOOLEAN CharacterDialogue( UINT8 ubCharacterNum, UINT16 usQuoteNum, INT32 iFaceIndex, UINT8 bUIHandlerID, BOOLEAN fFromSoldier, BOOLEAN fDelayed ); +BOOLEAN SnitchCharacterDialogue( UINT8 ubCharacterNum, UINT16 usQuoteNum, INT32 iFaceIndex, + UINT32 uiSpecialEventFlag, UINT32 uiSpecialEventData1, UINT32 uiSpecialEventData2, + UINT32 uiSpecialEventData3, UINT32 uiSpecialEventData4, + UINT8 bUIHandlerID, BOOLEAN fFromSoldier, BOOLEAN fDelayed ); + // A special event can be setup which can be queued with other speech BOOLEAN SpecialCharacterDialogueEvent( UINT32 uiSpecialEventFlag, UINT32 uiSpecialEventData1, UINT32 uiSpecialEventData2, UINT32 uiSpecialEventData3, INT32 iFaceIndex, UINT8 bUIHandlerID ); @@ -355,6 +364,8 @@ BOOLEAN SpecialCharacterDialogueEventWithExtraParam( UINT32 uiSpecialEventFlag, // execute specific character dialogue BOOLEAN ExecuteCharacterDialogue( UINT8 ubCharacterNum, UINT16 usQuoteNum, INT32 iFaceIndex, UINT8 bUIHandlerID, BOOLEAN fSoldier ); +BOOLEAN ExecuteSnitchCharacterDialogue( UINT8 ubCharacterNum, UINT16 usQuoteNum, INT32 iFaceIndex, UINT8 bUIHandlerID, UINT8 ubSnitchEventType, UINT8 ubSnitchTargetID, UINT8 ubSecondarySnitchTargetID ); + // Called when a face stops talking... void HandleDialogueEnd( FACETYPE *pFace ); diff --git a/Tactical/Faces.cpp b/Tactical/Faces.cpp index 45c0a704..320ae5c1 100644 --- a/Tactical/Faces.cpp +++ b/Tactical/Faces.cpp @@ -1345,7 +1345,17 @@ void HandleTalkingAutoFace( INT32 iFaceIndex ) // Check if we have finished, set some flags for the final delay down if so! if ( !SoundIsPlaying( pFace->uiSoundID ) && !pFace->fFinishTalking ) { - SetupFinalTalkingDelay( pFace ); + if( subsequentsounds.ubMaxSndCounter != 0 && subsequentsounds.ubSndCounter < subsequentsounds.ubMaxSndCounter ) + { + + pFace->uiSoundID = PlayJA2GapSample( subsequentsounds.zSoundFiles[subsequentsounds.ubSndCounter], RATE_11025, HIGHVOLUME, 1, MIDDLEPAN, &(pFace->GapList ) ); + subsequentsounds.ubSndCounter++; + } + else + { + subsequentsounds.ubMaxSndCounter = 0; + SetupFinalTalkingDelay( pFace ); + } } } else @@ -3003,6 +3013,58 @@ BOOLEAN SetFaceTalking( INT32 iFaceIndex, CHAR8 *zSoundFile, STR16 zTextString, } + +BOOLEAN SetFaceTalkingMultipleSounds( INT32 iFaceIndex, CHAR8 zSoundFiles[][64], UINT8 ubMaxSoundsCount, + STR16 zTextString, UINT32 usRate, UINT32 ubVolume, UINT32 ubLoops, UINT32 uiPan ) +{ + CHAR8 zExistingSoundFiles[10][64]; + UINT8 ubSoundsCount = 0; + + FACETYPE *pFace; + + pFace = &gFacesData[ iFaceIndex ]; + + // Set face to talking + pFace->fTalking = TRUE; + pFace->fAnimatingTalking = TRUE; + pFace->fFinishTalking = FALSE; + + + // only play sounds that do exist + for( UINT8 i = 0; i < ubMaxSoundsCount; i++ ) + { + if( FileExists(zSoundFiles[i]) ) + { + strcpy(zExistingSoundFiles[ubSoundsCount], zSoundFiles[i]); + ubSoundsCount++; + } + } + + // Play sample + if( gGameSettings.fOptions[ TOPTION_SPEECH ] ) + pFace->uiSoundID = PlayJA2MultipleGapSample( zExistingSoundFiles, ubSoundsCount, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN, &(pFace->GapList ) ); + else + pFace->uiSoundID = SOUND_ERROR; + + if ( pFace->uiSoundID != SOUND_ERROR ) + { + pFace->fValidSpeech = TRUE; + + pFace->uiTalkingFromVeryBeginningTimer = GetJA2Clock( ); + } + else + { + pFace->fValidSpeech = FALSE; + + // Set delay based on sound... + pFace->uiTalkingTimer = pFace->uiTalkingFromVeryBeginningTimer = GetJA2Clock( ); + + pFace->uiTalkingDuration = FindDelayForString( zTextString ); + } + + return( TRUE ); +} + BOOLEAN ExternSetFaceTalking( INT32 iFaceIndex, UINT32 uiSoundID ) { FACETYPE *pFace; diff --git a/Tactical/Food.cpp b/Tactical/Food.cpp index 520ebd69..1806e035 100644 --- a/Tactical/Food.cpp +++ b/Tactical/Food.cpp @@ -202,30 +202,30 @@ BOOLEAN ApplyFood( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObject, BOOLEAN fForce, B if ( moralemod > 0 ) { - while ( moralemod > 0 && moralemod >= gbMoraleEvent[MORALE_GOOD_FOOD].bChange ) + while ( moralemod > 0 && moralemod >= gMoraleSettings.bValues[MORALE_GOOD_FOOD] )//gbMoraleEvent[MORALE_GOOD_FOOD].bChange ) { HandleMoraleEvent( pSoldier, MORALE_GOOD_FOOD, pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ); - moralemod -= gbMoraleEvent[MORALE_GOOD_FOOD].bChange; + moralemod -= gMoraleSettings.bValues[MORALE_GOOD_FOOD];//gbMoraleEvent[MORALE_GOOD_FOOD].bChange; } - while ( moralemod > 0 && moralemod >= gbMoraleEvent[MORALE_FOOD].bChange ) + while ( moralemod > 0 && moralemod >= gMoraleSettings.bValues[MORALE_FOOD] )//gbMoraleEvent[MORALE_FOOD].bChange ) { HandleMoraleEvent( pSoldier, MORALE_FOOD, pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ); - moralemod -= gbMoraleEvent[MORALE_FOOD].bChange; + moralemod -= gMoraleSettings.bValues[MORALE_FOOD];//gbMoraleEvent[MORALE_FOOD].bChange; } } else if ( moralemod < 0 ) { - while ( moralemod < 0 && moralemod <= gbMoraleEvent[MORALE_LOATHSOME_FOOD].bChange ) + while ( moralemod < 0 && moralemod <= gMoraleSettings.bValues[MORALE_LOATHSOME_FOOD] )//gbMoraleEvent[MORALE_LOATHSOME_FOOD].bChange ) { HandleMoraleEvent( pSoldier, MORALE_LOATHSOME_FOOD, pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ); - moralemod -= gbMoraleEvent[MORALE_LOATHSOME_FOOD].bChange; + moralemod -= gMoraleSettings.bValues[MORALE_LOATHSOME_FOOD];//gbMoraleEvent[MORALE_LOATHSOME_FOOD].bChange; } - while ( moralemod < 0 && moralemod <= gbMoraleEvent[MORALE_BAD_FOOD].bChange ) + while ( moralemod < 0 && moralemod <= gMoraleSettings.bValues[MORALE_BAD_FOOD] )//gbMoraleEvent[MORALE_BAD_FOOD].bChange ) { HandleMoraleEvent( pSoldier, MORALE_BAD_FOOD, pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ); - moralemod -= gbMoraleEvent[MORALE_BAD_FOOD].bChange; + moralemod -= gMoraleSettings.bValues[MORALE_BAD_FOOD];//gbMoraleEvent[MORALE_BAD_FOOD].bChange; } } /////////////////// MORALE ////////////////////// diff --git a/Tactical/GAP.H b/Tactical/GAP.H index 72e966fe..8a2eda41 100644 --- a/Tactical/GAP.H +++ b/Tactical/GAP.H @@ -6,7 +6,16 @@ typedef UINT8 AudioSample8; typedef INT16 AudioSample16; +typedef struct +{ + SOUNDPARMS spParams; + CHAR8 zSoundFiles[10][64]; + UINT8 ubSndCounter; + UINT8 ubMaxSndCounter; +} SUBSEQUENTSOUNDS; + +extern SUBSEQUENTSOUNDS subsequentsounds; void AudioGapListInit( CHAR8 *zSoundFile, AudioGapList *pGapList ); void AudioGapListDone( AudioGapList *pGapList ); @@ -16,6 +25,6 @@ void PollAudioGap( UINT32 uiSampleNum, AudioGapList *pGapList ); UINT32 PlayJA2GapSample( CHAR8 *zSoundFile, UINT32 usRate, UINT32 ubVolume, UINT32 ubLoops, UINT32 uiPan, AudioGapList* pData ); - +UINT32 PlayJA2MultipleGapSample( CHAR8 zSoundFiles[][64], UINT8 ubSoundsCount, UINT32 usRate, UINT32 ubVolume, UINT32 ubLoops, UINT32 uiPan, AudioGapList* pData ); #endif diff --git a/Tactical/GAP.cpp b/Tactical/GAP.cpp index ac245c50..8a84b648 100644 --- a/Tactical/GAP.cpp +++ b/Tactical/GAP.cpp @@ -12,6 +12,8 @@ #include "FileMan.h" #endif +SUBSEQUENTSOUNDS subsequentsounds; + #if 0 static void AILCALLBACK timer_func( UINT32 user ) { @@ -272,6 +274,33 @@ UINT32 PlayJA2GapSample( CHAR8 *zSoundFile, UINT32 usRate, UINT32 ubVolume, UINT return(SoundPlayStreamedFile( zSoundFile, &spParms)); } +// anv: for playing multiple sounds in row (with one text) +UINT32 PlayJA2MultipleGapSample( CHAR8 zSoundFiles[][64], UINT8 ubSoundsCount, UINT32 usRate, UINT32 ubVolume, UINT32 ubLoops, UINT32 uiPan, AudioGapList* pData ) +{ + SOUNDPARMS spParms; + memset(&spParms, 0xff, sizeof(SOUNDPARMS)); + + spParms.uiSpeed = usRate; + spParms.uiVolume = (UINT32) ( ( ubVolume / (FLOAT) HIGHVOLUME ) * GetSpeechVolume( ) ); + spParms.uiLoop = ubLoops; + spParms.uiPan = uiPan; + spParms.uiPriority=GROUP_PLAYER; + + subsequentsounds.ubSndCounter = 1; + subsequentsounds.ubMaxSndCounter = ubSoundsCount; + for( UINT8 i = 0; i < ubSoundsCount; i++ ) + { + strcpy(subsequentsounds.zSoundFiles[i], zSoundFiles[i]); + } + subsequentsounds.spParams = spParms; + + // Setup Gap Detection, if it is not null + if( pData != NULL ) + AudioGapListInit( zSoundFiles[0], pData ); + + return( SoundPlayStreamedFile( zSoundFiles[0], &spParms)); + // rest of sounds (if there are any) will be called from HandleTalkingAutoFace when current one ends +} diff --git a/Tactical/Morale.cpp b/Tactical/Morale.cpp index 24070ddb..d28a7cb6 100644 --- a/Tactical/Morale.cpp +++ b/Tactical/Morale.cpp @@ -31,15 +31,19 @@ #include "connect.h" #include "fresh_header.h" -#define MORALE_MOD_MAX 50 // morale *mod* range is -50 to 50, if you change this, check the decay formulas! -#define DRUG_EFFECT_MORALE_MOD 150 -#define ALCOHOL_EFFECT_MORALE_MOD 160 +#include "Random.h" -#define HOURS_BETWEEN_STRATEGIC_DECAY 3 +#include "Merc Contract.h" -#define PHOBIC_LIMIT -20 +//#define MORALE_MOD_MAX 50 // morale *mod* range is -50 to 50, if you change this, check the decay formulas! +//#define DRUG_EFFECT_MORALE_MOD 150 +//#define ALCOHOL_EFFECT_MORALE_MOD 160 + +//#define HOURS_BETWEEN_STRATEGIC_DECAY 3 + +//#define PHOBIC_LIMIT -20 // macros #define SOLDIER_IN_SECTOR( pSoldier, sX, sY, bZ ) ( !pSoldier->flags.fBetweenSectors && ( pSoldier->sSectorX == sX ) && ( pSoldier->sSectorY == sY ) && ( pSoldier->bSectorZ == bZ ) ) @@ -94,6 +98,13 @@ MoraleEvent gbMoraleEvent[NUM_MORALE_EVENTS] = { TACTICAL_MORALE_EVENT, 5}, //MORALE_GOOD_FOOD, { TACTICAL_MORALE_EVENT, -1}, //MORALE_BAD_FOOD, { TACTICAL_MORALE_EVENT, -5}, //MORALE_LOATHSOME_FOOD, + // added by anv + { STRATEGIC_MORALE_EVENT, -5}, //MORALE_BUDDY_FIRED, + { STRATEGIC_MORALE_EVENT, -8}, //MORALE_BUDDY_FIRED_ON_BAD_TERMS, + { STRATEGIC_MORALE_EVENT, -8}, //MORALE_BUDDY_FIRED_EARLY + { STRATEGIC_MORALE_EVENT, -2}, //MORALE_BAD_EQUIPMENT, + { STRATEGIC_MORALE_EVENT, -3}, //MORALE_OWED_MONEY, + { STRATEGIC_MORALE_EVENT, -3}, //MORALE_PLAYER_INACTIVE, }; BOOLEAN gfSomeoneSaidMoraleQuote = FALSE; @@ -207,7 +218,7 @@ void DecayTacticalMoraleModifiers( void ) if ( pSoldier->bSectorZ > 0 ) { // underground, no recovery... in fact, if tact morale is high, decay - if ( pSoldier->aiData.bTacticalMoraleMod > PHOBIC_LIMIT ) + if ( pSoldier->aiData.bTacticalMoraleMod > gMoraleSettings.bModifiers[PHOBIC_LIMIT] ) { HandleMoraleEvent( pSoldier, MORALE_CLAUSTROPHOBE_UNDERGROUND, pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ); } @@ -257,7 +268,7 @@ void DecayTacticalMoraleModifiers( void ) if ( fHandleNervous ) { - if ( pSoldier->aiData.bTacticalMoraleMod == PHOBIC_LIMIT ) + if ( pSoldier->aiData.bTacticalMoraleMod == gMoraleSettings.bModifiers[PHOBIC_LIMIT] ) { // don't change morale //continue; @@ -321,11 +332,12 @@ void RefreshSoldierMorale( SOLDIERTYPE * pSoldier ) } // CJC, April 19, 1999: added up to 20% morale boost according to progress - iActualMorale = DEFAULT_MORALE + (INT32) pSoldier->aiData.bTeamMoraleMod + (INT32) pSoldier->aiData.bTacticalMoraleMod + (INT32) pSoldier->aiData.bStrategicMoraleMod + (INT32) (CurrentPlayerProgressPercentage() / 5); + //iActualMorale = DEFAULT_MORALE + (INT32) pSoldier->aiData.bTeamMoraleMod + (INT32) pSoldier->aiData.bTacticalMoraleMod + (INT32) pSoldier->aiData.bStrategicMoraleMod + (INT32) (CurrentPlayerProgressPercentage() / 5); + iActualMorale = gMoraleSettings.ubDefaultMorale + (INT32) pSoldier->aiData.bTeamMoraleMod + (INT32) pSoldier->aiData.bTacticalMoraleMod + (INT32) pSoldier->aiData.bStrategicMoraleMod + (INT32) (CurrentPlayerProgressPercentage() / 5); // ATE: Modify morale based on drugs.... - iActualMorale += ( ( pSoldier->drugs.bDrugEffect[ DRUG_TYPE_ADRENALINE ] * DRUG_EFFECT_MORALE_MOD ) / 100 ); - iActualMorale += ( ( pSoldier->drugs.bDrugEffect[ DRUG_TYPE_ALCOHOL ] * ALCOHOL_EFFECT_MORALE_MOD ) / 100 ); + iActualMorale += ( ( pSoldier->drugs.bDrugEffect[ DRUG_TYPE_ADRENALINE ] * gMoraleSettings.sDrugAndAlcoholModifiers[DRUG_EFFECT_MORALE_MOD] ) / 100 ); + iActualMorale += ( ( pSoldier->drugs.bDrugEffect[ DRUG_TYPE_ALCOHOL ] * gMoraleSettings.sDrugAndAlcoholModifiers[ALCOHOL_EFFECT_MORALE_MOD] ) / 100 ); iActualMorale = __min( 100, iActualMorale ); iActualMorale = __max( 0, iActualMorale ); @@ -405,7 +417,7 @@ void UpdateSoldierMorale( SOLDIERTYPE * pSoldier, INT8 bMoraleEvent ) }//hayden ubType = gbMoraleEvent[bMoraleEvent].ubType; - bMoraleMod = gbMoraleEvent[bMoraleEvent].bChange; + bMoraleMod = gReputationSettings.bValues[bMoraleEvent];//gbMoraleEvent[bMoraleEvent].bChange; pProfile = &(gMercProfiles[ pSoldier->ubProfile ]); @@ -426,19 +438,19 @@ void UpdateSoldierMorale( SOLDIERTYPE * pSoldier, INT8 bMoraleEvent ) case CHAR_TRAIT_SOCIABLE: bNumMercs = CheckMercsNearForCharTraits( pSoldier->ubProfile, CHAR_TRAIT_SOCIABLE ); if ( bNumMercs == 0 ) - bMoraleMod -= 5; + bMoraleMod += gMoraleSettings.bModifiers[MORALE_MODIFIER_SOCIABLE_NO_MERCS_NEARBY];// -= 5; else if ( bNumMercs == 1 ) - bMoraleMod -= 2; + bMoraleMod += gMoraleSettings.bModifiers[MORALE_MODIFIER_SOCIABLE_ONE_MERC_NEARBY];// -= 2; break; case CHAR_TRAIT_LONER: bNumMercs = CheckMercsNearForCharTraits( pSoldier->ubProfile, CHAR_TRAIT_LONER ); if ( bNumMercs > 1 ) - bMoraleMod -= 5; + bMoraleMod += gMoraleSettings.bModifiers[MORALE_MODIFIER_LONER_MORE_MERCS_NEARBY];// -= 5; else if ( bNumMercs == 1 ) - bMoraleMod -= 2; + bMoraleMod += gMoraleSettings.bModifiers[MORALE_MODIFIER_LONER_ONE_MERC_NEARBY];// -= 2; break; case CHAR_TRAIT_OPTIMIST: - bMoraleMod += 1; + bMoraleMod += gMoraleSettings.bModifiers[MORALE_MODIFIER_OPTIMIST];//1; break; case CHAR_TRAIT_AGGRESSIVE: switch ( bMoraleEvent ) @@ -447,7 +459,7 @@ void UpdateSoldierMorale( SOLDIERTYPE * pSoldier, INT8 bMoraleEvent ) case MORALE_DID_LOTS_OF_DAMAGE: case MORALE_MONSTER_QUEEN_KILLED: case MORALE_DEIDRANNA_KILLED: - bMoraleMod += 1; + bMoraleMod += gMoraleSettings.bModifiers[MORALE_MODIFIER_AGRESSIVE_VIOLENT_ACTION];//1; break; } break; @@ -462,14 +474,14 @@ void UpdateSoldierMorale( SOLDIERTYPE * pSoldier, INT8 bMoraleEvent ) case MORALE_MONSTER_QUEEN_KILLED: case MORALE_DEIDRANNA_KILLED: case MORALE_QUEEN_BATTLE_WON: - bMoraleMod -= 5; + bMoraleMod += gMoraleSettings.bModifiers[MORALE_MODIFIER_PACIFIST_VIOLENT_ACTION];//-= 5; break; } break; } if ( IsShowOffNearBy( pSoldier ) ) { - bMoraleMod -= 2; + bMoraleMod += gMoraleSettings.bModifiers[MORALE_MODIFIER_SHOWOFF_AROUND];//-= 2; } } @@ -478,11 +490,13 @@ void UpdateSoldierMorale( SOLDIERTYPE * pSoldier, INT8 bMoraleEvent ) switch( pProfile->bAttitude ) { case ATT_OPTIMIST: + bMoraleMod += gMoraleSettings.bModifiers[MORALE_MODIFIER_OT_OPTIMIST_GOOD_EVENT];//1; + break; case ATT_AGGRESSIVE: - bMoraleMod += 1; + bMoraleMod += gMoraleSettings.bModifiers[MORALE_MODIFIER_OT_AGGRESSIVE_GOOD_EVENT];//1; break; case ATT_PESSIMIST: - bMoraleMod -= 1; + bMoraleMod += gMoraleSettings.bModifiers[MORALE_MODIFIER_OT_PESSIMIST_GOOD_EVENT];//-= 1; break; default: break; @@ -518,7 +532,7 @@ void UpdateSoldierMorale( SOLDIERTYPE * pSoldier, INT8 bMoraleEvent ) // Check for character traits if ( pProfile->bCharacterTrait == CHAR_TRAIT_OPTIMIST ) { - bMoraleMod += 1; + bMoraleMod += gMoraleSettings.bModifiers[MORALE_MODIFIER_OPTIMIST];//1; } // Fearless character does not suffer morale loss for these so much else if( pProfile->bCharacterTrait == CHAR_TRAIT_DAUNTLESS ) @@ -526,12 +540,16 @@ void UpdateSoldierMorale( SOLDIERTYPE * pSoldier, INT8 bMoraleEvent ) switch ( bMoraleEvent ) { case MORALE_SQUADMATE_DIED: + bMoraleMod += gMoraleSettings.bModifiers[MORALE_MODIFIER_DAUNTLESS_SQUADMATE_DIED];//3; + break; case MORALE_SUPPRESSED: + bMoraleMod += gMoraleSettings.bModifiers[MORALE_MODIFIER_DAUNTLESS_SUPPRESSED];//3; + break; case MORALE_TOOK_LOTS_OF_DAMAGE: - bMoraleMod += 3; + bMoraleMod += gMoraleSettings.bModifiers[MORALE_MODIFIER_DAUNTLESS_TOOK_LOTS_OF_DAMAGE];//3; break; case MORALE_TEAMMATE_DIED: - bMoraleMod += 2; + bMoraleMod += gMoraleSettings.bModifiers[MORALE_MODIFIER_DAUNTLESS_TEAMMATE_DIED];//2; break; } } @@ -541,13 +559,13 @@ void UpdateSoldierMorale( SOLDIERTYPE * pSoldier, INT8 bMoraleEvent ) switch( pProfile->bAttitude ) { case ATT_OPTIMIST: - bMoraleMod += 1; + bMoraleMod += gMoraleSettings.bModifiers[MORALE_MODIFIER_OT_OPTIMIST_BAD_EVENT];//1; break; case ATT_PESSIMIST: - bMoraleMod -= 1; + bMoraleMod += gMoraleSettings.bModifiers[MORALE_MODIFIER_OT_PESSIMIST_BAD_EVENT];//-= 1; break; case ATT_COWARD: - bMoraleMod -= 2; + bMoraleMod += gMoraleSettings.bModifiers[MORALE_MODIFIER_OT_COWARD_BAD_EVENT];//-= 2; default: break; } @@ -573,22 +591,22 @@ void UpdateSoldierMorale( SOLDIERTYPE * pSoldier, INT8 bMoraleEvent ) if (ubType == TACTICAL_MORALE_EVENT) { iMoraleModTotal = (INT32) pSoldier->aiData.bTacticalMoraleMod + (INT32) bMoraleMod; - iMoraleModTotal = __min( iMoraleModTotal, MORALE_MOD_MAX ); - iMoraleModTotal = __max( iMoraleModTotal, -MORALE_MOD_MAX ); + iMoraleModTotal = __min( iMoraleModTotal, gMoraleSettings.bModifiers[MORALE_MOD_MAX] ); + iMoraleModTotal = __max( iMoraleModTotal, -gMoraleSettings.bModifiers[MORALE_MOD_MAX] ); pSoldier->aiData.bTacticalMoraleMod = (INT8) iMoraleModTotal; } else if ( gTacticalStatus.fEnemyInSector && !pSoldier->bInSector ) // delayed strategic { iMoraleModTotal = (INT32) pSoldier->bDelayedStrategicMoraleMod + (INT32) bMoraleMod; - iMoraleModTotal = __min( iMoraleModTotal, MORALE_MOD_MAX ); - iMoraleModTotal = __max( iMoraleModTotal, -MORALE_MOD_MAX ); + iMoraleModTotal = __min( iMoraleModTotal, gMoraleSettings.bModifiers[MORALE_MOD_MAX] ); + iMoraleModTotal = __max( iMoraleModTotal, -gMoraleSettings.bModifiers[MORALE_MOD_MAX] ); pSoldier->bDelayedStrategicMoraleMod = (INT8) iMoraleModTotal; } else // strategic { iMoraleModTotal = (INT32) pSoldier->aiData.bStrategicMoraleMod + (INT32) bMoraleMod; - iMoraleModTotal = __min( iMoraleModTotal, MORALE_MOD_MAX ); - iMoraleModTotal = __max( iMoraleModTotal, -MORALE_MOD_MAX ); + iMoraleModTotal = __min( iMoraleModTotal, gMoraleSettings.bModifiers[MORALE_MOD_MAX] ); + iMoraleModTotal = __max( iMoraleModTotal, -gMoraleSettings.bModifiers[MORALE_MOD_MAX] ); pSoldier->aiData.bStrategicMoraleMod = (INT8) iMoraleModTotal; } @@ -674,7 +692,7 @@ void HandleMoraleEvent( SOLDIERTYPE *pSoldier, INT8 bMoraleEvent, INT16 sMapX, I Assert( pSoldier ); // affects the soldier only, should be ignored if tactical morale mod is -20 or less // SANDRO - really?? I think it also shouldn't go lower if strategic morale mod is less than -20 - if ( pSoldier->aiData.bTacticalMoraleMod > PHOBIC_LIMIT && pSoldier->aiData.bStrategicMoraleMod > PHOBIC_LIMIT ) + if ( pSoldier->aiData.bTacticalMoraleMod > gMoraleSettings.bModifiers[PHOBIC_LIMIT] && pSoldier->aiData.bStrategicMoraleMod > gMoraleSettings.bModifiers[PHOBIC_LIMIT] ) { HandleMoraleEventForSoldier( pSoldier, bMoraleEvent ); } @@ -771,7 +789,7 @@ void HandleMoraleEvent( SOLDIERTYPE *pSoldier, INT8 bMoraleEvent, INT16 sMapX, I { if ( gGameOptions.fNewTraitSystem && bMoraleEvent != MORALE_DEIDRANNA_KILLED) { - if ( !SOLDIER_IN_SECTOR( pTeamSoldier, sMapX, sMapY, bMapZ ) && ( gbMoraleEvent[bMoraleEvent].bChange > 0 ) && + if ( !SOLDIER_IN_SECTOR( pTeamSoldier, sMapX, sMapY, bMapZ ) && ( gMoraleSettings.bValues[bMoraleEvent] > 0 ) && //( gbMoraleEvent[bMoraleEvent].bChange > 0 ) && gMercProfiles[pTeamSoldier->ubProfile].bCharacterTrait == CHAR_TRAIT_ASSERTIVE ) { // No morale gain for assertive people from actions of others @@ -988,7 +1006,12 @@ void HandleMoraleEvent( SOLDIERTYPE *pSoldier, INT8 bMoraleEvent, INT16 sMapX, I case MORALE_DEIDRANNA_KILLED: ModifyPlayerReputation(REPUTATION_KILLED_DEIDRANNA); break; - + case MORALE_BAD_EQUIPMENT: + ModifyPlayerReputation(REPUTATION_MERC_COMPLAIN_EQUIPMENT); + case MORALE_OWED_MONEY: + ModifyPlayerReputation(REPUTATION_MERC_OWED_MONEY); + case MORALE_PLAYER_INACTIVE_DAYS: + ModifyPlayerReputation(REPUTATION_PLAYER_IS_INACTIVE); default: // no reputation impact break; @@ -1168,11 +1191,11 @@ void HourlyMoraleUpdate( void ) // SANDRO - morale is going down faster if not fighting for malicious characters if ( gGameOptions.fNewTraitSystem && pProfile->bCharacterTrait == CHAR_TRAIT_MALICIOUS ) { - bTeamMoraleModChange -= 1; + bTeamMoraleModChange += gMoraleSettings.bModifiers[MORALE_MODIFIER_MALICIOUS_HOURLY_DECAY];//-= 1; } pSoldier->aiData.bTeamMoraleMod += bTeamMoraleModChange; - pSoldier->aiData.bTeamMoraleMod = __min( pSoldier->aiData.bTeamMoraleMod, MORALE_MOD_MAX ); - pSoldier->aiData.bTeamMoraleMod = __max( pSoldier->aiData.bTeamMoraleMod, -MORALE_MOD_MAX ); + pSoldier->aiData.bTeamMoraleMod = __min( pSoldier->aiData.bTeamMoraleMod, gMoraleSettings.bModifiers[MORALE_MOD_MAX] ); + pSoldier->aiData.bTeamMoraleMod = __max( pSoldier->aiData.bTeamMoraleMod, -gMoraleSettings.bModifiers[MORALE_MOD_MAX] ); // New, December 3rd, 1998, by CJC -- // If delayed strategic modifier exists then incorporate it in strategic mod @@ -1180,8 +1203,8 @@ void HourlyMoraleUpdate( void ) { pSoldier->aiData.bStrategicMoraleMod += pSoldier->bDelayedStrategicMoraleMod; pSoldier->bDelayedStrategicMoraleMod = 0; - pSoldier->aiData.bStrategicMoraleMod = __min( pSoldier->aiData.bStrategicMoraleMod, MORALE_MOD_MAX ); - pSoldier->aiData.bStrategicMoraleMod = __max( pSoldier->aiData.bStrategicMoraleMod, -MORALE_MOD_MAX ); + pSoldier->aiData.bStrategicMoraleMod = __min( pSoldier->aiData.bStrategicMoraleMod, gMoraleSettings.bModifiers[MORALE_MOD_MAX] ); + pSoldier->aiData.bStrategicMoraleMod = __max( pSoldier->aiData.bStrategicMoraleMod, -gMoraleSettings.bModifiers[MORALE_MOD_MAX] ); } // refresh the morale value for the soldier based on the recalculated team modifier @@ -1191,7 +1214,7 @@ void HourlyMoraleUpdate( void ) bStrategicMoraleUpdateCounter++; - if ( bStrategicMoraleUpdateCounter == HOURS_BETWEEN_STRATEGIC_DECAY ) + if ( bStrategicMoraleUpdateCounter == gMoraleSettings.ubHoursBetweenStrategicDelay ) { DecayStrategicMoraleModifiers(); bStrategicMoraleUpdateCounter = 0; @@ -1199,6 +1222,280 @@ void HourlyMoraleUpdate( void ) } +void HandleSnitchCheck( void ) +{ + INT8 bMercID, bOtherID; + INT8 bOpinion=-1; + INT8 bLastTeamID; + SOLDIERTYPE * pSoldier; + SOLDIERTYPE * pOtherSoldier; + MERCPROFILESTRUCT * pProfile; + BOOLEAN fSameGroupOnly; + // anv: save merc id and his negative morale event for snitches + INT8 ubSnitchEventsCounter = 0; + INT8 bSnitchesCounter = 0; + SnitchEvent SnitchEvents[64]; + + bMercID = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; + bLastTeamID = gTacticalStatus.Team[ gbPlayerNum ].bLastID; + + // loop through all mercs to calculate their morale + for ( pSoldier = MercPtrs[ bMercID ]; bMercID <= bLastTeamID; bMercID++,pSoldier++) + { + //if the merc is active, in Arulco, not POW + if ( pSoldier->bActive && pSoldier->ubProfile != NO_PROFILE && + !(pSoldier->bAssignment == IN_TRANSIT || + pSoldier->bAssignment == ASSIGNMENT_DEAD || + pSoldier->bAssignment == ASSIGNMENT_POW) ) + { + // calculate the guy's opinion of the people he is with + pProfile = &(gMercProfiles[ pSoldier->ubProfile ]); + + // if we're moving + if (pSoldier->ubGroupID != 0 && PlayerIDGroupInMotion( pSoldier->ubGroupID )) + { + // we only check our opinions of people in our squad + fSameGroupOnly = TRUE; + } + else + { + fSameGroupOnly = FALSE; + } + // loop through all other mercs + bOtherID = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; + for ( pOtherSoldier = MercPtrs[ bOtherID ]; bOtherID <= bLastTeamID; bOtherID++,pOtherSoldier++) + { + // skip past ourselves and all inactive mercs + if (bOtherID != bMercID && pOtherSoldier->bActive && pOtherSoldier->ubProfile != NO_PROFILE && + !(pOtherSoldier->bAssignment == IN_TRANSIT || + pOtherSoldier->bAssignment == ASSIGNMENT_DEAD || + pOtherSoldier->bAssignment == ASSIGNMENT_POW)) + { + if (fSameGroupOnly) + { + // all we have to check is the group ID + if (pSoldier->ubGroupID != pOtherSoldier->ubGroupID) + { + continue; + } + } + else + { + // check to see if the location is the same + if (pOtherSoldier->sSectorX != pSoldier->sSectorX || + pOtherSoldier->sSectorY != pSoldier->sSectorY || + pOtherSoldier->bSectorZ != pSoldier->bSectorZ) + { + continue; + } + + // if the OTHER soldier is in motion then we don't do anything! + if (pOtherSoldier->ubGroupID != 0 && PlayerIDGroupInMotion( pOtherSoldier->ubGroupID )) + { + continue; + } + } + bOpinion = SoldierRelation( pSoldier, pOtherSoldier); + if( bOpinion <= gSkillTraitValues.bSNTMercOpinionAboutMercTreshold ) + { + ubSnitchEventsCounter = RememberSnitchableEvent(pSoldier->ubProfile,pOtherSoldier->ubProfile,fSameGroupOnly,SNITCH_HATED_PERSON,SnitchEvents,ubSnitchEventsCounter); + } + } + } + + // check death rate vs. merc's tolerance once/day (ignores buddies!) + if( MercThinksDeathRateTooHigh( pSoldier->ubProfile ) ) + { + // too high, inform + ubSnitchEventsCounter = RememberSnitchableEvent(pSoldier->ubProfile,NOBODY,fSameGroupOnly,SNITCH_DEATH_RATE,SnitchEvents,ubSnitchEventsCounter); + } + + // check his morale vs. his morale tolerance once/day (ignores buddies!) + if( MercThinksHisMoraleIsTooLow( pSoldier ) ) + { + // too low, inform + ubSnitchEventsCounter = RememberSnitchableEvent(pSoldier->ubProfile,NOBODY,fSameGroupOnly,SNITCH_LOW_MORALE,SnitchEvents,ubSnitchEventsCounter); + } + + // check his opinion about player's reputation + if( MercThinksBadReputationTooHigh( pSoldier->ubProfile ) ) + { + // too high, inform + ubSnitchEventsCounter = RememberSnitchableEvent(pSoldier->ubProfile,NOBODY,fSameGroupOnly,SNITCH_REPUTATION,SnitchEvents,ubSnitchEventsCounter); + } + + // check his opinion about player activity + if( MercThinksPlayerIsInactiveTooLong( pSoldier->ubProfile ) ) + { + // player inactive, inform + ubSnitchEventsCounter = RememberSnitchableEvent(pSoldier->ubProfile,NOBODY,fSameGroupOnly,SNITCH_PROGRESS,SnitchEvents,ubSnitchEventsCounter); + } + + // check if player owes him money + if( MercIsOwedTooMuchMoney( pSoldier->ubProfile ) ) + { + // player owes him money, inform + ubSnitchEventsCounter = RememberSnitchableEvent(pSoldier->ubProfile,NOBODY,fSameGroupOnly,SNITCH_OWED_MONEY,SnitchEvents,ubSnitchEventsCounter); + } + + // check if contract is running out, and will not renew + // but only if he hasn't another contract signed, so there's still a chance to renew if player reacts properly + if( ContractIsGoingToExpireSoon(pSoldier) ) + { + if( ( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__AIM_MERC ) ) + { + // Only do this if they don't want to renew..... + if ( !WillMercRenew( pSoldier, FALSE ) && !(pSoldier->flags.fSignedAnotherContract) ) + { + ubSnitchEventsCounter = RememberSnitchableEvent(pSoldier->ubProfile,NOBODY,fSameGroupOnly,SNITCH_GONNA_QUIT,SnitchEvents,ubSnitchEventsCounter); + } + } + } + } + } + + // anv: handle snitches informing player about reasons for morale drops + HandleSnitchesReports( SnitchEvents, ubSnitchEventsCounter ); +} + +void HandleSnitchesReports( SnitchEvent *SnitchEvents, UINT8 ubSnitchEventsCounter ) +{ + UINT8 bSnitchID; + SOLDIERTYPE *pSnitch; + BOOLEAN fSleepingSnitch = FALSE; + + + + for( UINT8 bCounter = 0; bCounter < ubSnitchEventsCounter; bCounter++ ) + { + if( SnitchEvents[bCounter].ubEventType != NOBODY ) + { + bSnitchID = SnitchEvents[bCounter].ubSnitchID; + pSnitch = FindSoldierByProfileID(bSnitchID,TRUE); + + if( pSnitch->flags.fMercAsleep ) + fSleepingSnitch = TRUE; + + // snitch introduction + + if( fSleepingSnitch ) + TacticalCharacterDialogueWithSpecialEvent( FindSoldierByProfileID(bSnitchID,TRUE), 0, DIALOGUE_SPECIAL_EVENT_SLEEP, 0,0 ); + + SnitchTacticalCharacterDialogue(FindSoldierByProfileID(bSnitchID,TRUE),0,SNITCH_INTRODUCTION,NOBODY,NOBODY); + + // process all reports by the same snitch in row + for(UINT8 bCounter2 = bCounter; bCounter2 < ubSnitchEventsCounter; bCounter2++ ) + { + if( SnitchEvents[bCounter2].ubSnitchID == bSnitchID ) + { + // say this info + SnitchTacticalCharacterDialogue(FindSoldierByProfileID(bSnitchID,TRUE),SnitchEvents[bCounter2].ubEventType,SnitchEvents[bCounter2].ubEventType, + SnitchEvents[bCounter2].ubTargetProfile,SnitchEvents[bCounter2].ubSecondaryTargetProfile); + + // clear info + SnitchEvents[bCounter2].ubEventType = NOBODY; + } + } + if( fSleepingSnitch ) + TacticalCharacterDialogueWithSpecialEvent( FindSoldierByProfileID(bSnitchID,TRUE), 0, DIALOGUE_SPECIAL_EVENT_SLEEP, 1,0 ); + } + } + ubSnitchEventsCounter = 0; +} + +INT8 RememberSnitchableEvent( UINT8 ubTargetProfile, UINT8 ubSecondaryTargetProfile, BOOLEAN fSameGroupOnly, UINT8 ubEventType, SnitchEvent SnitchEvents[], INT8 ubSnitchEventsCounter ) +{ + INT8 bSnitchID; + INT16 sSnitchingChance = 0; + UINT8 ubSnitchProfile; + SOLDIERTYPE * pSnitch; + SOLDIERTYPE * pSoldier; + SOLDIERTYPE * pOtherSoldier; + + pSoldier = FindSoldierByProfileID(ubTargetProfile,FALSE); + pOtherSoldier = FindSoldierByProfileID(ubSecondaryTargetProfile,FALSE); + + + // loop through all other mercs + bSnitchID = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; + for ( pSnitch = MercPtrs[ bSnitchID ]; bSnitchID <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; bSnitchID++,pSnitch++) + { + ubSnitchProfile = pSnitch->ubProfile; + // skip past ourselves and all inactive mercs + if (ProfileHasSkillTrait(ubSnitchProfile,SNITCH_NT) && + ubSnitchProfile != ubTargetProfile && ubSnitchProfile != ubSecondaryTargetProfile + && pSnitch->bActive && ubSnitchProfile != NO_PROFILE && + !(pSnitch->bAssignment == IN_TRANSIT || + pSnitch->bAssignment == ASSIGNMENT_DEAD || + pSnitch->bAssignment == ASSIGNMENT_POW)) + { + if (fSameGroupOnly) + { + // all we have to check is the group ID + if (pSoldier->ubGroupID != pSnitch->ubGroupID) + { + continue; + } + } + else + { + // check to see if the location is the same + if (pSnitch->sSectorX != pSoldier->sSectorX || + pSnitch->sSectorY != pSoldier->sSectorY || + pSnitch->bSectorZ != pSoldier->bSectorZ) + { + continue; + } + + // if snitch is in motion then we don't do anything! + if (pSnitch->ubGroupID != 0 && PlayerIDGroupInMotion( pSnitch->ubGroupID )) + { + continue; + } + } + // calculate chances of snitching + + // decreased if target doesn't like snitch, increased if snitch doesn't like him + sSnitchingChance = gSkillTraitValues.ubSNTBaseChance; + sSnitchingChance = (INT16)(sSnitchingChance + + SoldierRelation( pSoldier, pSnitch)*gSkillTraitValues.fSNTMercOpinionAboutSnitchBonusModifier+ + SoldierRelation( pSnitch, pSoldier)*gSkillTraitValues.fSNTSnitchOpinionAboutMercBonusModifier+ + gMercProfiles[ubSnitchProfile].bLeadership*gSkillTraitValues.fSNTSnitchLeadershipBonusModifer); + if ( pSoldier->bAssignment == pSnitch->bAssignment ) + { + sSnitchingChance += gSkillTraitValues.bSNTSameAssignmentBonus; + } + if ( gMercProfiles[pSnitch->ubProfile].bCharacterTrait == CHAR_TRAIT_SOCIABLE ) + { + sSnitchingChance += gSkillTraitValues.bSNTSociableMercBonus; + } + if ( gMercProfiles[pSnitch->ubProfile].bCharacterTrait == CHAR_TRAIT_LONER) + { + sSnitchingChance += gSkillTraitValues.bSNTLonerMercBonus; + } + if ( ubEventType == SNITCH_HATED_PERSON ) + { + if ( gSkillTraitValues.bSNTMercOpinionAboutMercTreshold != HATED_OPINION ) + { + sSnitchingChance = (INT16)( sSnitchingChance * + ( 1.0 - (FLOAT)( SoldierRelation( pSoldier, pOtherSoldier ) - HATED_OPINION ) / + (FLOAT)( gSkillTraitValues.bSNTMercOpinionAboutMercTreshold - HATED_OPINION ) ) ); + } + } + sSnitchingChance = max(0, sSnitchingChance); + if( Random(100) < (UINT8)sSnitchingChance ) + { + //information gathered succesfully, remember event to report it later + SnitchEvents[ubSnitchEventsCounter].ubEventType = ubEventType; + SnitchEvents[ubSnitchEventsCounter].ubSnitchID = ubSnitchProfile; + SnitchEvents[ubSnitchEventsCounter].ubTargetProfile = ubTargetProfile; + SnitchEvents[ubSnitchEventsCounter].ubSecondaryTargetProfile = ubSecondaryTargetProfile; + ubSnitchEventsCounter++; + } + } + } + return ubSnitchEventsCounter; +} void DailyMoraleUpdate(SOLDIERTYPE *pSoldier) { diff --git a/Tactical/Morale.h b/Tactical/Morale.h index 88532d4d..1ad95c3b 100644 --- a/Tactical/Morale.h +++ b/Tactical/Morale.h @@ -4,8 +4,7 @@ #include "Types.h" #include "Soldier Control.h" - -#define DEFAULT_MORALE 50 +//#define DEFAULT_MORALE 50 typedef enum { @@ -45,20 +44,67 @@ typedef enum MORALE_QUEEN_BATTLE_WON, MORALE_SEX, // added by SANDRO - MORALE_HEAT_INTOLERANT_IN_DESERT, + MORALE_HEAT_INTOLERANT_IN_DESERT, // 35 MORALE_PSYCHO_UNABLE_TO_PSYCHO, MORALE_PACIFIST_GAIN_NONCOMBAT, MORALE_MALICIOUS_HIT, // added by Flugente MORALE_FOOD, - MORALE_GOOD_FOOD, + MORALE_GOOD_FOOD, // 40 MORALE_BAD_FOOD, MORALE_LOATHSOME_FOOD, - NUM_MORALE_EVENTS + // added by anv + MORALE_BUDDY_FIRED, + MORALE_BUDDY_FIRED_EARLY, + MORALE_BUDDY_FIRED_ON_BAD_TERMS, //45 + MORALE_BAD_EQUIPMENT, + MORALE_OWED_MONEY, + MORALE_OWED_MONEY_DAYS, + MORALE_PLAYER_INACTIVE, + MORALE_PLAYER_INACTIVE_DAYS, + MORALE_PLAYER_INACTIVE_DAYS_AGGRESSIVE_BONUS, + MORALE_PLAYER_INACTIVE_DAYS_PACIFIST_BONUS, + + NUM_MORALE_EVENTS, } MoraleEventNames; +typedef enum +{ + MORALE_MOD_MAX = 0, + PHOBIC_LIMIT, + MORALE_MODIFIER_SOCIABLE_ONE_MERC_NEARBY, + MORALE_MODIFIER_SOCIABLE_NO_MERCS_NEARBY, + MORALE_MODIFIER_LONER_ONE_MERC_NEARBY, + MORALE_MODIFIER_LONER_MORE_MERCS_NEARBY, + MORALE_MODIFIER_AGRESSIVE_VIOLENT_ACTION, + MORALE_MODIFIER_PACIFIST_VIOLENT_ACTION, + MORALE_MODIFIER_OPTIMIST, + MORALE_MODIFIER_SHOWOFF_AROUND, + MORALE_MODIFIER_DAUNTLESS_SQUADMATE_DIED, + MORALE_MODIFIER_DAUNTLESS_SUPPRESSED, + MORALE_MODIFIER_DAUNTLESS_TOOK_LOTS_OF_DAMAGE, + MORALE_MODIFIER_DAUNTLESS_TEAMMATE_DIED, + MORALE_MODIFIER_OT_OPTIMIST_GOOD_EVENT, + MORALE_MODIFIER_OT_AGGRESSIVE_GOOD_EVENT, + MORALE_MODIFIER_OT_PESSIMIST_GOOD_EVENT, + MORALE_MODIFIER_OT_OPTIMIST_BAD_EVENT, + MORALE_MODIFIER_OT_PESSIMIST_BAD_EVENT, + MORALE_MODIFIER_OT_COWARD_BAD_EVENT, + MORALE_MODIFIER_MALICIOUS_HOURLY_DECAY, + + NUM_MORALE_MODIFIERS, +} MoraleModifierNames; + +typedef enum +{ + DRUG_EFFECT_MORALE_MOD = 0, + ALCOHOL_EFFECT_MORALE_MOD, + + NUM_DRUG_AND_ALCOHOL_MODIFIERS, +} DrugAndAlcoholModifierNames; + typedef enum { TACTICAL_MORALE_EVENT = 0, @@ -71,11 +117,44 @@ typedef struct MoraleEvent INT8 bChange; } MoraleEvent; +#define MAX_SNITCH_EVENTS 64; +#define MAX_SNITCHES 16; + + +typedef enum +{ + SNITCH_INTRODUCTION= 0, + SNITCH_DEATH_RATE, // current death rate higher than preferable + SNITCH_REPUTATION, // current reputation worse than preferable + SNITCH_LOW_MORALE, // merc's morale worse than preferable + SNITCH_HATED_PERSON, // merc dislikes another person (not necessarily hates him) + SNITCH_GONNA_QUIT, // merc's contract going to end and he won't renew + SNITCH_PROGRESS, // merc thinks player is inactive too long + SNITCH_OWED_MONEY, // merc is owed money + + SNITCH_TEAM_ROTATION, // unused at the moment (will have to add specific rotation tolerance to mercs or something) + // maybe with personal opinion on rotation depending on opinions (so they get pissed faster when liked mercs are fired) + + NUM_SNITCH_EVENTS, + +} SnitchEventType; + +typedef struct SnitchEvent +{ + UINT8 ubEventType; + UINT8 ubSnitchID; + UINT8 ubTargetProfile; + UINT8 ubSecondaryTargetProfile; +} SnitchEvent; + extern void HandleMoraleEvent( SOLDIERTYPE * pSoldier, INT8 bMoraleEvent, INT16 sMapX, INT16 sMapY, INT8 bMapZ ); extern void RefreshSoldierMorale( SOLDIERTYPE * pSoldier ); extern INT8 GetMoraleModifier( SOLDIERTYPE * pSoldier ); void HourlyMoraleUpdate( void ); +void HandleSnitchCheck( void ); +void HandleSnitchesReports( SnitchEvent *SnitchEvents, UINT8 ubSnitchEventsCounter ); +INT8 RememberSnitchableEvent( UINT8 ubTargetProfile, UINT8 ubSecondaryTargetProfile, BOOLEAN fSameGroupOnly, UINT8 ubEventType, SnitchEvent SnitchEvents[], INT8 ubSnitchEventsCounter ); void DailyMoraleUpdate( SOLDIERTYPE *pSoldier ); void DecayTacticalMoraleModifiers( void ); diff --git a/Tactical/Soldier Control.cpp b/Tactical/Soldier Control.cpp index b3252e07..bd5af867 100644 --- a/Tactical/Soldier Control.cpp +++ b/Tactical/Soldier Control.cpp @@ -20483,11 +20483,11 @@ BOOLEAN HAS_SKILL_TRAIT( SOLDIERTYPE * pSoldier, UINT8 uiSkillTraitNumber ) if (gGameOptions.fNewTraitSystem) { // exception for special merc - if ( gSkillTraitValues.fAllowSpecialMercTraitsException && pSoldier->ubProfile == gSkillTraitValues.ubSpecialMercID) - { - bMaxTraits++; - bMaxMajorTraits++; - } + //if ( gSkillTraitValues.fAllowSpecialMercTraitsException && pSoldier->ubProfile == gSkillTraitValues.ubSpecialMercID) + //{ + // bMaxTraits++; + // bMaxMajorTraits++; + //} for ( INT8 bCnt = 0; bCnt < min(30,bMaxTraits); bCnt++ ) { @@ -20540,11 +20540,11 @@ INT8 NUM_SKILL_TRAITS( SOLDIERTYPE * pSoldier, UINT8 uiSkillTraitNumber ) if (gGameOptions.fNewTraitSystem) { // exception for special merc - if ( gSkillTraitValues.fAllowSpecialMercTraitsException && pSoldier->ubProfile == gSkillTraitValues.ubSpecialMercID) - { - bMaxTraits++; - bMaxMajorTraits++; - } + //if ( gSkillTraitValues.fAllowSpecialMercTraitsException && pSoldier->ubProfile == gSkillTraitValues.ubSpecialMercID) + //{ + // bMaxTraits++; + // bMaxMajorTraits++; + //} for ( INT8 bCnt = 0; bCnt < min(30,bMaxTraits); bCnt++ ) { diff --git a/Tactical/Soldier Create.cpp b/Tactical/Soldier Create.cpp index a46bb4d8..df917a5c 100644 --- a/Tactical/Soldier Create.cpp +++ b/Tactical/Soldier Create.cpp @@ -1924,7 +1924,8 @@ void InitSoldierStruct( SOLDIERTYPE *pSoldier ) pSoldier->iFaceIndex = -1; // Set morale default - pSoldier->aiData.bMorale = DEFAULT_MORALE; + //pSoldier->aiData.bMorale = DEFAULT_MORALE; + pSoldier->aiData.bMorale = gMoraleSettings.ubDefaultMorale; pSoldier->ubAttackerID = NOBODY; pSoldier->ubPreviousAttackerID = NOBODY; diff --git a/Tactical/Soldier Profile.cpp b/Tactical/Soldier Profile.cpp index 94b99d7b..196dce0f 100644 --- a/Tactical/Soldier Profile.cpp +++ b/Tactical/Soldier Profile.cpp @@ -2913,11 +2913,11 @@ INT8 ProfileHasSkillTrait( INT32 ubProfileID, INT8 bSkillTrait ) if (gGameOptions.fNewTraitSystem) { // exception for special merc - if ( gSkillTraitValues.fAllowSpecialMercTraitsException && ubProfileID == gSkillTraitValues.ubSpecialMercID) - { - bMaxTraits++; - bMaxMajorTraits++; - } + //if ( gSkillTraitValues.fAllowSpecialMercTraitsException && ubProfileID == gSkillTraitValues.ubSpecialMercID) + //{ + // bMaxTraits++; + // bMaxMajorTraits++; + //} for ( INT8 bCnt = 0; bCnt < bMaxTraits; bCnt++ ) { diff --git a/Tactical/faces.h b/Tactical/faces.h index 1c2a85ae..a744e371 100644 --- a/Tactical/faces.h +++ b/Tactical/faces.h @@ -122,6 +122,11 @@ typedef struct INT32 iVideoOverlay; // Value for video overlay ( not used too much ) UINT32 uiSoundID; // Sound ID if one being played + + UINT32 uiSound1ID; // anv: snitch + UINT32 uiSound2ID; + UINT32 uiSound3ID; + UINT8 ubSoldierID; // SoldierID if one specified UINT8 ubCharacterNum; // Profile ID num @@ -235,6 +240,8 @@ BOOLEAN SetFaceTalking( INT32 iFaceIndex, CHAR8 *zSoundFile, STR16 zTextString, // This function will setup appropriate face data and begin the speech process. It can fail if the sound //cannot be played for any reason. +BOOLEAN SetFaceTalkingMultipleSounds( INT32 iFaceIndex, CHAR8 zSoundFiles[][64], UINT8 ubMaxSoundsCount, STR16 zTextString, UINT32 usRate, UINT32 ubVolume, UINT32 ubLoops, UINT32 uiPan ); + // Set some face talking flags without need to play sound BOOLEAN ExternSetFaceTalking( INT32 iFaceIndex, UINT32 uiSoundID ); diff --git a/Tactical/soldier profile type.h b/Tactical/soldier profile type.h index 638db447..26b42739 100644 --- a/Tactical/soldier profile type.h +++ b/Tactical/soldier profile type.h @@ -162,12 +162,13 @@ typedef enum // Flugente: new traits have to go here, even if they are major traits, as otherwise the existing traits in profiles get mixed up COVERT_NT, // 20 RADIO_OPERATOR_NT, //21 // a minor trait + SNITCH_NT, //22 // a minor trait NUM_SKILLTRAITS_NT } SkillTraitNew; #define NUM_MAJOR_TRAITS 10 -#define NUM_MINOR_TRAITS 11 +#define NUM_MINOR_TRAITS 12 #define NUM_ORIGINAL_MAJOR_TRAITS 9 diff --git a/Utils/_ChineseText.cpp b/Utils/_ChineseText.cpp index 26b2e9d3..cef84e98 100644 --- a/Utils/_ChineseText.cpp +++ b/Utils/_ChineseText.cpp @@ -2369,30 +2369,32 @@ STR16 gzMercSkillTextNew[] = // new minor traits L"无线电操作员", // 21 + L"Snitch", // 22 // TODO.Translate // second names for major skills L"机枪手", L"掷弹兵", L"狙击手", - L"游骑兵", // 25 + L"游骑兵", // 26 L"枪斗术", L"武术家", L"班长", L"工兵", L"军医", // placeholders for minor traits - L"Placeholder", // 31 + L"Placeholder", // 32 L"Placeholder", L"Placeholder", L"Placeholder", L"Placeholder", - L"Placeholder", // 36 + L"Placeholder", // 37 L"Placeholder", L"Placeholder", L"Placeholder", - L"Placeholder", // 40 - L"间谍", // 41 + L"Placeholder", // 41 + L"间谍", // 42 L"Placeholder", // for radio operator (minor trait) + L"Placeholder", // for snitch (minor trait) L"更多...", L"various", // for VARIOUSSKILLS // TODO.Translate }; diff --git a/Utils/_DutchText.cpp b/Utils/_DutchText.cpp index 9aeefb04..afdae446 100644 --- a/Utils/_DutchText.cpp +++ b/Utils/_DutchText.cpp @@ -2363,29 +2363,32 @@ STR16 gzMercSkillTextNew[] = L"Covert Ops", // 20 // new minor traits L"Radio Operator", // 21 + L"Snitch", // 22 // TODO.Translate + // second names for major skills - L"Machinegunner", // 22 + L"Machinegunner", // 23 L"Bombardier", L"Sniper", L"Ranger", - L"Gunfighter", // 26 + L"Gunfighter", // 27 L"Martial Arts", L"Squadleader", L"Engineer", - L"Doctor", // 30 + L"Doctor", // 31 // placeholders for minor traits - L"Placeholder", // 31 + L"Placeholder", // 32 L"Placeholder", L"Placeholder", L"Placeholder", L"Placeholder", - L"Placeholder", // 36 + L"Placeholder", // 37 L"Placeholder", L"Placeholder", L"Placeholder", - L"Placeholder", // 40 - L"Spy", // 41 + L"Placeholder", // 41 + L"Spy", // 42 L"Placeholder", // for radio operator (minor trait) + L"Placeholder", // for snitch (minor trait) L"More...", L"various", // for VARIOUSSKILLS // TODO.Translate }; diff --git a/Utils/_EnglishText.cpp b/Utils/_EnglishText.cpp index 53c4823f..cae9e32f 100644 --- a/Utils/_EnglishText.cpp +++ b/Utils/_EnglishText.cpp @@ -2369,31 +2369,33 @@ STR16 gzMercSkillTextNew[] = // new minor traits L"Radio Operator", // 21 + L"Snitch", // 22 // second names for major skills - L"Machinegunner", // 22 + L"Machinegunner", // 23 L"Bombardier", L"Sniper", L"Ranger", - L"Gunfighter", // 26 + L"Gunfighter", // 27 L"Martial Arts", L"Squadleader", L"Engineer", - L"Doctor", // 30 + L"Doctor", // 31 // placeholders for minor traits - L"Placeholder", // 31 + L"Placeholder", // 32 L"Placeholder", L"Placeholder", L"Placeholder", L"Placeholder", - L"Placeholder", // 36 + L"Placeholder", // 37 L"Placeholder", L"Placeholder", L"Placeholder", - L"Placeholder", // 40 - L"Spy", // 41 + L"Placeholder", // 41 + L"Spy", // 42 L"Placeholder", // for radio operator (minor trait) - L"More...", // 43 + L"Placeholder", // for snitch (minor trait) + L"More...", // 45 L"various", // for VARIOUSSKILLS }; ////////////////////////////////////////////////////////// diff --git a/Utils/_FrenchText.cpp b/Utils/_FrenchText.cpp index 2db12ce6..754bf83a 100644 --- a/Utils/_FrenchText.cpp +++ b/Utils/_FrenchText.cpp @@ -2374,6 +2374,8 @@ STR16 gzMercSkillTextNew[] = // new minor traits L"Radio Operator", // 21 + L"Snitch", // 22 // TODO.Translate + // second names for major skills L"Mitrailleur", L"Bombardier", @@ -2385,18 +2387,19 @@ STR16 gzMercSkillTextNew[] = L"Ingénieur", L"Chirurgien", // placeholders for minor traits - L"Placeholder", // 31 + L"Placeholder", // 32 L"Placeholder", L"Placeholder", L"Placeholder", L"Placeholder", - L"Placeholder", // 36 + L"Placeholder", // 37 L"Placeholder", L"Placeholder", L"Placeholder", - L"Placeholder", // 40 - L"Espion", // 41 + L"Placeholder", // 41 + L"Espion", // 42 L"Placeholder", // for radio operator (minor trait) + L"Placeholder", // for snitch(minor trait) L"Plus...", L"various", // for VARIOUSSKILLS // TODO.Translate }; diff --git a/Utils/_GermanText.cpp b/Utils/_GermanText.cpp index c0637d83..9598a968 100644 --- a/Utils/_GermanText.cpp +++ b/Utils/_GermanText.cpp @@ -2378,6 +2378,8 @@ STR16 gzMercSkillTextNew[] = L"Geheimagent", // new minor traits L"Funker", // 21 + L"Snitch", // 22 // TODO.Translate + // second names for major skills L"MG-Veteran", L"Artillerist", @@ -2389,18 +2391,19 @@ STR16 gzMercSkillTextNew[] = L"Ingenieur", L"Arzt", // placeholders for minor traits - L"Placeholder", // 31 + L"Placeholder", // 32 L"Placeholder", L"Placeholder", L"Placeholder", L"Placeholder", - L"Placeholder", // 36 + L"Placeholder", // 37 L"Placeholder", L"Placeholder", L"Placeholder", - L"Placeholder", // 40 - L"Spion", // 41 + L"Placeholder", // 41 + L"Spion", // 42 L"Placeholder", // for radio operator (minor trait) + L"Placeholder", // for snitch(minor trait) L"Mehr...", L"diverse", // for VARIOUSSKILLS }; diff --git a/Utils/_ItalianText.cpp b/Utils/_ItalianText.cpp index bdd7ead5..30a8a030 100644 --- a/Utils/_ItalianText.cpp +++ b/Utils/_ItalianText.cpp @@ -2360,29 +2360,32 @@ STR16 gzMercSkillTextNew[] = L"Covert Ops", // 20 // new minor traits L"Radio Operator", // 21 + L"Snitch", // 22 // TODO.Translate + // second names for major skills - L"Machinegunner", // 22 + L"Machinegunner", // 23 L"Bombardier", L"Sniper", L"Ranger", - L"Gunfighter", // 26 + L"Gunfighter", // 27 L"Martial Arts", L"Squadleader", L"Engineer", - L"Doctor", // 30 + L"Doctor", // 31 // placeholders for minor traits - L"Placeholder", // 31 + L"Placeholder", // 32 L"Placeholder", L"Placeholder", L"Placeholder", L"Placeholder", - L"Placeholder", // 36 + L"Placeholder", // 37 L"Placeholder", L"Placeholder", L"Placeholder", - L"Placeholder", // 40 - L"Spy", // 41 + L"Placeholder", // 41 + L"Spy", // 42 L"Placeholder", // for radio operator (minor trait) + L"Placeholder", // for snitch(minor trait) L"More...", L"various", // for VARIOUSSKILLS // TODO.Translate }; diff --git a/Utils/_Ja25ChineseText.cpp b/Utils/_Ja25ChineseText.cpp index bf5d2e0c..a6449bd7 100644 --- a/Utils/_Ja25ChineseText.cpp +++ b/Utils/_Ja25ChineseText.cpp @@ -374,6 +374,11 @@ STR16 gzIMPMinorTraitsHelpTextsScouting[]= L"防止血猫偷袭你的队伍\n",// L"Prevents the bloodcats to ambush your squad\n", }; +STR16 gzIMPMinorTraitsHelpTextsSnitch[]= +{ + L"Will occasionally inform you about his teammates' opinions.\n", // TODO.Translate +}; + STR16 gzIMPMinorTraitsHelpTextsNone[]= { L"无奖励",// L"No bonuses", diff --git a/Utils/_Ja25DutchText.cpp b/Utils/_Ja25DutchText.cpp index 0f7c87d2..2c4514c8 100644 --- a/Utils/_Ja25DutchText.cpp +++ b/Utils/_Ja25DutchText.cpp @@ -376,6 +376,10 @@ STR16 gzIMPMinorTraitsHelpTextsScouting[]= L"Prevents enemy ambushes on your squad\n", L"Prevents bloodcat ambushes on your squad\n", }; +STR16 gzIMPMinorTraitsHelpTextsSnitch[]= +{ + L"Will occasionally inform you about his teammates' opinions.\n", // TODO.Translate +}; STR16 gzIMPMinorTraitsHelpTextsNone[]= { diff --git a/Utils/_Ja25DutchText.h b/Utils/_Ja25DutchText.h index 96adfeee..84889539 100644 --- a/Utils/_Ja25DutchText.h +++ b/Utils/_Ja25DutchText.h @@ -31,6 +31,7 @@ extern STR16 gzIMPMinorTraitsHelpTextsBodybuilding[]; extern STR16 gzIMPMinorTraitsHelpTextsDemolitions[]; extern STR16 gzIMPMinorTraitsHelpTextsTeaching[]; extern STR16 gzIMPMinorTraitsHelpTextsScouting[]; +extern STR16 gzIMPMinorTraitsHelpTextsSnitch[]; extern STR16 gzIMPMinorTraitsHelpTextsNone[]; extern STR16 gzIMPOldSkillTraitsHelpTexts[]; diff --git a/Utils/_Ja25EnglishText.cpp b/Utils/_Ja25EnglishText.cpp index a94b43ad..45d6f4ed 100644 --- a/Utils/_Ja25EnglishText.cpp +++ b/Utils/_Ja25EnglishText.cpp @@ -377,6 +377,11 @@ STR16 gzIMPMinorTraitsHelpTextsScouting[]= L"Prevents bloodcat ambushes on your squad\n", }; +STR16 gzIMPMinorTraitsHelpTextsSnitch[]= +{ + L"Will occasionally inform you about his teammates' opinions.\n", +}; + STR16 gzIMPMinorTraitsHelpTextsNone[]= { L"No bonuses", diff --git a/Utils/_Ja25EnglishText.h b/Utils/_Ja25EnglishText.h index 3b61a519..03b96410 100644 --- a/Utils/_Ja25EnglishText.h +++ b/Utils/_Ja25EnglishText.h @@ -31,6 +31,7 @@ extern STR16 gzIMPMinorTraitsHelpTextsBodybuilding[]; extern STR16 gzIMPMinorTraitsHelpTextsDemolitions[]; extern STR16 gzIMPMinorTraitsHelpTextsTeaching[]; extern STR16 gzIMPMinorTraitsHelpTextsScouting[]; +extern STR16 gzIMPMinorTraitsHelpTextsSnitch[]; extern STR16 gzIMPMinorTraitsHelpTextsNone[]; extern STR16 gzIMPOldSkillTraitsHelpTexts[]; diff --git a/Utils/_Ja25FrenchText.cpp b/Utils/_Ja25FrenchText.cpp index f61befa1..4f59dfa7 100644 --- a/Utils/_Ja25FrenchText.cpp +++ b/Utils/_Ja25FrenchText.cpp @@ -375,6 +375,10 @@ STR16 gzIMPMinorTraitsHelpTextsScouting[]= L"Empêche les chats sauvages de prendre en embuscade votre escouade\n", }; +STR16 gzIMPMinorTraitsHelpTextsSnitch[]= +{ + L"Will occasionally inform you about his teammates' opinions.\n", // TODO.Translate +}; STR16 gzIMPMinorTraitsHelpTextsNone[]= { L"Pas de bonus", diff --git a/Utils/_Ja25FrenchText.h b/Utils/_Ja25FrenchText.h index 96adfeee..84889539 100644 --- a/Utils/_Ja25FrenchText.h +++ b/Utils/_Ja25FrenchText.h @@ -31,6 +31,7 @@ extern STR16 gzIMPMinorTraitsHelpTextsBodybuilding[]; extern STR16 gzIMPMinorTraitsHelpTextsDemolitions[]; extern STR16 gzIMPMinorTraitsHelpTextsTeaching[]; extern STR16 gzIMPMinorTraitsHelpTextsScouting[]; +extern STR16 gzIMPMinorTraitsHelpTextsSnitch[]; extern STR16 gzIMPMinorTraitsHelpTextsNone[]; extern STR16 gzIMPOldSkillTraitsHelpTexts[]; diff --git a/Utils/_Ja25GermanText.cpp b/Utils/_Ja25GermanText.cpp index ef88c10d..2979471f 100644 --- a/Utils/_Ja25GermanText.cpp +++ b/Utils/_Ja25GermanText.cpp @@ -372,6 +372,10 @@ STR16 gzIMPMinorTraitsHelpTextsScouting[]= L"Verhindert, das Umzingeln der Gruppe durch Bloodcats\n", }; +STR16 gzIMPMinorTraitsHelpTextsSnitch[]= +{ + L"Will occasionally inform you about his teammates' opinions.\n", // TODO.Translate +}; STR16 gzIMPMinorTraitsHelpTextsNone[]= { L"Keine Boni", diff --git a/Utils/_Ja25GermanText.h b/Utils/_Ja25GermanText.h index 1a43b826..775b0081 100644 --- a/Utils/_Ja25GermanText.h +++ b/Utils/_Ja25GermanText.h @@ -31,6 +31,7 @@ extern STR16 gzIMPMinorTraitsHelpTextsBodybuilding[]; extern STR16 gzIMPMinorTraitsHelpTextsDemolitions[]; extern STR16 gzIMPMinorTraitsHelpTextsTeaching[]; extern STR16 gzIMPMinorTraitsHelpTextsScouting[]; +extern STR16 gzIMPMinorTraitsHelpTextsSnitch[]; extern STR16 gzIMPMinorTraitsHelpTextsNone[]; extern STR16 gzIMPOldSkillTraitsHelpTexts[]; diff --git a/Utils/_Ja25ItalianText.cpp b/Utils/_Ja25ItalianText.cpp index db55189d..517dd41b 100644 --- a/Utils/_Ja25ItalianText.cpp +++ b/Utils/_Ja25ItalianText.cpp @@ -374,7 +374,10 @@ STR16 gzIMPMinorTraitsHelpTextsScouting[]= L"Prevents enemy ambushes on your squad\n", L"Prevents bloodcat ambushes on your squad\n", }; - +STR16 gzIMPMinorTraitsHelpTextsSnitch[]= +{ + L"Will occasionally inform you about his teammates' opinions.\n", // TODO.Translate +}; STR16 gzIMPMinorTraitsHelpTextsNone[]= { L"No bonuses", diff --git a/Utils/_Ja25ItalianText.h b/Utils/_Ja25ItalianText.h index 96adfeee..84889539 100644 --- a/Utils/_Ja25ItalianText.h +++ b/Utils/_Ja25ItalianText.h @@ -31,6 +31,7 @@ extern STR16 gzIMPMinorTraitsHelpTextsBodybuilding[]; extern STR16 gzIMPMinorTraitsHelpTextsDemolitions[]; extern STR16 gzIMPMinorTraitsHelpTextsTeaching[]; extern STR16 gzIMPMinorTraitsHelpTextsScouting[]; +extern STR16 gzIMPMinorTraitsHelpTextsSnitch[]; extern STR16 gzIMPMinorTraitsHelpTextsNone[]; extern STR16 gzIMPOldSkillTraitsHelpTexts[]; diff --git a/Utils/_Ja25PolishText.cpp b/Utils/_Ja25PolishText.cpp index 770191b9..a1937ee1 100644 --- a/Utils/_Ja25PolishText.cpp +++ b/Utils/_Ja25PolishText.cpp @@ -376,7 +376,10 @@ STR16 gzIMPMinorTraitsHelpTextsScouting[]= L"Prevents enemy ambushes on your squad\n", L"Prevents bloodcat ambushes on your squad\n", }; - +STR16 gzIMPMinorTraitsHelpTextsSnitch[]= +{ + L"Okazyjnie poinformuje cię o opiniach kolegów z oddziału.\n", +}; STR16 gzIMPMinorTraitsHelpTextsNone[]= { L"No bonuses", diff --git a/Utils/_Ja25PolishText.h b/Utils/_Ja25PolishText.h index 96adfeee..84889539 100644 --- a/Utils/_Ja25PolishText.h +++ b/Utils/_Ja25PolishText.h @@ -31,6 +31,7 @@ extern STR16 gzIMPMinorTraitsHelpTextsBodybuilding[]; extern STR16 gzIMPMinorTraitsHelpTextsDemolitions[]; extern STR16 gzIMPMinorTraitsHelpTextsTeaching[]; extern STR16 gzIMPMinorTraitsHelpTextsScouting[]; +extern STR16 gzIMPMinorTraitsHelpTextsSnitch[]; extern STR16 gzIMPMinorTraitsHelpTextsNone[]; extern STR16 gzIMPOldSkillTraitsHelpTexts[]; diff --git a/Utils/_Ja25RussianText.cpp b/Utils/_Ja25RussianText.cpp index 45483762..69ca173f 100644 --- a/Utils/_Ja25RussianText.cpp +++ b/Utils/_Ja25RussianText.cpp @@ -373,6 +373,10 @@ STR16 gzIMPMinorTraitsHelpTextsScouting[]= L"Предотвращает попадание отряда в засады кошек-убийц\n", }; +STR16 gzIMPMinorTraitsHelpTextsSnitch[]= +{ + L"Will occasionally inform you about his teammates' opinions.\n", // TODO.Translate +}; STR16 gzIMPMinorTraitsHelpTextsNone[]= { L"Нет преимуществ", diff --git a/Utils/_Ja25RussianText.h b/Utils/_Ja25RussianText.h index 96adfeee..84889539 100644 --- a/Utils/_Ja25RussianText.h +++ b/Utils/_Ja25RussianText.h @@ -31,6 +31,7 @@ extern STR16 gzIMPMinorTraitsHelpTextsBodybuilding[]; extern STR16 gzIMPMinorTraitsHelpTextsDemolitions[]; extern STR16 gzIMPMinorTraitsHelpTextsTeaching[]; extern STR16 gzIMPMinorTraitsHelpTextsScouting[]; +extern STR16 gzIMPMinorTraitsHelpTextsSnitch[]; extern STR16 gzIMPMinorTraitsHelpTextsNone[]; extern STR16 gzIMPOldSkillTraitsHelpTexts[]; diff --git a/Utils/_Ja25TaiwaneseText.cpp b/Utils/_Ja25TaiwaneseText.cpp index c0a38003..e93783df 100644 --- a/Utils/_Ja25TaiwaneseText.cpp +++ b/Utils/_Ja25TaiwaneseText.cpp @@ -377,7 +377,10 @@ STR16 gzIMPMinorTraitsHelpTextsScouting[]= L"Prevents enemy ambushes on your squad\n", L"Prevents bloodcat ambushes on your squad\n", }; - +STR16 gzIMPMinorTraitsHelpTextsSnitch[]= +{ + L"Will occasionally inform you about his teammates' opinions.\n", // TODO.Translate +}; STR16 gzIMPMinorTraitsHelpTextsNone[]= { L"No bonuses", diff --git a/Utils/_Ja25TaiwaneseText.h b/Utils/_Ja25TaiwaneseText.h index 96adfeee..84889539 100644 --- a/Utils/_Ja25TaiwaneseText.h +++ b/Utils/_Ja25TaiwaneseText.h @@ -31,6 +31,7 @@ extern STR16 gzIMPMinorTraitsHelpTextsBodybuilding[]; extern STR16 gzIMPMinorTraitsHelpTextsDemolitions[]; extern STR16 gzIMPMinorTraitsHelpTextsTeaching[]; extern STR16 gzIMPMinorTraitsHelpTextsScouting[]; +extern STR16 gzIMPMinorTraitsHelpTextsSnitch[]; extern STR16 gzIMPMinorTraitsHelpTextsNone[]; extern STR16 gzIMPOldSkillTraitsHelpTexts[]; diff --git a/Utils/_PolishText.cpp b/Utils/_PolishText.cpp index 22df5b2e..90969b63 100644 --- a/Utils/_PolishText.cpp +++ b/Utils/_PolishText.cpp @@ -2373,9 +2373,11 @@ STR16 gzMercSkillTextNew[] = L"Uczenie", L"Zwiad", // covert ops is a major trait that was added later - L"Covert Ops", // 20 // TODO.Translate + L"Tajne Operacje", // 20 // new minor traits - L"Radio Operator", // 21 + L"Radiooperator", // 21 + L"Kapuś", // 22 + // second names for major skills L"Strzelec RKMu", L"Bombardier", @@ -2386,20 +2388,21 @@ STR16 gzMercSkillTextNew[] = L"Dowódca Drużyny", L"Inżynier", L"Doktor", - L"Placeholder", // 31 + L"Placeholder", // 32 L"Placeholder", L"Placeholder", L"Placeholder", L"Placeholder", - L"Placeholder", // 36 + L"Placeholder", // 37 L"Placeholder", L"Placeholder", L"Placeholder", - L"Placeholder", // 40 - L"Spy", // 41 // TODO.Translate + L"Placeholder", // 41 + L"Szpieg", // 42 L"Placeholder", // for radio operator (minor trait) + L"Placeholder", // for snitch(minor trait) L"Więcej...", - L"various", // for VARIOUSSKILLS // TODO.Translate + L"różne", // for VARIOUSSKILLS }; ////////////////////////////////////////////////////////// diff --git a/Utils/_RussianText.cpp b/Utils/_RussianText.cpp index def26d70..99d484d2 100644 --- a/Utils/_RussianText.cpp +++ b/Utils/_RussianText.cpp @@ -2368,6 +2368,8 @@ STR16 gzMercSkillTextNew[] = L"Covert Ops", // 20 // TODO.Translate // new minor traits L"Radio Operator", // 21 + L"Snitch", // 22 // TODO.Translate + // second names for major skills L"Пулемётчик", //Machinegunner L"Артиллерист", //Bombardier @@ -2378,18 +2380,19 @@ STR16 gzMercSkillTextNew[] = L"Командир", //Squadleader L"Инженер", //Engineer L"Доктор", //Doctor - L"Placeholder", // 31 + L"Placeholder", // 32 L"Placeholder", L"Placeholder", L"Placeholder", L"Placeholder", - L"Placeholder", // 36 + L"Placeholder", // 37 L"Placeholder", L"Placeholder", L"Placeholder", - L"Placeholder", // 40 - L"Шпион", // 41 + L"Placeholder", // 41 + L"Шпион", // 42 L"Placeholder", // for radio operator (minor trait) + L"Placeholder", // for snitch(minor trait) L"Ещё...", L"various", // for VARIOUSSKILLS // TODO.Translate }; diff --git a/Utils/_TaiwaneseText.cpp b/Utils/_TaiwaneseText.cpp index 5c910369..35fc4384 100644 --- a/Utils/_TaiwaneseText.cpp +++ b/Utils/_TaiwaneseText.cpp @@ -2368,30 +2368,32 @@ STR16 gzMercSkillTextNew[] = L"Covert Ops", // 20 // new minor traits L"Radio Operator", // 21 + L"Snitch", // 22 // TODO.Translate // second names for major skills - L"Machinegunner", // 22 + L"Machinegunner", // 23 L"Bombardier", L"Sniper", L"Ranger", - L"Gunfighter", // 26 + L"Gunfighter", // 27 L"Martial Arts", L"Squadleader", L"Engineer", - L"Doctor", // 30 + L"Doctor", // 31 // placeholders for minor traits - L"Placeholder", // 31 + L"Placeholder", // 32 L"Placeholder", L"Placeholder", L"Placeholder", L"Placeholder", - L"Placeholder", // 36 + L"Placeholder", // 37 L"Placeholder", L"Placeholder", L"Placeholder", - L"Placeholder", // 40 - L"Spy", // 41 + L"Placeholder", // 41 + L"Spy", // 42 L"Placeholder", // for radio operator (minor trait) + L"Placeholder", // for snitch(minor trait) L"More...", L"various", // for VARIOUSSKILLS // TODO.Translate }; diff --git a/gameloop.cpp b/gameloop.cpp index 7cc95792..4383cc9d 100644 --- a/gameloop.cpp +++ b/gameloop.cpp @@ -141,6 +141,10 @@ BOOLEAN InitializeGame(void) LoadTauntsSettings(); // Load helicopter repair settings LoadHelicopterRepairRefuelSettings(); + // Load externalised morale settings + LoadMoraleSettings(); + // Load externalised reputation settings + LoadReputationSettings(); #ifdef JA2UB LoadGameUBOptions(); // JA25 UB