diff --git a/artifacts/example_mods/AutoCloseBox/gl_auto_closebox.int b/artifacts/example_mods/AutoCloseBox/gl_auto_closebox.int index 9a7fb151..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 42e5f308..0c6f9e23 100644 --- a/artifacts/example_mods/AutoCloseBox/gl_auto_closebox.ssl +++ b/artifacts/example_mods/AutoCloseBox/gl_auto_closebox.ssl @@ -13,8 +13,10 @@ Requires sfall 4.2.2/3.8.29 or higher #include "..\headers\sfall\define_extra.h" procedure start; +procedure close; variable lootObject; +variable closeObject; procedure start begin if (game_loaded) then begin @@ -26,8 +28,14 @@ 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 obj_close(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 + +procedure close begin + obj_close(closeObject); +end diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index b596aa7b..f948c506 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -365,6 +365,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 990dacc1..294c9215 100644 --- a/artifacts/scripting/sfall function notes.txt +++ b/artifacts/scripting/sfall function notes.txt @@ -796,6 +796,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/EngineUtils.cpp b/sfall/FalloutEngine/EngineUtils.cpp index a9d08d4f..2071a615 100644 --- a/sfall/FalloutEngine/EngineUtils.cpp +++ b/sfall/FalloutEngine/EngineUtils.cpp @@ -98,6 +98,14 @@ long AnimCodeByWeapon(fo::GameObject* weapon) { return 0; } +bool CheckProtoID(DWORD pid) { + if (pid == 0) return false; + long type = pid >> 24; + if (type > fo::ObjType::OBJ_TYPE_MISC) return false; + + return (static_cast(pid & 0xFFFF) < fo::var::protoLists[type].totalCount); +} + bool GetProto(long pid, fo::Proto** outProto) { return (fo::func::proto_ptr(pid, outProto) != -1); } diff --git a/sfall/FalloutEngine/EngineUtils.h b/sfall/FalloutEngine/EngineUtils.h index a5822c82..d0ad2a51 100644 --- a/sfall/FalloutEngine/EngineUtils.h +++ b/sfall/FalloutEngine/EngineUtils.h @@ -57,6 +57,8 @@ fo::Queue* QueueFind(fo::GameObject* object, long type); // returns weapon animation code long AnimCodeByWeapon(fo::GameObject* 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, fo::Proto** outProto); diff --git a/sfall/FalloutEngine/Functions_def.h b/sfall/FalloutEngine/Functions_def.h index 7fb50e76..696c94c9 100644 --- a/sfall/FalloutEngine/Functions_def.h +++ b/sfall/FalloutEngine/Functions_def.h @@ -192,6 +192,7 @@ WRAP_WATCOM_FUNC2(long, perk_level, fo::GameObject*, critter, long, perkId) WRAP_WATCOM_FUNC6(long, pick_death, fo::GameObject*, attacker, fo::GameObject*, target, fo::GameObject*, 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, fo::Proto**, 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/FalloutEngine/Structs.h b/sfall/FalloutEngine/Structs.h index 91d4507b..c9ced4cc 100644 --- a/sfall/FalloutEngine/Structs.h +++ b/sfall/FalloutEngine/Structs.h @@ -619,6 +619,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 Proto { struct Tile { diff --git a/sfall/FalloutEngine/VariableOffsets.h b/sfall/FalloutEngine/VariableOffsets.h index 0b0b111e..4f0f5b15 100644 --- a/sfall/FalloutEngine/VariableOffsets.h +++ b/sfall/FalloutEngine/VariableOffsets.h @@ -225,6 +225,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 diff --git a/sfall/FalloutEngine/Variables_def.h b/sfall/FalloutEngine/Variables_def.h index 89ab642e..6f765749 100644 --- a/sfall/FalloutEngine/Variables_def.h +++ b/sfall/FalloutEngine/Variables_def.h @@ -175,6 +175,7 @@ VAR_(preload_list_index, DWORD) VARA(procTableStrs, const char*, (int)fo::Scripts::ScriptProc::count) // table of procId (from define.h) => procName map VAR_(proto_main_msg_file, fo::MessageList) VARA(proto_msg_files, fo::MessageList, 6) // array of 6 elements +VARA(protoLists, fo::ProtoList, 11) VAR_(ptable, DWORD) VAR_(pud, DWORD) VAR_(queue, fo::Queue*) diff --git a/sfall/Modules/Scripting/Handlers/Metarule.cpp b/sfall/Modules/Scripting/Handlers/Metarule.cpp index 513d70e5..0c517ec6 100644 --- a/sfall/Modules/Scripting/Handlers/Metarule.cpp +++ b/sfall/Modules/Scripting/Handlers/Metarule.cpp @@ -121,6 +121,7 @@ static const SfallMetarule metarules[] = { {"obj_under_cursor", mf_obj_under_cursor, 2, 2, 0, {ARG_INT, ARG_INT}}, {"objects_in_radius", mf_objects_in_radius, 3, 4, 0, {ARG_INT, ARG_INT, ARG_INT, ARG_INT}}, {"outlined_object", mf_outlined_object, 0, 0}, + {"proto_exists", mf_proto_exists, 1, 1, 0, {ARG_INT}}, {"real_dude_obj", mf_real_dude_obj, 0, 0}, {"remove_timer_event", mf_remove_timer_event, 0, 1, -1, {ARG_INT}}, {"set_can_rest_on_map", mf_set_rest_on_map, 3, 3, -1, {ARG_INT, ARG_INT, ARG_INT}}, diff --git a/sfall/Modules/Scripting/Handlers/Objects.cpp b/sfall/Modules/Scripting/Handlers/Objects.cpp index a739cae3..a554dbc4 100644 --- a/sfall/Modules/Scripting/Handlers/Objects.cpp +++ b/sfall/Modules/Scripting/Handlers/Objects.cpp @@ -446,6 +446,10 @@ void mf_get_loot_object(OpcodeContext& ctx) { ctx.setReturn((GetLoopFlags() & INTFACELOOT) ? fo::var::target_stack[fo::var::target_curr_stack] : 0); } +void mf_proto_exists(OpcodeContext& ctx) { + ctx.setReturn(fo::CheckProtoID(ctx.arg(0).rawValue())); +} + static bool protoMaxLimitPatch = false; void op_get_proto_data(OpcodeContext& ctx) { diff --git a/sfall/Modules/Scripting/Handlers/Objects.h b/sfall/Modules/Scripting/Handlers/Objects.h index ba1d8d7e..a3b43f18 100644 --- a/sfall/Modules/Scripting/Handlers/Objects.h +++ b/sfall/Modules/Scripting/Handlers/Objects.h @@ -89,6 +89,8 @@ void mf_obj_under_cursor(OpcodeContext&); void mf_get_loot_object(OpcodeContext&); +void mf_proto_exists(OpcodeContext&); + void op_get_proto_data(OpcodeContext&); void op_set_proto_data(OpcodeContext&);