From dfd810c9e4893d6c5174d7f6a96471d1a89c4417 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Sun, 29 Aug 2021 10:20:01 +0800 Subject: [PATCH] Fixed the Jet addiction was not removed when using the antidote (#405) (BGforgeNet/Fallout2_Restoration_Project#118) --- sfall/FalloutEngine/EngineUtils.cpp | 4 +- sfall/FalloutEngine/Structs.h | 8 ++-- sfall/Modules/BugFixes.cpp | 60 +++++++++++++++++++---------- sfall/Modules/Drugs.cpp | 4 +- 4 files changed, 48 insertions(+), 28 deletions(-) diff --git a/sfall/FalloutEngine/EngineUtils.cpp b/sfall/FalloutEngine/EngineUtils.cpp index fb95f765..40bc92a0 100644 --- a/sfall/FalloutEngine/EngineUtils.cpp +++ b/sfall/FalloutEngine/EngineUtils.cpp @@ -212,10 +212,10 @@ long CheckAddictByPid(fo::GameObject* critter, long pid) { // Checks whether the player is under the influence of negative effects of radiation long __fastcall IsRadInfluence() { - fo::QueueRadiation* queue = (fo::QueueRadiation*)fo::func::queue_find_first(fo::var::obj_dude, fo::radiation_event); + fo::QueueRadiationData* queue = (fo::QueueRadiationData*)fo::func::queue_find_first(fo::var::obj_dude, fo::radiation_event); while (queue) { if (queue->init && queue->level >= 2) return 1; - queue = (fo::QueueRadiation*)fo::func::queue_find_next(fo::var::obj_dude, fo::radiation_event); + queue = (fo::QueueRadiationData*)fo::func::queue_find_next(fo::var::obj_dude, fo::radiation_event); } return 0; } diff --git a/sfall/FalloutEngine/Structs.h b/sfall/FalloutEngine/Structs.h index c2815ff7..453a7b85 100644 --- a/sfall/FalloutEngine/Structs.h +++ b/sfall/FalloutEngine/Structs.h @@ -993,12 +993,12 @@ struct Queue { Queue* next; }; -struct QueueRadiation { +struct QueueRadiationData { long level; long init; // 1 - for removing effect }; -struct QueueDrug { +struct QueueDrugData { DWORD pid; fo::Stat stat0; fo::Stat stat1; @@ -1008,8 +1008,8 @@ struct QueueDrug { long amount2; }; -struct QueueAddict { - long init; // 1 - perk is not active yet +struct QueueAddictData { + long wait; // 1 - waiting for applying the addiction effects (perk is not active yet) DWORD drugPid; fo::Perk perkId; // effect of addiction }; diff --git a/sfall/Modules/BugFixes.cpp b/sfall/Modules/BugFixes.cpp index 1ac3c631..6014d0b4 100644 --- a/sfall/Modules/BugFixes.cpp +++ b/sfall/Modules/BugFixes.cpp @@ -264,29 +264,49 @@ skip: } } -static void __declspec(naked) item_d_check_addict_hack() { // replace engine function +static void __declspec(naked) item_wd_process_hack() { __asm { - push 0x47A6A1; // return addr - mov edx, 2; // type = addiction + cmp esi, PERK_add_jet; // esi - queue_addict.perk + je jetAddict; + retn; +jetAddict: + push ecx; + xor edx, edx; // init (0 - effects of addiction have already been applied) + mov eax, ecx; // critter (any party members or dude) + push [ebx + 0x4]; // queue_addict.drugPid (PID_JET) + mov ebx, 10080; // time (7 days) + mov ecx, esi; // addict perk (PERK_add_jet) + call fo::funcoffs::insert_withdrawal_; + pop ecx; + mov [esp], 0x47A3FB; // return addr + retn; + } +} + +// replaces the item_d_check_addict_ function in item_d_take_drug_ with an alternative implementation +static void __declspec(naked) item_d_take_drug_hook() { // eax - pid, esi - critter + __asm { + mov edx, addict_event; // type = addiction cmp eax, -1; // Has drug_pid? jne skip; // No mov eax, dword ptr ds:[FO_VAR_obj_dude]; - jmp fo::funcoffs::queue_find_first_; // return player addiction + jmp fo::funcoffs::queue_find_first_; // return queue of player addiction skip: mov ebx, eax; // ebx = drug_pid mov eax, esi; // eax = who call fo::funcoffs::queue_find_first_; -loopQueue: test eax, eax; // Has something in the list? jz end; // No +loopQueue: cmp ebx, dword ptr [eax + 0x4]; // drug_pid == queue_addict.drug_pid? je end; // Has specific addiction mov eax, esi; // eax = who - mov edx, 2; // type = addiction + mov edx, addict_event; // type = addiction call fo::funcoffs::queue_find_next_; - jmp loopQueue; + test eax, eax; // Has something in the list? + jnz loopQueue; end: - retn; + retn; // return null or pointer to queue_addict } } @@ -304,18 +324,15 @@ end: static void __declspec(naked) item_d_take_drug_hack() { __asm { - cmp dword ptr [eax], 0; // queue_addict.init + cmp dword ptr [eax], 0; // queue_addict.wait (queue returned from item_d_take_drug_hook) jne skip; // Addiction is not active yet - mov edx, PERK_add_jet; mov eax, esi; call fo::funcoffs::perform_withdrawal_end_; -skip: +skip: // remove event from queue mov dword ptr ds:[FO_VAR_wd_obj], esi; - mov eax, 2; // type = addiction + mov eax, addict_event; // type = addiction mov edx, offset RemoveJetAddictFunc; - call fo::funcoffs::queue_clear_type_; - push 0x479FD1; - retn; + jmp fo::funcoffs::queue_clear_type_; } } @@ -535,7 +552,7 @@ loopAddict: call fo::funcoffs::item_d_check_addict_; test eax, eax; // Has addiction? jz noAddict; // No - cmp dword ptr [eax], 0; // queue_addict.init + cmp dword ptr [eax], 0; // queue_addict.wait jne noAddict; // Addiction is not active yet mov edx, dword ptr [eax + 0x8]; // queue_addict.perk mov eax, ebx; @@ -3326,16 +3343,19 @@ void BugFixes::init() //if (IniReader::GetConfigInt("Misc", "JetAntidoteFix", 1)) { dlog("Applying Jet Antidote fix.", DL_FIX); - // the original jet antidote fix - MakeJump(0x47A013, (void*)0x47A168); + // Fix for Jet antidote not being removed after removing the addiction effect (when using the item) + MakeJump(0x47A013, (void*)0x47A168); // item_d_take_drug_ dlogr(" Done", DL_FIX); //} //if (IniReader::GetConfigInt("Misc", "NPCDrugAddictionFix", 1)) { dlog("Applying NPC's drug addiction fix.", DL_FIX); // proper checks for NPC's addiction instead of always using global vars - MakeJump(0x47A644, item_d_check_addict_hack); - MakeJump(0x479FC5, item_d_take_drug_hack); + HookCalls(item_d_take_drug_hook, {0x479FBC, 0x47A0AE}); + MakeCall(0x479FCA, item_d_take_drug_hack, 2); + // just add a new "addict" event every 7 days (the previous one is deleted) until the Jet addiction is removed by the antidote + // Note: for critters who are not party members, any addiction is removed after leaving the map + MakeCall(0x47A3A4, item_wd_process_hack); dlogr(" Done", DL_FIX); //} diff --git a/sfall/Modules/Drugs.cpp b/sfall/Modules/Drugs.cpp index 49b3193d..5ae956e6 100644 --- a/sfall/Modules/Drugs.cpp +++ b/sfall/Modules/Drugs.cpp @@ -68,11 +68,11 @@ static long __fastcall AllowUseDrug(fo::GameObject* critter, DWORD pid) { if (drugs[i].drugPid == pid) { if (drugs[i].numEffects == -1) break; // use NumEffects value from engine if (drugs[i].numEffects == 0) return 1; - auto queue = (fo::QueueDrug*)fo::func::queue_find_first(critter, 0); + auto queue = (fo::QueueDrugData*)fo::func::queue_find_first(critter, 0); if (!queue) return 1; int num = 0; while (queue->pid != pid || ++num < drugs[i].numEffects) { - queue = (fo::QueueDrug*)fo::func::queue_find_next(critter, 0); + queue = (fo::QueueDrugData*)fo::func::queue_find_next(critter, 0); if (!queue) return 1; } return 0; // not allow