diff --git a/artifacts/scripting/sfall function notes.txt b/artifacts/scripting/sfall function notes.txt index 4a7ee35b..2bdb4e27 100644 --- a/artifacts/scripting/sfall function notes.txt +++ b/artifacts/scripting/sfall function notes.txt @@ -262,7 +262,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 @@ -452,6 +455,7 @@ Some utility/math functions are available: > array sfall_func2("get_ini_section", string fileName, string section) - returns an associative array of keys and values for a given INI file and section +- NOTE: all keys and their values will be of String type > int sfall_func0("car_gas_amount") - returns current amount of fuel in player's car (between 0 and 80000) diff --git a/sfall/Modules/DebugEditor.cpp b/sfall/Modules/DebugEditor.cpp index 05836a2b..2e91c419 100644 --- a/sfall/Modules/DebugEditor.cpp +++ b/sfall/Modules/DebugEditor.cpp @@ -321,12 +321,15 @@ artNotExist: push eax; push artDbgMsg; call fo::funcoffs::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 fo::funcoffs::sprintf_; + add esp, 20; + lea eax, [esp + 4]; + jmp fo::funcoffs::display_print_; } } @@ -365,7 +368,7 @@ static void DebugModePatch() { if (iniGetInt("Debugging", "HideObjIsNullMsg", 0, ::sfall::ddrawIni)) { 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/Modules/LoadGameHook.cpp b/sfall/Modules/LoadGameHook.cpp index eb4ec310..2147ff27 100644 --- a/sfall/Modules/LoadGameHook.cpp +++ b/sfall/Modules/LoadGameHook.cpp @@ -523,9 +523,9 @@ end: static void __declspec(naked) DialogHook() { __asm { - cmp dword ptr [esp + 0x14], 0x45A5C9; // call from op_gsay_end_ - je changeMode; - jmp fo::funcoffs::gdProcess_; + test inLoop, DIALOG; // check bit flag + jz changeMode; + jmp fo::funcoffs::gdProcess_; changeMode: _InLoop(1, DIALOG); call fo::funcoffs::gdProcess_; diff --git a/sfall/Modules/Scripting/Handlers/Arrays.cpp b/sfall/Modules/Scripting/Handlers/Arrays.cpp index a88780b8..7d76a586 100644 --- a/sfall/Modules/Scripting/Handlers/Arrays.cpp +++ b/sfall/Modules/Scripting/Handlers/Arrays.cpp @@ -31,7 +31,7 @@ namespace script void sf_create_array(OpcodeContext& ctx) { auto arrayId = CreateArray(ctx.arg(0).rawValue(), ctx.arg(1).rawValue()); - ctx.setReturn(arrayId, DataType::INT); + ctx.setReturn(arrayId); } void sf_set_array(OpcodeContext& ctx) { @@ -55,7 +55,7 @@ void sf_get_array(OpcodeContext& ctx) { ); } else if (ctx.arg(0).isString()) { if (ctx.arg(1).isInt()) { - auto str = Substring(ctx.arg(0).strValue(), ctx.arg(1).rawValue(), 1); + const char* str = Substring(ctx.arg(0).strValue(), ctx.arg(1).rawValue(), 1); ctx.setReturn(str); // returns char of string } else { ctx.printOpcodeError("%s() - index must be numeric when used on a string.", ctx.getOpcodeName()); @@ -83,7 +83,7 @@ void sf_resize_array(OpcodeContext& ctx) { void sf_temp_array(OpcodeContext& ctx) { auto arrayId = TempArray(ctx.arg(0).rawValue(), ctx.arg(1).rawValue()); - ctx.setReturn(arrayId, DataType::INT); + ctx.setReturn(arrayId); } void sf_fix_array(OpcodeContext& ctx) { @@ -200,7 +200,7 @@ static DWORD ListAsArray(DWORD type) { void sf_list_as_array(OpcodeContext& ctx) { auto arrayId = ListAsArray(ctx.arg(0).rawValue()); - ctx.setReturn(arrayId, DataType::INT); + ctx.setReturn(arrayId); } static DWORD ListBegin(DWORD type) { @@ -212,7 +212,7 @@ static DWORD ListBegin(DWORD type) { } void sf_list_begin(OpcodeContext& ctx) { - ctx.setReturn(ListBegin(ctx.arg(0).rawValue()), DataType::INT); + ctx.setReturn(ListBegin(ctx.arg(0).rawValue())); } static fo::GameObject* ListNext(sList* list) { diff --git a/sfall/Modules/Scripting/Handlers/Misc.cpp b/sfall/Modules/Scripting/Handlers/Misc.cpp index de65a97e..dc6aa34f 100644 --- a/sfall/Modules/Scripting/Handlers/Misc.cpp +++ b/sfall/Modules/Scripting/Handlers/Misc.cpp @@ -92,7 +92,7 @@ void __declspec(naked) op_game_loaded() { movzx edx, al; mov eax, ebx; _RET_VAL_INT; - pop ecx; + pop ecx; retn; } } diff --git a/sfall/Modules/Scripting/Handlers/Utils.cpp b/sfall/Modules/Scripting/Handlers/Utils.cpp index 6f542d81..3f640b47 100644 --- a/sfall/Modules/Scripting/Handlers/Utils.cpp +++ b/sfall/Modules/Scripting/Handlers/Utils.cpp @@ -190,29 +190,40 @@ void sf_string_split(OpcodeContext& ctx) { ctx.setReturn(StringSplit(ctx.arg(0).strValue(), ctx.arg(1).strValue())); } -char* Substring(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]; // memory leak!!! - if (length > 0) - memcpy(newstr, &str[pos], length); - newstr[length] = '\0'; - return newstr; +static char* tempTextBuf = nullptr; + +char* 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; } void sf_substr(OpcodeContext& ctx) { - ctx.setReturn( - Substring(ctx.arg(0).strValue(), ctx.arg(1).rawValue(), ctx.arg(2).rawValue()) - ); + const char* str = ctx.arg(0).strValue(); + if (*str != '\0') str = Substring(str, ctx.arg(1).rawValue(), ctx.arg(2).rawValue()); + ctx.setReturn(str); } void sf_string_compare(OpcodeContext& ctx) { @@ -225,7 +236,6 @@ void sf_string_compare(OpcodeContext& ctx) { } } -static char* sprintfbuf = nullptr; // A safer version of sprintf for using in user scripts. static char* _stdcall sprintf_lite(const char* format, ScriptValue value) { int fmtlen = strlen(format); @@ -290,18 +300,18 @@ static char* _stdcall sprintf_lite(const char* format, ScriptValue value) { } else { buflen = j + 30; // numbers } - if (sprintfbuf) { - delete[] sprintfbuf; + if (tempTextBuf) { + delete[] tempTextBuf; } - sprintfbuf = new char[buflen + 1]; + tempTextBuf = new char[buflen + 1]; if (value.isFloat()) { - _snprintf(sprintfbuf, buflen, newfmt, value.floatValue()); + _snprintf(tempTextBuf, buflen, newfmt, value.floatValue()); } else { - _snprintf(sprintfbuf, buflen, newfmt, value.rawValue()); + _snprintf(tempTextBuf, buflen, newfmt, value.rawValue()); } - sprintfbuf[buflen] = '\0'; // just in case + tempTextBuf[buflen] = '\0'; // just in case delete[] newfmt; - return sprintfbuf; + return tempTextBuf; } void sf_sprintf(OpcodeContext& ctx) { diff --git a/sfall/Modules/Scripting/Handlers/Utils.h b/sfall/Modules/Scripting/Handlers/Utils.h index ed2be87a..0477c169 100644 --- a/sfall/Modules/Scripting/Handlers/Utils.h +++ b/sfall/Modules/Scripting/Handlers/Utils.h @@ -23,7 +23,7 @@ namespace sfall namespace script { -char* Substring(const char* str, int pos, int length); +char* Substring(const char* str, int startPos, int length); class OpcodeContext;