From 17383dbd642decd4489b0fdaa2e8b29b4e47b61e Mon Sep 17 00:00:00 2001 From: NovaRain Date: Mon, 25 May 2026 14:42:38 +0800 Subject: [PATCH] Fixed set_unique_id script function * it unassigned unique ID even when the object doesn't have one. * it didn't sync the attached script's owner id after unassignment. Added a safeguard to prevent item_identical function returning false when comparing a unique_id item to itself. (ref. fallout2-ce/fallout2-ce#466) --- sfall/Modules/Objects.cpp | 10 ++++++++-- sfall/Modules/Objects.h | 1 + sfall/Modules/Scripting/Handlers/Objects.cpp | 16 +++++++++------- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/sfall/Modules/Objects.cpp b/sfall/Modules/Objects.cpp index 3b637231..b4e2113b 100644 --- a/sfall/Modules/Objects.cpp +++ b/sfall/Modules/Objects.cpp @@ -35,7 +35,7 @@ bool Objects::IsUniqueID(long id) { return (id > UniqueID::Start || (id >= fo::PLAYER_ID && id < 83536)); // 65535 maximum possible number of prototypes } -static void SetScriptObjectID(fo::GameObject* obj) { +void Objects::SetScriptObjectID(fo::GameObject* obj) { fo::ScriptInstance* script; if (fo::func::scr_ptr(obj->scriptId, &script) != -1) { script->ownerObjectId = obj->id; @@ -74,8 +74,11 @@ void Objects::SetNewEngineID(fo::GameObject* obj) { } static __declspec(naked) void item_identical_hack() { + static const DWORD item_identical_End = 0x477AD5; using namespace fo::Fields; __asm { + cmp esi, edi; // inv_item == place_item? (safeguard) + je identical; mov ecx, [edi]; // place_item id cmp ecx, Start; // start unique ID jg notIdentical; @@ -87,6 +90,9 @@ static __declspec(naked) void item_identical_hack() { cmp eax, ebx; notIdentical: retn; // if ZF == 0 then item is not identical +identical: + add esp, 4; + jmp item_identical_End; } } @@ -111,7 +117,7 @@ static void map_fix_critter_id() { if (obj->IsCritter()) { if (obj->id < fo::PLAYER_ID) { obj->id = npcStartID++; - SetScriptObjectID(obj); + Objects::SetScriptObjectID(obj); } Stats::UpdateHPStat(obj); } diff --git a/sfall/Modules/Objects.h b/sfall/Modules/Objects.h index fad6a348..13f26e42 100644 --- a/sfall/Modules/Objects.h +++ b/sfall/Modules/Objects.h @@ -36,6 +36,7 @@ public: static long uniqueID; static bool IsUniqueID(long id); + static void SetScriptObjectID(fo::GameObject* obj); static long __fastcall SetObjectUniqueID(fo::GameObject* obj); static long __fastcall SetSpecialID(fo::GameObject* obj); diff --git a/sfall/Modules/Scripting/Handlers/Objects.cpp b/sfall/Modules/Scripting/Handlers/Objects.cpp index 8819a8a9..fafab9d7 100644 --- a/sfall/Modules/Scripting/Handlers/Objects.cpp +++ b/sfall/Modules/Scripting/Handlers/Objects.cpp @@ -584,14 +584,16 @@ void mf_set_drugs_data(OpcodeContext& ctx) { void mf_set_unique_id(OpcodeContext& ctx) { fo::GameObject* obj = ctx.arg(0).object(); - long id; - if (ctx.arg(1).rawValue() == -1) { - id = fo::func::new_obj_id(); - obj->id = id; - } else { - id = Objects::SetObjectUniqueID(obj); + if (ctx.numArgs() > 1 && ctx.arg(1).rawValue() == -1) { + // unassign unique ID only if the object currently has one + if (obj->id > UniqueID::Start) { + obj->id = fo::func::new_obj_id(); + Objects::SetScriptObjectID(obj); + } + ctx.setReturn(obj->id); + return; } - ctx.setReturn(id); + ctx.setReturn(Objects::SetObjectUniqueID(obj)); } void mf_objects_in_radius(OpcodeContext& ctx) {