diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index ad5c4e6a..52a11781 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -280,6 +280,7 @@ #define get_outline(obj) sfall_func1("get_outline", obj) #define get_sfall_arg_at(argNum) sfall_func1("get_sfall_arg_at", argNum) #define get_string_pointer(text) sfall_func1("get_string_pointer", text) +#define get_text_width(text) sfall_func1("get_text_width", text) #define has_fake_perk_npc(npc, perk) sfall_func2("has_fake_perk_npc", npc, perk) #define has_fake_trait_npc(npc, trait) sfall_func2("has_fake_trait_npc", npc, trait) #define hide_window(winName) sfall_func1("hide_window", winName) @@ -313,13 +314,15 @@ #define set_rest_heal_time(time) sfall_func1("set_rest_heal_time", time) #define set_rest_mode(mode) sfall_func1("set_rest_mode", mode) #define set_unique_id(obj) sfall_func1("set_unique_id", obj) -#define unset_unique_id(obj) sfall_func2("set_unique_id", obj, -1) #define set_unjam_locks_time(time) sfall_func1("set_unjam_locks_time", time) #define set_window_flag(winID, flag, value) sfall_func3("set_window_flag", winID, flag, value) #define show_window(winName) sfall_func1("show_window", winName) #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 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) #define unwield_slot(critter, slot) sfall_func2("unwield_slot", critter, slot) #define set_fake_perk_npc(npc, perk, level, image, desc) sfall_func5("set_fake_perk_npc", npc, perk, level, image, desc) diff --git a/artifacts/scripting/sfall function notes.txt b/artifacts/scripting/sfall function notes.txt index fbdf1c49..4a7ee35b 100644 --- a/artifacts/scripting/sfall function notes.txt +++ b/artifacts/scripting/sfall function notes.txt @@ -601,8 +601,8 @@ Some utility/math functions are available: > void sfall_func5("draw_image", string/int pathFile/artId, int frame, int x, int y, bool noTransparent) > void sfall_func6("draw_image_scaled", string/int pathFile/artId, int frame, int x, int y, int width, int height) -- displays the specified FRM image in the active window created by vanilla CreateWin or sfall's create_win script function -- pathFile/artId: path to the FRM file (e.g. "art\\inven\\5mmap.frm"), or its FRM ID number (e.g. 117440550, see specification of the FID format) +- displays the specified PCX or FRM image in the active window created by vanilla CreateWin or sfall's create_win script function +- pathFile/artId: path to the PCX/FRM file (e.g. "art\\inven\\5mmap.frm"), or its FRM ID number (e.g. 117440550, see specification of the FID format) optional arguments: - frame: frame number, the first frame starts from zero - x/y: offset relative to the top-left corner of the window @@ -669,6 +669,15 @@ optional argument: - flag: the flag to change (see WIN_FLAG_* constants in define_extra.h) - value: true - set the flag, false - unset the flag +> int sfall_func1("get_text_width", string text) +- returns the text width in pixels for the currently set font + +> bool sfall_func2("string_compare", string str1, string str2) +> bool sfall_func3("string_compare", string str1, string str2, int codePage) +- compares two strings case-insensitive, and returns True if the two strings are matched +- codePage: code page number to properly compare national characters in the range 128-255 of the ASCII code table + available encodings: 1250-1252, 866 + ------------------------ ------ MORE INFO ------- ------------------------ diff --git a/sfall/FalloutEngine/EngineUtils.cpp b/sfall/FalloutEngine/EngineUtils.cpp index 17e7c3dc..7c481ec9 100644 --- a/sfall/FalloutEngine/EngineUtils.cpp +++ b/sfall/FalloutEngine/EngineUtils.cpp @@ -211,14 +211,11 @@ DWORD GetTextHeight() { //--------------------------------------------------------- //gets the length of a string using the currently selected font -DWORD GetTextWidth(char *TextMsg) { - DWORD TxtWidth; +DWORD GetTextWidth(const char *TextMsg) { __asm { mov eax, TextMsg; call dword ptr ds:[FO_VAR_text_width]; //get text width - mov TxtWidth, eax; } - return TxtWidth; } //--------------------------------------------------------- diff --git a/sfall/FalloutEngine/EngineUtils.h b/sfall/FalloutEngine/EngineUtils.h index 8832ac18..dbe177b9 100644 --- a/sfall/FalloutEngine/EngineUtils.h +++ b/sfall/FalloutEngine/EngineUtils.h @@ -81,7 +81,7 @@ void PrintText(char *displayText, BYTE colorIndex, DWORD x, DWORD y, DWORD textW // gets the height of the currently selected font DWORD GetTextHeight(); // gets the length of a string using the currently selected font -DWORD GetTextWidth(char *textMsg); +DWORD GetTextWidth(const char *textMsg); // get width of Char for current font DWORD GetCharWidth(char charVal); // get maximum string length for current font - if all characters were maximum width diff --git a/sfall/Modules/Scripting/Handlers/Metarule.cpp b/sfall/Modules/Scripting/Handlers/Metarule.cpp index 8a55a855..01e749ca 100644 --- a/sfall/Modules/Scripting/Handlers/Metarule.cpp +++ b/sfall/Modules/Scripting/Handlers/Metarule.cpp @@ -90,6 +90,7 @@ static const SfallMetarule metarules[] = { {"get_outline", sf_get_outline, 1, 1, {ARG_OBJECT}}, {"get_sfall_arg_at", sf_get_sfall_arg_at, 1, 1, {ARG_INT}}, {"get_string_pointer", sf_get_string_pointer, 1, 1, {ARG_STRING}}, + {"get_text_width", sf_get_text_width, 1, 1}, {"has_fake_perk_npc", sf_has_fake_perk_npc, 2, 2, {ARG_OBJECT, ARG_STRING}}, {"has_fake_trait_npc", sf_has_fake_trait_npc, 2, 2, {ARG_OBJECT, ARG_STRING}}, {"hide_window", sf_hide_window, 0, 1, {ARG_STRING}}, @@ -129,6 +130,7 @@ static const SfallMetarule metarules[] = { {"set_window_flag", sf_set_window_flag, 3, 3, {ARG_INTSTR, ARG_INT, ARG_INT}}, {"show_window", sf_show_window, 0, 1, {ARG_STRING}}, {"spatial_radius", sf_spatial_radius, 1, 1, {ARG_OBJECT}}, + {"string_compare", sf_string_compare, 2, 3, {ARG_STRING, ARG_STRING, ARG_INT}}, {"tile_refresh_display", sf_tile_refresh_display, 0, 0}, {"unjam_lock", sf_unjam_lock, 1, 1, {ARG_OBJECT}}, {"unwield_slot", sf_unwield_slot, 2, 2, {ARG_OBJECT, ARG_INT}}, @@ -136,7 +138,7 @@ static const SfallMetarule metarules[] = { {"validate_test", sf_test, 2, 5, {ARG_INT, ARG_NUMBER, ARG_STRING, ARG_OBJECT, ARG_ANY}}, #endif }; -// + // returns current contents of metarule table static void sf_get_metarule_table(OpcodeContext& ctx) { DWORD arrId = TempArray(metaruleTable.size(), 0); diff --git a/sfall/Modules/Scripting/Handlers/Misc.cpp b/sfall/Modules/Scripting/Handlers/Misc.cpp index ce06d7fc..1072056a 100644 --- a/sfall/Modules/Scripting/Handlers/Misc.cpp +++ b/sfall/Modules/Scripting/Handlers/Misc.cpp @@ -42,129 +42,35 @@ namespace sfall namespace script { -static DWORD defaultMaleModelNamePtr = (DWORD)defaultMaleModelName; -static DWORD defaultFemaleModelNamePtr = (DWORD)defaultFemaleModelName; -static DWORD movieNamesPtr = (DWORD)MoviePaths; +const char* stringTooLong = "%s() - the string length exceeds maximum of 64 characters."; - -//// *** End Helios *** /// -static void _stdcall strcpy_p(char* to, const char* from) { - strcpy_s(to, 64, from); +void sf_set_dm_model(OpcodeContext& ctx) { + auto model = ctx.arg(0).strValue(); + if (strlen(model) > 64) { + ctx.printOpcodeError(stringTooLong, ctx.getOpcodeName()); + return; + } + strcpy(defaultMaleModelName, model); } -/************************************************************************/ -/* TODO: Rewrite these raw handlers using OpcodeContext */ -/************************************************************************/ - -void __declspec(naked) op_set_dm_model() { - __asm { - push ebx; - push ecx; - push edx; - push edi; - mov edi, eax; - call fo::funcoffs::interpretPopShort_; - mov edx, eax; - mov eax, edi; - call fo::funcoffs::interpretPopLong_; - cmp dx, VAR_TYPE_STR2; - jz next; - cmp dx, VAR_TYPE_STR; - jnz end; -next: - mov ebx, eax; - mov eax, edi; - call fo::funcoffs::interpretGetString_; - push eax; - push defaultMaleModelNamePtr; - call strcpy_p; -end: - pop edi; - pop edx; - pop ecx; - pop ebx; - retn; +void sf_set_df_model(OpcodeContext& ctx) { + auto model = ctx.arg(0).strValue(); + if (strlen(model) > 64) { + ctx.printOpcodeError(stringTooLong, ctx.getOpcodeName()); + return; } + strcpy(defaultFemaleModelName, model); } -void __declspec(naked) op_set_df_model() { - __asm { - push ebx; - push ecx; - push edx; - push edi; - mov edi, eax; - call fo::funcoffs::interpretPopShort_; - mov edx, eax; - mov eax, edi; - call fo::funcoffs::interpretPopLong_; - cmp dx, VAR_TYPE_STR2; - jz next; - cmp dx, VAR_TYPE_STR; - jnz end; -next: - mov ebx, eax; - mov eax, edi; - call fo::funcoffs::interpretGetString_; - push eax; - push defaultFemaleModelNamePtr; - call strcpy_p; -end: - pop edi; - pop edx; - pop ecx; - pop ebx; - retn; - } -} - -void __declspec(naked) op_set_movie_path() { - __asm { - push ebx; - push ecx; - push edx; - push edi; - push esi; - mov edi, eax; - call fo::funcoffs::interpretPopShort_; - mov ebx, eax; - mov eax, edi; - call fo::funcoffs::interpretPopLong_; - mov esi, eax; - mov eax, edi; - call fo::funcoffs::interpretPopShort_; - mov edx, eax; - mov eax, edi; - call fo::funcoffs::interpretPopLong_; - cmp dx, VAR_TYPE_STR2; - jz next; - cmp dx, VAR_TYPE_STR; - jnz end; -next: - cmp bx, VAR_TYPE_INT; - jnz end; - cmp esi, 0; - jl end; - cmp esi, MaxMovies; - jge end; - mov ebx, eax; - mov eax, edi; - call fo::funcoffs::interpretGetString_; - push eax; - mov eax, esi; - mov esi, 65; - mul si; - add eax, movieNamesPtr; - push eax; - call strcpy_p; -end: - pop esi; - pop edi; - pop edx; - pop ecx; - pop ebx; - retn; +void sf_set_movie_path(OpcodeContext& ctx) { + long movieID = ctx.arg(1).rawValue(); + if (movieID < 0 || movieID >= MaxMovies) return; + auto fileName = ctx.arg(0).strValue(); + if (strlen(fileName) > 64) { + ctx.printOpcodeError(stringTooLong, ctx.getOpcodeName()); + return; } + strcpy(&MoviePaths[movieID * 65], fileName); } void sf_get_year(OpcodeContext& ctx) { @@ -181,14 +87,12 @@ void sf_get_year(OpcodeContext& ctx) { void __declspec(naked) op_game_loaded() { __asm { push ecx; - push edx; push eax; push eax; // script call ScriptHasLoaded; movzx edx, al; pop eax; _RET_VAL_INT(ecx); - pop edx; pop ecx; retn; } @@ -197,15 +101,13 @@ void __declspec(naked) op_game_loaded() { void __declspec(naked) op_set_pipboy_available() { __asm { push ecx; - push edx; _GET_ARG_INT(end); cmp eax, 0; jl end; cmp eax, 1; jg end; - mov byte ptr ds:[FO_VAR_gmovie_played_list + 0x3], al; + mov byte ptr ds:[FO_VAR_gmovie_played_list][0x3], al; end: - pop edx; pop ecx; retn; } @@ -795,17 +697,6 @@ end: //numbers subgame functions void __declspec(naked) op_nb_create_char() { __asm { - /*pushad; - push eax; - call NumbersCreateChar; - mov edx, eax; - pop eax; - mov ecx, eax; - call fo::funcoffs::interpretPushLong_; - mov eax, ecx; - mov edx, VAR_TYPE_INT; - call fo::funcoffs::interpretPushShort_; - popad;*/ retn; } } @@ -959,7 +850,7 @@ end: void __declspec(naked) op_modified_ini() { __asm { push ecx; - mov edx, modifiedIni; + mov edx, modifiedIni; _RET_VAL_INT(ecx); pop ecx; retn; diff --git a/sfall/Modules/Scripting/Handlers/Misc.h b/sfall/Modules/Scripting/Handlers/Misc.h index dfbf73a8..26310c87 100644 --- a/sfall/Modules/Scripting/Handlers/Misc.h +++ b/sfall/Modules/Scripting/Handlers/Misc.h @@ -29,13 +29,11 @@ namespace script class OpcodeContext; -// TODO: rewrite all op_* functions using OpcodeContext +void sf_set_dm_model(OpcodeContext&); -void __declspec() op_set_dm_model(); +void sf_set_df_model(OpcodeContext&); -void __declspec() op_set_df_model(); - -void __declspec() op_set_movie_path(); +void sf_set_movie_path(OpcodeContext&); void sf_get_year(OpcodeContext&); diff --git a/sfall/Modules/Scripting/Handlers/Utils.cpp b/sfall/Modules/Scripting/Handlers/Utils.cpp index 55e04f66..0894c898 100644 --- a/sfall/Modules/Scripting/Handlers/Utils.cpp +++ b/sfall/Modules/Scripting/Handlers/Utils.cpp @@ -19,6 +19,7 @@ #include #include "..\..\..\FalloutEngine\Fallout2.h" +#include "..\..\..\FalloutEngine\EngineUtils.h" #include "..\..\ScriptExtender.h" #include "..\..\FileSystem.h" #include "..\..\Message.h" @@ -33,6 +34,69 @@ namespace sfall namespace script { +// compares strings case-insensitive with specifics for Fallout +static bool FalloutStringCompare(const char* str1, const char* str2, long codePage) { + while (true) { + unsigned char c1 = *str1; + unsigned char c2 = *str2; + if (c1 == 0 && c2 == 0) return true; // end - strings are equal + if (c1 == 0 || c2 == 0) return false; // strings are not equal + str1++; + str2++; + if (c1 == c2) continue; + if (codePage == 866) { + // replace Russian 'x' to English (Fallout specific) + if (c1 == 229) c1 -= 229 - 'x'; + if (c2 == 229) c2 -= 229 - 'x'; + } + + // 0 - 127 (standard ASCII) + // upper to lower case + if (c1 >= 'A' && c1 <= 'Z') c1 |= 32; + if (c2 >= 'A' && c2 <= 'Z') c2 |= 32; + if (c1 == c2) continue; + if (c1 < 128 || c2 < 128) return false; + + // 128 - 255 (international/extended) + switch (codePage) { + case 866: + if (c1 != 149 && c2 != 149) { + // upper to lower case + if (c1 >= 0x80 && c1 <= 0x9F) { + c1 |= 32; + } else if (c1 >= 224 && c1 <= 239) { + c1 -= 48; // shift lower range + } else if (c1 == 240) { + c1++; + } + if (c2 >= 0x80 && c2 <= 0x9F) { + c2 |= 32; + } else if (c2 >= 224 && c2 <= 239) { + c2 -= 48; // shift lower range + } else if (c2 == 240) { + c2++; + } + } + break; + case 1251: + // upper to lower case + if (c1 >= 0xC0 && c1 <= 0xDF) c1 |= 32; + if (c2 >= 0xC0 && c2 <= 0xDF) c2 |= 32; + if (c1 == 0xA8) c1 += 16; + if (c2 == 0xA8) c2 += 16; + break; + case 1250: + case 1252: + if (c1 != 0xD7 && c1 != 0xF7 && c2 != 0xD7 && c2 != 0xF7) { + if (c1 >= 0xC0 && c1 <= 0xDE) c1 |= 32; + if (c2 >= 0xC0 && c2 <= 0xDE) c2 |= 32; + } + break; + } + if (c1 != c2) return false; // strings are not equal + } +} + void sf_sqrt(OpcodeContext& ctx) { ctx.setReturn(sqrt(ctx.arg(0).asFloat())); } @@ -68,22 +132,22 @@ void sf_strlen(OpcodeContext& ctx) { } void sf_atoi(OpcodeContext& ctx) { - auto str = ctx.arg(0).asString(); + auto str = ctx.arg(0).strValue(); ctx.setReturn( static_cast(strtol(str, (char**)nullptr, 0)) // auto-determine radix ); } void sf_atof(OpcodeContext& ctx) { - auto str = ctx.arg(0).asString(); + auto str = ctx.arg(0).strValue(); ctx.setReturn( static_cast(atof(str)) ); } void sf_ord(OpcodeContext& ctx) { - char firstChar = ctx.arg(0).asString()[0]; - ctx.setReturn(static_cast(firstChar)); + unsigned char firstChar = ctx.arg(0).strValue()[0]; + ctx.setReturn(static_cast(firstChar)); } void sf_typeof(OpcodeContext& ctx) { @@ -123,10 +187,10 @@ static int _stdcall StringSplit(const char* str, const char* split) { } void sf_string_split(OpcodeContext& ctx) { - ctx.setReturn(StringSplit(ctx.arg(0).asString(), ctx.arg(1).asString())); + ctx.setReturn(StringSplit(ctx.arg(0).strValue(), ctx.arg(1).strValue())); } -char* _stdcall Substring(const char* str, int pos, int length) { +char* Substring(const char* str, int pos, int length) { char* newstr; int srclen; srclen = strlen(str); @@ -138,7 +202,7 @@ char* _stdcall Substring(const char* str, int pos, int length) { length = 0; else if (length + pos > srclen) length = srclen - pos; - newstr = new char[length + 1]; + newstr = new char[length + 1]; // memory leak!!! if (length > 0) memcpy(newstr, &str[pos], length); newstr[length] = '\0'; @@ -147,10 +211,20 @@ char* _stdcall Substring(const char* str, int pos, int length) { void sf_substr(OpcodeContext& ctx) { ctx.setReturn( - Substring(ctx.arg(0).asString(), ctx.arg(1).asInt(), ctx.arg(2).asInt()) + Substring(ctx.arg(0).strValue(), ctx.arg(1).rawValue(), ctx.arg(2).rawValue()) ); } +void sf_string_compare(OpcodeContext& ctx) { + if (ctx.numArgs() < 3) { + ctx.setReturn( + (_stricmp(ctx.arg(0).strValue(), ctx.arg(1).strValue()) ? 0 : 1) + ); + } else { + ctx.setReturn(FalloutStringCompare(ctx.arg(0).strValue(), ctx.arg(1).strValue(), ctx.arg(2).rawValue())); + } +} + static char* sprintfbuf = nullptr; // A safer version of sprintf for using in user scripts. static char* _stdcall sprintf_lite(const char* format, ScriptValue value) { @@ -232,7 +306,7 @@ static char* _stdcall sprintf_lite(const char* format, ScriptValue value) { void sf_sprintf(OpcodeContext& ctx) { ctx.setReturn( - sprintf_lite(ctx.arg(0).asString(), ctx.arg(1)) + sprintf_lite(ctx.arg(0).strValue(), ctx.arg(1)) ); } @@ -315,7 +389,11 @@ void sf_floor2(OpcodeContext& ctx) { } void sf_get_string_pointer(OpcodeContext& ctx) { - ctx.setReturn(reinterpret_cast(ctx.arg(0).asString()), DataType::INT); + ctx.setReturn(reinterpret_cast(ctx.arg(0).strValue()), DataType::INT); +} + +void sf_get_text_width(OpcodeContext& ctx) { + ctx.setReturn(fo::GetTextWidth(ctx.arg(0).asString())); } } diff --git a/sfall/Modules/Scripting/Handlers/Utils.h b/sfall/Modules/Scripting/Handlers/Utils.h index a2b8bbd6..ed2be87a 100644 --- a/sfall/Modules/Scripting/Handlers/Utils.h +++ b/sfall/Modules/Scripting/Handlers/Utils.h @@ -23,6 +23,8 @@ namespace sfall namespace script { +char* Substring(const char* str, int pos, int length); + class OpcodeContext; void sf_sqrt(OpcodeContext&); @@ -47,6 +49,8 @@ void sf_substr(OpcodeContext&); void sf_strlen(OpcodeContext&); +void sf_string_compare(OpcodeContext&); + void sf_sprintf(OpcodeContext&); void sf_ord(OpcodeContext&); @@ -71,7 +75,7 @@ void sf_floor2(OpcodeContext&); void sf_get_string_pointer(OpcodeContext&); -char* _stdcall Substring(const char* str, int pos, int length); +void sf_get_text_width(OpcodeContext&); } } diff --git a/sfall/Modules/Scripting/OpcodeContext.cpp b/sfall/Modules/Scripting/OpcodeContext.cpp index 4ee830b0..6de2d1fb 100644 --- a/sfall/Modules/Scripting/OpcodeContext.cpp +++ b/sfall/Modules/Scripting/OpcodeContext.cpp @@ -33,10 +33,10 @@ OpcodeContext::OpcodeContext(fo::Program* program, DWORD opcode, int argNum, boo assert(argNum < OP_MAX_ARGUMENTS); } -OpcodeContext::OpcodeContext(fo::Program* program, DWORD opcode, int argNum, bool hasReturn, const char* opcodeName) - : OpcodeContext::OpcodeContext(program, opcode, argNum, hasReturn) +OpcodeContext::OpcodeContext(fo::Program* program, const SfallOpcodeInfo* info) + : _program(program), _opcode(info->opcode), _numArgs(info->argNum), _hasReturn(info->hasReturn), _opcodeName(info->name), _argShift(0) { - _opcodeName = opcodeName; + assert(_numArgs < OP_MAX_ARGUMENTS); } const char* OpcodeContext::getOpcodeName() const { diff --git a/sfall/Modules/Scripting/OpcodeContext.h b/sfall/Modules/Scripting/OpcodeContext.h index e0caafbb..f85d1766 100644 --- a/sfall/Modules/Scripting/OpcodeContext.h +++ b/sfall/Modules/Scripting/OpcodeContext.h @@ -92,9 +92,9 @@ public: // hasReturn - true if opcode has return value (is expression) // opcodeName - name of a function (for logging) OpcodeContext(fo::Program* program, DWORD opcode, int argNum, bool hasReturn); - OpcodeContext(fo::Program* program, DWORD opcode, int argNum, bool hasReturn, const char* opcodeName); + OpcodeContext(fo::Program* program, const SfallOpcodeInfo* info); - const char* getOpcodeName() const; + const char* getOpcodeName() const; const char* getMetaruleName() const; // currently executed metarule func @@ -115,7 +115,7 @@ public: // returns argument with given index, possible shifted by argShift const ScriptValue& arg(int index) const; - + // current return value const ScriptValue& returnValue() const; @@ -124,13 +124,13 @@ public: // current opcode number DWORD opcode() const; - + // set return value for current opcode void setReturn(unsigned long value, DataType type); - + // set return value for current opcode void setReturn(const ScriptValue& val); - + // writes error message to debug.log along with the name of script & procedure void printOpcodeError(const char* fmt, ...) const; diff --git a/sfall/Modules/Scripting/Opcodes.cpp b/sfall/Modules/Scripting/Opcodes.cpp index d64f2855..3f96265d 100644 --- a/sfall/Modules/Scripting/Opcodes.cpp +++ b/sfall/Modules/Scripting/Opcodes.cpp @@ -74,6 +74,9 @@ static SfallOpcodeInfo opcodeInfoArray[] = { {0x163, "get_year", sf_get_year, 0, true}, {0x16c, "key_pressed", sf_key_pressed, 1, true, {ARG_INT}}, {0x171, "force_encounter", sf_force_encounter, 1, false, {ARG_INT}}, + {0x175, "set_dm_model", sf_set_dm_model, 1, false, {ARG_STRING}}, + {0x176, "set_df_model", sf_set_df_model, 1, false, {ARG_STRING}}, + {0x177, "set_movie_path", sf_set_movie_path, 2, false, {ARG_STRING, ARG_INT}}, {0x190, "get_perk_available", sf_get_perk_available, 1, true, {ARG_INT}}, {0x195, "set_weapon_knockback", sf_set_object_knockback, 3, false, {ARG_OBJECT, ARG_INT, ARG_NUMBER}}, @@ -165,7 +168,7 @@ static SfallOpcodeInfo opcodeInfoArray[] = { {0x241, "get_npc_level", sf_get_npc_level, 1, true, {ARG_INTSTR}}, {0x24e, "substr", sf_substr, 3, true, {ARG_STRING, ARG_INT, ARG_INT}}, - {0x24f, "strlen", sf_strlen, 1, true, {ARG_STRING}}, + {0x24f, "strlen", sf_strlen, 1, true}, {0x250, "sprintf", sf_sprintf, 2, true, {ARG_STRING, ARG_ANY}}, {0x251, "charcode", sf_ord, 1, true, {ARG_STRING}}, // 0x252 // RESERVED @@ -238,7 +241,7 @@ void __fastcall defaultOpcodeHandlerCall(fo::Program* program, DWORD opcodeOffse auto iter = opcodeInfoMap.find(opcode); if (iter != opcodeInfoMap.end()) { auto info = iter->second; - OpcodeContext ctx(program, opcode, info->argNum, info->hasReturn, info->name); + OpcodeContext ctx(program, info); ctx.handleOpcode(info->handler, info->argValidation); } else { fo::func::interpretError("Unknown opcode: %d", opcode); @@ -298,9 +301,7 @@ void InitNewOpcodes() { opcodes[0x172] = op_set_world_map_pos; opcodes[0x173] = op_get_world_map_x_pos; opcodes[0x174] = op_get_world_map_y_pos; - opcodes[0x175] = op_set_dm_model; - opcodes[0x176] = op_set_df_model; - opcodes[0x177] = op_set_movie_path; + for (int i = 0x178; i < 0x189; i++) { opcodes[i] = op_set_perk_value; }