From 66c237d2974e9ee7fbc76d40b34bc478e7496592 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Fri, 29 Nov 2019 12:13:36 +0800 Subject: [PATCH] Refactored the code for "substr" script function * fixed the crashing bug and added a new behavior. Changed the error message due to missing critter frame (again): * replaced the interruption with printing the error message to in-game message window. --- artifacts/scripting/sfall function notes.txt | 5 +- sfall/DebugEditor.cpp | 17 ++- sfall/LoadGameHook.cpp | 6 +- sfall/ScriptExtender.h | 2 +- sfall/ScriptOps/ScriptArrays.hpp | 2 +- sfall/ScriptOps/ScriptUtils.hpp | 142 +++++++------------ 6 files changed, 70 insertions(+), 104 deletions(-) diff --git a/artifacts/scripting/sfall function notes.txt b/artifacts/scripting/sfall function notes.txt index df511166..227a3304 100644 --- a/artifacts/scripting/sfall function notes.txt +++ b/artifacts/scripting/sfall function notes.txt @@ -248,7 +248,10 @@ Some utility/math functions are available: - you can use this to search for a substring in a string like this: strlen(get_array(string_split(haystack, needle), 0)) > string substr(string, start, length) -- cuts a substring from a string starting at "start" up to "length" characters. If start is negative - it indicates starting position from the end of the string (for example substr("test", -2, 2) will return last 2 charactes: "st"). If length is negative - it means so many characters will be omitted from the end of string (example: substr("test", 0, -2) will return string without last 2 characters: "te") +- cuts a substring from a string starting at "start" up to "length" characters. The first character position starts with 0 (zero). +- If start is negative - it indicates starting position from the end of the string (for example substr("test", -2, 2) will return last 2 charactes: "st"). +- If length is negative - it means so many characters will be omitted from the end of string (example: substr("test", 0, -2) will return string without last 2 characters: "te"). +- If length is zero - it will return a string from the starting position to the end of the string **New behavior** for sfall 4.2.2/3.8.22 > int strlen(string string) - returns string length diff --git a/sfall/DebugEditor.cpp b/sfall/DebugEditor.cpp index f5cd8fa0..c03be412 100644 --- a/sfall/DebugEditor.cpp +++ b/sfall/DebugEditor.cpp @@ -313,12 +313,15 @@ artNotExist: push eax; push artDbgMsg; call debug_printf_; - add esp, 8; - cmp isDebug, 0; - jz skip; - int 3; // break program -skip: - retn; + mov eax, [esp + 0x124 - 0x1C + 12]; // filename + push eax; + push artDbgMsg; + lea eax, [esp + 0x124 - 0x124 + 20]; // buf + push eax; + call sprintf_; + add esp, 20; + lea eax, [esp + 4]; + jmp display_print_; } } @@ -357,7 +360,7 @@ static void DebugModePatch() { if (iniGetInt("Debugging", "HideObjIsNullMsg", 0, ddrawIniDef)) { MakeJump(0x453FD2, dbg_error_hack); } - // prints a debug message about missing art file for critters and interrupts game execution + // prints a debug message about missing art file for critters to debug.log and the message window HookCall(0x419B65, art_data_size_hook); dlogr(" Done", DL_INIT); diff --git a/sfall/LoadGameHook.cpp b/sfall/LoadGameHook.cpp index 016dbd4c..75e64f49 100644 --- a/sfall/LoadGameHook.cpp +++ b/sfall/LoadGameHook.cpp @@ -472,9 +472,9 @@ end: static void __declspec(naked) DialogHook() { __asm { - cmp dword ptr [esp + 0x14], 0x45A5C9; // call from op_gsay_end_ - je changeMode; - jmp gdProcess_; + test inLoop, DIALOG; // check bit flag + jz changeMode; + jmp gdProcess_; changeMode: or inLoop, DIALOG; call gdProcess_; diff --git a/sfall/ScriptExtender.h b/sfall/ScriptExtender.h index 5984a543..05e9119f 100644 --- a/sfall/ScriptExtender.h +++ b/sfall/ScriptExtender.h @@ -94,7 +94,7 @@ void _stdcall AddTimerEventScripts(DWORD script, long time, long param); void _stdcall RemoveTimerEventScripts(DWORD script, long param); void _stdcall RemoveTimerEventScripts(DWORD script); -char* _stdcall mysubstr(const char* str, int pos, int length); +char* _stdcall Substring(const char* str, int startPos, int length); // variables static char reg_anim_combat_check = 1; diff --git a/sfall/ScriptOps/ScriptArrays.hpp b/sfall/ScriptOps/ScriptArrays.hpp index 7d188e5d..63dd5545 100644 --- a/sfall/ScriptOps/ScriptArrays.hpp +++ b/sfall/ScriptOps/ScriptArrays.hpp @@ -151,7 +151,7 @@ callsubstr: push 1; push edi; push eax; - call mysubstr; + call Substring; mov edx, eax; // result substring mov ebx, VAR_TYPE_STR; // result type jmp end; diff --git a/sfall/ScriptOps/ScriptUtils.hpp b/sfall/ScriptOps/ScriptUtils.hpp index 8f8e8bb9..7712f8ed 100644 --- a/sfall/ScriptOps/ScriptUtils.hpp +++ b/sfall/ScriptOps/ScriptUtils.hpp @@ -513,30 +513,40 @@ end: } } -char* _stdcall mysubstr(const char* str, int pos, int length) { - char* newstr; - int srclen; - srclen = strlen(str); - if (pos < 0) - pos = srclen + pos; - if (length < 0) - length = srclen - pos + length; - if (pos >= srclen) - length = 0; - else if (length + pos > srclen) - length = srclen - pos; - newstr = new char[length + 1]; - if (length > 0) - memcpy(newstr, &str[pos], length); - newstr[length] = '\0'; - return newstr; +static char* tempTextBuf = nullptr; + +char* _stdcall Substring(const char* str, int startPos, int length) { + int len = strlen(str); + + if (startPos < 0) { + startPos += len; // start from end + if (startPos < 0) startPos = 0; + } + if (length < 0) { + length += len - startPos; // cutoff at end + if (length == 0) { + return ""; + } else if (length < 0) { + length = -length; // length can't be negative + } + } + // check position + if (startPos >= len) return ""; // start position is out of string length, return empty string + if (length == 0 || length + startPos > len) { + length = len - startPos; // set the correct length, the length of characters goes beyond the end of the string + } + + if (tempTextBuf) delete[] tempTextBuf; + tempTextBuf = new char[length + 1]; + memcpy(tempTextBuf, &str[startPos], length); + tempTextBuf[length] = '\0'; + return tempTextBuf; } static DWORD _stdcall mystrlen(const char* str) { return strlen(str); } -static char* sprintfbuf = nullptr; static char* _stdcall mysprintf(const char* format, DWORD value, DWORD valueType) { valueType = valueType & 0xFFFF; // use lower 2 bytes int fmtlen = strlen(format); @@ -601,87 +611,37 @@ static char* _stdcall mysprintf(const char* format, DWORD value, DWORD valueType } else { buflen = j + 30; // numbers } - if (sprintfbuf) { - delete[] sprintfbuf; + if (tempTextBuf) { + delete[] tempTextBuf; } - sprintfbuf = new char[buflen + 1]; + tempTextBuf = new char[buflen + 1]; if (valueType == VAR_TYPE_FLOAT) { - _snprintf(sprintfbuf, buflen, newfmt, *(float*)(&value)); + _snprintf(tempTextBuf, buflen, newfmt, *(float*)(&value)); } else { - _snprintf(sprintfbuf, buflen, newfmt, value); + _snprintf(tempTextBuf, buflen, newfmt, value); } - sprintfbuf[buflen] = '\0'; // just in case + tempTextBuf[buflen] = '\0'; // just in case delete[] newfmt; - return sprintfbuf; + return tempTextBuf; +} + +static void _stdcall op_substr2() { + const ScriptValue &strArg = opHandler.arg(0), + &startArg = opHandler.arg(1), + &lenArg = opHandler.arg(2); + + if (strArg.isString() && startArg.isInt() && lenArg.isInt()) { + const char* str = strArg.strValue(); + if (*str != '\0') str = Substring(str, startArg.rawValue(), lenArg.rawValue()); + opHandler.setReturn(str); + } else { + OpcodeInvalidArgs("substr"); + opHandler.setReturn(-1); + } } static void __declspec(naked) op_substr() { - __asm { - pushad; - mov edi, eax; - call interpretPopShort_; - push eax; - mov eax, edi; - call interpretPopLong_; // length - push eax; - mov eax, edi; - call interpretPopShort_; - push eax; - mov eax, edi; - call interpretPopLong_; // position - push eax; - mov eax, edi; - call interpretPopShort_; - push eax; - mov eax, edi; - call interpretPopLong_; // string - push eax; - - movzx eax, word ptr [esp+12]; - cmp eax, VAR_TYPE_INT; - jne fail; - movzx eax, word ptr [esp+20]; - cmp eax, VAR_TYPE_INT; - jne fail; - movzx eax, word ptr [esp+4]; - cmp eax, VAR_TYPE_STR2; - je next1; - cmp eax, VAR_TYPE_STR; - jne fail; -next1: - mov eax, edi; - mov edx, [esp+4]; - mov ebx, [esp]; - call interpretGetString_; - mov ebx, [esp+16]; - mov edx, [esp+8]; - push ebx; - push edx; - push eax; - call mysubstr; - mov edx, eax; - mov eax, edi; - call interpretAddString_; - mov edx, eax; - mov eax, edi; - call interpretPushLong_; - mov edx, VAR_TYPE_STR; - mov eax, edi; - call interpretPushShort_; - jmp end; -fail: - xor edx, edx; - dec edx; - mov eax, edi; - call interpretPushLong_; - mov edx, VAR_TYPE_INT; - mov eax, edi; - call interpretPushShort_; -end: - add esp, 24; - popad; - retn; - } + _WRAP_OPCODE(op_substr2, 3, 1) } static void __declspec(naked) op_strlen() {