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)
This commit is contained in:
NovaRain
2026-05-25 14:42:38 +08:00
parent d74ec5f4fa
commit 17383dbd64
3 changed files with 18 additions and 9 deletions
+8 -2
View File
@@ -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 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; fo::ScriptInstance* script;
if (fo::func::scr_ptr(obj->scriptId, &script) != -1) { if (fo::func::scr_ptr(obj->scriptId, &script) != -1) {
script->ownerObjectId = obj->id; script->ownerObjectId = obj->id;
@@ -74,8 +74,11 @@ void Objects::SetNewEngineID(fo::GameObject* obj) {
} }
static __declspec(naked) void item_identical_hack() { static __declspec(naked) void item_identical_hack() {
static const DWORD item_identical_End = 0x477AD5;
using namespace fo::Fields; using namespace fo::Fields;
__asm { __asm {
cmp esi, edi; // inv_item == place_item? (safeguard)
je identical;
mov ecx, [edi]; // place_item id mov ecx, [edi]; // place_item id
cmp ecx, Start; // start unique ID cmp ecx, Start; // start unique ID
jg notIdentical; jg notIdentical;
@@ -87,6 +90,9 @@ static __declspec(naked) void item_identical_hack() {
cmp eax, ebx; cmp eax, ebx;
notIdentical: notIdentical:
retn; // if ZF == 0 then item is not identical 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->IsCritter()) {
if (obj->id < fo::PLAYER_ID) { if (obj->id < fo::PLAYER_ID) {
obj->id = npcStartID++; obj->id = npcStartID++;
SetScriptObjectID(obj); Objects::SetScriptObjectID(obj);
} }
Stats::UpdateHPStat(obj); Stats::UpdateHPStat(obj);
} }
+1
View File
@@ -36,6 +36,7 @@ public:
static long uniqueID; static long uniqueID;
static bool IsUniqueID(long id); static bool IsUniqueID(long id);
static void SetScriptObjectID(fo::GameObject* obj);
static long __fastcall SetObjectUniqueID(fo::GameObject* obj); static long __fastcall SetObjectUniqueID(fo::GameObject* obj);
static long __fastcall SetSpecialID(fo::GameObject* obj); static long __fastcall SetSpecialID(fo::GameObject* obj);
+9 -7
View File
@@ -584,14 +584,16 @@ void mf_set_drugs_data(OpcodeContext& ctx) {
void mf_set_unique_id(OpcodeContext& ctx) { void mf_set_unique_id(OpcodeContext& ctx) {
fo::GameObject* obj = ctx.arg(0).object(); fo::GameObject* obj = ctx.arg(0).object();
long id; if (ctx.numArgs() > 1 && ctx.arg(1).rawValue() == -1) {
if (ctx.arg(1).rawValue() == -1) { // unassign unique ID only if the object currently has one
id = fo::func::new_obj_id(); if (obj->id > UniqueID::Start) {
obj->id = id; obj->id = fo::func::new_obj_id();
} else { Objects::SetScriptObjectID(obj);
id = Objects::SetObjectUniqueID(obj);
} }
ctx.setReturn(id); ctx.setReturn(obj->id);
return;
}
ctx.setReturn(Objects::SetObjectUniqueID(obj));
} }
void mf_objects_in_radius(OpcodeContext& ctx) { void mf_objects_in_radius(OpcodeContext& ctx) {