From 5c4eb31bc3372c5f23ebdff38a9181708621f180 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Tue, 20 Aug 2019 00:26:35 +0800 Subject: [PATCH] Added IniConfigFolder option to override the path of all scripted ini Fixed a crash bug in message_str_game function when passing a negative fileId value. --- artifacts/ddraw.ini | 7 +++- sfall/Modules/ScriptExtender.cpp | 15 +++++++ sfall/Modules/ScriptExtender.h | 2 + sfall/Modules/Scripting/Handlers/Misc.cpp | 46 +++++++++++++++++----- sfall/Modules/Scripting/Handlers/Utils.cpp | 2 +- sfall/Utils.cpp | 13 ++++++ sfall/Utils.h | 2 + 7 files changed, 76 insertions(+), 11 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index fbbc411f..b2c8d5b9 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -364,7 +364,7 @@ AdditionalWeaponAnims=1 ;If the ExtraKillTypes option is enabled, this should be set to 3, with containing entries for any new types ;Must be non-zero to use the edit/get/reset_critical script functions OverrideCriticalTable=2 -;Uncomment the next line to specify an alternative path and file name for the critical table file +;To change the path and filename of the critical table file, uncomment the next line ;OverrideCriticalFile=CriticalOverrides.ini ;Set to 1 to get notification of karma changes in the notification window @@ -724,6 +724,11 @@ CreditsAtBottom=0 ;Paths outside of scripts folder are supported GlobalScriptPaths=scripts\gl*.int,scripts\sfall\gl*.int +;Uncomment the option to specify a common folder path for all scripted ini configuration files +;You will need to place all the available ini files of the mods to this directory +;The maximum length of the specified path is 61 characters +;IniConfigFolder=IniConfig + ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX [Debugging] ;Extra sfall configuration settings that can be used by modders diff --git a/sfall/Modules/ScriptExtender.cpp b/sfall/Modules/ScriptExtender.cpp index e6ee6327..eff5a4a7 100644 --- a/sfall/Modules/ScriptExtender.cpp +++ b/sfall/Modules/ScriptExtender.cpp @@ -53,6 +53,8 @@ static DWORD _stdcall HandleMapUpdateForScripts(const DWORD procId); static int idle; +std::string ScriptExtender::iniConfigFolder; + struct GlobalScript { ScriptProgram prog; int count; @@ -724,6 +726,19 @@ void ScriptExtender::init() { dlogr("Arrays in backward-compatiblity mode.", DL_SCRIPT); } + iniConfigFolder = GetConfigString("Scripts", "IniConfigFolder", ""); + size_t len = iniConfigFolder.length(); + if (len) { + char c = iniConfigFolder[len - 1]; + bool pathSeparator = (c == '\\' || c == '/'); + if (len > 62 || (len == 62 && !pathSeparator)) { + iniConfigFolder.clear(); + dlogr("Error: IniConfigFolder path is too long.", DL_SCRIPT); + } else if (!pathSeparator) { + iniConfigFolder += '\\'; + } + } + alwaysFindScripts = isDebug && (GetPrivateProfileIntA("Debugging", "AlwaysFindScripts", 0, ::sfall::ddrawIni) != 0); if (alwaysFindScripts) dlogr("Always searching for global scripts behavior enabled.", DL_SCRIPT); diff --git a/sfall/Modules/ScriptExtender.h b/sfall/Modules/ScriptExtender.h index bde1fb27..c7473730 100644 --- a/sfall/Modules/ScriptExtender.h +++ b/sfall/Modules/ScriptExtender.h @@ -32,6 +32,8 @@ public: const char* name() { return "ScriptExtender"; } void init(); + static std::string iniConfigFolder; + // Called before map exit (before map_exit_p_proc handlers in normal scripts) static Delegate<>& OnMapExit(); }; diff --git a/sfall/Modules/Scripting/Handlers/Misc.cpp b/sfall/Modules/Scripting/Handlers/Misc.cpp index ec107999..3a9087d1 100644 --- a/sfall/Modules/Scripting/Handlers/Misc.cpp +++ b/sfall/Modules/Scripting/Handlers/Misc.cpp @@ -18,6 +18,7 @@ #include +#include "..\..\..\Utils.h" #include "..\..\..\FalloutEngine\Fallout2.h" #include "..\..\AI.h" #include "..\..\Combat.h" @@ -523,7 +524,8 @@ static int ParseIniSetting(const char* iniString, const char* &key, char section if (!key) return -1; DWORD filelen = (DWORD)key - (DWORD)iniString; - if (filelen >= 64) return -1; + if (ScriptExtender::iniConfigFolder.empty() && filelen >= 64) return -1; + const char* fileEnd = key; key = strstr(key + 1, "|"); if (!key) return -1; @@ -533,9 +535,24 @@ static int ParseIniSetting(const char* iniString, const char* &key, char section file[0] = '.'; file[1] = '\\'; - memcpy(&file[2], iniString, filelen); - file[filelen + 2] = 0; - + if (!ScriptExtender::iniConfigFolder.empty()) { + const char* pos = strfind(iniString, &::sfall::ddrawIni[2]); + if (pos && pos < fileEnd) goto ddraw; + size_t len = ScriptExtender::iniConfigFolder.length(); // limit to 62 characters + memcpy(&file[2], ScriptExtender::iniConfigFolder.c_str(), len); + int n = 0; // position of the beginning of the file name + for (int i = filelen - 4; i > 0; i--) { + if (iniString[i] == '\\' || iniString[i] == '/') { + n = i + 1; + break; + } + } + strncpy_s(&file[2 + len], (128 - 2) - len, &iniString[n], filelen - n); // copy filename (max len 63) + } else { +ddraw: + memcpy(&file[2], iniString, filelen); + file[filelen + 2] = 0; + } memcpy(section, &iniString[filelen + 1], seclen); section[seclen] = 0; @@ -546,7 +563,7 @@ static int ParseIniSetting(const char* iniString, const char* &key, char section static char IniStrBuffer[256]; static DWORD GetIniSetting(const char* str, bool isString) { const char* key; - char section[33], file[67]; + char section[33], file[128]; if (ParseIniSetting(str, key, section, file) < 0) { return -1; @@ -1232,11 +1249,23 @@ void sf_set_ini_setting(OpcodeContext& ctx) { } } +static std::string GetIniFilePath(const ScriptValue& arg) { + std::string fileName(".\\"); + if (ScriptExtender::iniConfigFolder.empty()) { + fileName += arg.strValue(); + } else { + fileName += ScriptExtender::iniConfigFolder; + std::string name(arg.strValue()); + int pos = name.find_last_of("\\/"); + fileName += (pos > 0) ? name.substr(pos + 1) : name; + } + return fileName; +} + char getIniSectionBuf[5120]; void sf_get_ini_sections(OpcodeContext& ctx) { - auto fileName = std::string(".\\") + ctx.arg(0).asString(); - GetPrivateProfileSectionNamesA(getIniSectionBuf, 5120, fileName.data()); + GetPrivateProfileSectionNamesA(getIniSectionBuf, 5120, GetIniFilePath(ctx.arg(0)).data()); std::vector sections; char* section = getIniSectionBuf; while (*section != 0) { @@ -1256,9 +1285,8 @@ void sf_get_ini_sections(OpcodeContext& ctx) { } void sf_get_ini_section(OpcodeContext& ctx) { - auto fileName = std::string(".\\") + ctx.arg(0).asString(); auto section = ctx.arg(1).asString(); - GetPrivateProfileSectionA(section, getIniSectionBuf, 5120, fileName.data()); + GetPrivateProfileSectionA(section, getIniSectionBuf, 5120, GetIniFilePath(ctx.arg(0)).data()); int arrayId = TempArray(-1, 0); // associative auto& arr = arrays[arrayId]; char *key = getIniSectionBuf, *val = nullptr; diff --git a/sfall/Modules/Scripting/Handlers/Utils.cpp b/sfall/Modules/Scripting/Handlers/Utils.cpp index 1feda9cd..d5f85ee6 100644 --- a/sfall/Modules/Scripting/Handlers/Utils.cpp +++ b/sfall/Modules/Scripting/Handlers/Utils.cpp @@ -281,7 +281,7 @@ void sf_message_str_game(OpcodeContext& ctx) { int fileId = fileIdArg.asInt(); int msgId = msgIdArg.asInt(); - if (fileId < 20) { // main msg files + if (fileId >= 0 && fileId <= 19) { // main msg files msg = fo::GetMessageStr(gameMsgFiles[fileId], msgId); } else if (fileId >= 0x1000 && fileId <= 0x1005) { // proto msg files msg = fo::GetMessageStr(&fo::var::proto_msg_files[fileId - 0x1000], msgId); diff --git a/sfall/Utils.cpp b/sfall/Utils.cpp index d8137911..bbf36fba 100644 --- a/sfall/Utils.cpp +++ b/sfall/Utils.cpp @@ -47,4 +47,17 @@ void strtrim(char* str) { } } +// returns position, find word must be lowercase +const char* strfind(const char* source, const char* word) { + if (source == 0 || word == 0 || *word == 0) return 0; + const char *w_pos, *s_pos; + while(*source != 0) { + w_pos = word, s_pos = source++; + while (tolower(*s_pos++) == *w_pos++) { + if (*w_pos == 0) return s_pos - (w_pos - word); + } + } + return 0; +} + } diff --git a/sfall/Utils.h b/sfall/Utils.h index 4231203c..9980376b 100644 --- a/sfall/Utils.h +++ b/sfall/Utils.h @@ -32,4 +32,6 @@ bool isSpace(char c); void strtrim(char* str); +const char* strfind(const char* source, const char* word); + }