From 65c4cf644a3ae756854a8ed7647361908314489f Mon Sep 17 00:00:00 2001 From: NovaRain Date: Sat, 24 Oct 2020 12:56:26 +0800 Subject: [PATCH] Added "win_fill_color" script function --- artifacts/scripting/headers/sfall.h | 2 + artifacts/scripting/sfall function notes.txt | 9 ++- sfall/FalloutEngine/EngineUtils.cpp | 18 ++++- sfall/FalloutEngine/EngineUtils.h | 5 +- sfall/FalloutEngine/Functions_def.h | 1 + sfall/FalloutEngine/Structs.h | 69 ++++++++++++------- .../Modules/Scripting/Handlers/Interface.cpp | 18 ++++- sfall/Modules/Scripting/Handlers/Interface.h | 2 + sfall/Modules/Scripting/Handlers/Metarule.cpp | 1 + sfall/Modules/TalkingHeads.cpp | 17 +++-- 10 files changed, 103 insertions(+), 39 deletions(-) diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index 1bd44389..61cd9060 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -294,6 +294,7 @@ #define art_cache_clear sfall_func0("art_cache_clear") #define attack_is_aimed sfall_func0("attack_is_aimed") #define car_gas_amount sfall_func0("car_gas_amount") +#define clear_window sfall_func0("win_fill_color") #define combat_data sfall_func0("combat_data") #define create_win(winName, x, y, w, h) sfall_func5("create_win", winName, x, y, w, h) #define create_win_flag(winName, x, y, w, h, flag) sfall_func6("create_win", winName, x, y, w, h, flag) @@ -384,6 +385,7 @@ #define unjam_lock(obj) sfall_func1("unjam_lock", obj) #define unset_unique_id(obj) sfall_func2("set_unique_id", obj, -1) #define unwield_slot(critter, slot) sfall_func2("unwield_slot", critter, slot) +#define win_fill_color(x, y, width, height, color) sfall_func5("win_fill_color", x, y, width, height, color) #define set_fake_perk_npc(npc, perk, level, image, desc) sfall_func5("set_fake_perk_npc", npc, perk, level, image, desc) #define set_fake_trait_npc(npc, trait, active, image, desc) sfall_func5("set_fake_trait_npc", npc, trait, active, image, desc) diff --git a/artifacts/scripting/sfall function notes.txt b/artifacts/scripting/sfall function notes.txt index ef459784..0c0951b1 100644 --- a/artifacts/scripting/sfall function notes.txt +++ b/artifacts/scripting/sfall function notes.txt @@ -732,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/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) +- color1/color2: the color index in the game 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", int stat) > int sfall_func1("get_stat_max", int stat) @@ -762,7 +762,7 @@ optional arguments: - text: the text to be printed. Use the '\n' control character to move text to a new line (example: "Hello\nWorld!") - winType: the type number of the interface window (see WINTYPE_* constants in sfall.h) - x/y: offset relative to the top-left corner of the window -- color: the color index in Fallout palette. Pass 0 if the text color was previously set by vanilla SetTextColor function +- color: the color index in the game palette. Pass 0 if the text color was previously set by vanilla SetTextColor function it can also take additional flags (via bwor) for displaying text: 0x0010000 - adds a shadow to the text, the 'textshadow' compiler constant 0x1000000 - prevents immediate redrawing of the interface window, the 'textdirect' compiler constant (works the other way around) @@ -774,6 +774,11 @@ optional arguments: - can be used in conjunction with the get_object_data and set_object_data functions example: sfall_func3("set_object_data", sfall_func0("combat_data"), C_ATTACK_UNUSED, 255); +> int sfall_func0("win_fill_color") +> int sfall_func5("win_fill_color", int x, int y, int width, int height, int color) +- fills the rectangle area of the currently selected script window with the specified color, or clears the entire window with transparent color (called without arguments) +- color: the color index in the game palette (from 0 to 255) + ------------------------ ------ MORE INFO ------- ------------------------ diff --git a/sfall/FalloutEngine/EngineUtils.cpp b/sfall/FalloutEngine/EngineUtils.cpp index 6b649774..7fec3827 100644 --- a/sfall/FalloutEngine/EngineUtils.cpp +++ b/sfall/FalloutEngine/EngineUtils.cpp @@ -366,11 +366,25 @@ void DrawToSurface(long width, long height, long fromX, long fromY, long fromWid } } -// Fills the specified non-scripted interface window with index color 0 (black color) +// Fills the specified interface window with index color +void WinFillRect(long winID, long x, long y, long width, long height, BYTE indexColor) { + fo::Window* win = fo::func::GNW_find(winID); + BYTE* surf = win->surface + (win->width * y) + x; + long pitch = win->width - width; + while (height--) { + long w = width; + while (w--) *surf++ = indexColor; + surf += pitch; + }; +} + +// Fills the specified interface window with index color 0 (black color) void ClearWindow(long winID, bool refresh) { fo::Window* win = fo::func::GNW_find(winID); + BYTE* surf = win->surface; for (long i = 0; i < win->height; i++) { - std::memset(win->surface, 0, win->width); + std::memset(surf, 0, win->width); + surf += win->width; } if (refresh) { fo::func::GNW_win_refresh(win, &win->rect, 0); diff --git a/sfall/FalloutEngine/EngineUtils.h b/sfall/FalloutEngine/EngineUtils.h index 0f27a422..8035be38 100644 --- a/sfall/FalloutEngine/EngineUtils.h +++ b/sfall/FalloutEngine/EngineUtils.h @@ -115,7 +115,10 @@ void DrawToSurface(long width, long height, long fromX, long fromY, long fromWid void DrawToSurface(long width, long height, long fromX, long fromY, long fromWidth, BYTE* fromSurf, long toX, long toY, long toWidth, long toHeight, BYTE* toSurf); -// Fills the specified non-scripted interface window with index color 0 (black color) +// Fills the specified interface window with index color +void WinFillRect(long winID, long x, long y, long width, long height, BYTE indexColor); + +// Fills the specified interface window with index color 0 (black color) void ClearWindow(long winID, bool refresh = true); // Print text to surface diff --git a/sfall/FalloutEngine/Functions_def.h b/sfall/FalloutEngine/Functions_def.h index 9ebb178d..2d0242ad 100644 --- a/sfall/FalloutEngine/Functions_def.h +++ b/sfall/FalloutEngine/Functions_def.h @@ -234,6 +234,7 @@ WRAP_WATCOM_FUNC3(long, register_object_take_out, GameObject*, object, long, hol WRAP_WATCOM_FUNC3(long, register_object_turn_towards, GameObject*, object, long, tileNum, long, nothing) WRAP_WATCOM_FUNC2(long, roll_random, long, minValue, long, maxValue) WRAP_WATCOM_FUNC1(long*, runProgram, Program*, progPtr) +WRAP_WATCOM_FUNC1(long, selectWindowID, long, sWinID) WRAP_WATCOM_FUNC1(ScriptInstance*, scr_find_first_at, long, elevation) WRAP_WATCOM_FUNC0(ScriptInstance*, scr_find_next_at) WRAP_WATCOM_FUNC1(GameObject*, scr_find_obj_from_program, Program*, program) diff --git a/sfall/FalloutEngine/Structs.h b/sfall/FalloutEngine/Structs.h index 015bd4b2..35d59eec 100644 --- a/sfall/FalloutEngine/Structs.h +++ b/sfall/FalloutEngine/Structs.h @@ -188,8 +188,7 @@ struct CombatGcsd { struct ScriptInstance { long id; long next; - // first 3 bits - elevation, rest - tile number - long elevationAndTile; + long elevationAndTile; // first 3 bits - elevation, rest - tile number long spatialRadius; long flags; long scriptIdx; @@ -205,31 +204,50 @@ struct ScriptInstance { GameObject *targetObject; long actionNum; long scriptOverrides; - char gap_48[4]; + long field_48; long howMuch; - char gap_50[4]; + long field_50; long procedureTable[28]; }; // Script run-time data struct Program { - const char* fileName; + const char* fileName; // path and file name of the script "scripts\*.int" long *codeStackPtr; - long gap_8; - long gap_9; + long field_8; + long field_C; long *codePtr; long field_14; - long gap_18; + long field_18; long *dStackPtr; long *aStackPtr; long *dStackOffs; long *aStackOffs; - long gap_2C; + long field_2C; long *stringRefPtr; - long gap_34; - long *procTablePtr; + long field_34; // procTablePtr + long *procTablePtr; // field_38 + long regs[12]; + long field_6C; + long field_70; + long field_74; + long field_78; + long field_7C; + union { + long flags; + struct { + char flags1; + char flags2; + char flags3; + char flags4; + }; + }; + long currentScriptWin; // current window for executing script + long field_88; }; +static_assert(sizeof(Program) == 140, "Incorrect Program definition."); + struct ItemButtonItem { GameObject* item; union { @@ -584,8 +602,7 @@ struct Proto { long flags; long flagsExt; - // 0x0Y00XXXX: Y - script type (0=s_system, 1=s_spatial, 2=s_time, 3=s_item, 4=s_critter); XXXX - number in scripts.lst. -1 means no script. - long scriptId; + long scriptId; // 0x0Y00XXXX: Y - script type (0=s_system, 1=s_spatial, 2=s_time, 3=s_item, 4=s_critter); XXXX - number in scripts.lst. -1 means no script. ItemType type; union { @@ -730,14 +747,14 @@ struct Window { long width; long height; long clearColour; - long rand1; - long rand2; + long randX; + long randY; BYTE *surface; // bytes frame data ref to palette long *buttonsList; - long unknown5; // buttonptr? - long unknown6; + long buttonT1; // buttonptr? + long buttonT2; long *menuBar; - long *drawFunc; + long *drawFunc; // trans_buf_to_buf_ }; struct sWindow { @@ -745,18 +762,18 @@ struct sWindow { long wID; long width; long height; - long unknown1; - long unknown2; - long unknown3; - long unknown4; + long region1; + long region2; + long region3; + long region4; long *buttons; long numButtons; - long unknown5; - long unknown6; + long setPositionX; + long setPositionY; long clearColour; long flags; - long unknown7; - long unknown8; + float randX; + float randY; }; struct LSData { diff --git a/sfall/Modules/Scripting/Handlers/Interface.cpp b/sfall/Modules/Scripting/Handlers/Interface.cpp index 13b77615..619b8f14 100644 --- a/sfall/Modules/Scripting/Handlers/Interface.cpp +++ b/sfall/Modules/Scripting/Handlers/Interface.cpp @@ -474,7 +474,7 @@ static fo::FrmFile* LoadArtFile(const char* file, long frame, long direction, fo fo::FrmFile* frmPtr = nullptr; if (checkPCX) { const char* pos = strrchr(file, '.'); - if (pos && _stricmp(pos, ".PCX") == 0) { + if (pos && _stricmp(++pos, "PCX") == 0) { long w, h; BYTE* data = fo::func::loadPCX(file, &w, &h); if (!data) return nullptr; @@ -511,6 +511,7 @@ static long GetArtFIDFile(long fid, const char* &file) { } static long DrawImage(OpcodeContext& ctx, bool isScaled) { + fo::func::selectWindowID(ctx.program()->currentScriptWin); if (*(DWORD*)FO_VAR_currentWindow == -1) { ctx.printOpcodeError("%s() - no created/selected window for the image.", ctx.getMetaruleName()); return 0; @@ -782,5 +783,20 @@ void mf_interface_print(OpcodeContext& ctx) { // same as vanilla PrintRect if (!(color & 0x1000000)) fo::func::GNW_win_refresh(win, &win->rect, 0); } +void mf_win_fill_color(OpcodeContext& ctx) { + fo::func::selectWindowID(ctx.program()->currentScriptWin); + long iWin = *(DWORD*)FO_VAR_currentWindow; + if (iWin == -1) { + ctx.printOpcodeError("%s() - no created or selected window.", ctx.getMetaruleName()); + ctx.setReturn(-1); + return; + } + if (ctx.numArgs() > 0) { + fo::WinFillRect(fo::var::sWindows[iWin].wID, ctx.arg(0).rawValue(), ctx.arg(1).rawValue(), ctx.arg(2).rawValue(), ctx.arg(3).rawValue(), (BYTE)ctx.arg(4).rawValue()); + } else { + fo::ClearWindow(fo::var::sWindows[iWin].wID, false); // full clear + } +} + } } diff --git a/sfall/Modules/Scripting/Handlers/Interface.h b/sfall/Modules/Scripting/Handlers/Interface.h index 332f50f4..fda2a9c8 100644 --- a/sfall/Modules/Scripting/Handlers/Interface.h +++ b/sfall/Modules/Scripting/Handlers/Interface.h @@ -119,5 +119,7 @@ void mf_get_window_attribute(OpcodeContext&); void mf_interface_print(OpcodeContext&); +void mf_win_fill_color(OpcodeContext&); + } } diff --git a/sfall/Modules/Scripting/Handlers/Metarule.cpp b/sfall/Modules/Scripting/Handlers/Metarule.cpp index db55a41c..3794d01d 100644 --- a/sfall/Modules/Scripting/Handlers/Metarule.cpp +++ b/sfall/Modules/Scripting/Handlers/Metarule.cpp @@ -150,6 +150,7 @@ static const SfallMetarule metarules[] = { {"tile_refresh_display", mf_tile_refresh_display, 0, 0}, {"unjam_lock", mf_unjam_lock, 1, 1, -1, {ARG_OBJECT}}, {"unwield_slot", mf_unwield_slot, 2, 2, -1, {ARG_OBJECT, ARG_INT}}, + {"win_fill_color", mf_win_fill_color, 0, 5, -1, {ARG_INT, ARG_INT, ARG_INT, ARG_INT, ARG_INT}}, #ifndef NDEBUG {"validate_test", mf_test, 2, 5, -1, {ARG_INT, ARG_NUMBER, ARG_STRING, ARG_OBJECT, ARG_ANY}}, #endif diff --git a/sfall/Modules/TalkingHeads.cpp b/sfall/Modules/TalkingHeads.cpp index c762b84c..41dbe032 100644 --- a/sfall/Modules/TalkingHeads.cpp +++ b/sfall/Modules/TalkingHeads.cpp @@ -172,24 +172,27 @@ static bool LoadFrm(Frm* frm) { return true; } -static long dialogWinX = 0, dialogWinY = 0; +static struct DialogWinPos { + long x = -1; + long y; +} dialogWinPos; static void __fastcall DrawHeadFrame(Frm* frm, int frameno) { if (frm && !frm->broken) { if (!frm->loaded && !LoadFrm(frm)) goto loadFail; fo::FrmFrameData* frame = fo::func::frame_ptr((fo::FrmHeaderData*)frm, frameno, 0); - if (dialogWinX == -1) { + if (dialogWinPos.x == -1) { fo::Window* dialogWin = fo::func::GNW_find(fo::var::dialogueBackWindow); if (texHighlight) Graphics::SetHighlightTexture(texHighlight, dialogWin->rect.x, dialogWin->rect.y); - dialogWinX = dialogWin->rect.x; - dialogWinY = dialogWin->rect.y; + dialogWinPos.x = dialogWin->rect.x; + dialogWinPos.y = dialogWin->rect.y; } Graphics::SetHeadTex(frm->textures[frameno], frame->width, frame->height, - frame->x + frm->xshift + dialogWinX, - frame->y + frm->yshift + dialogWinY, + frame->x + frm->xshift + dialogWinPos.x, + frame->y + frm->yshift + dialogWinPos.y, (frm->showHighlights == 2) ); showHighlights = frm->showHighlights; @@ -219,7 +222,7 @@ void __declspec(naked) gdDestroyHeadWindow_hack() { __asm { call Graphics::SetDefaultTechnique; mov showHighlights, 0; - //mov dialogWinX, -1; // uncomment if the dialog window position is supposed to change + //mov dword ptr ds:[dialogWinPos], -1; // uncomment if the dialog window position is supposed to change pop ebp; pop edi; pop edx;