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.
This commit is contained in:
NovaRain
2019-11-29 11:52:35 +08:00
parent 11fee91f2f
commit 84076a2586
7 changed files with 63 additions and 46 deletions
+5 -1
View File
@@ -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)
+10 -7
View File
@@ -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);
+3 -3
View File
@@ -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_;
+5 -5
View File
@@ -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) {
+1 -1
View File
@@ -92,7 +92,7 @@ void __declspec(naked) op_game_loaded() {
movzx edx, al;
mov eax, ebx;
_RET_VAL_INT;
pop ecx;
pop ecx;
retn;
}
}
+38 -28
View File
@@ -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) {
+1 -1
View File
@@ -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;