mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Added "unwield_slot" script function
Re-fixed obj_art_fid for player's FID (commit 50f4885)
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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 -------
|
||||
------------------------
|
||||
|
||||
@@ -519,8 +519,8 @@ struct Proto {
|
||||
// for each DamageType
|
||||
long damageThreshold[7];
|
||||
long perk;
|
||||
long maleFrameNum;
|
||||
long femaleFrameNum;
|
||||
long maleFID;
|
||||
long femaleFID;
|
||||
};
|
||||
|
||||
struct Container {
|
||||
|
||||
@@ -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;
|
||||
|
||||
+10
-10
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<fo::InvenType>(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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,5 +103,7 @@ void sf_draw_image(OpcodeContext&);
|
||||
|
||||
void sf_draw_image_scaled(OpcodeContext&);
|
||||
|
||||
void sf_unwield_slot(OpcodeContext&);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user