From 893847cc6a48239708b2d2df5b4470c8d56ad067 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Mon, 27 Jan 2020 20:52:01 +0800 Subject: [PATCH] Added "dialog_box" script function Added a new attrType value to "get_window_attribute" function. Tweaked the arg type check for "force_encounter_with_flags" function. --- artifacts/scripting/headers/sfall.h | 8 +- artifacts/scripting/sfall function notes.txt | 14 ++- sfall/Define.h | 10 +++ sfall/FalloutEngine.cpp | 39 +++++++-- sfall/FalloutEngine.h | 10 ++- sfall/PartyControl.cpp | 4 +- sfall/ScriptExtender.cpp | 1 + sfall/ScriptOps/InterfaceOp.hpp | 91 ++++++++++++-------- sfall/ScriptOps/MetaruleOp.hpp | 3 +- sfall/ScriptOps/WorldmapOps.hpp | 30 +++---- 10 files changed, 143 insertions(+), 67 deletions(-) diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index a5821dac..4d393bdd 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -59,7 +59,7 @@ #define LIST_ALL (9) //Valid window types for get_window_attribute -#define WINTYPE_INVENTORY (0) // any inventory window +#define WINTYPE_INVENTORY (0) // any inventory window (player/loot/use/barter) #define WINTYPE_DIALOG (1) #define WINTYPE_PIPBOY (2) #define WINTYPE_WORLDMAP (3) @@ -244,6 +244,7 @@ #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) #define critter_inven_obj2(obj, type) sfall_func2("critter_inven_obj2", obj, type) +#define dialog_box(text) sfall_func1("dialog_box", 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) @@ -253,8 +254,8 @@ #define get_current_inven_size(obj) sfall_func1("get_current_inven_size", obj) #define get_cursor_mode sfall_func0("get_cursor_mode") #define get_flags(obj) sfall_func1("get_flags", obj) -#define get_interface_x(winType) sfall_func2("get_window_attribute", winType, 0) -#define get_interface_y(winType) sfall_func2("get_window_attribute", winType, 1) +#define get_interface_x(winType) sfall_func2("get_window_attribute", winType, 1) +#define get_interface_y(winType) sfall_func2("get_window_attribute", winType, 2) #define get_inven_ap_cost sfall_func0("get_inven_ap_cost") #define get_map_enter_position sfall_func0("get_map_enter_position") #define get_metarule_table sfall_func0("get_metarule_table") @@ -265,6 +266,7 @@ #define hide_window(winName) sfall_func1("hide_window", winName) #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) #define intface_redraw sfall_func0("intface_redraw") #define intface_show sfall_func0("intface_show") #define inventory_redraw(invSide) sfall_func1("inventory_redraw", invSide) diff --git a/artifacts/scripting/sfall function notes.txt b/artifacts/scripting/sfall function notes.txt index 47db92e9..18de2260 100644 --- a/artifacts/scripting/sfall function notes.txt +++ b/artifacts/scripting/sfall function notes.txt @@ -611,15 +611,25 @@ optional arguments: > void sfall_func3("set_terrain_name", int x, int y, string name) - overrides the terrain type name for the sub-tile on the world map by the specified coordinates -int sfall_func2("get_window_attribute", int winType, int attrType) +> int sfall_func1("get_window_attribute", int winType) +> int sfall_func2("get_window_attribute", int winType, int attrType) - returns the attribute of the specified interface window by the attrType argument - winType: the type number of the interface window (see WINTYPE_* constants in sfall.h) -- attrType: 0 - X position, 1 - Y position (relative to the top-left corner of the game screen) +- attrType: 0 - returns a value of 1 if the specified interface window is created by the game (same as without the argument) + 1 - X position, 2 - Y position (relative to the top-left corner of the game screen) +- returns -1 if the specified attribute cannot be obtained > void sfall_func2("set_town_title", int areaID, string title) - sets a floating text for a town on the world map when hovering the cursor over the player's marker - areaID: the ID number of the town from city.txt +> int sfall_func1("dialog_box", string text1) +> int sfall_func2("dialog_box", string text1, string text2) +> int sfall_func3("dialog_box", string text1, string text2, string text3) +- creates a dialog box with text and returns the result of pressing the button: 0 - No, 1 - Yes +- text1/text2/text3: corresponding text in the dialog box for the first, second, and third lines +- returns -1 if for some reason the dialog box cannot be created + ------------------------ ------ MORE INFO ------- ------------------------ diff --git a/sfall/Define.h b/sfall/Define.h index c66193d3..e41594f9 100644 --- a/sfall/Define.h +++ b/sfall/Define.h @@ -444,3 +444,13 @@ enum QueueType : long map_update_event = 12, gsound_sfx_event = 13 // no object }; + +enum DialogOutFlags : long +{ + DIALOGOUT_NORMAL = 0x01, // uses regular graphic + DIALOGOUT_SMALL = 0x02, // uses smaller graphic + DIALOGOUT_ALIGN_LEFT = 0x04, // text aligned to left + DIALOGOUT_ALIGN_TOP = 0x08, // text aligned to top + DIALOGOUT_YESNO = 0x10, // DONE button replaced by YES/NO buttons - WIP: currently useless in scripts + DIALOGOUT_CLEAN = 0x20 // no buttons +}; diff --git a/sfall/FalloutEngine.cpp b/sfall/FalloutEngine.cpp index 8c741895..786c7811 100644 --- a/sfall/FalloutEngine.cpp +++ b/sfall/FalloutEngine.cpp @@ -989,8 +989,12 @@ long __fastcall ScrSetLocalVar(long sid, long varId, long value) { WRAP_WATCOM_FCALL3(scr_set_local_var_, sid, varId, value) } +long __stdcall IntfaceIsHidden() { + WRAP_WATCOM_CALL0(intface_is_hidden_) +} + // redraws the main game interface windows (useful after changing some data like active hand, etc.) -void __stdcall InterfaceRedraw() { +void __stdcall IntfaceRedraw() { WRAP_WATCOM_CALL0(intface_redraw_) } @@ -1081,21 +1085,36 @@ long __stdcall WinRegisterButton(DWORD winRef, long xPos, long yPos, long width, void __stdcall DialogOut(const char* text) { __asm { - push 1; // flag + push 1; // DIALOGOUT_NORMAL flag xor eax, eax; push eax; // ColorMsg - push eax; // DisplayMsg + push eax; // DisplayMsg (unknown) mov al, byte ptr ds:[0x6AB718]; push eax; // ColorIndex push 116; // y mov ecx, 192; // x mov eax, text; // DisplayText - xor ebx, ebx; // ? - xor edx, edx; // ? + xor ebx, ebx; + xor edx, edx; call dialog_out_; } } +long __fastcall DialogOutEx(const char* text, const char** textEx, long count, long flags) { + __asm { + mov eax, 145; // Color index + push flags; // flag + push eax; // ColorMsg2 + push 0; // DisplayMsg (unknown) + push eax; // ColorMsg1 + mov eax, ecx; // DisplayText first line + push 116; // y + mov ecx, 192; // x + mov ebx, count; // count text lines 0-2 + call dialog_out_; // edx - DisplayText second/third line + } +} + void __fastcall DrawWinLine(int winRef, DWORD startXPos, DWORD endXPos, DWORD startYPos, DWORD endYPos, BYTE colour) { __asm { xor eax, eax; @@ -1160,6 +1179,14 @@ long __fastcall WordWrap(const char* text, int maxWidth, DWORD* buf, BYTE* count WRAP_WATCOM_FCALL4(_word_wrap_, text, maxWidth, buf, count) } +long __stdcall Gmouse3dGetMode() { + WRAP_WATCOM_CALL0(gmouse_3d_get_mode_) +} + +void __stdcall Gmouse3dSetMode(long mode) { + WRAP_WATCOM_CALL1(gmouse_3d_set_mode_, mode) +} + long __stdcall GsoundBackgroundVolumeGetSet(long setVolume) { WRAP_WATCOM_CALL1(gsound_background_volume_get_set_, setVolume) } @@ -1480,7 +1507,7 @@ long __fastcall GetTopWindowID(long xPos, long yPos) { } enum WinNameType { - WINTYPE_Inventory = 0, // any inventory window + WINTYPE_Inventory = 0, // any inventory window (player/loot/use/barter) WINTYPE_Dialog = 1, WINTYPE_PipBoy = 2, WINTYPE_WorldMap = 3, diff --git a/sfall/FalloutEngine.h b/sfall/FalloutEngine.h index fbeb158a..0dde5ad8 100644 --- a/sfall/FalloutEngine.h +++ b/sfall/FalloutEngine.h @@ -1139,8 +1139,10 @@ void __fastcall RegisterObjectCall(long* target, long* source, void* func, long long __fastcall ScrGetLocalVar(long sid, long varId, long* value); long __fastcall ScrSetLocalVar(long sid, long varId, long value); +long __stdcall IntfaceIsHidden(); + // redraws the main game interface windows (useful after changing some data like active hand, etc.) -void __stdcall InterfaceRedraw(); +void __stdcall IntfaceRedraw(); void __stdcall ProcessBk(); @@ -1186,6 +1188,8 @@ long __stdcall WinRegisterButton(DWORD winRef, long xPos, long yPos, long width, void __stdcall DialogOut(const char* text); +long __fastcall DialogOutEx(const char* text, const char** textEx, long count, long flags); + void __fastcall WindowDisplayBuf(long x, long width, long y, long height, void* data, long noTrans); void __fastcall DisplayInWindow(long w_here, long width, long height, void* data); @@ -1196,6 +1200,10 @@ long __fastcall GetGameConfigString(const char* outValue, const char* section, c long __fastcall WordWrap(const char* text, int maxWidth, DWORD* buf, BYTE* count); +long __stdcall Gmouse3dGetMode(); + +void __stdcall Gmouse3dSetMode(long mode); + long __stdcall GsoundBackgroundVolumeGetSet(long setVolume); WINinfo* __stdcall GNWFind(long winRef); diff --git a/sfall/PartyControl.cpp b/sfall/PartyControl.cpp index 2b762d85..75c62181 100644 --- a/sfall/PartyControl.cpp +++ b/sfall/PartyControl.cpp @@ -160,7 +160,7 @@ static void TakeControlOfNPC(TGameObj* npc) { delayedExperience = 0; SetInventoryCheck(true); - InterfaceRedraw(); + IntfaceRedraw(); } // restores the real dude state @@ -195,7 +195,7 @@ static void RestoreRealDudeState(bool redraw = true) { SafeWrite8(0x422BDE, 1); } - if (redraw) InterfaceRedraw(); + if (redraw) IntfaceRedraw(); SetInventoryCheck(false); isControllingNPC = false; diff --git a/sfall/ScriptExtender.cpp b/sfall/ScriptExtender.cpp index 72a4fda8..8faab9d8 100644 --- a/sfall/ScriptExtender.cpp +++ b/sfall/ScriptExtender.cpp @@ -417,6 +417,7 @@ static const SfallOpcodeMetadata opcodeMetaArray[] = { {sf_add_g_timer_event, "add_g_timer_event", {DATATYPE_MASK_INT, DATATYPE_MASK_INT}}, {sf_add_trait, "add_trait", {DATATYPE_MASK_INT}}, {sf_create_win, "create_win", {DATATYPE_MASK_STR, DATATYPE_MASK_INT, DATATYPE_MASK_INT, DATATYPE_MASK_INT, DATATYPE_MASK_INT, DATATYPE_MASK_INT}}, + {sf_dialog_box, "dialog_box", {DATATYPE_MASK_STR, DATATYPE_MASK_STR, DATATYPE_MASK_STR}}, {sf_draw_image, "draw_image", {DATATYPE_MASK_INT | DATATYPE_MASK_STR, DATATYPE_MASK_INT, DATATYPE_MASK_INT, DATATYPE_MASK_INT, DATATYPE_MASK_INT}}, {sf_draw_image_scaled, "draw_image_scaled", {DATATYPE_MASK_INT | DATATYPE_MASK_STR, DATATYPE_MASK_INT, DATATYPE_MASK_INT, DATATYPE_MASK_INT, DATATYPE_MASK_INT, DATATYPE_MASK_INT}}, {sf_hide_window, "hide_window", {DATATYPE_MASK_STR}}, diff --git a/sfall/ScriptOps/InterfaceOp.hpp b/sfall/ScriptOps/InterfaceOp.hpp index 8ba555fe..a2760183 100644 --- a/sfall/ScriptOps/InterfaceOp.hpp +++ b/sfall/ScriptOps/InterfaceOp.hpp @@ -168,13 +168,15 @@ static void __declspec(naked) resume_game() { } } -static bool dialogShow = false; static void _stdcall create_message_window2() { const ScriptValue &strArg = opHandler.arg(0); if (strArg.isString()) { + static bool dialogShow = false; if (dialogShow) return; + const char* str = strArg.strValue(); if (!str || str[0] == 0) return; + dialogShow = true; DialogOut(str); dialogShow = false; @@ -187,6 +189,26 @@ static void __declspec(naked) create_message_window() { _WRAP_OPCODE(create_message_window2, 1, 0) } +static void sf_dialog_box() { + const char* str = opHandler.arg(0).strValue(); + if (!str || str[0] == 0) return; + + const char* str2[2]; + long lines = 0; + if (opHandler.numArgs() > 1) { + ++lines; + str2[0] = opHandler.arg(1).strValue(); + } + if (opHandler.numArgs() > 2) { + ++lines; + str2[1] = opHandler.arg(2).strValue(); + } + *(DWORD*)_script_engine_running = 0; + long result = DialogOutEx(str, str2, lines, DIALOGOUT_NORMAL | DIALOGOUT_YESNO); + *(DWORD*)_script_engine_running = 1; + opHandler.setReturn(result); +} + static void __declspec(naked) GetViewportX() { __asm { mov edx, ds:[_wmWorldOffsetX]; @@ -302,7 +324,7 @@ static void __declspec(naked) IsIfaceTagActive() { } static void sf_intface_redraw() { - InterfaceRedraw(); + IntfaceRedraw(); } static void sf_intface_show() { @@ -314,12 +336,7 @@ static void sf_intface_hide() { } static void sf_intface_is_hidden() { - int isHidden; - __asm { - call intface_is_hidden_; - mov isHidden, eax; - } - opHandler.setReturn(isHidden); + opHandler.setReturn(IntfaceIsHidden()); } static void sf_tile_refresh_display() { @@ -327,20 +344,11 @@ static void sf_tile_refresh_display() { } static void sf_get_cursor_mode() { - int cursorMode; - __asm { - call gmouse_3d_get_mode_; - mov cursorMode, eax; - } - opHandler.setReturn(cursorMode); + opHandler.setReturn(Gmouse3dGetMode()); } static void sf_set_cursor_mode() { - int cursorMode = opHandler.arg(0).rawValue(); - __asm { - mov eax, cursorMode; - call gmouse_3d_set_mode_; - } + Gmouse3dSetMode(opHandler.arg(0).rawValue()); } static void sf_display_stats() { @@ -590,8 +598,7 @@ static void sf_draw_image_scaled() { } // initialize other args int frameno = 0, x = 0, y = 0, wsize = 0; - const int argNums = opHandler.numArgs(); - switch (argNums) { + switch (opHandler.numArgs()) { case 6: case 5: wsize = opHandler.arg(4).rawValue(); @@ -611,17 +618,17 @@ static void sf_draw_image_scaled() { framePtr = (FrmFrameData*)offsFrame; } } - if (argNums < 3) { + if (opHandler.numArgs() < 3) { DisplayInWindow(framePtr->width, framePtr->width, framePtr->height, framePtr->data); // scaled to window size (w/o transparent) } else { // draw to scale long s_width, s_height; - if (argNums < 5) { + if (opHandler.numArgs() < 5) { s_width = framePtr->width; s_height = framePtr->height; } else { s_width = wsize; - s_height = (argNums > 5) ? opHandler.arg(5).rawValue() : -1; + s_height = (opHandler.numArgs() > 5) ? opHandler.arg(5).rawValue() : -1; } // scale with aspect ratio if w or h is set to -1 if (s_width <= -1 && s_height > 0) { @@ -708,30 +715,42 @@ static void sf_unwield_slot() { } void sf_get_window_attribute() { - const ScriptValue &winArg = opHandler.arg(0), - &attrArg = opHandler.arg(1); - - if (winArg.isInt() && attrArg.isInt()) { + const ScriptValue &winArg = opHandler.arg(0); + if (winArg.isInt()) { + long attr = 0; + if (opHandler.numArgs() > 1) { + const ScriptValue &attrArg = opHandler.arg(1); + if (!attrArg.isInt()) goto invalidArgs; + attr = attrArg.rawValue(); + } WINinfo* win = GetUIWindow(winArg.rawValue()); if (win == nullptr) { - opHandler.printOpcodeError("get_window_attribute() - failed to get the interface window."); + if (attr != 0) { + opHandler.printOpcodeError("get_window_attribute() - failed to get the interface window."); + opHandler.setReturn(-1); + } return; } if ((long)win == -1) { opHandler.printOpcodeError("get_window_attribute() - invalid window type number."); + opHandler.setReturn(-1); return; } - long pos = 0; - switch (attrArg.rawValue()) { - case 0: // x - pos = win->wRect.left; + long result = 0; + switch (attr) { + case 0: // check if window exists + result = 1; break; - case 1: // y - pos = win->wRect.top; + case 1: // x + result = win->wRect.left; + break; + case 2: // y + result = win->wRect.top; break; } - opHandler.setReturn(pos); + opHandler.setReturn(result); } else { +invalidArgs: OpcodeInvalidArgs("get_window_attribute"); opHandler.setReturn(0); } diff --git a/sfall/ScriptOps/MetaruleOp.hpp b/sfall/ScriptOps/MetaruleOp.hpp index b60cc93d..a216bbcb 100644 --- a/sfall/ScriptOps/MetaruleOp.hpp +++ b/sfall/ScriptOps/MetaruleOp.hpp @@ -126,6 +126,7 @@ static const SfallMetarule metaruleArray[] = { {"create_win", sf_create_win, 5, 6}, {"critter_inven_obj2", sf_critter_inven_obj2, 2, 2}, {"dialog_obj", sf_get_dialog_object, 0, 0}, + {"dialog_box", sf_dialog_box, 1, 3}, {"display_stats", sf_display_stats, 0, 0}, // refresh {"draw_image", sf_draw_image, 1, 5}, {"draw_image_scaled", sf_draw_image_scaled, 1, 6}, @@ -141,7 +142,7 @@ static const SfallMetarule metaruleArray[] = { {"get_outline", sf_get_outline, 1, 1}, {"get_sfall_arg_at", sf_get_sfall_arg_at, 1, 1}, {"get_text_width", sf_get_text_width, 1, 1}, - {"get_window_attribute", sf_get_window_attribute, 2, 2}, + {"get_window_attribute", sf_get_window_attribute, 1, 2}, {"hide_window", sf_hide_window, 0, 1}, {"intface_hide", sf_intface_hide, 0, 0}, {"intface_is_hidden", sf_intface_is_hidden, 0, 0}, diff --git a/sfall/ScriptOps/WorldmapOps.hpp b/sfall/ScriptOps/WorldmapOps.hpp index 0869b53b..6d43d0ab 100644 --- a/sfall/ScriptOps/WorldmapOps.hpp +++ b/sfall/ScriptOps/WorldmapOps.hpp @@ -81,31 +81,29 @@ static void _stdcall ForceEncounter2() { const ScriptValue &mapIDArg = opHandler.arg(0); if (mapIDArg.isInt()) { + DWORD flags = 0; + if (opHandler.numArgs() > 1) { + const ScriptValue &flagsArg = opHandler.arg(1); + if (!flagsArg.isInt()) goto invalidArgs; + flags = flagsArg.rawValue(); + if (flags & 2) { // _Lock flag + flags |= (1 << 31); // set bit 31 + } else { + flags &= ~(1 << 31); + } + } DWORD mapID = mapIDArg.rawValue(); if (mapID < 0) { - opHandler.printOpcodeError("force_encounter() - invalid map number."); + opHandler.printOpcodeError("force_encounter/force_encounter_with_flags() - invalid map number."); return; } if (ForceEncounterMapID == -1) MakeJump(0x4C06D1, wmRndEncounterOccurred_hack); ForceEncounterMapID = mapID; - DWORD flags = 0; - if (opHandler.numArgs() > 1) { - const ScriptValue &flagsArg = opHandler.arg(1); - if (flagsArg.isInt()) { - flags = opHandler.arg(1).rawValue(); - if (flags & 2) { // _Lock flag - flags |= (1 << 31); // set bit 31 - } else { - flags &= ~(1 << 31); - } - } else { - opHandler.printOpcodeError("force_encounter_with_flags() - invalid flags."); - } - } ForceEncounterFlags = flags; } else { - OpcodeInvalidArgs("force_encounter"); +invalidArgs: + OpcodeInvalidArgs("force_encounter/force_encounter_with_flags"); } }