diff --git a/artifacts/config_files/Perks.ini b/artifacts/config_files/Perks.ini index e89ce435..eab36c3b 100644 --- a/artifacts/config_files/Perks.ini +++ b/artifacts/config_files/Perks.ini @@ -7,22 +7,51 @@ ; be used to remove their hardcoded effects, and add new stat/skill effects [PerksTweak] -;Change the penalty distance and distance bonus for 'Weapon Scope Range' weapon perk +;Changes the bonus for 'Master Trader' perk (ID 17) +;25 - default bonus +MasterTraderBonus=25 + +;Changes the distance bonus for 'Weapon Long Range' weapon perk (ID 58) +;2 - no bonus, 4 - default bonus +WeaponLongRangeBonus=4 + +;Changes the hit chance bonus for 'Weapon Accurate' weapon perk (ID 59) +;0 - no bonus, 125 - maximum bonus, 20 - default bonus +WeaponAccurateBonus=20 + +;Change the penalty distance and distance bonus for 'Weapon Scope Range' weapon perk (ID 64) ;0 - no penalty, 8 - default penalty WeaponScopeRangePenalty=8 ;2 - no bonus, 5 - default bonus WeaponScopeRangeBonus=5 -;Changes the distance bonus for 'Weapon Long Range' weapon perk -;2 - no bonus, 4 - default bonus -WeaponLongRangeBonus=4 +;Changes the resistance bonuses for 'Vault City Inoculations' perk (ID 78) +;valid range: -100..100, 10 - default bonus +VaultCityInoculationsPoisonBonus=10 +VaultCityInoculationsRadBonus=10 -;Changes the hit chance bonus for 'Weapon Accurate' weapon perk -;0 - no bonus, 200 - maximum bonus, 20 - default bonus -WeaponAccurateBonus=20 +;Changes the damage bonus per level for 'Demolition Expert' perk (ID 82) +;10 - default bonus +DemolitionExpertBonus=10 -;Changes the strength bonus for 'Weapon Handling' perk -;0 - no bonus, 10 - maximum bonus, 3 - default bonus +;Changes the damage bonus for 'Living Anatomy' perk (ID 97) +;125 - maximum bonus, 5 - default bonus +LivingAnatomyBonus=5 + +;Changes the damage bonus for 'Pyromaniac' perk (ID 101) +;125 - maximum bonus, 5 - default bonus +PyromaniacBonus=5 + +;Changes the skill bonus per level for 'Salesman' perk (ID 103) +;125 - maximum bonus, 20 - default bonus +SalesmanBonus=20 + +;Changes the percent chance for 'Stonewall' perk (ID 104) +;valid range: 0..100, 50 - default percent +StonewallPercent=50 + +;Changes the strength bonus for 'Weapon Handling' perk (ID 106) +;0 - no bonus, 10 - maximum bonus, 3 - default bonus WeaponHandlingBonus=3 ;############################################################################## diff --git a/sfall/AI.cpp b/sfall/AI.cpp index a79bcc30..d447e948 100644 --- a/sfall/AI.cpp +++ b/sfall/AI.cpp @@ -473,6 +473,7 @@ void AI_Init() { HookCall(0x421666, combat_safety_invalidate_weapon_func_hook_check); // Fix AI weapon switching when not having enough action points + // AI will try to change attack mode before deciding to switch weapon HookCall(0x42AB57, ai_try_attack_hook_switch_fix); // Fix for duplicate critters being added to the list of potential targets for AI diff --git a/sfall/Perks.cpp b/sfall/Perks.cpp index d4d47449..dcc74808 100644 --- a/sfall/Perks.cpp +++ b/sfall/Perks.cpp @@ -623,7 +623,208 @@ void __stdcall ApplyHeaveHoFix() { // not really a fix perkHeaveHoModFix = true; } +//////////////////////////////// ENGINE PERKS ///////////////////////////////// + +static class EnginePerkBonus { +public: + long WeaponScopeRangePenalty; + long WeaponScopeRangeBonus; + long WeaponLongRangeBonus; + long WeaponAccurateBonus; + long WeaponHandlingBonus; + + float MasterTraderBonus; + long SalesmanBonus; + + long LivingAnatomyBonus; + long PyromaniacBonus; + + long StonewallPercent; + + long DemolitionExpertBonus; + + long VaultCityInoculationsPoisonBonus; + long VaultCityInoculationsRadBonus; + + EnginePerkBonus() { + WeaponScopeRangePenalty = 8; + WeaponScopeRangeBonus = 5; + WeaponLongRangeBonus = 4; + WeaponAccurateBonus = 20; + WeaponHandlingBonus = 3; + + MasterTraderBonus = 25; + SalesmanBonus = 20; + + LivingAnatomyBonus = 5; + PyromaniacBonus = 5; + + StonewallPercent = 50; + + DemolitionExpertBonus = 10; + + VaultCityInoculationsPoisonBonus = 10; + VaultCityInoculationsRadBonus = 10; + } + + /////////////////////////////////////////// + + void setWeaponScopeRangePenalty(long value) { + if (value < 0) return; + WeaponScopeRangePenalty = value; + SafeWrite32(0x42448E, value); + } + + void setWeaponScopeRangeBonus(long value) { + if (value < 2) return; + WeaponScopeRangeBonus = value; + SafeWrite32(0x424489, value); + } + + void setWeaponLongRangeBonus(long value) { + if (value < 2) return; + WeaponLongRangeBonus = value; + SafeWrite32(0x424474, value); + } + + void setWeaponAccurateBonus(long value) { + if (value < 0) return; + WeaponAccurateBonus = value; + if (WeaponAccurateBonus > 125) WeaponAccurateBonus = 125; + SafeWrite8(0x42465D, static_cast(WeaponAccurateBonus)); + } + + void setWeaponHandlingBonus(long value) { + if (value < 0) return; + WeaponHandlingBonus = value; + if (WeaponHandlingBonus > 10) WeaponHandlingBonus = 10; + SafeWrite8(0x424636, static_cast(WeaponHandlingBonus)); + SafeWrite8(0x4251CE, static_cast(-WeaponHandlingBonus)); + } + + void setMasterTraderBonus(long value) { + if (value < 0) return; + MasterTraderBonus = static_cast(value); + SafeWrite32(0x474BB3, *(DWORD*)&MasterTraderBonus); // write float data + } + + void setSalesmanBonus(long value) { + if (value < 0) return; + SalesmanBonus = value; + if (SalesmanBonus > 125) SalesmanBonus = 125; + SafeWrite8(0x496F60, static_cast(SalesmanBonus)); + } + + void setLivingAnatomyBonus(long value) { + if (value < 0) return; + LivingAnatomyBonus = value; + if (LivingAnatomyBonus > 125) LivingAnatomyBonus = 125; + SafeWrite8(0x424A91, static_cast(LivingAnatomyBonus)); + } + + void setPyromaniacBonus(long value) { + if (value < 0) return; + PyromaniacBonus = value; + if (PyromaniacBonus > 125) PyromaniacBonus = 125; + SafeWrite8(0x424AB6, static_cast(PyromaniacBonus)); + } + + void setStonewallPercent(long value) { + if (value < 0) return; + StonewallPercent = value; + if (StonewallPercent > 100) StonewallPercent = 100; + SafeWrite8(0x424B50, static_cast(StonewallPercent)); + } + + void setDemolitionExpertBonus(long value) { + if (value < 0) return; + DemolitionExpertBonus = value; + } + + void setVaultCityInoculationsPoisonBonus(long value) { + if (value < -100) value = -100; + if (value > 100) value = 100; + VaultCityInoculationsPoisonBonus = value; + SafeWrite8(0x4AF26A, static_cast(VaultCityInoculationsPoisonBonus)); + } + + void setVaultCityInoculationsRadBonus(long value) { + if (value < -100) value = -100; + if (value > 100) value = 100; + VaultCityInoculationsRadBonus = value; + SafeWrite8(0x4AF287, static_cast(VaultCityInoculationsRadBonus)); + } + +} enginePerks; + +static void __declspec(naked) perk_adjust_skill_hack_salesman() { + __asm { + imul eax, [enginePerks.SalesmanBonus]; + add ecx, eax; // barter_skill + (perkLevel * SalesmanBonus) + mov eax, ecx + retn; + } +} + +static void __declspec(naked) queue_explode_exit_hack_demolition_expert() { + __asm { + imul eax, [enginePerks.DemolitionExpertBonus]; + add ecx, eax; // maxBaseDmg + (perkLevel * DemolitionExpertBonus) + add ebx, eax // minBaseDmg + (perkLevel * DemolitionExpertBonus) + retn; + } +} + +static void EnginePerkBonusInit() { + // Allows the current perk level to affect the calculation of its bonus value + MakeCall(0x496F5E, perk_adjust_skill_hack_salesman); + MakeCall(0x4A289C, queue_explode_exit_hack_demolition_expert, 1); +} + +static void ReadPerksBonuses(const char* perksFile) { + int wScopeRangeMod = iniGetInt("PerksTweak", "WeaponScopeRangePenalty", 8, perksFile); + if (wScopeRangeMod != 8) enginePerks.setWeaponScopeRangePenalty(wScopeRangeMod); + wScopeRangeMod = iniGetInt("PerksTweak", "WeaponScopeRangeBonus", 5, perksFile); + if (wScopeRangeMod != 5) enginePerks.setWeaponScopeRangeBonus(wScopeRangeMod); + + int enginePerkMod = iniGetInt("PerksTweak", "WeaponLongRangeBonus", 4, perksFile); + if (enginePerkMod != 4) enginePerks.setWeaponLongRangeBonus(enginePerkMod); + + enginePerkMod = iniGetInt("PerksTweak", "WeaponAccurateBonus", 20, perksFile); + if (enginePerkMod != 20) enginePerks.setWeaponAccurateBonus(enginePerkMod); + + enginePerkMod = iniGetInt("PerksTweak", "WeaponHandlingBonus", 3, perksFile); + if (enginePerkMod != 3) enginePerks.setWeaponHandlingBonus(enginePerkMod); + + int masterTraderBonus = iniGetInt("PerksTweak", "MasterTraderBonus", 25, perksFile); + if (masterTraderBonus != 25) enginePerks.setMasterTraderBonus(masterTraderBonus); + + int salesmanBonus = iniGetInt("PerksTweak", "SalesmanBonus", 20, perksFile); + if (salesmanBonus != 20) enginePerks.setSalesmanBonus(salesmanBonus); + + int livingAnatomyBonus = iniGetInt("PerksTweak", "LivingAnatomyBonus", 5, perksFile); + if (livingAnatomyBonus != 5) enginePerks.setLivingAnatomyBonus(livingAnatomyBonus); + + int pyromaniacBonus = iniGetInt("PerksTweak", "PyromaniacBonus", 5, perksFile); + if (pyromaniacBonus != 5) enginePerks.setPyromaniacBonus(pyromaniacBonus); + + int stonewallPercent = iniGetInt("PerksTweak", "StonewallPercent", 50, perksFile); + if (stonewallPercent != 50) enginePerks.setStonewallPercent(stonewallPercent); + + int demolitionExpertBonus = iniGetInt("PerksTweak", "DemolitionExpertBonus", 10, perksFile); + if (demolitionExpertBonus != 10) enginePerks.setDemolitionExpertBonus(demolitionExpertBonus); + + int vaultCityInoculationsBonus = iniGetInt("PerksTweak", "VaultCityInoculationsPoisonBonus", 10, perksFile); + if (vaultCityInoculationsBonus != 10) enginePerks.setVaultCityInoculationsPoisonBonus(vaultCityInoculationsBonus); + vaultCityInoculationsBonus = iniGetInt("PerksTweak", "VaultCityInoculationsRadBonus", 10, perksFile); + if (vaultCityInoculationsBonus != 10) enginePerks.setVaultCityInoculationsRadBonus(vaultCityInoculationsBonus); +} + +/////////////////////////////////////////////////////////////////////////////// + static void PerkEngineInit() { + EnginePerkBonusInit(); + // Character screen (list_perks_) HookCall(0x434256, PlayerHasTraitHook); // jz func MakeJump(0x43436B, PlayerHasPerkHack); @@ -1240,25 +1441,6 @@ void Perks_Init() { } // Engine perks settings - long enginePerkMod = iniGetInt("PerksTweak", "WeaponScopeRangePenalty", -1, perksFile); - if (enginePerkMod >= 0 && enginePerkMod != 8) SafeWrite32(0x42448E, enginePerkMod); - enginePerkMod = iniGetInt("PerksTweak", "WeaponScopeRangeBonus", -1, perksFile); - if (enginePerkMod >= 2 && enginePerkMod != 5) SafeWrite32(0x424489, enginePerkMod); - - enginePerkMod = iniGetInt("PerksTweak", "WeaponLongRangeBonus", -1, perksFile); - if (enginePerkMod >= 2 && enginePerkMod != 4) SafeWrite32(0x424474, enginePerkMod); - - enginePerkMod = iniGetInt("PerksTweak", "WeaponAccurateBonus", -1, perksFile); - if (enginePerkMod >= 0 && enginePerkMod != 20) { - if (enginePerkMod > 200) enginePerkMod = 200; - SafeWrite8(0x42465D, static_cast(enginePerkMod)); - } - - enginePerkMod = iniGetInt("PerksTweak", "WeaponHandlingBonus", -1, perksFile); - if (enginePerkMod >= 0 && enginePerkMod != 3) { - if (enginePerkMod > 10) enginePerkMod = 10; - SafeWrite8(0x424636, static_cast(enginePerkMod)); - SafeWrite8(0x4251CE, static_cast(-enginePerkMod)); - } + ReadPerksBonuses(perksFile); } }