diff --git a/artifacts/example_mods/AutoCloseBox/gl_auto_closebox.int b/artifacts/example_mods/AutoCloseBox/gl_auto_closebox.int index 64aa7da2..96d5499a 100644 Binary files a/artifacts/example_mods/AutoCloseBox/gl_auto_closebox.int and b/artifacts/example_mods/AutoCloseBox/gl_auto_closebox.int differ diff --git a/artifacts/example_mods/AutoCloseBox/gl_auto_closebox.ssl b/artifacts/example_mods/AutoCloseBox/gl_auto_closebox.ssl index b69213d6..0c6f9e23 100644 --- a/artifacts/example_mods/AutoCloseBox/gl_auto_closebox.ssl +++ b/artifacts/example_mods/AutoCloseBox/gl_auto_closebox.ssl @@ -28,9 +28,10 @@ procedure start begin lootObject := loot_obj; if (obj_type(lootObject) != OBJ_TYPE_ITEM) then lootObject = 0; end else if (lootObject andAlso get_sfall_arg_at(1) == INTFACELOOT) then begin - if (get_object_data(lootObject, OBJ_DATA_CUR_FRM) > 1) then call close in 1; - closeObject = lootObject; - lootObject = 0; + if (get_object_data(lootObject, OBJ_DATA_CUR_FRM) > 1) then begin + closeObject = lootObject; + call close in 0; + end end end end diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index 1dc6b0d1..ba8b4e67 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -332,6 +332,7 @@ #define overlay_clear(winType) sfall_func2("interface_overlay", winType, 2) #define overlay_clear_rectangle(winType, x, y, w, h) sfall_func6("interface_overlay", winType, 2, x, y, w, h) #define overlay_destroy(winType) sfall_func2("interface_overlay", winType, 0) +#define proto_exists(pid) sfall_func1("proto_exists", pid) #define real_dude_obj sfall_func0("real_dude_obj") #define remove_all_timer_events sfall_func0("remove_timer_event") #define remove_timer_event(fixedParam) sfall_func1("remove_timer_event", fixedParam) diff --git a/artifacts/scripting/sfall function notes.txt b/artifacts/scripting/sfall function notes.txt index ef12cfcf..c02e7392 100644 --- a/artifacts/scripting/sfall function notes.txt +++ b/artifacts/scripting/sfall function notes.txt @@ -742,6 +742,9 @@ optional arguments: - gvarNumber: the number of the global variable controlling the quest - thresholdValue: the value of the global variable at which the quest is counted as a failure +> bool sfall_func1("proto_exists", int pid) +- returns True if the specified PID number exists in the list of registered protos + ------------------------ ------ MORE INFO ------- ------------------------ diff --git a/sfall/FalloutEngine.cpp b/sfall/FalloutEngine.cpp index 8c87fbbd..c63beca0 100644 --- a/sfall/FalloutEngine.cpp +++ b/sfall/FalloutEngine.cpp @@ -576,6 +576,14 @@ long AnimCodeByWeapon(TGameObj* weapon) { return 0; } +bool CheckProtoID(DWORD pid) { + if (pid == 0) return false; + long type = pid >> 24; + if (type > OBJ_TYPE_MISC) return false; + + return (static_cast(pid & 0xFFFF) < ptr_protoLists[type].totalCount); +} + bool GetProto(long pid, sProto** outProto) { return (fo_proto_ptr(pid, outProto) != -1); } diff --git a/sfall/FalloutEngine.h b/sfall/FalloutEngine.h index 940a1a54..ede38623 100644 --- a/sfall/FalloutEngine.h +++ b/sfall/FalloutEngine.h @@ -243,6 +243,7 @@ #define FO_VAR_procTableStrs 0x51C758 // table of procId (from define.h) => procName map #define FO_VAR_proto_main_msg_file 0x6647FC #define FO_VAR_proto_msg_files 0x6647AC +#define FO_VAR_protoLists 0x51C290 #define FO_VAR_ptable 0x59E934 #define FO_VAR_pud 0x59E960 #define FO_VAR_quest_count 0x51C12C @@ -522,6 +523,8 @@ Queue* QueueFind(TGameObj* object, long type); // returns weapon animation code long AnimCodeByWeapon(TGameObj* weapon); +bool CheckProtoID(DWORD pid); + // returns False if the prototype does not exist, or pointer to prototype by PID in the outProto argument bool GetProto(long pid, sProto** outProto); diff --git a/sfall/FalloutFuncOffs_def.h b/sfall/FalloutFuncOffs_def.h index 09759cc0..ecc10ba0 100644 --- a/sfall/FalloutFuncOffs_def.h +++ b/sfall/FalloutFuncOffs_def.h @@ -476,6 +476,7 @@ FUNC(protinst_use_item_on_, 0x49C3CC) FUNC(proto_dude_init_, 0x49FA64) FUNC(proto_dude_update_gender_, 0x49F984) FUNC(proto_list_str_, 0x49E758) +FUNC(proto_make_path_, 0x49E270) FUNC(proto_ptr_, 0x4A2108) // eax - PID, edx - int** - pointer to a pointer to a proto struct FUNC(pushLongStack_, 0x46736C) FUNC(qsort_, 0x4F05B6) diff --git a/sfall/FalloutFuncs_def.h b/sfall/FalloutFuncs_def.h index e270461d..9d015c20 100644 --- a/sfall/FalloutFuncs_def.h +++ b/sfall/FalloutFuncs_def.h @@ -168,6 +168,7 @@ WRAP_WATCOM_FUNC2(long, perk_level, TGameObj*, critter, long, perkId) WRAP_WATCOM_FUNC6(long, pick_death, TGameObj*, attacker, TGameObj*, target, TGameObj*, weapon, long, amount, long, anim, long, hitFromBack) WRAP_WATCOM_FUNC0(void, process_bk) WRAP_WATCOM_FUNC0(void, proto_dude_update_gender) +WRAP_WATCOM_FUNC2(void, proto_make_path, char*, buffer, long, pid) // Places pointer to a prototype structure into ptrPtr and returns 0 on success or -1 on failure WRAP_WATCOM_FUNC2(long, proto_ptr, long, pid, sProto**, ptrPtr) WRAP_WATCOM_FUNC2(void, queue_clear_type, long, qType, void*, func) // removes all events of the given type and performs func before removal diff --git a/sfall/FalloutStructs.h b/sfall/FalloutStructs.h index c832fe08..223dfd2b 100644 --- a/sfall/FalloutStructs.h +++ b/sfall/FalloutStructs.h @@ -593,6 +593,19 @@ struct PremadeChar { char unknown[20]; }; +struct ProtoListBlock { + long* protoMem[16]; + long count; + ProtoListBlock* next; +}; + +struct ProtoList { + ProtoListBlock* block; + ProtoListBlock* lastBlock; + long countBlocks; // current + long totalCount; // total number of prototypes for this type +}; + // In-memory PROTO structure, not the same as PRO file format. struct sProto { struct Tile { diff --git a/sfall/FalloutVars_def.h b/sfall/FalloutVars_def.h index 15f458b0..47508a23 100644 --- a/sfall/FalloutVars_def.h +++ b/sfall/FalloutVars_def.h @@ -166,6 +166,7 @@ PTR_(preload_list_index, DWORD) PTR_(procTableStrs, const char*) // table of procId (from define.h) => procName map PTR_(proto_main_msg_file, MSGList) PTR_(proto_msg_files, MSGList) // array of 6 elements +PTR_(protoLists, ProtoList) // array of 11 elements PTR_(ptable, DWORD) PTR_(pud, DWORD) PTR_(queue, Queue*) diff --git a/sfall/ScriptOps/MetaruleOps.hpp b/sfall/ScriptOps/MetaruleOps.hpp index cb409101..398bbb88 100644 --- a/sfall/ScriptOps/MetaruleOps.hpp +++ b/sfall/ScriptOps/MetaruleOps.hpp @@ -164,6 +164,7 @@ static const SfallMetarule metaruleArray[] = { {"obj_under_cursor", mf_obj_under_cursor, 2, 2}, {"objects_in_radius", mf_objects_in_radius, 3, 4}, {"outlined_object", mf_outlined_object, 0, 0}, + {"proto_exists", mf_proto_exists, 1, 1}, {"real_dude_obj", mf_real_dude_obj, 0, 0}, {"remove_timer_event", mf_remove_timer_event, 0, 1}, {"set_car_intface_art", mf_set_car_intface_art, 1, 1}, diff --git a/sfall/ScriptOps/ObjectsOps.hpp b/sfall/ScriptOps/ObjectsOps.hpp index 39134699..fe50226d 100644 --- a/sfall/ScriptOps/ObjectsOps.hpp +++ b/sfall/ScriptOps/ObjectsOps.hpp @@ -596,6 +596,17 @@ static void mf_get_loot_object() { opHandler.setReturn((GetLoopFlags() & INTFACELOOT) ? ptr_target_stack[*ptr_target_curr_stack] : 0); } +static void mf_proto_exists() { + const ScriptValue &pidArg = opHandler.arg(0); + + if (pidArg.isInt()) { + opHandler.setReturn(CheckProtoID(pidArg.rawValue())); + } else { + OpcodeInvalidArgs("proto_exists"); + opHandler.setReturn(0); + } +} + static bool protoMaxLimitPatch = false; static void __stdcall op_get_proto_data2() {