From 19f4901328508bdc7fda56827bebc17be3f3c5d7 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Fri, 31 Jan 2020 00:24:25 +0800 Subject: [PATCH] Small optimization for receiving/passing script arguments * combined related engine interpreter functions into a single function for aligning the compiled ASM code better. Minor changes to some other code and documents. --- artifacts/scripting/headers/define_extra.h | 12 ++- artifacts/scripting/sfall function notes.txt | 4 +- sfall/FalloutEngine/Enums.h | 2 +- sfall/FalloutEngine/Functions.cpp | 87 +++++++++++++------ sfall/FalloutEngine/Functions.h | 14 ++- .../Modules/Scripting/Handlers/Interface.cpp | 6 +- sfall/Modules/Scripting/Handlers/Metarule.cpp | 8 +- sfall/Modules/Scripting/OpcodeContext.cpp | 20 +---- sfall/Modules/Worldmap.cpp | 27 +++--- 9 files changed, 97 insertions(+), 83 deletions(-) diff --git a/artifacts/scripting/headers/define_extra.h b/artifacts/scripting/headers/define_extra.h index 8702c8e9..eb8c4886 100644 --- a/artifacts/scripting/headers/define_extra.h +++ b/artifacts/scripting/headers/define_extra.h @@ -87,7 +87,7 @@ #define FLAG_SEEN (0x40000000) #define FLAG_SHOOTTHRU (0x80000000) -/* Critter Flags */ +/* Critter flags */ #define CFLG_BARTER 2 // 0x00000002 - Barter (can trade with) #define CFLG_NOSTEAL 32 // 0x00000020 - Steal (cannot steal from) #define CFLG_NODROP 64 // 0x00000040 - Drop (doesn't drop items) @@ -100,12 +100,20 @@ #define CFLG_RANGED 8192 // 0x00002000 - Range (melee attack is possible at a distance) #define CFLG_NOKNOCKDOWN 16384 // 0x00004000 - Knock (cannot be knocked down) -/* Window Flags */ +/* Window flags */ #define WIN_FLAG_MOVEONTOP (0x4) #define WIN_FLAG_HIDDEN (0x8) #define WIN_FLAG_EXCLUSIVE (0x10) #define WIN_FLAG_TRANSPARENT (0x20) +/* Message window flags */ +#define MSGBOX_AUTOSIZE (0x0) +#define MSGBOX_NORMAL (0x1) +#define MSGBOX_SMALL (0x2) +#define MSGBOX_ALIGN_LEFT (0x4) // text aligned to left +#define MSGBOX_ALIGN_TOP (0x8) // text aligned to top +#define MSGBOX_YESNO (0x10) // uses YES/NO buttons instead of DONE +#define MSGBOX_CLEAN (0x20) // no buttons //remove inven obj defines #define RMOBJ_CONSUME_DRUG 4666772 diff --git a/artifacts/scripting/sfall function notes.txt b/artifacts/scripting/sfall function notes.txt index 04377ec6..34d83043 100644 --- a/artifacts/scripting/sfall function notes.txt +++ b/artifacts/scripting/sfall function notes.txt @@ -718,11 +718,11 @@ optional argument: - areaID: the ID number of the town from city.txt > int sfall_func4("message_box", string message, int flags, int color1, int color2) -- creates a dialog box with text and returns the result of pressing the button: 0 - No, 1 - Yes/Done +- creates a dialog box with text and returns the result of pressing the button: 0 - No (Escape), 1 - Yes/Done (Enter) - returns -1 if for some reason the dialog box cannot be created - 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 DIALOGOUT_* constants in define_extra.h). Pass -1 to skip setting the flags (default flags are DIALOGOUT_NORMAL|DIALOGOUT_YESNO) +- 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) ------------------------ diff --git a/sfall/FalloutEngine/Enums.h b/sfall/FalloutEngine/Enums.h index a0c2d0e7..cd918c4e 100644 --- a/sfall/FalloutEngine/Enums.h +++ b/sfall/FalloutEngine/Enums.h @@ -795,7 +795,7 @@ enum DialogOutFlags : long 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_YESNO = 0x10, // DONE button replaced by YES/NO buttons DIALOGOUT_CLEAN = 0x20 // no buttons }; diff --git a/sfall/FalloutEngine/Functions.cpp b/sfall/FalloutEngine/Functions.cpp index 7cb510cc..7be1802d 100644 --- a/sfall/FalloutEngine/Functions.cpp +++ b/sfall/FalloutEngine/Functions.cpp @@ -228,24 +228,48 @@ DWORD __stdcall interpretPopLong(Program* scriptPtr) { WRAP_WATCOM_CALL1(interpretPopLong_, scriptPtr) } -// pushes value to Data stack (must be followed by InterpretPushShort) -void __stdcall interpretPushLong(Program* scriptPtr, DWORD val) { - WRAP_WATCOM_CALL2(interpretPushLong_, scriptPtr, val) -} - -// pushes value type to Data stack (must be preceded by InterpretPushLong) -void __stdcall interpretPushShort(Program* scriptPtr, DWORD valType) { - WRAP_WATCOM_CALL2(interpretPushShort_, scriptPtr, valType) -} - -DWORD __stdcall interpretAddString(Program* scriptPtr, const char* strval) { - WRAP_WATCOM_CALL2(interpretAddString_, scriptPtr, strval) -} - const char* __fastcall interpretGetString(Program* scriptPtr, DWORD dataType, DWORD strId) { WRAP_WATCOM_FCALL3(interpretGetString_, scriptPtr, dataType, strId) } +void interpretReturnValue(Program* scriptPtr, DWORD val, DWORD valType) { + __asm { + mov esi, scriptPtr; + mov edx, val; + cmp valType, VAR_TYPE_STR; + jne isNotStr; + mov eax, esi; + call fo::funcoffs::interpretAddString_; + mov edx, eax; +isNotStr: + mov eax, esi; + call fo::funcoffs::interpretPushLong_; // pushes value to Data stack (must be followed by InterpretPushShort) + mov edx, valType; + mov eax, esi; + call fo::funcoffs::interpretPushShort_; // pushes value type to Data stack (must be preceded by InterpretPushLong) + } +} + +DWORD __fastcall interpretGetValue(Program* scriptPtr, DWORD &outType) { + __asm { + mov eax, ecx; + call fo::funcoffs::interpretPopShort_; // pops value type from Data stack (must be followed by InterpretPopLong) + mov [edx], eax; // out type + mov edx, eax; + mov eax, ecx; + call fo::funcoffs::interpretPopLong_; // pops value from Data stack (must be preceded by InterpretPopShort) + cmp dx, VAR_TYPE_STR2; + je getStr; + cmp dx, VAR_TYPE_STR; + jne isNotStr; +getStr: + mov ebx, eax; + mov eax, ecx; + call fo::funcoffs::interpretGetString_; // retrieve string argument +isNotStr: + } +} + // prints scripting error in debug.log and stops current script execution by performing longjmp // USE WITH CAUTION void __declspec(naked) interpretError(const char* fmt, ...) { @@ -402,37 +426,44 @@ long __stdcall win_register_button(DWORD winRef, long xPos, long yPos, long widt } } -void __fastcall DialogOut(const char* text, const char** textEx, long lines) { +void __stdcall DialogOut(const char* text) { __asm { push 1; // DIALOGOUT_NORMAL flag - xor eax, eax; - mov al, byte ptr ds:[0x6AB718]; - push eax; // ColorMsg - push 0; // DisplayMsg (unknown) - push eax; // ColorIndex - mov eax, ecx; // DisplayText - push 116; // y + xor edx, edx; + push edx; + push edx; + mov dl, byte ptr ds:[0x6AB718]; + push edx; // ColorMsg mov ecx, 192; // x - mov ebx, lines; // count text lines 0-5 + push 116; // y + mov eax, text; // DisplayText + xor ebx, ebx; call fo::funcoffs::dialog_out_; } } long __fastcall DialogOutEx(const char* text, const char** textEx, long lines, long flags, long colors) { __asm { + mov ebx, colors; // Color index xor eax, eax; - mov ebx, colors;// Color index + push flags; + test ebx, ebx; + jnz cColor; + mov al, byte ptr ds:[0x6AB718]; + mov bl, al; + jmp skip; +cColor: mov al, bh; - push flags; // flag and ebx, 0xFF +skip: push eax; // ColorMsg2 push 0; // DisplayMsg (unknown) - mov eax, ecx; // DisplayText first line + mov eax, ecx; // DisplayText (first line) push ebx; // ColorMsg1 mov ecx, 192; // x push 116; // y - mov ebx, lines; // count text lines 0-5 - call fo::funcoffs::dialog_out_; // edx - DisplayText second and later lines + mov ebx, lines; // count second lines + call fo::funcoffs::dialog_out_; // edx - DisplayText (seconds lines) } } diff --git a/sfall/FalloutEngine/Functions.h b/sfall/FalloutEngine/Functions.h index 070dc15a..02e3ed0e 100644 --- a/sfall/FalloutEngine/Functions.h +++ b/sfall/FalloutEngine/Functions.h @@ -120,15 +120,11 @@ DWORD __stdcall interpretPopShort(Program* scriptPtr); // pops value from Data stack (must be preceded by InterpretPopShort) DWORD __stdcall interpretPopLong(Program* scriptPtr); -// pushes value to Data stack (must be followed by InterpretPushShort) -void __stdcall interpretPushLong(Program* scriptPtr, DWORD val); - -// pushes value type to Data stack (must be preceded by InterpretPushLong) -void __stdcall interpretPushShort(Program* scriptPtr, DWORD valType); - const char* __fastcall interpretGetString(Program* scriptPtr, DWORD dataType, DWORD strId); -DWORD __stdcall interpretAddString(Program* scriptPtr, const char* str); +void interpretReturnValue(Program* scriptPtr, DWORD val, DWORD valType); + +DWORD __fastcall interpretGetValue(Program* scriptPtr, DWORD &outType); // prints scripting error in debug.log and stops current script execution by performing longjmp // USE WITH CAUTION @@ -206,9 +202,9 @@ long __stdcall stat_level(GameObject* critter, long statId); // pictureUp/pictureDown - pointers to a surface long __stdcall win_register_button(DWORD winRef, long xPos, long yPos, long width, long height, long hoverOn, long hoverOff, long buttonDown, long buttonUp, BYTE* pictureUp, BYTE* pictureDown, long arg12, long buttonType); -void __fastcall DialogOut(const char* text, const char** textEx, long lines); +void __stdcall DialogOut(const char* text); -long __fastcall DialogOutEx(const char* text, const char** textEx, long lines, long flags, long colors); +long __fastcall DialogOutEx(const char* text, const char** textEx, long lines, long flags, long colors = 0); // draws an image to the buffer without scaling and with transparency display toggle void __fastcall windowDisplayBuf(long x, long width, long y, long height, void* data, long noTrans); diff --git a/sfall/Modules/Scripting/Handlers/Interface.cpp b/sfall/Modules/Scripting/Handlers/Interface.cpp index 1f41c868..6abb4ac6 100644 --- a/sfall/Modules/Scripting/Handlers/Interface.cpp +++ b/sfall/Modules/Scripting/Handlers/Interface.cpp @@ -130,14 +130,14 @@ void __declspec(naked) op_resume_game() { // copy and split static void SplitToBuffer(const char* str, const char** str_ptr, long &lines) { size_t i = 0; - do { + while (str[i]) { if (str[i] == '\n' && lines < 4) { ScriptExtender::gTextBuffer[i] = '\0'; str_ptr[lines++] = &ScriptExtender::gTextBuffer[++i]; } else { ScriptExtender::gTextBuffer[i] = str[i++]; } - } while (str[i]); + }; ScriptExtender::gTextBuffer[i] = '\0'; } @@ -153,7 +153,7 @@ void sf_create_message_window(OpcodeContext &ctx) { SplitToBuffer(str, str_ptr, lines); dialogShow = true; - fo::func::DialogOut(ScriptExtender::gTextBuffer, str_ptr, lines); + fo::func::DialogOutEx(ScriptExtender::gTextBuffer, str_ptr, lines, fo::DIALOGOUT_NORMAL); dialogShow = false; } diff --git a/sfall/Modules/Scripting/Handlers/Metarule.cpp b/sfall/Modules/Scripting/Handlers/Metarule.cpp index 983c6573..28c23ffa 100644 --- a/sfall/Modules/Scripting/Handlers/Metarule.cpp +++ b/sfall/Modules/Scripting/Handlers/Metarule.cpp @@ -163,12 +163,8 @@ static void sf_metarule_exist(OpcodeContext& ctx) { bool result = false; auto funcXName = ctx.arg(0).asString(); if (funcXName[0] != '\0') { - for (auto it = metaruleTable.begin(); it != metaruleTable.end(); it++) { - if (it->first == funcXName) { - result = true; - break; - } - } + const auto &it = metaruleTable.find(funcXName); + if (it != metaruleTable.cend()) result = true; } ctx.setReturn(result); } diff --git a/sfall/Modules/Scripting/OpcodeContext.cpp b/sfall/Modules/Scripting/OpcodeContext.cpp index 00d6c30d..ea872012 100644 --- a/sfall/Modules/Scripting/OpcodeContext.cpp +++ b/sfall/Modules/Scripting/OpcodeContext.cpp @@ -228,16 +228,9 @@ void OpcodeContext::_popArguments() { // process arguments on stack (reverse order) for (int i = _numArgs - 1; i >= 0; i--) { // get argument from stack - DWORD rawValueType = fo::func::interpretPopShort(_program); - DWORD rawValue = fo::func::interpretPopLong(_program); - DataType type = getSfallTypeByScriptType(rawValueType); - - // retrieve string argument - if (type == DataType::STR) { - _args[i] = fo::func::interpretGetString(_program, rawValueType, rawValue); - } else { - _args[i] = ScriptValue(type, rawValue); - } + DWORD rawValueType; + DWORD rawValue = fo::func::interpretGetValue(_program, rawValueType); + _args[i] = ScriptValue(getSfallTypeByScriptType(rawValueType), rawValue); } } @@ -245,12 +238,7 @@ void OpcodeContext::_pushReturnValue() { if (_ret.type() == DataType::NONE) { _ret = ScriptValue(0); // if no value was set in handler, force return 0 to avoid stack error } - DWORD rawResult = _ret.rawValue(); - if (_ret.type() == DataType::STR) { - rawResult = fo::func::interpretAddString(_program, _ret.strValue()); - } - fo::func::interpretPushLong(_program, rawResult); - fo::func::interpretPushShort(_program, getScriptTypeBySfallType(_ret.type())); + fo::func::interpretReturnValue(_program, _ret.rawValue(), getScriptTypeBySfallType(_ret.type())); } } diff --git a/sfall/Modules/Worldmap.cpp b/sfall/Modules/Worldmap.cpp index 3194a619..f4b26f4c 100644 --- a/sfall/Modules/Worldmap.cpp +++ b/sfall/Modules/Worldmap.cpp @@ -43,7 +43,7 @@ struct levelRest { std::unordered_map mapRestInfo; std::vector> wmTerrainTypeNames; // pair first: x + y * number of horizontal sub-tiles -std::vector> wmAreaHotSpotTitle; +std::unordered_map wmAreaHotSpotTitle; static bool restMap; static bool restMode; @@ -616,14 +616,13 @@ void Worldmap::SetTerrainTypeName(long x, long y, const char* name) { long subTileID = x + y * (fo::var::wmNumHorizontalTiles * 7); wmTerrainTypeNames.push_back(std::make_pair(subTileID, name)); } -/* + // TODO: someone might need to know the name of a terrain type? -const char* Worldmap::GetTerrainTypeName(long x, long y) { - //const char* name = GetOverrideTerrainName(x, y); - //return (name) ? name : fo::GetMessageStr(&fo::var::wmMsgFile, 1000 + fo::wmGetTerrainType(x, y)); - return nullptr; -} -*/ +/*const char* Worldmap::GetTerrainTypeName(long x, long y) { + const char* name = GetOverrideTerrainName(x, y); + return (name) ? name : fo::GetMessageStr(&fo::var::wmMsgFile, 1000 + fo::wmGetTerrainType(x, y)); +}*/ + // Returns the name of the terrain type in the position of the player's marker on the world map const char* Worldmap::GetCurrentTerrainName() { const char* name = GetOverrideTerrainName(fo::var::world_xpos / 50, fo::var::world_ypos / 50); @@ -635,17 +634,13 @@ bool Worldmap::AreaTitlesIsEmpty() { } void Worldmap::SetCustomAreaTitle(long areaID, const char* msg) { - wmAreaHotSpotTitle.push_back(std::make_pair(areaID, msg)); + wmAreaHotSpotTitle[areaID] = msg; } const char* Worldmap::GetCustomAreaTitle(long areaID) { - if (wmAreaHotSpotTitle.empty()) return nullptr; - - auto it = std::find_if(wmAreaHotSpotTitle.crbegin(), wmAreaHotSpotTitle.crend(), - [=](const std::pair &el) - { return el.first == areaID; } - ); - return (it != wmAreaHotSpotTitle.crend()) ? it->second.c_str() : nullptr; + if (AreaTitlesIsEmpty()) return nullptr; + const auto &it = wmAreaHotSpotTitle.find(areaID); + return (it != wmAreaHotSpotTitle.cend()) ? it->second.c_str() : nullptr; } void Worldmap::init() {