From 7eec7a132ecbd9f844fcb963abf516d7e8b8e651 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Mon, 27 Jan 2025 21:06:15 +0800 Subject: [PATCH] Added settings about Educated, Healer, and Lifegiver to perks.ini --- artifacts/config_files/Perks.ini | 21 +++- sfall/Modules/SubModules/EnginePerks.cpp | 133 ++++++++++++++++------- 2 files changed, 109 insertions(+), 45 deletions(-) diff --git a/artifacts/config_files/Perks.ini b/artifacts/config_files/Perks.ini index e3900b14..ae4dff26 100644 --- a/artifacts/config_files/Perks.ini +++ b/artifacts/config_files/Perks.ini @@ -2,10 +2,12 @@ ;When adding extra perks to a mod, it's advisable to use the fake perk scripting functions rather than make ; modifications in this file, as some perks have hardcoded effects which may catch you out +;Set the bonus value to 0 in the 'PerksTweak' section for perks to get around this problem -;Since traits need to be picked before any scripts run, they have an additional NoHardcode option in this file which can -; be used to remove their hardcoded effects, and add new stat/skill effects +;Since traits need to be picked before any scripts run, they have an additional 'NoHardcode' option in this file +; which can be used to remove their hardcoded effects, and add new stat/skill effects +;############################################################################## [PerksTweak] ;Changes the light level bonus for 'Night Vision' perk (ID 9) ;valid range: 0..100, 20 - default bonus @@ -19,6 +21,20 @@ SurvivalistBonus=25 ;25 - default bonus MasterTraderBonus=25 +;Changes the skill point bonus for 'Educated' perk (ID 18) +;125 - maximum bonus, 2 - default bonus +EducatedBonus=2 + +;Changes the hit point bonuses for 'Healer' perk (ID 19) +;999 - maximum bonus, 4 - default bonus +HealerMinBonus=4 +;999 - maximum bonus, 10 - default bonus +HealerMaxBonus=10 + +;Changes the hit point bonus for 'Lifegiver' perk (ID 28) +;125 - maximum bonus, 4 - default bonus +LifegiverBonus=4 + ;Changes the Science and Repair skill bonus for 'Mr.Fixit' perk (ID 31) ;125 - maximum bonus, 10 - default bonus MrFixitBonus=10 @@ -155,7 +171,6 @@ Enable=0 ;If the value is set to -99999, the variable will be ignored (similar to comment out that line) -;############################################################################## ;This is a modification to perk 119 [119] Name=Example diff --git a/sfall/Modules/SubModules/EnginePerks.cpp b/sfall/Modules/SubModules/EnginePerks.cpp index f4b243f4..d1ab28f8 100644 --- a/sfall/Modules/SubModules/EnginePerks.cpp +++ b/sfall/Modules/SubModules/EnginePerks.cpp @@ -31,6 +31,10 @@ static long SalesmanBonus = 20; static long DemolitionExpertBonus = 10; static long NightVisionBonus = 13107; // 20% of max light static long ComprehensionBonus = 150; // +50% of earned skill points +static long EducatedBonus = 2; +static long HealerMinBonus = 4; +static long HealerMaxBonus = 10; +static long LifegiverBonus = 4; static bool TryGetModifiedInt(const char* key, int defaultValue, int& outValue, const char* perksFile) { outValue = IniReader::GetInt("PerksTweak", key, defaultValue, perksFile); @@ -78,21 +82,46 @@ static __declspec(naked) void queue_explode_exit_hack_demolition_expert() { } static __declspec(naked) void light_set_ambient_hack_night_vision() { + static const DWORD light_set_ambient_night_vision_Ret = 0x47A932; __asm { imul eax, [NightVisionBonus]; - pop edx; - add edx, 16; // skip code (to 0x47A932) - jmp edx; + jmp light_set_ambient_night_vision_Ret; } } static __declspec(naked) void obj_use_book_hack_comprehension() { + static const DWORD obj_use_book_comprehension_Ret = 0x49BADD; __asm { imul esi, [ComprehensionBonus]; mov edx, esi; - pop ebx; - add ebx, 11; // skip code (to 0x49BADD) - jmp ebx; + jmp obj_use_book_comprehension_Ret; + } +} + +static __declspec(naked) void UpdateLevel_hack_educated() { + __asm { + call fo::funcoffs::perk_level_; + imul eax, [EducatedBonus]; + retn; + } +} + +static __declspec(naked) void skill_use_hack_healer() { + static const DWORD skill_use_healer_Ret = 0x4AADDC; + __asm { + mov edx, eax; + imul edx, [HealerMinBonus]; + mov [esp + 0xC8 - 0x34], edx; // minimumHpToHeal + imul eax, [HealerMaxBonus]; + jmp skill_use_healer_Ret; + } +} + +static __declspec(naked) void statPcExperience_hack_lifegiver() { + __asm { + call fo::funcoffs::perk_level_; + imul eax, [LifegiverBonus]; + retn; } } @@ -101,8 +130,12 @@ void EnginePerkBonusInit() { MakeCall(0x496F5E, perk_adjust_skill_hack_salesman); MakeCall(0x4A289C, queue_explode_exit_hack_demolition_expert, 1); // Allow configurable bonuses - MakeCall(0x47A91D, light_set_ambient_hack_night_vision); - MakeCall(0x49BACD, obj_use_book_hack_comprehension); + MakeJump(0x47A91D, light_set_ambient_hack_night_vision); + MakeJump(0x49BACD, obj_use_book_hack_comprehension); + MakeCall(0x43C287, UpdateLevel_hack_educated, 2); + MakeJump(0x4AADC5, skill_use_hack_healer, 2); + MakeCall(0x4AFBCC, statPcExperience_hack_lifegiver, 3); // statPCAddExperienceCheckPMs_ + MakeCall(0x4AFCBB, statPcExperience_hack_lifegiver, 3); // statPcResetExperience_ } void ReadPerksBonuses(const char* perksFile) { @@ -111,32 +144,50 @@ void ReadPerksBonuses(const char* perksFile) { TryPatchValue32("WeaponScopeRangeBonus", 5, 2, 100, 0x424489, perksFile); TryPatchValue32("WeaponLongRangeBonus", 4, 2, 100, 0x424474, perksFile); TryPatchSkillBonus8("WeaponAccurateBonus", 20, 0x42465D, perksFile); - if (TryGetModifiedInt("WeaponHandlingBonus", 3, value, perksFile) && value >= 0) { - if (value > 10) value = 10; - SafeWrite8(0x424636, static_cast(value)); - SafeWrite8(0x4251CE, static_cast(-value)); + + TryPatchSkillBonus8("SurvivalistBonus", 25, 0x496FAB, perksFile); + TryPatchSkillBonus8("MrFixitBonus", 10, 0x496E00, perksFile); + TryPatchSkillBonus32("MedicFirstAidBonus", 10, 0x496E19, perksFile); + TryPatchSkillBonus32("MedicDoctorBonus", 10, 0x496E4E, perksFile); + TryPatchSkillBonus8("MasterThiefBonus", 15, 0x496EE0, perksFile); + TryPatchSkillBonus32("SpeakerBonus", 20, 0x496F1B, perksFile); + TryPatchSkillBonus32("GhostBonus", 20, 0x496EA9, perksFile); + TryPatchSkillBonus32("RangerOutdoorsmanBonus", 15, 0x496F95, perksFile); + TryPatchValue8("CautiousNatureBonus", 3, -12, 20, 0x4C1756, perksFile); // -12 - force distance to 0 + TryPatchSkillBonus32("GamblerBonus", 20, 0x496F79, perksFile); + TryPatchSkillBonus8("HarmlessBonus", 20, 0x496F02, perksFile); + TryPatchSkillBonus8("LivingAnatomyBonus", 5, 0x424A91, perksFile); + TryPatchSkillBonus8("LivingAnatomyDoctorBonus", 10, 0x496E66, perksFile); + TryPatchSkillBonus8("NegotiatorBonus", 10, 0x496F48, perksFile); + TryPatchSkillBonus8("PyromaniacBonus", 5, 0x424AB6, perksFile); + TryPatchValue8("StonewallPercent", 50, 0, 100, 0x424B50, perksFile); + TryPatchSkillBonus8("ThiefBonus", 10, 0x496EC1, perksFile); + TryPatchSkillBonus8("VaultCityTrainingFirstAidBonus", 5, 0x496E35, perksFile); + TryPatchSkillBonus8("VaultCityTrainingDoctorBonus", 5, 0x496E7F, perksFile); + TryPatchSkillBonus8("ExpertExcrementExpeditorBonus", 5, 0x496F33, perksFile); + + if (TryGetModifiedInt("NightVisionBonus", 20, value, perksFile) && value >= 0) { + if (value > 100) value = 100; + NightVisionBonus = (65536 * value) / 100; } if (TryGetModifiedInt("MasterTraderBonus", 25, value, perksFile) && value >= 0) { float floatValue = static_cast(value); SafeWrite32(0x474BB3, *(DWORD*)&floatValue); // write float data } - if (TryGetModifiedInt("NightVisionBonus", 20, value, perksFile) && value >= 0) { - if (value > 100) value = 100; - NightVisionBonus = (65536 * value) / 100; + if (TryGetModifiedInt("EducatedBonus", EducatedBonus, value, perksFile) && value >= 0) { + EducatedBonus = min(value, 125); + SafeWrite8(0x43CA6D, static_cast(EducatedBonus)); } - if (TryGetModifiedInt("SalesmanBonus", SalesmanBonus, value, perksFile) && value >= 0) { - SalesmanBonus = min(value, 999); + if (TryGetModifiedInt("HealerMinBonus", HealerMinBonus, value, perksFile) && value >= 0) { + HealerMinBonus = min(value, 999); } - TryPatchSkillBonus8("LivingAnatomyBonus", 5, 0x424A91, perksFile); - TryPatchSkillBonus8("LivingAnatomyDoctorBonus", 10, 0x496E66, perksFile); - TryPatchSkillBonus8("PyromaniacBonus", 5, 0x424AB6, perksFile); - TryPatchValue8("StonewallPercent", 50, 0, 100, 0x424B50, perksFile); - TryPatchValue8("CautiousNatureBonus", 3, -12, 20, 0x4C1756, perksFile); // -12 - force distance to 0 - if (TryGetModifiedInt("ComprehensionBonus", 50, value, perksFile) && value >= 0) { - ComprehensionBonus = value + 100; + if (TryGetModifiedInt("HealerMaxBonus", HealerMaxBonus, value, perksFile) && value >= 0) { + HealerMaxBonus = min(value, 999); } - if (TryGetModifiedInt("DemolitionExpertBonus", DemolitionExpertBonus, value, perksFile) && value >= 0) { - DemolitionExpertBonus = min(value, 999); + if (TryGetModifiedInt("LifegiverBonus", LifegiverBonus, value, perksFile) && value >= 0) { + LifegiverBonus = min(value, 125); + const DWORD lifegiverBonusAddr[] = {0x43CA2C, 0x43CA3D}; + SafeWriteBatch(static_cast(LifegiverBonus), lifegiverBonusAddr); } if (TryGetModifiedInt("VaultCityInoculationsPoisonBonus", 10, value, perksFile)) { SafeWrite8(0x4AF26A, static_cast(clamp(value, -100, 100))); @@ -144,22 +195,20 @@ void ReadPerksBonuses(const char* perksFile) { if (TryGetModifiedInt("VaultCityInoculationsRadBonus", 10, value, perksFile)) { SafeWrite8(0x4AF287, static_cast(clamp(value, -100, 100))); } - TryPatchSkillBonus8("VaultCityTrainingFirstAidBonus", 5, 0x496E35, perksFile); - TryPatchSkillBonus8("VaultCityTrainingDoctorBonus", 5, 0x496E7F, perksFile); - TryPatchSkillBonus32("MedicFirstAidBonus", 10, 0x496E19, perksFile); - TryPatchSkillBonus32("MedicDoctorBonus", 10, 0x496E4E, perksFile); - - TryPatchSkillBonus32("GhostBonus", 20, 0x496EA9, perksFile); - TryPatchSkillBonus8("ThiefBonus", 10, 0x496EC1, perksFile); - TryPatchSkillBonus8("MasterThiefBonus", 15, 0x496EE0, perksFile); - TryPatchSkillBonus8("HarmlessBonus", 20, 0x496F02, perksFile); - TryPatchSkillBonus32("SpeakerBonus", 20, 0x496F1B, perksFile); - TryPatchSkillBonus8("ExpertExcrementExpeditorBonus", 5, 0x496F33, perksFile); - TryPatchSkillBonus8("NegotiatorBonus", 10, 0x496F48, perksFile); - TryPatchSkillBonus32("GamblerBonus", 20, 0x496F79, perksFile); - TryPatchSkillBonus32("RangerOutdoorsmanBonus", 15, 0x496F95, perksFile); - TryPatchSkillBonus8("SurvivalistBonus", 25, 0x496FAB, perksFile); - TryPatchSkillBonus8("MrFixitBonus", 10, 0x496E00, perksFile); + if (TryGetModifiedInt("ComprehensionBonus", 50, value, perksFile) && value >= 0) { + ComprehensionBonus = value + 100; + } + if (TryGetModifiedInt("DemolitionExpertBonus", DemolitionExpertBonus, value, perksFile) && value >= 0) { + DemolitionExpertBonus = min(value, 999); + } + if (TryGetModifiedInt("SalesmanBonus", SalesmanBonus, value, perksFile) && value >= 0) { + SalesmanBonus = min(value, 999); + } + if (TryGetModifiedInt("WeaponHandlingBonus", 3, value, perksFile) && value >= 0) { + if (value > 10) value = 10; + SafeWrite8(0x424636, static_cast(value)); + SafeWrite8(0x4251CE, static_cast(-value)); + } } }