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 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_format(format, a1, a2) sfall_func3("string_format", format, a1, a2)
|
||||
#define tile_refresh_display sfall_func0("tile_refresh_display")
|
||||
#define unjam_lock(obj) sfall_func1("unjam_lock", obj)
|
||||
#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))
|
||||
|
||||
> 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 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
|
||||
@@ -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
|
||||
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 -------
|
||||
------------------------
|
||||
|
||||
@@ -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 {
|
||||
mov edx, dataType;
|
||||
mov ebx, strId;
|
||||
mov eax, scriptPtr;
|
||||
mov eax, ecx;
|
||||
call interpretGetString_;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1084,7 +1084,7 @@ void __stdcall InterpretPushLong(TProgram* scriptPtr, DWORD val);
|
||||
// pushes value type to Data stack (must be preceded by InterpretPushLong)
|
||||
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);
|
||||
|
||||
|
||||
@@ -337,7 +337,7 @@ public:
|
||||
|
||||
// retrieve string argument
|
||||
if (type == DATATYPE_STR) {
|
||||
_args[i] = InterpretGetString(program, rawValue, rawValueType);
|
||||
_args[i] = InterpretGetString(program, rawValueType, rawValue);
|
||||
} else {
|
||||
_args[i] = ScriptValue(type, rawValue);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
Notes:
|
||||
- DO NOT add any comments within macros
|
||||
- every macro should contain __asm {} block
|
||||
- every macro should contain __asm {} block
|
||||
- every assembly line should start with __asm and should NOT have semicolon in the end!
|
||||
- use this macros outside of other __asm {} blocks (obviously)
|
||||
*/
|
||||
@@ -42,6 +42,7 @@
|
||||
Gets argument from stack to eax and puts its type to edx register
|
||||
eax register must contain the script_ptr
|
||||
jlabel - name of the jump label in case the value type is not INT
|
||||
return: eax - arg value
|
||||
*/
|
||||
#define _GET_ARG_INT(jlabel) __asm { \
|
||||
__asm mov edx, eax \
|
||||
@@ -71,7 +72,7 @@
|
||||
checks argument (which may be any type) if it's a string and retrieves it (overwrites value in rval)
|
||||
num - any number, but it must be unique (used for label names)
|
||||
r16type - 16bit register where value type is stored
|
||||
rval - r32 where value is stored
|
||||
rval - r32 where value is stored
|
||||
*/
|
||||
#define _CHECK_PARSE_STR(num, rscript, r16type, rval) __asm { \
|
||||
__asm cmp r16type, VAR_TYPE_STR2 \
|
||||
@@ -131,7 +132,14 @@ notstring##num:
|
||||
__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
|
||||
num - any unique number
|
||||
type - register or other expression (like memory address) where value type is stored (usually [esp])
|
||||
@@ -154,8 +162,8 @@ __asm resultnotstr##num: \
|
||||
__asm call interpretPushShort_ \
|
||||
}
|
||||
|
||||
/*
|
||||
better way of handling new opcodes:
|
||||
/*
|
||||
better way of handling new opcodes:
|
||||
- no ASM code required
|
||||
- all type checks should be done in the wrapped C-function
|
||||
- use opArgs, opArgTypes to access arguments
|
||||
|
||||
+151
-218
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -19,303 +19,236 @@
|
||||
#pragma once
|
||||
|
||||
#include "main.h"
|
||||
#include "ScriptExtender.h"
|
||||
//#include "ScriptExtender.h"
|
||||
|
||||
#define START_VALID_ADDR 0x410000
|
||||
#define END_VALID_ADDR 0x6B403F
|
||||
|
||||
// memory_reading_funcs
|
||||
static void __declspec(naked) ReadByte() {
|
||||
__asm {
|
||||
push ebx;
|
||||
push ecx;
|
||||
push edx;
|
||||
mov ecx, eax;
|
||||
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;
|
||||
_GET_ARG_INT(error);
|
||||
test eax, eax;
|
||||
jz error;
|
||||
movzx edx, byte ptr ds:[eax]; // read memory
|
||||
result:
|
||||
mov eax, ecx;
|
||||
call interpretPushLong_;
|
||||
mov edx, VAR_TYPE_INT;
|
||||
mov eax, ecx;
|
||||
call interpretPushShort_;
|
||||
pop edx;
|
||||
pop ecx;
|
||||
pop ebx;
|
||||
retn;
|
||||
mov eax, ebx;
|
||||
_J_RET_VAL_TYPE(VAR_TYPE_INT);
|
||||
// retn;
|
||||
error:
|
||||
xor edx, edx;
|
||||
jmp result;
|
||||
}
|
||||
}
|
||||
|
||||
static void __declspec(naked) ReadShort() {
|
||||
__asm {
|
||||
push ebx;
|
||||
push ecx;
|
||||
push edx;
|
||||
mov ecx, eax;
|
||||
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;
|
||||
_GET_ARG_INT(error);
|
||||
test eax, eax;
|
||||
jz error;
|
||||
movzx edx, word ptr ds:[eax]; // read memory
|
||||
result:
|
||||
mov eax, ecx;
|
||||
call interpretPushLong_;
|
||||
mov edx, VAR_TYPE_INT;
|
||||
mov eax, ecx;
|
||||
call interpretPushShort_;
|
||||
pop edx;
|
||||
pop ecx;
|
||||
pop ebx;
|
||||
retn;
|
||||
mov eax, ebx;
|
||||
_J_RET_VAL_TYPE(VAR_TYPE_INT);
|
||||
// retn;
|
||||
error:
|
||||
xor edx, edx;
|
||||
jmp result;
|
||||
}
|
||||
}
|
||||
|
||||
static void __declspec(naked) ReadInt() {
|
||||
__asm {
|
||||
push ebx;
|
||||
push ecx;
|
||||
push edx;
|
||||
mov ecx, eax;
|
||||
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;
|
||||
_GET_ARG_INT(error);
|
||||
test eax, eax;
|
||||
jz error;
|
||||
mov edx, dword ptr ds:[eax]; // read memory
|
||||
result:
|
||||
mov eax, ecx;
|
||||
call interpretPushLong_;
|
||||
mov edx, VAR_TYPE_INT;
|
||||
mov eax, ecx;
|
||||
call interpretPushShort_;
|
||||
pop edx;
|
||||
pop ecx;
|
||||
pop ebx;
|
||||
retn;
|
||||
mov eax, ebx;
|
||||
_J_RET_VAL_TYPE(VAR_TYPE_INT);
|
||||
// retn;
|
||||
error:
|
||||
xor edx, edx;
|
||||
jmp result;
|
||||
}
|
||||
}
|
||||
|
||||
static void __declspec(naked) ReadString() {
|
||||
__asm {
|
||||
push ebx;
|
||||
push ecx;
|
||||
push edx;
|
||||
mov ecx, 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;
|
||||
_GET_ARG_INT(error);
|
||||
test eax, eax;
|
||||
jz error;
|
||||
mov edx, eax;
|
||||
result:
|
||||
mov eax, ecx;
|
||||
call interpretPushLong_;
|
||||
mov edx, VAR_TYPE_STR;
|
||||
mov eax, ecx;
|
||||
call interpretPushShort_;
|
||||
pop edx;
|
||||
pop ecx;
|
||||
pop ebx;
|
||||
retn;
|
||||
mov eax, ebx;
|
||||
_J_RET_VAL_TYPE(VAR_TYPE_STR);
|
||||
// retn;
|
||||
error:
|
||||
xor edx, edx;
|
||||
jmp result;
|
||||
}
|
||||
}
|
||||
|
||||
static void __declspec(naked) WriteByte() {
|
||||
__asm {
|
||||
pushad
|
||||
mov ecx, eax;
|
||||
push ecx;
|
||||
call interpretPopShort_;
|
||||
mov esi, eax;
|
||||
mov eax, ecx;
|
||||
mov ecx, eax; // type
|
||||
mov eax, ebx;
|
||||
call interpretPopLong_;
|
||||
mov edx, eax;
|
||||
mov eax, ecx;
|
||||
call interpretPopShort_;
|
||||
mov edi, eax;
|
||||
mov eax, ecx;
|
||||
call interpretPopLong_;
|
||||
cmp di, VAR_TYPE_INT;
|
||||
jnz end;
|
||||
cmp si, VAR_TYPE_INT;
|
||||
jnz end;
|
||||
//mov byte ptr ds:[eax], dl;
|
||||
and edx, 0xff;
|
||||
push edx;
|
||||
mov esi, eax; // write value
|
||||
mov eax, ebx;
|
||||
_GET_ARG_INT(end);
|
||||
cmp cx, VAR_TYPE_INT;
|
||||
jnz end;
|
||||
// check valid addr
|
||||
cmp eax, START_VALID_ADDR;
|
||||
jb end;
|
||||
cmp eax, END_VALID_ADDR;
|
||||
ja end;
|
||||
and esi, 0xFF;
|
||||
push esi;
|
||||
push eax;
|
||||
call SafeWrite8;
|
||||
end:
|
||||
popad;
|
||||
pop ecx;
|
||||
retn;
|
||||
}
|
||||
}
|
||||
|
||||
static void __declspec(naked) WriteShort() {
|
||||
__asm {
|
||||
pushad;
|
||||
mov ecx, eax;
|
||||
push ecx;
|
||||
call interpretPopShort_;
|
||||
mov esi, eax;
|
||||
mov eax, ecx;
|
||||
mov ecx, eax; // type
|
||||
mov eax, ebx;
|
||||
call interpretPopLong_;
|
||||
mov edx, eax;
|
||||
mov eax, ecx;
|
||||
call interpretPopShort_;
|
||||
mov edi, eax;
|
||||
mov eax, ecx;
|
||||
call interpretPopLong_;
|
||||
cmp di, VAR_TYPE_INT;
|
||||
jnz end;
|
||||
cmp si, VAR_TYPE_INT;
|
||||
jnz end;
|
||||
//mov word ptr ds:[eax], dx;
|
||||
and edx, 0xffff;
|
||||
push edx;
|
||||
mov esi, eax; // write value
|
||||
mov eax, ebx;
|
||||
_GET_ARG_INT(end);
|
||||
cmp cx, VAR_TYPE_INT;
|
||||
jnz end;
|
||||
// check valid addr
|
||||
cmp eax, START_VALID_ADDR;
|
||||
jb end;
|
||||
cmp eax, END_VALID_ADDR;
|
||||
ja end;
|
||||
and esi, 0xFFFF;
|
||||
push esi;
|
||||
push eax;
|
||||
call SafeWrite16;
|
||||
end:
|
||||
popad;
|
||||
pop ecx;
|
||||
retn;
|
||||
}
|
||||
}
|
||||
|
||||
static void __declspec(naked) WriteInt() {
|
||||
__asm {
|
||||
pushad
|
||||
mov ecx, eax;
|
||||
push ecx;
|
||||
call interpretPopShort_;
|
||||
mov esi, eax;
|
||||
mov eax, ecx;
|
||||
mov ecx, eax; // type
|
||||
mov eax, ebx;
|
||||
call interpretPopLong_;
|
||||
mov edx, eax;
|
||||
mov eax, ecx;
|
||||
call interpretPopShort_;
|
||||
mov edi, eax;
|
||||
mov eax, ecx;
|
||||
call interpretPopLong_;
|
||||
cmp di, VAR_TYPE_INT;
|
||||
jnz end;
|
||||
cmp si, VAR_TYPE_INT;
|
||||
jnz end;
|
||||
//mov dword ptr ds:[eax], edx;
|
||||
push edx;
|
||||
mov esi, eax; // write value
|
||||
mov eax, ebx;
|
||||
_GET_ARG_INT(end);
|
||||
cmp cx, VAR_TYPE_INT;
|
||||
jnz end;
|
||||
// check valid addr
|
||||
cmp eax, START_VALID_ADDR;
|
||||
jb end;
|
||||
cmp eax, END_VALID_ADDR;
|
||||
ja end;
|
||||
push esi;
|
||||
push eax;
|
||||
call SafeWrite32;
|
||||
end:
|
||||
popad
|
||||
pop ecx;
|
||||
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) {
|
||||
if (!*addr) hitnull = true;
|
||||
if (hitnull && addr[1]) break;
|
||||
*addr = *str;
|
||||
addr++;
|
||||
str++;
|
||||
if (!addr[0] && addr[1]) break; // addr[1] as *(addr + 1)
|
||||
*addr++ = *str++;
|
||||
}
|
||||
*addr = 0;
|
||||
}
|
||||
|
||||
static void __declspec(naked) WriteString() {
|
||||
__asm {
|
||||
pushad;
|
||||
mov ecx, eax;
|
||||
push ecx;
|
||||
call interpretPopShort_;
|
||||
mov esi, eax;
|
||||
mov eax, ecx;
|
||||
mov ecx, eax; // type
|
||||
mov eax, ebx;
|
||||
call interpretPopLong_;
|
||||
mov edi, eax;
|
||||
mov eax, ecx;
|
||||
call interpretPopShort_;
|
||||
mov edx, eax;
|
||||
mov eax, ecx;
|
||||
call interpretPopLong_;
|
||||
cmp dx, VAR_TYPE_INT;
|
||||
jnz end;
|
||||
cmp si, VAR_TYPE_STR2;
|
||||
jz next;
|
||||
cmp si, VAR_TYPE_STR;
|
||||
jnz end;
|
||||
mov esi, eax; // str value
|
||||
mov eax, ebx;
|
||||
_GET_ARG_INT(end);
|
||||
cmp cx, VAR_TYPE_STR2;
|
||||
je next;
|
||||
cmp cx, VAR_TYPE_STR;
|
||||
jnz end;
|
||||
next:
|
||||
mov ebx, edi;
|
||||
mov edx, esi;
|
||||
mov esi, eax;
|
||||
mov eax, ecx;
|
||||
call interpretGetString_;
|
||||
push esi;
|
||||
push eax;
|
||||
// ecx - type, esi - value
|
||||
// edx - type, eax - addr
|
||||
// check valid address
|
||||
cmp eax, START_VALID_ADDR;
|
||||
jb end;
|
||||
cmp eax, END_VALID_ADDR;
|
||||
ja end;
|
||||
push ebx; // script
|
||||
push esi; // str value
|
||||
mov edx, ecx; // type
|
||||
mov ecx, eax; // addr
|
||||
call WriteStringInternal;
|
||||
jmp end;
|
||||
end:
|
||||
popad;
|
||||
pop ecx;
|
||||
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;
|
||||
} else {
|
||||
__asm {
|
||||
mov eax, args[4]; // args[1]
|
||||
mov edx, args[8]; // args[2]
|
||||
mov ebx, args[12]; // args[3]
|
||||
mov ecx, args[16]; // args[4]
|
||||
mov edi, args[0]; // args[0]
|
||||
call edi;
|
||||
mov args[0], eax;
|
||||
mov eax, args[4];
|
||||
mov edx, args[8];
|
||||
mov ebx, args[12];
|
||||
mov ecx, args[16];
|
||||
call args[0];
|
||||
mov args[0], eax;
|
||||
}
|
||||
}
|
||||
if (ret) {
|
||||
if (func >= 5) { // has return
|
||||
__asm {
|
||||
mov eax, script;
|
||||
mov edx, args[0];
|
||||
call interpretPushLong_;
|
||||
mov eax, script;
|
||||
mov edx, VAR_TYPE_INT;
|
||||
call interpretPushShort_;
|
||||
mov ebx, eax;
|
||||
_RET_VAL_INT2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void __declspec(naked) CallOffset() {
|
||||
__asm {
|
||||
pushad;
|
||||
push eax;
|
||||
push edx;
|
||||
call CallOffsetInternal;
|
||||
popad;
|
||||
push ecx;
|
||||
mov ecx, eax;
|
||||
call CallOffsetInternal; // edx - func
|
||||
pop ecx;
|
||||
retn;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,6 +169,7 @@ static const SfallMetarule metaruleArray[] = {
|
||||
{"show_window", sf_show_window, 0, 1},
|
||||
{"spatial_radius", sf_spatial_radius, 1, 1},
|
||||
{"string_compare", sf_string_compare, 2, 3},
|
||||
{"string_format", sf_string_format, 2, 5},
|
||||
{"tile_refresh_display", sf_tile_refresh_display, 0, 0},
|
||||
{"unjam_lock", sf_unjam_lock, 1, 1},
|
||||
{"unwield_slot", sf_unwield_slot, 2, 2},
|
||||
|
||||
@@ -591,7 +591,7 @@ char* _stdcall Substring(const char* str, int startPos, int length) {
|
||||
if (length < 0) {
|
||||
length += len - startPos; // cutoff at end
|
||||
if (length == 0) return "";
|
||||
abs(length); // length can't be negative
|
||||
length = abs(length); // length can't be negative
|
||||
}
|
||||
// check position
|
||||
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() {
|
||||
const ScriptValue &base = opHandler.arg(0),
|
||||
&power = opHandler.arg(1);
|
||||
|
||||
@@ -268,6 +268,7 @@ end:
|
||||
retn;
|
||||
}
|
||||
}
|
||||
|
||||
static void __declspec(naked) get_critter_skill_points() {
|
||||
__asm {
|
||||
pushad;
|
||||
|
||||
Reference in New Issue
Block a user