diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index 0be063f6..f5c86376 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -331,6 +331,7 @@ #define message_box(text) sfall_func1("message_box", text) #define metarule_exist(metaruleName) sfall_func1("metarule_exist", metaruleName) #define npc_engine_level_up(toggle) sfall_func1("npc_engine_level_up", toggle) +#define obj_is_openable(obj) sfall_func1("obj_is_openable", obj) #define obj_under_cursor(onlyCritter, includeDude) sfall_func2("obj_under_cursor", onlyCritter, includeDude) #define objects_in_radius(tile, radius, elev, type) sfall_func4("objects_in_radius", tile, radius, elev, type) #define outlined_object sfall_func0("outlined_object") diff --git a/artifacts/scripting/sfall function notes.md b/artifacts/scripting/sfall function notes.md index 8b76d5a3..6c1f80aa 100644 --- a/artifacts/scripting/sfall function notes.md +++ b/artifacts/scripting/sfall function notes.md @@ -971,6 +971,11 @@ sfall_funcX metarule functions - Passing an empty string ("") to the `name` argument or omitting it will allow the game to get the name for the object from pro_*.msg files - __NOTE:__ this function is intended for use in normal game scripts and overrides the name only once for the same object until reset +---- +#### obj_is_openable +`bool sfall_func1("obj_is_openable", object obj)` +- Returns True if the object is openable (i.e. has an opening/closing animation) + **** _See other documentation files (arrays.md, hookscripts.md) for related functions reference._ diff --git a/sfall/BugFixes.cpp b/sfall/BugFixes.cpp index 31b230a2..f6a1970f 100644 --- a/sfall/BugFixes.cpp +++ b/sfall/BugFixes.cpp @@ -3129,28 +3129,6 @@ noObject: } } -static void __declspec(naked) obj_is_open_hack() { - __asm { - je checkMaxFrames; // curr.frame == 0 - setnz al; - and eax, 0xFF; - retn; -checkMaxFrames: - push edx; - sub esp, 4; - mov eax, [eax + artFid]; - mov edx, esp; - call art_ptr_lock_; - call art_frame_max_frame_; - add esp, 4; - cmp eax, 1; - pop edx; - setle al; // 1 - is open if frames == 1 - and eax, 0xFF; - retn; - } -} - void BugFixes_OnGameLoad() { dudeIsAnimDeath = false; combat_ai_reset(); @@ -3975,7 +3953,4 @@ void BugFixes_Init() // Fix to prevent the main menu music from stopping when entering the load game screen BlockCall(0x480B25); - - // Fix the return value of obj_is_open function for containers with only one frame (e.g. shelves) - MakeJump(0x49D2E8, obj_is_open_hack, 3); } diff --git a/sfall/FalloutEngine.cpp b/sfall/FalloutEngine.cpp index a46f4c3a..6e34e0e5 100644 --- a/sfall/FalloutEngine.cpp +++ b/sfall/FalloutEngine.cpp @@ -674,6 +674,19 @@ AttackSubType GetWeaponType(DWORD weaponFlag) { return (type < 9) ? weapon_types[type] : ATKSUBTYPE_NONE; } +long ObjIsOpenable(TGameObj* object) { + long result = 0; + if (fo_obj_is_openable(object)) { + DWORD lock; + FrmHeaderData* frm = fo_art_ptr_lock(object->artFid, &lock); + if (frm) { + if (frm->numFrames > 1) result = 1; + fo_art_ptr_unlock(lock); + } + } + return result; +} + bool HeroIsFemale() { return (fo_stat_level(*ptr_obj_dude, STAT_gender) == GENDER_FEMALE); } diff --git a/sfall/FalloutEngine.h b/sfall/FalloutEngine.h index 4d7ae52b..37422f6f 100644 --- a/sfall/FalloutEngine.h +++ b/sfall/FalloutEngine.h @@ -604,6 +604,8 @@ long GetCurrentAttackMode(); AttackSubType GetWeaponType(DWORD weaponFlag); +long ObjIsOpenable(TGameObj* object); + bool HeroIsFemale(); // Checks whether the player is under the influence of negative effects of radiation diff --git a/sfall/FalloutFuncOffs_def.h b/sfall/FalloutFuncOffs_def.h index cab27875..71c2f1b0 100644 --- a/sfall/FalloutFuncOffs_def.h +++ b/sfall/FalloutFuncOffs_def.h @@ -435,6 +435,10 @@ FUNC(obj_find_next_, 0x48B41C) FUNC(obj_find_next_at_, 0x48B510) FUNC(obj_find_next_at_tile_, 0x48B608) FUNC(obj_is_a_portal_, 0x49D140) +FUNC(obj_is_lockable_, 0x49D178) +FUNC(obj_is_locked_, 0x49D1C8) +FUNC(obj_is_open_, 0x49D2E4) +FUNC(obj_is_openable_, 0x49D294) FUNC(obj_lock_is_jammed_, 0x49D410) FUNC(obj_move_to_tile_, 0x48A568) // int aObj, int aTile, int aElev FUNC(obj_new_, 0x489A84) // int aObj*, int aPid diff --git a/sfall/FalloutFuncs_def.h b/sfall/FalloutFuncs_def.h index 156b1b35..0e6f95d9 100644 --- a/sfall/FalloutFuncs_def.h +++ b/sfall/FalloutFuncs_def.h @@ -168,6 +168,7 @@ WRAP_WATCOM_FUNC0(TGameObj*, obj_find_first) WRAP_WATCOM_FUNC0(TGameObj*, obj_find_next) WRAP_WATCOM_FUNC2(TGameObj*, obj_find_first_at_tile, long, elevation, long, tileNum) WRAP_WATCOM_FUNC0(TGameObj*, obj_find_next_at_tile) +WRAP_WATCOM_FUNC1(bool, obj_is_openable, TGameObj*, object) WRAP_WATCOM_FUNC2(long, obj_pid_new, TGameObj*, object, long, pid) WRAP_WATCOM_FUNC1(long, obj_lock_is_jammed, TGameObj*, object) // Checks/unjams jammed locks WRAP_WATCOM_FUNC1(void, obj_unjam_lock, TGameObj*, object) diff --git a/sfall/ScriptOps/MetaruleOps.hpp b/sfall/ScriptOps/MetaruleOps.hpp index 5aed6b57..86c8b10a 100644 --- a/sfall/ScriptOps/MetaruleOps.hpp +++ b/sfall/ScriptOps/MetaruleOps.hpp @@ -161,6 +161,7 @@ static const SfallMetarule metaruleArray[] = { {"message_box", mf_message_box, 1, 4}, {"metarule_exist", mf_metarule_exist, 1, 1}, {"npc_engine_level_up", mf_npc_engine_level_up, 1, 1}, + {"obj_is_openable", mf_obj_is_openable, 1, 1}, {"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}, diff --git a/sfall/ScriptOps/ObjectsOps.hpp b/sfall/ScriptOps/ObjectsOps.hpp index e9fbd0b3..608ef4f2 100644 --- a/sfall/ScriptOps/ObjectsOps.hpp +++ b/sfall/ScriptOps/ObjectsOps.hpp @@ -721,3 +721,13 @@ static void mf_npc_engine_level_up() { npcEngineLevelUp = false; } } + +static void mf_obj_is_openable() { + TGameObj* object = opHandler.arg(0).asObject(); + if (object) { + opHandler.setReturn(ObjIsOpenable(object)); + } else { + OpcodeInvalidArgs("obj_is_openable"); + opHandler.setReturn(0); + } +}