From e696db4b7bd2f3bf652aa2c6abdbe4d2bd9c4f63 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Sat, 26 Sep 2020 16:14:21 +0800 Subject: [PATCH] Added "interface_art_draw" script function Added an argument to "intface_redraw" function to redraw all interfaces. --- artifacts/scripting/headers/sfall.h | 9 ++- artifacts/scripting/sfall function notes.txt | 33 +++++--- sfall/FalloutEngine/EngineUtils.cpp | 4 +- sfall/FalloutEngine/EngineUtils.h | 2 +- sfall/Modules/Graphics.cpp | 3 +- sfall/Modules/Interface.cpp | 5 +- sfall/Modules/Movies.cpp | 2 +- sfall/Modules/Scripting/Arrays.cpp | 13 +++- sfall/Modules/Scripting/Arrays.h | 4 + .../Modules/Scripting/Handlers/Interface.cpp | 76 ++++++++++++++++++- sfall/Modules/Scripting/Handlers/Interface.h | 2 + sfall/Modules/Scripting/Handlers/Metarule.cpp | 3 +- 12 files changed, 131 insertions(+), 25 deletions(-) diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index 279757d1..117c3409 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -89,6 +89,7 @@ #define WINTYPE_CHARACTER (5) #define WINTYPE_SKILLDEX (6) #define WINTYPE_ESCMENU (7) // escape menu +#define WINTYPE_AUTOMAP (8) //Valid flags for force_encounter_with_flags #define ENCOUNTER_FLAG_NO_CAR (0x1) @@ -299,8 +300,8 @@ #define dialog_message(text) sfall_func1("dialog_message", text) #define dialog_obj sfall_func0("dialog_obj") #define display_stats sfall_func0("display_stats") -#define draw_image(pathFile, frame, x, y, noTrans) sfall_func5("draw_image", pathFile, frame, x, y, noTrans) -#define draw_image_scaled(pathFile, frame, x, y, w, h) sfall_func6("draw_image_scaled", pathFile, frame, x, y, w, h) +#define draw_image(artFile, frame, x, y, noTrans) sfall_func5("draw_image", artFile, frame, x, y, noTrans) +#define draw_image_scaled(artFile, frame, x, y, w, h) sfall_func6("draw_image_scaled", artFile, frame, x, y, w, h) #define exec_map_update_scripts sfall_func0("exec_map_update_scripts") #define floor2(value) sfall_func1("floor2", value) #define get_can_rest_on_map(map, elev) sfall_func2("get_can_rest_on_map", map, elev) @@ -327,6 +328,10 @@ #define has_fake_perk_npc(npc, perk) sfall_func2("has_fake_perk_npc", npc, perk) #define has_fake_trait_npc(npc, trait) sfall_func2("has_fake_trait_npc", npc, trait) #define hide_window(winName) sfall_func1("hide_window", winName) +#define interface_art_draw(winID, artFile, x, y) sfall_func4("interface_art_draw", winID, artFile, x, y) +#define interface_art_draw_frame(wID, art, x, y, frame) sfall_func5("interface_art_draw", wID, art, x, y, frame) +#define interface_art_draw_ex(wID, art, x, y, frm, prm) sfall_func6("interface_art_draw", wID, art, x, y, frm, prm) +#define interface_redraw_all sfall_func1("intface_redraw", 1) #define intface_hide sfall_func0("intface_hide") #define intface_is_hidden sfall_func0("intface_is_hidden") #define intface_is_shown(winType) sfall_func1("get_window_attribute", winType) diff --git a/artifacts/scripting/sfall function notes.txt b/artifacts/scripting/sfall function notes.txt index 41e52cb8..bf411080 100644 --- a/artifacts/scripting/sfall function notes.txt +++ b/artifacts/scripting/sfall function notes.txt @@ -356,7 +356,7 @@ Some utility/math functions are available: - returns first object blocking given tile using given blocking function or 0 if tile is clear > array tile_get_objs(int tileNum, int elevation) -- returns array of all objects at given tile +- returns an array of all objects at given tile - it will include any hidden, dead or system objects (like cursor), so make sure to check properly when iterating > array party_member_list(int includeHidden) @@ -402,8 +402,9 @@ Some utility/math functions are available: - works just like vanilla critter_inven_obj, but correctly reports item in player's inactive hand slot > void sfall_func0("intface_redraw") -- redraws main game interface -- useful after direct changes to current player weapons or stats to reflect changes +> void sfall_func1("intface_redraw", bool eachWin) +- redraws main game interface, useful to reflect changes after directly changing current player weapons or stats +- eachWin: pass True to redraw all interface windows > void sfall_func0("intface_hide") - hides main interface @@ -612,15 +613,15 @@ Some utility/math functions are available: - there is also a unique ID number range for the player and party members from 18000 to 83535 - to assign a new ID number generated by the engine to the object (i.e. unassign a unique ID), call the function with two arguments and pass -1 for the flag argument -> void sfall_func5("draw_image", string/int pathFile/artId, int frame, int x, int y, bool noTransparent) -> void sfall_func6("draw_image_scaled", string/int pathFile/artId, int frame, int x, int y, int width, int height) +> void sfall_func5("draw_image", string/int artFile/artId, int frame, int x, int y, bool noTransparent) +> void sfall_func6("draw_image_scaled", string/int artFile/artId, int frame, int x, int y, int width, int height) - displays the specified PCX or FRM image in the active window created by vanilla CreateWin or sfall's create_win script function -- pathFile/artId: path to the PCX/FRM file (e.g. "art\\inven\\5mmap.frm"), or its FRM ID number (e.g. 0x7000026, see specification of the FID format) +- artFile/artId: path to the PCX/FRM file (e.g. "art\\inven\\5mmap.frm"), or its FRM ID number (e.g. 0x7000026, see specification of the FID format) optional arguments: - frame: frame number, the first frame starts from zero - x/y: offset relative to the top-left corner of the window -- width/height: image size, used to scale the image when displaying it. Pass -1 to either width or height to keep the aspect ratio when scaling -- noTransparent: pass true to display an image without transparent background +- width/height: the new width/height to scale the image to. Pass -1 to either width or height to keep the aspect ratio when scaling +- noTransparent: pass True to display an image without transparent background - NOTE: to omit optional arguments starting from the right, call the functions with different sfall_funcX (e.g. sfall_func4("draw_image", pathFile, frame, x, y)) - if draw_image_scaled is called without x/y/width/height arguments, the image will be scaled to fit the window without transparent background @@ -731,7 +732,7 @@ optional argument: - message: the text in the dialog box. Use the \n control character to move text to a new line (example: "Hello\nWorld!") optional arguments: - flags: mode flags (see MSGBOX_* constants in define_extra.h). Pass -1 to skip setting the flags (default flags are NORMAL and YESNO) -- color1/2: the color index in Fallout palette. color1 sets the text color for the first line, and color2 for all subsequent lines of text (default color is 145) +- color1/color2: the color index in Fallout palette. color1 sets the text color for the first line, and color2 for all subsequent lines of text (default color is 145) > int sfall_func1("get_stat_min", stat) > int sfall_func1("get_stat_max", stat) @@ -740,6 +741,20 @@ optional arguments: - returns the maximum or minimum set value of the specified stat (see set_stat_max/min functions) - who: 0 (false) or omitting the argument - returns the value of the player, 1 (true) - returns the value set for other critters +> int sfall_func4("interface_art_draw", int winType, string/int artFile/artId, int x, int y) +> int sfall_func5("interface_art_draw", int winType, string/int artFile/artId, int x, int y, int frame) +> int sfall_func6("interface_art_draw", int winType, string/int artFile/artId, int x, int y, int frame, array param) +- draws the specified PCX or FRM image in the game interface window, returns -1 in case of any error +- winType: the type number of the interface window (see WINTYPE_* constants in sfall.h) + this also takes the value of the flag (0x10000) to prevent immediate redrawing of the interface window +- artFile/artId: path to the PCX/FRM file (e.g. "art\\inven\\5mmap.frm"), or its FRM ID number (e.g. 0x7000026, see specification of the FID format) +- x/y: offset relative to the top-left corner of the window +optional arguments: +- frame: frame number, the first frame starts from zero +- param: an array which specifies additional parameters: + index 0 - the direction of multi-directional FRM + index 1/index 2 - the new width/height to scale the image to. Pass -1 to width or height to use the original image size + ------------------------ ------ MORE INFO ------- ------------------------ diff --git a/sfall/FalloutEngine/EngineUtils.cpp b/sfall/FalloutEngine/EngineUtils.cpp index be1709e8..25e6793a 100644 --- a/sfall/FalloutEngine/EngineUtils.cpp +++ b/sfall/FalloutEngine/EngineUtils.cpp @@ -481,9 +481,9 @@ void RedrawObject(GameObject* obj) { } // Redraws all interface windows -void RefreshGNW() { +void RefreshGNW(size_t from) { *(DWORD*)FO_VAR_doing_refresh_all = 1; - for (size_t i = 0; i < fo::var::num_windows; i++) { + for (size_t i = from; i < fo::var::num_windows; i++) { func::GNW_win_refresh(fo::var::window[i], &fo::var::scr_size, 0); } *(DWORD*)FO_VAR_doing_refresh_all = 0; diff --git a/sfall/FalloutEngine/EngineUtils.h b/sfall/FalloutEngine/EngineUtils.h index 4f060820..58de05bc 100644 --- a/sfall/FalloutEngine/EngineUtils.h +++ b/sfall/FalloutEngine/EngineUtils.h @@ -133,7 +133,7 @@ DWORD GetMaxCharWidth(); void RedrawObject(GameObject* obj); // Redraws all interface windows -void RefreshGNW(); +void RefreshGNW(size_t from); UnlistedFrm *LoadUnlistedFrm(char *frmName, unsigned int folderRef); diff --git a/sfall/Modules/Graphics.cpp b/sfall/Modules/Graphics.cpp index ecfdf43a..a7c21aa8 100644 --- a/sfall/Modules/Graphics.cpp +++ b/sfall/Modules/Graphics.cpp @@ -196,6 +196,7 @@ static void WindowInit() { ScriptShaders::LoadGlobalShader(); } +// pixel size for the current game resolution const float* Graphics::rcpresGet() { return rcpres; } @@ -770,7 +771,7 @@ public: if (d3d9Device->TestCooperativeLevel() == D3DERR_DEVICENOTRESET) { ResetDevice(false); DeviceLost = false; - fo::RefreshGNW(); + fo::RefreshGNW(0); } return !DeviceLost; } diff --git a/sfall/Modules/Interface.cpp b/sfall/Modules/Interface.cpp index 08a6604e..d4d837ca 100644 --- a/sfall/Modules/Interface.cpp +++ b/sfall/Modules/Interface.cpp @@ -46,11 +46,8 @@ enum WinNameType { EscMenu = 7, // escape menu Automap = 8, // TODO - IntfaceUse, - IntfaceLoot, DialogView, DialogPanel, - BarterPanel, MemberPanel, }; @@ -58,7 +55,7 @@ fo::Window* Interface::GetWindow(long winType) { long winID = 0; switch (winType) { case WinNameType::Inventory: - if (GetLoopFlags() & INVENTORY) winID = fo::var::i_wid; + if (GetLoopFlags() & (INVENTORY | INTFACEUSE | INTFACELOOT | BARTER)) winID = fo::var::i_wid; break; case WinNameType::Dialog: if (GetLoopFlags() & DIALOG) winID = fo::var::dialogueBackWindow; diff --git a/sfall/Modules/Movies.cpp b/sfall/Modules/Movies.cpp index 946cf785..ea0162b4 100644 --- a/sfall/Modules/Movies.cpp +++ b/sfall/Modules/Movies.cpp @@ -216,7 +216,7 @@ static void StopMovie() { aviPlayState = AviState::Stop; Graphics::SetMovieTexture(false); movieInterface.pControl->Stop(); - if (*(DWORD*)FO_VAR_subtitles == 0) fo::RefreshGNW(); // Note: it is only necessary when in the game + if (*(DWORD*)FO_VAR_subtitles == 0) fo::RefreshGNW(0); // Note: it is only necessary when in the game } DWORD FreeMovie(sDSTexture* movie) { diff --git a/sfall/Modules/Scripting/Arrays.cpp b/sfall/Modules/Scripting/Arrays.cpp index a9b68645..250337cb 100644 --- a/sfall/Modules/Scripting/Arrays.cpp +++ b/sfall/Modules/Scripting/Arrays.cpp @@ -539,8 +539,12 @@ void SetArray(DWORD id, const ScriptValue& key, const ScriptValue& val, bool all } int LenArray(DWORD id) { - if (arrays.find(id) == arrays.end()) return -1; - return arrays[id].size(); + array_itr it = arrays.find(id); + return (it != arrays.end()) ? it->second.size() : -1; +} + +bool ArrayExist(DWORD id) { + return (arrays.find(id) != arrays.end()); } template @@ -746,5 +750,10 @@ long StackArray(const ScriptValue& key, const ScriptValue& val) { return 0; } +sArrayVar* GetRawArray(DWORD id) { + array_itr it = arrays.find(id); + return (it != arrays.end()) ? &it->second : nullptr; +} + } } diff --git a/sfall/Modules/Scripting/Arrays.h b/sfall/Modules/Scripting/Arrays.h index d8d4d1c4..acb65151 100644 --- a/sfall/Modules/Scripting/Arrays.h +++ b/sfall/Modules/Scripting/Arrays.h @@ -185,6 +185,8 @@ void SetArray(DWORD id, const ScriptValue& key, const ScriptValue& val, bool all // number of elements in list or pairs in map int LenArray(DWORD id); +bool ArrayExist(DWORD id); + // change array size (only works with list) long ResizeArray(DWORD id, int newlen); @@ -203,5 +205,7 @@ void SaveArray(const ScriptValue& key, DWORD id); // special function that powers array expressions long StackArray(const ScriptValue& key, const ScriptValue& val); +sArrayVar* GetRawArray(DWORD id); + } } diff --git a/sfall/Modules/Scripting/Handlers/Interface.cpp b/sfall/Modules/Scripting/Handlers/Interface.cpp index c5054de7..da9dea33 100644 --- a/sfall/Modules/Scripting/Handlers/Interface.cpp +++ b/sfall/Modules/Scripting/Handlers/Interface.cpp @@ -24,6 +24,7 @@ #include "..\..\LoadGameHook.h" #include "..\..\ScriptExtender.h" #include "..\..\Interface.h" +#include "..\Arrays.h" #include "..\OpcodeContext.h" #include "..\..\HookScripts\InventoryHs.h" @@ -265,7 +266,11 @@ void op_is_iface_tag_active(OpcodeContext &ctx) { } void mf_intface_redraw(OpcodeContext& ctx) { - fo::func::intface_redraw(); + if (ctx.arg(0).rawValue() == 0) { + fo::func::intface_redraw(); + } else { + fo::func::RefreshGNW(1); // redraw all interfaces + } } void mf_intface_show(OpcodeContext& ctx) { @@ -458,7 +463,7 @@ static long GetArtFIDFile(long fid, const char* &file) { file = fo::func::art_get_name(_fid); // .frm if (_fid >> 24 == fo::OBJ_TYPE_CRITTER) { direction = (fid >> 28); - if (direction && !fo::func::db_access(file)) { + if (direction > 0 && !fo::func::db_access(file)) { file = fo::func::art_get_name(fid); // .fr# } } @@ -557,6 +562,73 @@ void mf_draw_image_scaled(OpcodeContext& ctx) { ctx.setReturn(DrawImage(ctx, true)); } +static long InterfaceDrawImage(OpcodeContext& ctx, fo::Window* interfaceWin) { + const char* file = nullptr; + bool useShift = false; + long direction = -1, w = -1, h = -1; + + if (ctx.arg(1).isInt()) { // art id + long fid = ctx.arg(1).rawValue(); + if (fid == -1) return -1; + + useShift = (((fid & 0xF000000) >> 24) == fo::OBJ_TYPE_CRITTER); + direction = GetArtFIDFile(fid, file); + } else { + file = ctx.arg(1).strValue(); // path to frm/pcx file + } + + if (ctx.numArgs() > 5) { // array params + sArrayVar* sArray = GetRawArray(ctx.arg(5).rawValue()); + if (sArray) { + if (direction < 0) direction = sArray->val[0].intVal; + int size = sArray->size(); + if (size > 1) w = sArray->val[1].intVal; + if (size > 2) h = sArray->val[2].intVal; + } + } + long frame = ctx.arg(4).rawValue(); + + fo::FrmFrameData* framePtr; + fo::FrmFile* frmPtr = LoadArtFile(file, frame, direction, framePtr); + if (frmPtr == nullptr) { + ctx.printOpcodeError("%s() - cannot open the file: %s", ctx.getMetaruleName(), file); + return -1; + } + int x = ctx.arg(2).rawValue(); + int y = ctx.arg(3).rawValue(); + + if (useShift && direction >= 0) { + x += frmPtr->xshift[direction]; + y += frmPtr->yshift[direction]; + } + if (x < 0) x = 0; + if (y < 0) y = 0; + + int width = (w >= 0) ? w : framePtr->width; + int height = (h >= 0) ? h : framePtr->height; + + fo::func::trans_cscale(framePtr->data, framePtr->width, framePtr->height, framePtr->width, + interfaceWin->surface + (y * interfaceWin->width) + x, width, height, interfaceWin->width + ); + + if (!(ctx.arg(0).rawValue() & 0x10000)) { + fo::func::GNW_win_refresh(interfaceWin, &interfaceWin->rect, 0); + } + fo::func::mem_free(frmPtr); + return 1; +} + +void mf_interface_art_draw(OpcodeContext& ctx) { + long result = -1; + fo::Window* win = Interface::GetWindow(ctx.arg(0).rawValue() & 0xFF); + if (win && (int)win != -1) { + result = InterfaceDrawImage(ctx, win); + } else { + ctx.printOpcodeError("%s() - the game interface window is not created or invalid value for the interface.", ctx.getMetaruleName()); + } + ctx.setReturn(result); +} + void mf_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) { diff --git a/sfall/Modules/Scripting/Handlers/Interface.h b/sfall/Modules/Scripting/Handlers/Interface.h index 1c47e79f..a0120fda 100644 --- a/sfall/Modules/Scripting/Handlers/Interface.h +++ b/sfall/Modules/Scripting/Handlers/Interface.h @@ -111,6 +111,8 @@ void mf_draw_image(OpcodeContext&); void mf_draw_image_scaled(OpcodeContext&); +void mf_interface_art_draw(OpcodeContext&); + void mf_unwield_slot(OpcodeContext&); void mf_get_window_attribute(OpcodeContext&); diff --git a/sfall/Modules/Scripting/Handlers/Metarule.cpp b/sfall/Modules/Scripting/Handlers/Metarule.cpp index 94c7908e..0fe3d88c 100644 --- a/sfall/Modules/Scripting/Handlers/Metarule.cpp +++ b/sfall/Modules/Scripting/Handlers/Metarule.cpp @@ -100,9 +100,10 @@ static const SfallMetarule metarules[] = { {"has_fake_perk_npc", mf_has_fake_perk_npc, 2, 2, 0, {ARG_OBJECT, ARG_STRING}}, {"has_fake_trait_npc", mf_has_fake_trait_npc, 2, 2, 0, {ARG_OBJECT, ARG_STRING}}, {"hide_window", mf_hide_window, 0, 1, -1, {ARG_STRING}}, + {"interface_art_draw", mf_interface_art_draw, 4, 6, -1, {ARG_INT, ARG_INTSTR, ARG_INT, ARG_INT, ARG_INT, ARG_INT}}, {"intface_hide", mf_intface_hide, 0, 0}, {"intface_is_hidden", mf_intface_is_hidden, 0, 0}, - {"intface_redraw", mf_intface_redraw, 0, 0}, + {"intface_redraw", mf_intface_redraw, 0, 1}, {"intface_show", mf_intface_show, 0, 0}, {"inventory_redraw", mf_inventory_redraw, 0, 1, -1, {ARG_INT}}, {"item_make_explosive", mf_item_make_explosive, 3, 4, -1, {ARG_INT, ARG_INT, ARG_INT, ARG_INT}},