mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Added "string_format" script function
Rewrote ASM code of opcode handlers in MemoryOp.hpp.
This commit is contained in:
@@ -277,6 +277,7 @@
|
|||||||
#define spatial_radius(obj) sfall_func1("spatial_radius", obj)
|
#define spatial_radius(obj) sfall_func1("spatial_radius", obj)
|
||||||
#define string_compare(str1, str2) sfall_func2("string_compare", str1, str2)
|
#define string_compare(str1, str2) sfall_func2("string_compare", str1, str2)
|
||||||
#define string_compare_locale(str1, str2, codePage) sfall_func3("string_compare", str1, str2, codePage)
|
#define string_compare_locale(str1, str2, codePage) sfall_func3("string_compare", str1, str2, codePage)
|
||||||
|
#define string_format(format, a1, a2) sfall_func3("string_format", format, a1, a2)
|
||||||
#define tile_refresh_display sfall_func0("tile_refresh_display")
|
#define tile_refresh_display sfall_func0("tile_refresh_display")
|
||||||
#define unjam_lock(obj) sfall_func1("unjam_lock", obj)
|
#define unjam_lock(obj) sfall_func1("unjam_lock", obj)
|
||||||
#define unset_unique_id(obj) sfall_func2("set_unique_id", obj, -1)
|
#define unset_unique_id(obj) sfall_func2("set_unique_id", obj, -1)
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ 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))
|
- 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)
|
> string substr(string, start, length)
|
||||||
- cuts a substring from a string starting at "start" up to "length" characters. The first character position starts with 0 (zero).
|
- cuts a substring from a string starting at "start" up to "length" characters. The first character position is 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 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 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
|
- 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
|
||||||
@@ -588,6 +588,10 @@ optional arguments:
|
|||||||
- codePage: code page number to properly compare national characters in the range 128-255 of the ASCII code table
|
- codePage: code page number to properly compare national characters in the range 128-255 of the ASCII code table
|
||||||
available encodings: 1250-1252, 866
|
available encodings: 1250-1252, 866
|
||||||
|
|
||||||
|
> string sfall_func3("string_format", string format, any val1, any val2, ...)
|
||||||
|
- formats given value using standard syntax of C printf function (google "printf" for format details). However it is limited to formatting up to 4 values
|
||||||
|
- formatting is only supported for %s and %d. The format string is limited to 1024 characters
|
||||||
|
|
||||||
------------------------
|
------------------------
|
||||||
------ MORE INFO -------
|
------ MORE INFO -------
|
||||||
------------------------
|
------------------------
|
||||||
|
|||||||
@@ -979,11 +979,10 @@ DWORD __stdcall InterpretAddString(TProgram* scriptPtr, const char* strval) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* __stdcall InterpretGetString(TProgram* scriptPtr, DWORD strId, DWORD dataType) {
|
const char* __fastcall InterpretGetString(TProgram* scriptPtr, DWORD dataType, DWORD strId) {
|
||||||
__asm {
|
__asm {
|
||||||
mov edx, dataType;
|
|
||||||
mov ebx, strId;
|
mov ebx, strId;
|
||||||
mov eax, scriptPtr;
|
mov eax, ecx;
|
||||||
call interpretGetString_;
|
call interpretGetString_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1084,7 +1084,7 @@ void __stdcall InterpretPushLong(TProgram* scriptPtr, DWORD val);
|
|||||||
// pushes value type to Data stack (must be preceded by InterpretPushLong)
|
// pushes value type to Data stack (must be preceded by InterpretPushLong)
|
||||||
void __stdcall InterpretPushShort(TProgram* scriptPtr, DWORD valType);
|
void __stdcall InterpretPushShort(TProgram* scriptPtr, DWORD valType);
|
||||||
|
|
||||||
const char* __stdcall InterpretGetString(TProgram* scriptPtr, DWORD strId, DWORD dataType);
|
const char* __fastcall InterpretGetString(TProgram* scriptPtr, DWORD dataType, DWORD strId);
|
||||||
|
|
||||||
DWORD __stdcall InterpretAddString(TProgram* scriptPtr, const char* str);
|
DWORD __stdcall InterpretAddString(TProgram* scriptPtr, const char* str);
|
||||||
|
|
||||||
|
|||||||
@@ -337,7 +337,7 @@ public:
|
|||||||
|
|
||||||
// retrieve string argument
|
// retrieve string argument
|
||||||
if (type == DATATYPE_STR) {
|
if (type == DATATYPE_STR) {
|
||||||
_args[i] = InterpretGetString(program, rawValue, rawValueType);
|
_args[i] = InterpretGetString(program, rawValueType, rawValue);
|
||||||
} else {
|
} else {
|
||||||
_args[i] = ScriptValue(type, rawValue);
|
_args[i] = ScriptValue(type, rawValue);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
Gets argument from stack to eax and puts its type to edx register
|
Gets argument from stack to eax and puts its type to edx register
|
||||||
eax register must contain the script_ptr
|
eax register must contain the script_ptr
|
||||||
jlabel - name of the jump label in case the value type is not INT
|
jlabel - name of the jump label in case the value type is not INT
|
||||||
|
return: eax - arg value
|
||||||
*/
|
*/
|
||||||
#define _GET_ARG_INT(jlabel) __asm { \
|
#define _GET_ARG_INT(jlabel) __asm { \
|
||||||
__asm mov edx, eax \
|
__asm mov edx, eax \
|
||||||
@@ -131,6 +132,13 @@ notstring##num:
|
|||||||
__asm call interpretPushShort_ \
|
__asm call interpretPushShort_ \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define _J_RET_VAL_TYPE(type) __asm { \
|
||||||
|
__asm call interpretPushLong_ \
|
||||||
|
__asm mov edx, type \
|
||||||
|
__asm mov eax, ebx \
|
||||||
|
__asm jmp interpretPushShort_ \
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
handle return value which may be of any type
|
handle return value which may be of any type
|
||||||
num - any unique number
|
num - any unique number
|
||||||
|
|||||||
+151
-218
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* sfall
|
* sfall
|
||||||
* Copyright (C) 2008, 2009, 2010, 2012 The sfall team
|
* Copyright (C) 2008-2016 The sfall team
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -19,303 +19,236 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "ScriptExtender.h"
|
//#include "ScriptExtender.h"
|
||||||
|
|
||||||
|
#define START_VALID_ADDR 0x410000
|
||||||
|
#define END_VALID_ADDR 0x6B403F
|
||||||
|
|
||||||
// memory_reading_funcs
|
// memory_reading_funcs
|
||||||
static void __declspec(naked) ReadByte() {
|
static void __declspec(naked) ReadByte() {
|
||||||
__asm {
|
__asm {
|
||||||
push ebx;
|
_GET_ARG_INT(error);
|
||||||
push ecx;
|
test eax, eax;
|
||||||
push edx;
|
jz error;
|
||||||
mov ecx, eax;
|
movzx edx, byte ptr ds:[eax]; // read memory
|
||||||
call interpretPopShort_;
|
|
||||||
mov edx, eax;
|
|
||||||
mov eax, ecx;
|
|
||||||
call interpretPopLong_;
|
|
||||||
cmp dx, VAR_TYPE_INT;
|
|
||||||
jnz error;
|
|
||||||
movzx edx, byte ptr ds:[eax];
|
|
||||||
jmp result;
|
|
||||||
error:
|
|
||||||
mov edx, 0;
|
|
||||||
result:
|
result:
|
||||||
mov eax, ecx;
|
mov eax, ebx;
|
||||||
call interpretPushLong_;
|
_J_RET_VAL_TYPE(VAR_TYPE_INT);
|
||||||
mov edx, VAR_TYPE_INT;
|
// retn;
|
||||||
mov eax, ecx;
|
error:
|
||||||
call interpretPushShort_;
|
xor edx, edx;
|
||||||
pop edx;
|
jmp result;
|
||||||
pop ecx;
|
|
||||||
pop ebx;
|
|
||||||
retn;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __declspec(naked) ReadShort() {
|
static void __declspec(naked) ReadShort() {
|
||||||
__asm {
|
__asm {
|
||||||
push ebx;
|
_GET_ARG_INT(error);
|
||||||
push ecx;
|
test eax, eax;
|
||||||
push edx;
|
jz error;
|
||||||
mov ecx, eax;
|
movzx edx, word ptr ds:[eax]; // read memory
|
||||||
call interpretPopShort_;
|
|
||||||
mov edx, eax;
|
|
||||||
mov eax, ecx;
|
|
||||||
call interpretPopLong_;
|
|
||||||
cmp dx, VAR_TYPE_INT;
|
|
||||||
jnz error;
|
|
||||||
movzx edx, word ptr ds:[eax];
|
|
||||||
jmp result;
|
|
||||||
error:
|
|
||||||
mov edx, 0;
|
|
||||||
result:
|
result:
|
||||||
mov eax, ecx;
|
mov eax, ebx;
|
||||||
call interpretPushLong_;
|
_J_RET_VAL_TYPE(VAR_TYPE_INT);
|
||||||
mov edx, VAR_TYPE_INT;
|
// retn;
|
||||||
mov eax, ecx;
|
error:
|
||||||
call interpretPushShort_;
|
xor edx, edx;
|
||||||
pop edx;
|
jmp result;
|
||||||
pop ecx;
|
|
||||||
pop ebx;
|
|
||||||
retn;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __declspec(naked) ReadInt() {
|
static void __declspec(naked) ReadInt() {
|
||||||
__asm {
|
__asm {
|
||||||
push ebx;
|
_GET_ARG_INT(error);
|
||||||
push ecx;
|
test eax, eax;
|
||||||
push edx;
|
jz error;
|
||||||
mov ecx, eax;
|
mov edx, dword ptr ds:[eax]; // read memory
|
||||||
call interpretPopShort_;
|
|
||||||
mov edx, eax;
|
|
||||||
mov eax, ecx;
|
|
||||||
call interpretPopLong_;
|
|
||||||
cmp dx, VAR_TYPE_INT;
|
|
||||||
jnz error;
|
|
||||||
mov edx, dword ptr ds:[eax];
|
|
||||||
jmp result;
|
|
||||||
error:
|
|
||||||
mov edx, 0;
|
|
||||||
result:
|
result:
|
||||||
mov eax, ecx;
|
mov eax, ebx;
|
||||||
call interpretPushLong_;
|
_J_RET_VAL_TYPE(VAR_TYPE_INT);
|
||||||
mov edx, VAR_TYPE_INT;
|
// retn;
|
||||||
mov eax, ecx;
|
error:
|
||||||
call interpretPushShort_;
|
xor edx, edx;
|
||||||
pop edx;
|
jmp result;
|
||||||
pop ecx;
|
|
||||||
pop ebx;
|
|
||||||
retn;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __declspec(naked) ReadString() {
|
static void __declspec(naked) ReadString() {
|
||||||
__asm {
|
__asm {
|
||||||
push ebx;
|
_GET_ARG_INT(error);
|
||||||
push ecx;
|
test eax, eax;
|
||||||
push edx;
|
jz error;
|
||||||
mov ecx, eax;
|
mov edx, eax;
|
||||||
call interpretPopShort_;
|
|
||||||
mov edx, eax;
|
|
||||||
mov eax, ecx;
|
|
||||||
call interpretPopLong_;
|
|
||||||
cmp dx, VAR_TYPE_INT;
|
|
||||||
jnz error;
|
|
||||||
mov edx, eax;
|
|
||||||
jmp result;
|
|
||||||
error:
|
|
||||||
mov edx, 0;
|
|
||||||
result:
|
result:
|
||||||
mov eax, ecx;
|
mov eax, ebx;
|
||||||
call interpretPushLong_;
|
_J_RET_VAL_TYPE(VAR_TYPE_STR);
|
||||||
mov edx, VAR_TYPE_STR;
|
// retn;
|
||||||
mov eax, ecx;
|
error:
|
||||||
call interpretPushShort_;
|
xor edx, edx;
|
||||||
pop edx;
|
jmp result;
|
||||||
pop ecx;
|
|
||||||
pop ebx;
|
|
||||||
retn;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __declspec(naked) WriteByte() {
|
static void __declspec(naked) WriteByte() {
|
||||||
__asm {
|
__asm {
|
||||||
pushad
|
push ecx;
|
||||||
mov ecx, eax;
|
|
||||||
call interpretPopShort_;
|
call interpretPopShort_;
|
||||||
mov esi, eax;
|
mov ecx, eax; // type
|
||||||
mov eax, ecx;
|
mov eax, ebx;
|
||||||
call interpretPopLong_;
|
call interpretPopLong_;
|
||||||
mov edx, eax;
|
mov esi, eax; // write value
|
||||||
mov eax, ecx;
|
mov eax, ebx;
|
||||||
call interpretPopShort_;
|
_GET_ARG_INT(end);
|
||||||
mov edi, eax;
|
cmp cx, VAR_TYPE_INT;
|
||||||
mov eax, ecx;
|
jnz end;
|
||||||
call interpretPopLong_;
|
// check valid addr
|
||||||
cmp di, VAR_TYPE_INT;
|
cmp eax, START_VALID_ADDR;
|
||||||
jnz end;
|
jb end;
|
||||||
cmp si, VAR_TYPE_INT;
|
cmp eax, END_VALID_ADDR;
|
||||||
jnz end;
|
ja end;
|
||||||
//mov byte ptr ds:[eax], dl;
|
and esi, 0xFF;
|
||||||
and edx, 0xff;
|
push esi;
|
||||||
push edx;
|
|
||||||
push eax;
|
push eax;
|
||||||
call SafeWrite8;
|
call SafeWrite8;
|
||||||
end:
|
end:
|
||||||
popad;
|
pop ecx;
|
||||||
retn;
|
retn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __declspec(naked) WriteShort() {
|
static void __declspec(naked) WriteShort() {
|
||||||
__asm {
|
__asm {
|
||||||
pushad;
|
push ecx;
|
||||||
mov ecx, eax;
|
|
||||||
call interpretPopShort_;
|
call interpretPopShort_;
|
||||||
mov esi, eax;
|
mov ecx, eax; // type
|
||||||
mov eax, ecx;
|
mov eax, ebx;
|
||||||
call interpretPopLong_;
|
call interpretPopLong_;
|
||||||
mov edx, eax;
|
mov esi, eax; // write value
|
||||||
mov eax, ecx;
|
mov eax, ebx;
|
||||||
call interpretPopShort_;
|
_GET_ARG_INT(end);
|
||||||
mov edi, eax;
|
cmp cx, VAR_TYPE_INT;
|
||||||
mov eax, ecx;
|
jnz end;
|
||||||
call interpretPopLong_;
|
// check valid addr
|
||||||
cmp di, VAR_TYPE_INT;
|
cmp eax, START_VALID_ADDR;
|
||||||
jnz end;
|
jb end;
|
||||||
cmp si, VAR_TYPE_INT;
|
cmp eax, END_VALID_ADDR;
|
||||||
jnz end;
|
ja end;
|
||||||
//mov word ptr ds:[eax], dx;
|
and esi, 0xFFFF;
|
||||||
and edx, 0xffff;
|
push esi;
|
||||||
push edx;
|
|
||||||
push eax;
|
push eax;
|
||||||
call SafeWrite16;
|
call SafeWrite16;
|
||||||
end:
|
end:
|
||||||
popad;
|
pop ecx;
|
||||||
retn;
|
retn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __declspec(naked) WriteInt() {
|
static void __declspec(naked) WriteInt() {
|
||||||
__asm {
|
__asm {
|
||||||
pushad
|
push ecx;
|
||||||
mov ecx, eax;
|
|
||||||
call interpretPopShort_;
|
call interpretPopShort_;
|
||||||
mov esi, eax;
|
mov ecx, eax; // type
|
||||||
mov eax, ecx;
|
mov eax, ebx;
|
||||||
call interpretPopLong_;
|
call interpretPopLong_;
|
||||||
mov edx, eax;
|
mov esi, eax; // write value
|
||||||
mov eax, ecx;
|
mov eax, ebx;
|
||||||
call interpretPopShort_;
|
_GET_ARG_INT(end);
|
||||||
mov edi, eax;
|
cmp cx, VAR_TYPE_INT;
|
||||||
mov eax, ecx;
|
jnz end;
|
||||||
call interpretPopLong_;
|
// check valid addr
|
||||||
cmp di, VAR_TYPE_INT;
|
cmp eax, START_VALID_ADDR;
|
||||||
jnz end;
|
jb end;
|
||||||
cmp si, VAR_TYPE_INT;
|
cmp eax, END_VALID_ADDR;
|
||||||
jnz end;
|
ja end;
|
||||||
//mov dword ptr ds:[eax], edx;
|
push esi;
|
||||||
push edx;
|
|
||||||
push eax;
|
push eax;
|
||||||
call SafeWrite32;
|
call SafeWrite32;
|
||||||
end:
|
end:
|
||||||
popad
|
pop ecx;
|
||||||
retn;
|
retn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static void _stdcall WriteStringInternal(const char* str, char* addr) {
|
|
||||||
bool hitnull = false;
|
static void __fastcall WriteStringInternal(char* addr, long type, long strID, TProgram* script) {
|
||||||
|
const char* str = InterpretGetString(script, type, strID);
|
||||||
while (*str) {
|
while (*str) {
|
||||||
if (!*addr) hitnull = true;
|
if (!addr[0] && addr[1]) break; // addr[1] as *(addr + 1)
|
||||||
if (hitnull && addr[1]) break;
|
*addr++ = *str++;
|
||||||
*addr = *str;
|
|
||||||
addr++;
|
|
||||||
str++;
|
|
||||||
}
|
}
|
||||||
*addr = 0;
|
*addr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __declspec(naked) WriteString() {
|
static void __declspec(naked) WriteString() {
|
||||||
__asm {
|
__asm {
|
||||||
pushad;
|
push ecx;
|
||||||
mov ecx, eax;
|
|
||||||
call interpretPopShort_;
|
call interpretPopShort_;
|
||||||
mov esi, eax;
|
mov ecx, eax; // type
|
||||||
mov eax, ecx;
|
mov eax, ebx;
|
||||||
call interpretPopLong_;
|
call interpretPopLong_;
|
||||||
mov edi, eax;
|
mov esi, eax; // str value
|
||||||
mov eax, ecx;
|
mov eax, ebx;
|
||||||
call interpretPopShort_;
|
_GET_ARG_INT(end);
|
||||||
mov edx, eax;
|
cmp cx, VAR_TYPE_STR2;
|
||||||
mov eax, ecx;
|
je next;
|
||||||
call interpretPopLong_;
|
cmp cx, VAR_TYPE_STR;
|
||||||
cmp dx, VAR_TYPE_INT;
|
jnz end;
|
||||||
jnz end;
|
|
||||||
cmp si, VAR_TYPE_STR2;
|
|
||||||
jz next;
|
|
||||||
cmp si, VAR_TYPE_STR;
|
|
||||||
jnz end;
|
|
||||||
next:
|
next:
|
||||||
mov ebx, edi;
|
// ecx - type, esi - value
|
||||||
mov edx, esi;
|
// edx - type, eax - addr
|
||||||
mov esi, eax;
|
// check valid address
|
||||||
mov eax, ecx;
|
cmp eax, START_VALID_ADDR;
|
||||||
call interpretGetString_;
|
jb end;
|
||||||
push esi;
|
cmp eax, END_VALID_ADDR;
|
||||||
push eax;
|
ja end;
|
||||||
|
push ebx; // script
|
||||||
|
push esi; // str value
|
||||||
|
mov edx, ecx; // type
|
||||||
|
mov ecx, eax; // addr
|
||||||
call WriteStringInternal;
|
call WriteStringInternal;
|
||||||
jmp end;
|
|
||||||
end:
|
end:
|
||||||
popad;
|
pop ecx;
|
||||||
retn;
|
retn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static void _stdcall CallOffsetInternal(DWORD func, DWORD script) {
|
|
||||||
func = (func >> 2) - 0x1d2;
|
|
||||||
bool ret = func >= 5;
|
|
||||||
int argcount = func % 5;
|
|
||||||
DWORD args[5];
|
|
||||||
DWORD illegalarg = 0;
|
|
||||||
for (int i = argcount * 4; i >= 0; i -= 4) {
|
|
||||||
__asm {
|
|
||||||
mov eax, script;
|
|
||||||
call interpretPopShort_;
|
|
||||||
cmp ax, VAR_TYPE_INT;
|
|
||||||
jz legal;
|
|
||||||
inc illegalarg;
|
|
||||||
legal:
|
|
||||||
mov eax, script;
|
|
||||||
call interpretPopLong_;
|
|
||||||
lea ecx, args;
|
|
||||||
add ecx, i;
|
|
||||||
mov [ecx], eax;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (illegalarg) {
|
static void __fastcall CallOffsetInternal(TProgram* script, DWORD func) {
|
||||||
|
func = (func >> 2) - 0x1d2;
|
||||||
|
DWORD args[5];
|
||||||
|
DWORD illegalArg = 0;
|
||||||
|
int argCount = func % 5;
|
||||||
|
|
||||||
|
for (int i = argCount; i >= 0; i--) {
|
||||||
|
if ((short)InterpretPopShort(script) != (short)VAR_TYPE_INT) illegalArg++;
|
||||||
|
args[i] = InterpretPopLong(script);
|
||||||
|
}
|
||||||
|
if (illegalArg || args[0] < 0x410010 || args[0] > 0x4FCE34) {
|
||||||
args[0] = 0;
|
args[0] = 0;
|
||||||
} else {
|
} else {
|
||||||
__asm {
|
__asm {
|
||||||
mov eax, args[4]; // args[1]
|
mov eax, args[4];
|
||||||
mov edx, args[8]; // args[2]
|
mov edx, args[8];
|
||||||
mov ebx, args[12]; // args[3]
|
mov ebx, args[12];
|
||||||
mov ecx, args[16]; // args[4]
|
mov ecx, args[16];
|
||||||
mov edi, args[0]; // args[0]
|
call args[0];
|
||||||
call edi;
|
mov args[0], eax;
|
||||||
mov args[0], eax;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ret) {
|
if (func >= 5) { // has return
|
||||||
__asm {
|
__asm {
|
||||||
mov eax, script;
|
mov eax, script;
|
||||||
mov edx, args[0];
|
mov edx, args[0];
|
||||||
call interpretPushLong_;
|
mov ebx, eax;
|
||||||
mov eax, script;
|
_RET_VAL_INT2;
|
||||||
mov edx, VAR_TYPE_INT;
|
|
||||||
call interpretPushShort_;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __declspec(naked) CallOffset() {
|
static void __declspec(naked) CallOffset() {
|
||||||
__asm {
|
__asm {
|
||||||
pushad;
|
push ecx;
|
||||||
push eax;
|
mov ecx, eax;
|
||||||
push edx;
|
call CallOffsetInternal; // edx - func
|
||||||
call CallOffsetInternal;
|
pop ecx;
|
||||||
popad;
|
|
||||||
retn;
|
retn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,6 +169,7 @@ static const SfallMetarule metaruleArray[] = {
|
|||||||
{"show_window", sf_show_window, 0, 1},
|
{"show_window", sf_show_window, 0, 1},
|
||||||
{"spatial_radius", sf_spatial_radius, 1, 1},
|
{"spatial_radius", sf_spatial_radius, 1, 1},
|
||||||
{"string_compare", sf_string_compare, 2, 3},
|
{"string_compare", sf_string_compare, 2, 3},
|
||||||
|
{"string_format", sf_string_format, 2, 5},
|
||||||
{"tile_refresh_display", sf_tile_refresh_display, 0, 0},
|
{"tile_refresh_display", sf_tile_refresh_display, 0, 0},
|
||||||
{"unjam_lock", sf_unjam_lock, 1, 1},
|
{"unjam_lock", sf_unjam_lock, 1, 1},
|
||||||
{"unwield_slot", sf_unwield_slot, 2, 2},
|
{"unwield_slot", sf_unwield_slot, 2, 2},
|
||||||
|
|||||||
@@ -591,7 +591,7 @@ char* _stdcall Substring(const char* str, int startPos, int length) {
|
|||||||
if (length < 0) {
|
if (length < 0) {
|
||||||
length += len - startPos; // cutoff at end
|
length += len - startPos; // cutoff at end
|
||||||
if (length == 0) return "";
|
if (length == 0) return "";
|
||||||
abs(length); // length can't be negative
|
length = abs(length); // length can't be negative
|
||||||
}
|
}
|
||||||
// check position
|
// check position
|
||||||
if (startPos >= len) return ""; // start position is out of string length, return empty string
|
if (startPos >= len) return ""; // start position is out of string length, return empty string
|
||||||
@@ -782,6 +782,76 @@ fail:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sf_string_format() {
|
||||||
|
const ScriptValue &fmtArg = opHandler.arg(0);
|
||||||
|
|
||||||
|
if (!fmtArg.isString()) {
|
||||||
|
OpcodeInvalidArgs("string_format");
|
||||||
|
opHandler.setReturn(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* format = fmtArg.strValue();
|
||||||
|
|
||||||
|
int fmtLen = strlen(format);
|
||||||
|
if (fmtLen == 0) {
|
||||||
|
opHandler.setReturn(format);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (fmtLen > 1024) {
|
||||||
|
opHandler.printOpcodeError("string_format() - the format string exceeds maximum length of 1024 characters.");
|
||||||
|
opHandler.setReturn("Error");
|
||||||
|
} else {
|
||||||
|
char* newFmt = new char[fmtLen + 1];
|
||||||
|
newFmt[fmtLen] = '\0';
|
||||||
|
// parse format to make it safe
|
||||||
|
int i = 0, arg = 0, totalArg = opHandler.numArgs(); // total passed args
|
||||||
|
do {
|
||||||
|
char c = format[i];
|
||||||
|
if (c == '%') {
|
||||||
|
char cf = format[i + 1];
|
||||||
|
if (cf != '%') {
|
||||||
|
if (arg >= 0) {
|
||||||
|
arg++;
|
||||||
|
if (arg == totalArg) arg = -1; // format '%' prefixes in the format string exceed the number of passed value args
|
||||||
|
}
|
||||||
|
if (arg < 0) { // have % more than passed value args
|
||||||
|
c = '^'; // delete %
|
||||||
|
}
|
||||||
|
// check string is valid or replace unsupported format
|
||||||
|
else if ((cf == 's' && (arg > 0 && !opHandler.arg(arg).isString())) || (cf != 's' && cf != 'd')) {
|
||||||
|
newFmt[i++] = c;
|
||||||
|
c = 'd'; // replace with %d
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newFmt[i++] = cf; // skip %%
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newFmt[i] = c;
|
||||||
|
} while (++i < fmtLen);
|
||||||
|
|
||||||
|
const long bufMaxLen = GlblTextBufferSize() - 1;
|
||||||
|
|
||||||
|
switch (totalArg) {
|
||||||
|
case 2 :
|
||||||
|
_snprintf(gTextBuffer, bufMaxLen, newFmt, opHandler.arg(1).rawValue());
|
||||||
|
break;
|
||||||
|
case 3 :
|
||||||
|
_snprintf(gTextBuffer, bufMaxLen, newFmt, opHandler.arg(1).rawValue(), opHandler.arg(2).rawValue());
|
||||||
|
break;
|
||||||
|
case 4 :
|
||||||
|
_snprintf(gTextBuffer, bufMaxLen, newFmt, opHandler.arg(1).rawValue(), opHandler.arg(2).rawValue(), opHandler.arg(3).rawValue());
|
||||||
|
break;
|
||||||
|
case 5 :
|
||||||
|
_snprintf(gTextBuffer, bufMaxLen, newFmt, opHandler.arg(1).rawValue(), opHandler.arg(2).rawValue(), opHandler.arg(3).rawValue(), opHandler.arg(4).rawValue());
|
||||||
|
}
|
||||||
|
gTextBuffer[bufMaxLen] = '\0'; // just in case
|
||||||
|
|
||||||
|
delete[] newFmt;
|
||||||
|
opHandler.setReturn(gTextBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void funcPow2() {
|
static void funcPow2() {
|
||||||
const ScriptValue &base = opHandler.arg(0),
|
const ScriptValue &base = opHandler.arg(0),
|
||||||
&power = opHandler.arg(1);
|
&power = opHandler.arg(1);
|
||||||
|
|||||||
@@ -268,6 +268,7 @@ end:
|
|||||||
retn;
|
retn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __declspec(naked) get_critter_skill_points() {
|
static void __declspec(naked) get_critter_skill_points() {
|
||||||
__asm {
|
__asm {
|
||||||
pushad;
|
pushad;
|
||||||
|
|||||||
Reference in New Issue
Block a user