From 1b6d6179a1ad30f4aa08e763f81522297fb92d01 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Tue, 8 Oct 2019 10:53:47 +0800 Subject: [PATCH] Added "unwield_slot" script function Re-fixed obj_art_fid for player's FID (commit 50f4885) --- artifacts/scripting/headers/sfall.h | 1 + artifacts/scripting/sfall function notes.txt | 5 ++ sfall/FalloutEngine/Structs.h | 4 +- sfall/Modules/HeroAppearance.cpp | 27 ++++---- sfall/Modules/Inventory.cpp | 20 +++--- .../Modules/Scripting/Handlers/Interface.cpp | 62 +++++++++++++++++++ sfall/Modules/Scripting/Handlers/Interface.h | 2 + sfall/Modules/Scripting/Handlers/Metarule.cpp | 1 + 8 files changed, 96 insertions(+), 26 deletions(-) diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index b684946f..eb9b9316 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -313,3 +313,4 @@ #define spatial_radius(obj) sfall_func1("spatial_radius", obj) #define tile_refresh_display sfall_func0("tile_refresh_display") #define unjam_lock(obj) sfall_func1("unjam_lock", obj) +#define unwield_slot(critter, slot) sfall_func2("unwield_slot", critter, slot) diff --git a/artifacts/scripting/sfall function notes.txt b/artifacts/scripting/sfall function notes.txt index 707f3c29..648cb885 100644 --- a/artifacts/scripting/sfall function notes.txt +++ b/artifacts/scripting/sfall function notes.txt @@ -622,6 +622,11 @@ optional argument: - fileNumber: the file ID number for the message_str_game function. The available range is from 0x2000 to 0x2FFF (see ExtraGameMsgFileList setting in ddraw.ini) use fileNumber only if you want to add a message file without editing ddraw.ini or existing scripts to support the old way +> void sfall_func2("unwield_slot", object critter, int slot) +- unequips an item from the specified slot for a critter or the player +- can take off player's equipped item when the inventory is opened, or the player is in the barter screen +- slot: 0 - armor slot, 1 - right slot, 2 - left slot (see INVEN_TYPE_* in define.h) + ------------------------ ------ MORE INFO ------- ------------------------ diff --git a/sfall/FalloutEngine/Structs.h b/sfall/FalloutEngine/Structs.h index e5c3065a..e46e76d1 100644 --- a/sfall/FalloutEngine/Structs.h +++ b/sfall/FalloutEngine/Structs.h @@ -519,8 +519,8 @@ struct Proto { // for each DamageType long damageThreshold[7]; long perk; - long maleFrameNum; - long femaleFrameNum; + long maleFID; + long femaleFID; }; struct Container { diff --git a/sfall/Modules/HeroAppearance.cpp b/sfall/Modules/HeroAppearance.cpp index 0321573e..c3b559ab 100644 --- a/sfall/Modules/HeroAppearance.cpp +++ b/sfall/Modules/HeroAppearance.cpp @@ -49,7 +49,7 @@ bool raceButtons = false, styleButtons = false; int currentRaceVal = 0, currentStyleVal = 0; // holds Appearance values to restore after global reset in NewGame2 function in LoadGameHooks.cpp DWORD critterListSize = 0, critterArraySize = 0; // Critter art list size -fo::PathNode **tempPathPtr = &fo::var::paths; +fo::PathNode **heroAppPaths = &fo::var::paths; // index: 0 - only folder (w/o extension .dat), 1 - file or folder .dat fo::PathNode *heroPathPtr[2] = {nullptr, nullptr}; fo::PathNode *racePathPtr[2] = {nullptr, nullptr}; @@ -219,7 +219,7 @@ static __declspec(noinline) int _stdcall LoadHeroDat(unsigned int race, unsigned } //heroPathPtr[1]->next = nullptr; - tempPathPtr = &heroPathPtr[1 - folderIsExist]; // set path for selected appearance + heroAppPaths = &heroPathPtr[1 - folderIsExist]; // set path for selected appearance heroPathPtr[0 + heroDatIsExist]->next = &fo::var::paths[0]; // heroPathPtr[] >> foPaths if (style != 0) { @@ -253,12 +253,12 @@ static __declspec(noinline) int _stdcall LoadHeroDat(unsigned int race, unsigned static void __declspec(naked) LoadNewHeroArt() { __asm { cmp byte ptr ds:[esi], 'r'; - je isReading; + jne isNotReading; + mov ecx, heroAppPaths; + mov ecx, dword ptr ds:[ecx]; // set app path + retn; +isNotReading: mov ecx, FO_VAR_paths; - jmp setPath; -isReading: - mov ecx, tempPathPtr; -setPath: mov ecx, dword ptr ds:[ecx]; retn; } @@ -1278,10 +1278,10 @@ static void __declspec(naked) CharScrnEnd() { //////////////////////////////////////////////////////////////////////FIX FUNCTIONS////////////////////////////////////////////////////////////////// -// Adjust PC SFX acm name. Skip Underscore char at the start of PC App Name +// Adjust PC SFX acm name. Skip Underscore char at the start of PC frm file name static void __declspec(naked) FixPcSFX() { __asm { - cmp byte ptr ds:[ebx], 0x5F; // check if Name begins with an '_' character + cmp byte ptr ds:[ebx], '_'; // check if Name begins with an 0x5F character jne endFunc; inc ebx; // shift address to next char endFunc: @@ -1325,11 +1325,10 @@ static void __declspec(naked) op_obj_art_fid_hack() { using namespace Fields; __asm { mov esi, [edi + artFid]; - push ecx; - call PartyControl::RealDudeObject; - pop ecx; - cmp eax, edi; // object is dude? - jnz skip; + mov eax, esi; + and eax, 0xFFF; // LST index + cmp eax, critterListSize; + jle skip; sub esi, critterListSize; // fix hero FrmID skip: jmp op_obj_art_fid_Ret; diff --git a/sfall/Modules/Inventory.cpp b/sfall/Modules/Inventory.cpp index b5a0f273..05e515e6 100644 --- a/sfall/Modules/Inventory.cpp +++ b/sfall/Modules/Inventory.cpp @@ -578,26 +578,26 @@ skip: DWORD __stdcall Inventory::adjust_fid_replacement() { DWORD fid; if (fo::var::inven_dude->TypeFid() == fo::OBJ_TYPE_CRITTER) { - DWORD frameNum; + DWORD indexNum; DWORD weaponAnimCode = 0; if (PartyControl::IsNpcControlled()) { // if NPC is under control, use current FID of critter - frameNum = fo::var::inven_dude->artFid & 0xFFF; + indexNum = fo::var::inven_dude->artFid & 0xFFF; } else { // vanilla logic: - frameNum = fo::var::art_vault_guy_num; + indexNum = fo::var::art_vault_guy_num; auto critterPro = fo::GetProto(fo::var::inven_pid); if (critterPro != nullptr) { - frameNum = critterPro->fid & 0xFFF; + indexNum = critterPro->fid & 0xFFF; } if (fo::var::i_worn != nullptr) { auto armorPro = fo::GetProto(fo::var::i_worn->protoId); - DWORD armorFrameNum = fo::func::stat_level(fo::var::inven_dude, fo::STAT_gender) == fo::GENDER_FEMALE - ? armorPro->item.armor.femaleFrameNum - : armorPro->item.armor.maleFrameNum; + DWORD armorFid = fo::func::stat_level(fo::var::inven_dude, fo::STAT_gender) == fo::GENDER_FEMALE + ? armorPro->item.armor.femaleFID + : armorPro->item.armor.maleFID; - if (armorFrameNum != -1) { - frameNum = armorFrameNum; + if (armorFid != -1) { + indexNum = armorFid; } } } @@ -611,7 +611,7 @@ DWORD __stdcall Inventory::adjust_fid_replacement() { weaponAnimCode = itemPro->item.weapon.animationCode; } } - fid = fo::func::art_id(fo::OBJ_TYPE_CRITTER, frameNum, 0, weaponAnimCode, 0); + fid = fo::func::art_id(fo::OBJ_TYPE_CRITTER, indexNum, 0, weaponAnimCode, 0); } else { fid = fo::var::inven_dude->artFid; } diff --git a/sfall/Modules/Scripting/Handlers/Interface.cpp b/sfall/Modules/Scripting/Handlers/Interface.cpp index 76fcf180..f8ef13e7 100644 --- a/sfall/Modules/Scripting/Handlers/Interface.cpp +++ b/sfall/Modules/Scripting/Handlers/Interface.cpp @@ -23,6 +23,8 @@ #include "..\..\ScriptExtender.h" #include "..\OpcodeContext.h" +#include "..\..\HookScripts\InventoryHs.h" + #include "Interface.h" namespace sfall @@ -450,5 +452,65 @@ void sf_draw_image_scaled(OpcodeContext& ctx) { DrawImage(ctx, true); } +void sf_unwield_slot(OpcodeContext& ctx) { + fo::InvenType slot = static_cast(ctx.arg(1).rawValue()); + if (slot < fo::INVEN_TYPE_WORN || slot > fo::INVEN_TYPE_LEFT_HAND) { + ctx.printOpcodeError("%s() - incorrect slot number.", ctx.getMetaruleName()); + return; + } + fo::GameObject* critter = ctx.arg(0).asObject(); + if (critter->Type() != fo::ObjType::OBJ_TYPE_CRITTER) { + ctx.printOpcodeError("%s() - the object is not a critter.", ctx.getMetaruleName()); + return; + } + bool isDude = (critter == fo::var::obj_dude); + bool update = false; + if (slot && (GetLoopFlags() && (INVENTORY | INTFACEUSE | INTFACELOOT | BARTER)) == false) { + if (fo::func::inven_unwield(critter, (slot == fo::INVEN_TYPE_LEFT_HAND) ? fo::Left : fo::Right) == 0) { + update = isDude; + } + } else { + // force unwield for opened inventory + bool forceAdd = false; + fo::GameObject* item = nullptr; + if (slot != fo::INVEN_TYPE_WORN) { + if (!isDude) return; + long* itemRef = nullptr; + if (slot == fo::INVEN_TYPE_LEFT_HAND) { + item = fo::var::i_lhand; + itemRef = (long*)FO_VAR_i_lhand; + } else { + item = fo::var::i_rhand; + itemRef = (long*)FO_VAR_i_rhand; + } + if (item) { + if (!CorrectFidForRemovedItem_wHook(critter, item, (slot == fo::INVEN_TYPE_LEFT_HAND) ? fo::ObjectFlag::Left_Hand : fo::ObjectFlag::Right_Hand)) { + return; + } + *itemRef = 0; + forceAdd = true; + update = true; + } + } else { + if (isDude) item = fo::var::i_worn; + if (!item) { + item = fo::func::inven_worn(critter); + } else { + fo::var::i_worn = nullptr; + forceAdd = true; + } + if (item) { + if (!CorrectFidForRemovedItem_wHook(critter, item, fo::ObjectFlag::Worn)) { + if (forceAdd) fo::var::i_worn = item; + return; + } + if (isDude) fo::func::intface_update_ac(0); + } + } + if (forceAdd) fo::func::item_add_force(critter, item, 1); + } + if (update) fo::func::intface_update_items(0, -1, -1); +} + } } diff --git a/sfall/Modules/Scripting/Handlers/Interface.h b/sfall/Modules/Scripting/Handlers/Interface.h index f6dcaa02..f1bfd5ac 100644 --- a/sfall/Modules/Scripting/Handlers/Interface.h +++ b/sfall/Modules/Scripting/Handlers/Interface.h @@ -103,5 +103,7 @@ void sf_draw_image(OpcodeContext&); void sf_draw_image_scaled(OpcodeContext&); +void sf_unwield_slot(OpcodeContext&); + } } diff --git a/sfall/Modules/Scripting/Handlers/Metarule.cpp b/sfall/Modules/Scripting/Handlers/Metarule.cpp index 618e1cc5..fb70a290 100644 --- a/sfall/Modules/Scripting/Handlers/Metarule.cpp +++ b/sfall/Modules/Scripting/Handlers/Metarule.cpp @@ -122,6 +122,7 @@ static const SfallMetarule metarules[] = { {"spatial_radius", sf_spatial_radius, 1, 1, {ARG_OBJECT}}, {"tile_refresh_display", sf_tile_refresh_display, 0, 0}, {"unjam_lock", sf_unjam_lock, 1, 1, {ARG_OBJECT}}, + {"unwield_slot", sf_unwield_slot, 2, 2, {ARG_OBJECT, ARG_INT}}, #ifndef NDEBUG {"validate_test", sf_test, 2, 5, {ARG_INT, ARG_NUMBER, ARG_STRING, ARG_OBJECT, ARG_ANY}}, #endif