diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index 0e2314f7..25312263 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -265,6 +265,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) @@ -341,5 +342,6 @@ #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) #endif diff --git a/artifacts/scripting/sfall function notes.txt b/artifacts/scripting/sfall function notes.txt index bc57408c..65686290 100644 --- a/artifacts/scripting/sfall function notes.txt +++ b/artifacts/scripting/sfall function notes.txt @@ -647,7 +647,7 @@ optional arguments: - 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) @@ -677,7 +677,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) @@ -689,6 +689,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.cpp b/sfall/FalloutEngine.cpp index ebe7dc94..c911fe5b 100644 --- a/sfall/FalloutEngine.cpp +++ b/sfall/FalloutEngine.cpp @@ -210,7 +210,7 @@ DWORD* ptr_stack_offset = reinterpret_cast(_stack_offset DWORD* ptr_stat_data = reinterpret_cast(_stat_data); DWORD* ptr_stat_flag = reinterpret_cast(_stat_flag); SubTitleList** ptr_subtitleList = reinterpret_cast(_subtitleList); -DWORD* ptr_sWindows = reinterpret_cast(_sWindows); // total 16 sWindow struct +sWindow* ptr_sWindows = reinterpret_cast(_sWindows); // array of 16 sWindow DWORD* ptr_Tag_ = reinterpret_cast(_Tag_); DWORD* ptr_tag_skill = reinterpret_cast(_tag_skill); DWORD* ptr_target_curr_stack = reinterpret_cast(_target_curr_stack); @@ -721,6 +721,7 @@ const DWORD scr_set_ext_param_ = 0x4A3B34; const DWORD scr_set_local_var_ = 0x4A6E58; const DWORD scr_set_objs_ = 0x4A3B0C; const DWORD scr_write_ScriptNode_ = 0x4A5704; +const DWORD selectWindowID_ = 0x4B81C4; const DWORD set_focus_func_ = 0x4C9438; const DWORD set_game_time_ = 0x4A347C; const DWORD setup_move_timer_win_ = 0x476AB8; @@ -1572,11 +1573,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) { + WINinfo* win = GNWFind(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) { WINinfo* win = GNWFind(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) { GNWWinRefresh(win, &win->rect, 0); diff --git a/sfall/FalloutEngine.h b/sfall/FalloutEngine.h index c2f79988..200f426f 100644 --- a/sfall/FalloutEngine.h +++ b/sfall/FalloutEngine.h @@ -515,7 +515,7 @@ extern DWORD* ptr_stack_offset; extern DWORD* ptr_stat_data; extern DWORD* ptr_stat_flag; extern SubTitleList** ptr_subtitleList; -extern DWORD* ptr_sWindows; // total 16 sWindow struct +extern sWindow* ptr_sWindows; // array of 16 sWindow extern DWORD* ptr_Tag_; extern DWORD* ptr_tag_skill; extern DWORD* ptr_target_curr_stack; @@ -1018,6 +1018,7 @@ extern const DWORD scr_set_ext_param_; extern const DWORD scr_set_local_var_; extern const DWORD scr_set_objs_; extern const DWORD scr_write_ScriptNode_; +extern const DWORD selectWindowID_; extern const DWORD set_focus_func_; extern const DWORD set_game_time_; extern const DWORD setup_move_timer_win_; @@ -1341,7 +1342,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/FalloutFuncs_def.h b/sfall/FalloutFuncs_def.h index 82bad015..36b9e96b 100644 --- a/sfall/FalloutFuncs_def.h +++ b/sfall/FalloutFuncs_def.h @@ -187,6 +187,7 @@ WRAP_WATCOM_FUNC3(long, RegisterObjectTakeOut, register_object_take_out_, TGameO WRAP_WATCOM_FUNC3(long, RegisterObjectTurnTowards, register_object_turn_towards_, TGameObj*, object, long, tileNum, long, nothing) WRAP_WATCOM_FUNC2(long, RollRandom, roll_random_, long, minValue, long, maxValue) WRAP_WATCOM_FUNC1(long*, RunProgram, runProgram_, TProgram*, progPtr) +WRAP_WATCOM_FUNC1(long, SelectWindowID, selectWindowID_, long, sWinID) WRAP_WATCOM_FUNC1(TScript*, ScrFindFirstAt, scr_find_first_at_, long, elevation) WRAP_WATCOM_FUNC0(TScript*, ScrFindNextAt, scr_find_next_at_) WRAP_WATCOM_FUNC1(TGameObj*, ScrFindObjFromProgram, scr_find_obj_from_program_, TProgram*, program) diff --git a/sfall/FalloutStructs.h b/sfall/FalloutStructs.h index 2372a0b9..9d257efb 100644 --- a/sfall/FalloutStructs.h +++ b/sfall/FalloutStructs.h @@ -158,8 +158,7 @@ struct CombatGcsd { struct TScript { 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; @@ -175,31 +174,50 @@ struct TScript { TGameObj *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 TProgram { - 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(TProgram) == 140, "Incorrect TProgram definition."); + struct ItemButtonItem { TGameObj* item; union { @@ -478,14 +496,14 @@ struct WINinfo { 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 { @@ -493,18 +511,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/ScriptExtender.cpp b/sfall/ScriptExtender.cpp index 14b876b5..d6adcdaf 100644 --- a/sfall/ScriptExtender.cpp +++ b/sfall/ScriptExtender.cpp @@ -880,6 +880,7 @@ static const SfallOpcodeMetadata opcodeMetaArray[] = { {mf_tile_by_position, "tile_by_position", {DATATYPE_MASK_INT, DATATYPE_MASK_INT}}, {mf_unjam_lock, "unjam_lock", {DATATYPE_MASK_VALID_OBJ}}, {mf_unwield_slot, "unwield_slot", {DATATYPE_MASK_VALID_OBJ, DATATYPE_MASK_INT}}, + {mf_win_fill_color, "win_fill_color", {DATATYPE_MASK_INT, DATATYPE_MASK_INT, DATATYPE_MASK_INT, DATATYPE_MASK_INT, DATATYPE_MASK_INT}}, #ifndef NDEBUG {mf_test, "validate_test", {DATATYPE_MASK_INT, DATATYPE_MASK_INT | DATATYPE_MASK_FLOAT, DATATYPE_MASK_STR, DATATYPE_NONE}}, #endif diff --git a/sfall/ScriptOps/InterfaceOps.hpp b/sfall/ScriptOps/InterfaceOps.hpp index 9254243d..e524f736 100644 --- a/sfall/ScriptOps/InterfaceOps.hpp +++ b/sfall/ScriptOps/InterfaceOps.hpp @@ -457,11 +457,9 @@ static void mf_create_win() { static void mf_show_window() { if (opHandler.numArgs() > 0) { const char* name = opHandler.arg(0).strValue(); - sWindow sWin; for (size_t i = 0; i < 16; i++) { - sWin = *(sWindow*)&ptr_sWindows[i * 23]; // sWindow struct = 92 bytes - if (_stricmp(name, sWin.name) == 0) { - WinShow(sWin.wID); + if (_stricmp(name, ptr_sWindows[i].name) == 0) { + WinShow(ptr_sWindows[i].wID); return; } } @@ -474,11 +472,9 @@ static void mf_show_window() { static void mf_hide_window() { if (opHandler.numArgs() > 0) { const char* name = opHandler.arg(0).strValue(); - sWindow sWin; for (size_t i = 0; i < 16; i++) { - sWin = *(sWindow*)&ptr_sWindows[i * 23]; // sWindow struct = 92 bytes - if (_stricmp(name, sWin.name) == 0) { - WinHide(sWin.wID); + if (_stricmp(name, ptr_sWindows[i].name) == 0) { + WinHide(ptr_sWindows[i].wID); return; } } @@ -503,16 +499,14 @@ static void mf_set_window_flag() { bool mode = opHandler.arg(2).asBool(); if (opHandler.arg(0).isString()) { const char* name = opHandler.arg(0).strValue(); - sWindow sWin; for (size_t i = 0; i < 16; i++) { - sWin = *(sWindow*)&ptr_sWindows[i * 23]; // sWindow struct = 92 bytes - if (_stricmp(name, sWin.name) == 0) { - WINinfo* win = GNWFind(sWin.wID); + if (_stricmp(name, ptr_sWindows[i].name) == 0) { + WINinfo* win = GNWFind(ptr_sWindows[i].wID); if (mode) { - sWin.flags |= bitFlag; + ptr_sWindows[i].flags |= bitFlag; win->flags |= bitFlag; } else { - sWin.flags &= ~bitFlag; + ptr_sWindows[i].flags &= ~bitFlag; win->flags &= ~bitFlag; } return; @@ -547,7 +541,7 @@ static FrmFile* LoadArtFile(const char* file, long frame, long direction, FrmFra 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 = LoadPCXData(file, &w, &h); if (!data) return nullptr; @@ -584,6 +578,7 @@ static long GetArtFIDFile(long fid, const char* &file) { } static void mf_draw_image() { + SelectWindowID(opHandler.program()->currentScriptWin); if (*(DWORD*)_currentWindow == -1) { opHandler.printOpcodeError("draw_image() - no created/selected window for the image."); opHandler.setReturn(0); @@ -604,7 +599,7 @@ static void mf_draw_image() { file = opHandler.arg(0).strValue(); // path to frm/pcx file } // initialize other args - int frameno = 0, x = 0, y = 0, noTrans = 0; + long frameno = 0, x = 0, y = 0, noTrans = 0; switch (opHandler.numArgs()) { case 5: noTrans = opHandler.arg(4).rawValue(); @@ -633,6 +628,7 @@ static void mf_draw_image() { } static void mf_draw_image_scaled() { + SelectWindowID(opHandler.program()->currentScriptWin); if (*(DWORD*)_currentWindow == -1) { opHandler.printOpcodeError("draw_image_scaled() - no created/selected window for the image."); opHandler.setReturn(0); @@ -653,7 +649,7 @@ static void mf_draw_image_scaled() { file = opHandler.arg(0).strValue(); // path to frm/pcx file } // initialize other args - int frameno = 0, x = 0, y = 0, wsize = 0; + long frameno = 0, x = 0, y = 0, wsize = 0; switch (opHandler.numArgs()) { case 6: case 5: @@ -907,3 +903,32 @@ static void mf_interface_print() { // same as vanilla PrintRect // no redraw (textdirect) if (!(color & 0x1000000)) GNWWinRefresh(win, &win->rect, 0); } + +static void mf_win_fill_color() { + SelectWindowID(opHandler.program()->currentScriptWin); + long iWin = *(DWORD*)_currentWindow; + if (iWin == -1) { + opHandler.printOpcodeError("win_fill_color() - no created or selected window."); + opHandler.setReturn(-1); + return; + } + // initialize args + long x = 0, y = 0, width = 0, height = 0, color = 0; + switch (opHandler.numArgs()) { + case 5: + color = opHandler.arg(4).rawValue(); + case 4: + height = opHandler.arg(3).rawValue(); + case 3: + width = opHandler.arg(2).rawValue(); + case 2: + y = opHandler.arg(1).rawValue(); + case 1: + x = opHandler.arg(0).rawValue(); + } + if (opHandler.numArgs() > 0) { + WinFillRect(ptr_sWindows[iWin].wID, x, y, width, height, (BYTE)color); + } else { + ClearWindow(ptr_sWindows[iWin].wID, false); // full clear + } +} diff --git a/sfall/ScriptOps/MetaruleOps.hpp b/sfall/ScriptOps/MetaruleOps.hpp index 5b57af8e..c2607726 100644 --- a/sfall/ScriptOps/MetaruleOps.hpp +++ b/sfall/ScriptOps/MetaruleOps.hpp @@ -184,6 +184,7 @@ static const SfallMetarule metaruleArray[] = { {"tile_refresh_display", mf_tile_refresh_display, 0, 0}, {"unjam_lock", mf_unjam_lock, 1, 1}, {"unwield_slot", mf_unwield_slot, 2, 2}, + {"win_fill_color", mf_win_fill_color, 0, 5}, #ifndef NDEBUG {"validate_test", mf_test, 2, 5}, #endif diff --git a/sfall/TalkingHeads.cpp b/sfall/TalkingHeads.cpp index 6d550835..350f6755 100644 --- a/sfall/TalkingHeads.cpp +++ b/sfall/TalkingHeads.cpp @@ -164,23 +164,28 @@ static bool LoadFrm(Frm* frm) { return true; } -static long dialogWinX = 0, dialogWinY = 0; +static struct DialogWinPos { + long x; + long y; + + DialogWinPos() : x(-1) {} +} dialogWinPos; static void __fastcall DrawHeadFrame(Frm* frm, int frameno) { if (frm && !frm->broken) { if (!frm->loaded && !LoadFrm(frm)) goto loadFail; FrmFrameData* frame = FramePtr((FrmHeaderData*)frm, frameno, 0); - if (dialogWinX == -1) { + if (dialogWinPos.x == -1) { WINinfo* dialogWin = GNWFind(*ptr_dialogueBackWindow); - dialogWinX = dialogWin->rect.x; - dialogWinY = dialogWin->rect.y; + dialogWinPos.x = dialogWin->rect.x; + dialogWinPos.y = dialogWin->rect.y; } Gfx_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 ); showHighlights = frm->showHighlights; return; @@ -209,7 +214,7 @@ void __declspec(naked) gdDestroyHeadWindow_hack() { __asm { call Gfx_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;