From 428cf42c7d3f528b0854ba2f00da8464482c1aed Mon Sep 17 00:00:00 2001 From: NovaRain Date: Tue, 31 Aug 2021 12:35:47 +0800 Subject: [PATCH] Added an additional '"Can't Use" flag to misc flags in item objects * it makes the weapon object unusable in combat. Edits to header files. --- artifacts/scripting/headers/define_extra.h | 8 +- artifacts/scripting/headers/sfall.h | 33 +++++--- sfall/FalloutEngine/Enums.h | 96 +++++++++++++--------- sfall/FalloutEngine/Structs.h | 14 +++- sfall/Modules/Inventory.cpp | 24 ++++++ 5 files changed, 116 insertions(+), 59 deletions(-) diff --git a/artifacts/scripting/headers/define_extra.h b/artifacts/scripting/headers/define_extra.h index c4672a94..841744db 100644 --- a/artifacts/scripting/headers/define_extra.h +++ b/artifacts/scripting/headers/define_extra.h @@ -141,8 +141,8 @@ #define RMOBJ_THROW 4266040 // (action_ranged_) #define RMOBJ_SUB_CONTAINER 4683191 // search and remove the item from nested containers in the inventory (item_remove_mult_) #define RMOBJ_AI_USE_DRUG_ON 4359920 // remove before AI uses the drug in combat (ai_check_drugs_) -//#define RMOBJ_AI_USE_DRUG_ON_1 4359639 // same as RMOBJ_AI_USE_DRUG_ON (obsolete, use only for sfall before 4.3.1) -//#define RMOBJ_AI_USE_DRUG_ON_2 4360176 // same as RMOBJ_AI_USE_DRUG_ON (obsolete, use only for sfall before 4.3.1) +//#define RMOBJ_AI_USE_DRUG_ON_1 4359639 // same as RMOBJ_AI_USE_DRUG_ON (obsolete, use only for sfall before 4.3.1/3.8.31) +//#define RMOBJ_AI_USE_DRUG_ON_2 4360176 // same as RMOBJ_AI_USE_DRUG_ON (obsolete, use only for sfall before 4.3.1/3.8.31) // common prototype offsets for get/set_proto_data #define PROTO_PID (1) @@ -406,9 +406,11 @@ #define OBJ_DATA_CUR_FRM (0x18) // current frame number #define OBJ_DATA_ROTATION (0x1C) #define OBJ_DATA_FID (0x20) +//#define OBJ_DATA_FLAGS (0x24) // the same flags set in prototypes (PROTO_FLAG) #define OBJ_DATA_ELEVATION (0x28) +#define OBJ_DATA_MISC_FLAGS (0x38) #define OBJ_DATA_PID (0x64) -#define OBJ_DATA_CID (0x68) // combat ID, used for savegame +#define OBJ_DATA_CID (0x68) // combat ID, used by critters in savegame (don't change while in combat) #define OBJ_DATA_SID (0x78) // script ID #define OBJ_DATA_SCRIPT_INDEX (0x80) // script index number in scripts.lst // items diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index 16d4bd22..9acc5d4e 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -1,7 +1,7 @@ #ifndef SFALL_H #define SFALL_H -//Recognised modes for set_shader_mode and get_game_mode +// Recognised modes for set_shader_mode and get_game_mode #define WORLDMAP (0x1) #define DIALOG (0x4) #define ESCMENU (0x8) @@ -24,7 +24,7 @@ #define COUNTERWIN (0x100000) // counter window for moving multiple items or setting a timer #define SPECIAL (0x80000000) -//Valid arguments to register_hook +// Valid arguments to register_hook #define HOOK_TOHIT (0) #define HOOK_AFTERHITROLL (1) #define HOOK_CALCAPCOST (2) @@ -75,7 +75,7 @@ #define HOOK_BESTWEAPON (47) #define HOOK_CANUSEWEAPON (48) -//Valid arguments to list_begin +// Valid arguments to list_begin #define LIST_CRITTERS (0) #define LIST_GROUNDITEMS (1) #define LIST_SCENERY (2) @@ -85,7 +85,7 @@ #define LIST_SPATIAL (6) #define LIST_ALL (9) -//Valid window types for get_window_attribute +// Valid window types for get_window_attribute #define WINTYPE_INVENTORY (0) // any inventory window (player/loot/use/barter) #define WINTYPE_DIALOG (1) #define WINTYPE_PIPBOY (2) @@ -96,14 +96,14 @@ #define WINTYPE_ESCMENU (7) // escape menu #define WINTYPE_AUTOMAP (8) -//Valid flags for force_encounter_with_flags +// Valid flags for force_encounter_with_flags #define ENCOUNTER_FLAG_NO_CAR (0x1) #define ENCOUNTER_FLAG_LOCK (0x2) // block new forced encounter by the next function call until the current specified encounter occurs #define ENCOUNTER_FLAG_NO_ICON (0x4) // disable displaying the flashing icon #define ENCOUNTER_FLAG_ICON_SP (0x8) // use special encounter icon #define ENCOUNTER_FLAG_FADEOUT (0x10) // fade out the screen on encounter (Note: you yourself should restore the fade screen when entering the encounter) -//The attack types returned by get_attack_type +// The attack types returned by get_attack_type #define ATKTYPE_LWEP1 (0) #define ATKTYPE_LWEP2 (1) #define ATKTYPE_RWEP1 (2) @@ -125,18 +125,18 @@ #define ATKTYPE_HOOKKICK (18) #define ATKTYPE_PIERCINGKICK (19) -//Some possible values for the 4th argument to hs_removeinvobj +// Some possible values for the 4th argument to hs_removeinvobj #define RMOBJ_DROP (0x49B875) // If the object is dropped manually by the player from the inventory screen #define RMOBJ_TRADE (0x47761D) // If the object is offered up as a trade #define RMOBJ_DROPMULTI (0x45C1CF) // When dropping a part of a stack (RMOBJ_DROP occurs first) -//Return values for "typeof" +// Return values for "typeof" #define VALTYPE_NONE (0) // not used yet #define VALTYPE_INT (1) #define VALTYPE_FLOAT (2) #define VALTYPE_STR (3) -//Arrays defines +/* ARRAYS FUNCTION DEFINES */ // create persistent list #define create_array_list(size) (create_array(size, 0)) @@ -232,7 +232,7 @@ #define CURSOR_COMMAND (1) #define CURSOR_TARGETING (2) -//Valid flags for set_rest_mode +// Valid flags for set_rest_mode #define RESTMODE_DISABLED (1) // disable resting on all maps #define RESTMODE_STRICT (2) // disable resting on maps with "can_rest_here=No" in Maps.txt, even if there are no other critters #define RESTMODE_NO_HEALING (4) // disable healing during resting @@ -272,6 +272,9 @@ #define ADD_PERK_MODE_PERK (2) // add to the player's perks list #define ADD_PERK_MODE_REMOVE (4) // remove from the list of selectable perks (after added to the player) + +/* MISC FUNCTION MACROS */ + // instantly apply the item to dude_obj (w/o animation) #define use_item_on_dude(item) set_self(dude_obj); \ set_self(dude_obj); \ @@ -286,8 +289,13 @@ // checks if the specified PID number exists in the list of registered protos #define check_pid(pid) (get_proto_data(pid, 0) != -1) +// sets the status of a broken weapon that cannot be used in combat (the hand slot will not be available for use) +#define set_broken_weapon_state_on(item) set_object_data(item, OBJ_DATA_MISC_FLAGS, get_object_data(item, OBJ_DATA_MISC_FLAGS) bwor 0x00000010) +#define set_broken_weapon_state_off(item) set_object_data(item, OBJ_DATA_MISC_FLAGS, get_object_data(item, OBJ_DATA_MISC_FLAGS) bwand 0xFFFFFFEF) + + +/* SFALL_FUNCX MACROS */ -/* sfall_funcX macros */ #define add_extra_msg_file(name) sfall_func1("add_extra_msg_file", name) #define add_global_timer_event(time, fixedParam) sfall_func2("add_g_timer_event", time, fixedParam) #define add_iface_tag sfall_func0("add_iface_tag") @@ -402,7 +410,8 @@ #define set_selectable_perk_npc(npc, perk, active, image, desc) sfall_func5("set_selectable_perk_npc", npc, perk, active, image, desc) -/* sfall metarule3 function macros */ +/* SFALL METARULE3 FUNCTION MACROS */ + // sets the number of days (range 1...127) for the Frank Horrigan encounter, or disable the encounter if days is set to 0 #define set_horrigan_days(day) metarule3(200, day, 0, 0) // clears the keyboard input buffer, use it in the HOOK_KEYPRESS hook to clear keyboard events before calling functions that are waiting for keyboard input diff --git a/sfall/FalloutEngine/Enums.h b/sfall/FalloutEngine/Enums.h index 1417b04e..3c7d81dc 100644 --- a/sfall/FalloutEngine/Enums.h +++ b/sfall/FalloutEngine/Enums.h @@ -113,10 +113,10 @@ enum BodyPart : long { enum CritterFlags : long { - Sneak = 0x01, // Can sneak ? + Sneak = 0x01, // Can sneak ? (unused) Barter = 0x02, // Can trade with - Level = 0x04, // Level received ? - Addict = 0x08, // Drug addiction ? + Level = 0x04, // Level received ? (unused) + Addict = 0x08, // Drug addiction ? (unused) NoSteal = 0x20, // Can't be stolen from NoDrop = 0x40, // Doesn't drop items NoLimbs = 0x80, // Can't lose limbs @@ -129,7 +129,7 @@ enum CritterFlags : long NoKnockBack = 0x4000, // Can't be knocked back }; -enum ItemFlags : long +enum ItemFlags : unsigned long // for FlagsExt { // Weapon Flags: BigGun = 0x00000100, @@ -143,6 +143,14 @@ enum ItemFlags : long HiddenItem = 0x08000000 // item is hidden }; +enum MiscFlags : unsigned long +{ + Opened = 0x00000001, + CantUse = 0x00000010, // determines whether the weapon can be used in combat (sfall flag) + Locked = 0x02000000, + Jammed = 0x04000000, +}; + enum DamageFlag : unsigned long { DAM_KNOCKED_OUT = 0x1, @@ -238,10 +246,10 @@ namespace ObjectFlag { Flat = 0x00000008, NoBlock = 0x00000010, Lighting = 0x00000020, - Temp = 0x00000400, + Temp = 0x00000400, // ??? MultiHex = 0x00000800, NoHighlight = 0x00001000, - Used = 0x00002000, + Used = 0x00002000, // set if there was/is any event for the object TransRed = 0x00004000, TransNone = 0x00008000, TransWall = 0x00010000, @@ -251,7 +259,7 @@ namespace ObjectFlag { Left_Hand = 0x01000000, Right_Hand = 0x02000000, Worn = 0x04000000, - HiddenItem = 0x08000000, + Unused = 0x08000000, // reserved WallTransEnd = 0x10000000, LightThru = 0x20000000, Seen = 0x40000000, @@ -789,49 +797,55 @@ enum CombatStateFlag : long namespace Fields { enum CommonObj : long { - id = 0x00, - tile = 0x04, - x = 0x08, - y = 0x0C, - sx = 0x10, - sy = 0x14, - frm = 0x18, - rotation = 0x1C, - artFid = 0x20, - flags = 0x24, - elevation = 0x28, - inventory = 0x2C, + id = 0x00, // saveable + tile = 0x04, // saveable + x = 0x08, // saveable + y = 0x0C, // saveable + sx = 0x10, // saveable + sy = 0x14, // saveable + frm = 0x18, // saveable + rotation = 0x1C, // saveable + artFid = 0x20, // saveable + flags = 0x24, // saveable + elevation = 0x28, // saveable + inventory = 0x2C, // saveable - protoId = 0x64, - cid = 0x68, // combatID, don't change while in combat - lightDistance = 0x6C, - lightIntensity = 0x70, - outline = 0x74, - scriptId = 0x78, + protoId = 0x64, // saveable + cid = 0x68, // saveable (critter CombatID, don't change while in combat) + lightDistance = 0x6C, // saveable + lightIntensity = 0x70, // saveable + outline = 0x74, // saveable + scriptId = 0x78, // saveable owner = 0x7C, - scriptIndex = 0x80, + scriptIndex = 0x80, // saveable }; enum CritterObj : long { - reaction = 0x38, - combatState = 0x3C, - movePoints = 0x40, - damageFlags = 0x44, - damageLastTurn = 0x48, - aiPacket = 0x4C, - teamNum = 0x50, - whoHitMe = 0x54, - health = 0x58, - rads = 0x5C, - poison = 0x60, + reaction = 0x38, // saveable + combatState = 0x3C, // saveable + movePoints = 0x40, // saveable + damageFlags = 0x44, // saveable + damageLastTurn = 0x48, // saveable + aiPacket = 0x4C, // saveable + teamNum = 0x50, // saveable + whoHitMe = 0x54, // saveable + health = 0x58, // saveable + rads = 0x5C, // saveable + poison = 0x60, // saveable }; enum ItemObj : long { - updatedFlags = 0x38, - charges = 0x3C, - ammoPid = 0x40, + miscFlags = 0x38, // saveable + charges = 0x3C, // saveable + ammoPid = 0x40, // saveable + }; + + enum SceneryObj : long + { + sceneryFlags = 0x38, // saveable + doorFlags = 0x3C, // saveable }; enum ComputeAttack : long @@ -886,7 +900,7 @@ namespace AIpref { whomever_attacking_me = 0, // attack the target that the player is attacking (only for party members) strongest = 1, // attack stronger targets (will always switch to stronger ones in combat) weakest = 2, // attack weaker targets (will always switch to weaker ones in combat) - whomever = 3, // anyone, will attack the chosen target until it dies, or until retaliation occurs (combatai_check_retalization_) + whomever = 3, // anyone, will attack the chosen target until it dies, or until retaliation occurs (combatai_check_retaliation_) closest = 4, // only attack near targets }; diff --git a/sfall/FalloutEngine/Structs.h b/sfall/FalloutEngine/Structs.h index 453a7b85..e9dfea3d 100644 --- a/sfall/FalloutEngine/Structs.h +++ b/sfall/FalloutEngine/Structs.h @@ -163,13 +163,14 @@ struct GameObject { union { struct { - long updatedFlags; + fo::MiscFlags miscFlags; // aka updated_flags // for weapons - ammo in magazine, for ammo - amount of ammo in last ammo pack long charges; // current type of ammo loaded in magazine long ammoPid; - long unused[8]; // offset 0x44 + long unused[8]; // offset 0x44 (not saved) } item; + struct { long reaction; // unused? // 1 - combat, 2 - enemies out of sight, 4 - running away @@ -216,14 +217,21 @@ struct GameObject { } } } critter; + + struct { + fo::MiscFlags sceneryFlags; // unused for scenery? (aka updated_flags) + fo::MiscFlags doorFlags; // used for doors states open/locked/jammed (aka cur_open_flags) + long unused[9]; // offset 0x40 (not saved) + } scenery; }; + DWORD protoId; // object PID long cid; // combat ID (don't change while in combat) long lightDistance; long lightIntensity; DWORD outline; long scriptId; // SID 0x0Y00XXXX: Y - type: 0=s_system, 1=s_spatial, 2=s_time, 3=s_item, 4=s_critter; XXXX - index in scripts.lst; 0xFFFFFFFF no attached script - GameObject* owner; + GameObject* owner; // not saved long scriptIndex; inline char Type() { diff --git a/sfall/Modules/Inventory.cpp b/sfall/Modules/Inventory.cpp index afed09e1..d474b0fa 100644 --- a/sfall/Modules/Inventory.cpp +++ b/sfall/Modules/Inventory.cpp @@ -595,6 +595,25 @@ static void __declspec(naked) do_move_timer_hack() { } } +static void __declspec(naked) can_use_weapon_hook() { + static const DWORD can_use_weapon_Ret = 0x477F9F; + using namespace fo; + using namespace fo::Fields; + __asm { + call fo::funcoffs::item_get_type_; + cmp eax, item_type_weapon; + je checkFlag; + retn; // eax - type +checkFlag: + test dword ptr [edx + miscFlags], CantUse; + jnz cantUse; + retn; // eax - type +cantUse: + add esp, 4; + jmp can_use_weapon_Ret; + } +} + static int invenApCost, invenApCostDef; static char invenApQPReduction; @@ -739,6 +758,11 @@ void Inventory::init() { // Note: the flag is not checked for the metarule(METARULE_INVEN_UNWIELD_WHO, x) function HookCall(0x45B0CE, op_inven_unwield_hook); // with fix to update interface slot after unwielding HookCall(0x45693C, op_wield_obj_critter_hook); + + // Add an additional "Can't Use" flag to the misc flags of item objects (offset 0x0038) + // Misc Flags: + // 0x00000010 - Can't Use (makes the weapon object unusable in combat) + HookCall(0x477F4C, can_use_weapon_hook); } void Inventory::InvokeAdjustFid(long fid) {