From a379e1f998c290db9ed6c32d95d12f85ab787aa4 Mon Sep 17 00:00:00 2001 From: phobos2077 Date: Mon, 13 Mar 2017 02:26:02 +0700 Subject: [PATCH] Added ability to load global scripts from different paths with new GlobalScriptPaths option --- artifacts/ddraw.ini | 6 +++ sfall/FalloutEngine/Functions.cpp | 4 +- sfall/FalloutEngine/Functions.h | 2 +- sfall/FalloutEngine/Functions_def.h | 1 + sfall/FalloutEngine/VariableOffsets.h | 1 + sfall/FalloutEngine/Variables_def.h | 1 + sfall/Logging.cpp | 4 +- sfall/Logging.h | 5 +- sfall/Modules/ScriptExtender.cpp | 70 ++++++++++++++++----------- sfall/Modules/ScriptExtender.h | 7 ++- sfall/Utils.cpp | 16 +++--- sfall/Utils.h | 2 + 12 files changed, 76 insertions(+), 43 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index f5963476..88ecf58d 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -566,6 +566,12 @@ NumbersInDialogue=0 ;Set to 1 to display sfall built-in credits at the bottom of credits.txt contents instead of at the top CreditsAtBottom=0 +[Scripts] +;Comma-separated list of masked paths to load global scripts from +;Only use single slash \ as directory separator +;Paths outside of scripts folder are supported +GlobalScriptPaths=scripts\gl*.int,scripts\sfall\gl*.int + ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX [Debugging] ;Extra sfall configuration settings that can be used by modders diff --git a/sfall/FalloutEngine/Functions.cpp b/sfall/FalloutEngine/Functions.cpp index 736d2fdb..96b98969 100644 --- a/sfall/FalloutEngine/Functions.cpp +++ b/sfall/FalloutEngine/Functions.cpp @@ -125,8 +125,8 @@ long __stdcall db_fwriteByteCount(DbFile* file, const BYTE* cptr, long count) { WRAP_WATCOM_CALL3(db_fwriteByteCount_, file, cptr, count) } -long __stdcall db_get_file_list(const char* searchMask, char* * *fileList, DWORD arg3, DWORD arg4) { - WRAP_WATCOM_CALL4(db_get_file_list_, searchMask, fileList, arg3, arg4) +long __stdcall db_get_file_list(const char* searchMask, char* * *fileList) { + WRAP_WATCOM_CALL2(db_get_file_list_, searchMask, fileList) } // prints message to debug.log file diff --git a/sfall/FalloutEngine/Functions.h b/sfall/FalloutEngine/Functions.h index cf4adefa..5b666559 100644 --- a/sfall/FalloutEngine/Functions.h +++ b/sfall/FalloutEngine/Functions.h @@ -75,7 +75,7 @@ long __stdcall db_fwriteByteCount(DbFile* file, const BYTE* cptr, long count); // searches files in DB by given path/filename mask and stores result in fileList // fileList is a pointer to a variable, that will be assigned with an address of an array of char* strings // returns number of elements in *fileList -long __stdcall db_get_file_list(const char* searchMask, char* * *fileList, DWORD arg3, DWORD arg4); +long __stdcall db_get_file_list(const char* searchMask, char* * *fileList); // prints message to debug.log file void __declspec() debug_printf(const char* fmt, ...); diff --git a/sfall/FalloutEngine/Functions_def.h b/sfall/FalloutEngine/Functions_def.h index 41539624..6deb197f 100644 --- a/sfall/FalloutEngine/Functions_def.h +++ b/sfall/FalloutEngine/Functions_def.h @@ -14,6 +14,7 @@ NOTES: be careful not to use reserved words, including ASM instructions (push, pop, mov, div, etc.) */ +WRAP_WATCOM_FUNC1(Program*, allocateProgram, const char*, filePath) WRAP_WATCOM_FUNC0(void, art_flush) WRAP_WATCOM_FUNC5(long, art_id, long, artType, long, lstIndex, long, animCode, long, weaponCode, long, directionCode) WRAP_WATCOM_FUNC3(BYTE*, art_frame_data, FrmFrameData*, frm, long, frameNum, long, rotation) diff --git a/sfall/FalloutEngine/VariableOffsets.h b/sfall/FalloutEngine/VariableOffsets.h index 30322cb6..334e1f6f 100644 --- a/sfall/FalloutEngine/VariableOffsets.h +++ b/sfall/FalloutEngine/VariableOffsets.h @@ -147,6 +147,7 @@ #define FO_VAR_read_callback 0x51DEEC #define FO_VAR_RedColor 0x6AB4D0 #define FO_VAR_retvals 0x43EA7C +#define FO_VAR_script_path_base 0x51C710 #define FO_VAR_scr_size 0x6AC9F0 #define FO_VAR_scriptListInfo 0x51C7C8 #define FO_VAR_skill_data 0x51D118 diff --git a/sfall/FalloutEngine/Variables_def.h b/sfall/FalloutEngine/Variables_def.h index 8e85eb5d..15565066 100644 --- a/sfall/FalloutEngine/Variables_def.h +++ b/sfall/FalloutEngine/Variables_def.h @@ -144,6 +144,7 @@ VAR_(quick_done, DWORD) VAR_(read_callback, DWORD) VAR_(RedColor, BYTE) VAR2(retvals, ElevatorExit, 24, 4) // 24 elevators, 4 exits each +VAR_(script_path_base, const char*) VAR_(scr_size, DWORD) VAR_(scriptListInfo, ScriptListInfoItem*) // dynamic array VARA(skill_data, SkillInfo, SKILL_count) diff --git a/sfall/Logging.cpp b/sfall/Logging.cpp index c70ea7ff..1e820b93 100644 --- a/sfall/Logging.cpp +++ b/sfall/Logging.cpp @@ -31,13 +31,13 @@ using namespace std; static int DebugTypes=0; static ofstream Log; -void dlog(const char* a, int type) { +void dlog(const std::string& a, int type) { if (isDebug && (type == DL_MAIN || (type & DebugTypes))) { Log << a; Log.flush(); } } -void dlogr(const char* a, int type) { +void dlogr(const std::string& a, int type) { if (isDebug && (type == DL_MAIN || (type & DebugTypes))) { Log << a << "\r\n"; Log.flush(); diff --git a/sfall/Logging.h b/sfall/Logging.h index 665c18fc..3cab718f 100644 --- a/sfall/Logging.h +++ b/sfall/Logging.h @@ -24,12 +24,13 @@ #ifndef NO_SFALL_DEBUG #include +#include namespace sfall { -void dlog(const char* msg, int type); -void dlogr(const char* msg, int type); +void dlog(const std::string&, int type); +void dlogr(const std::string&, int type); void dlog_f(const char *format, int type, ...); void LoggingInit(); diff --git a/sfall/Modules/ScriptExtender.cpp b/sfall/Modules/ScriptExtender.cpp index ce0f09fe..306fdd8f 100644 --- a/sfall/Modules/ScriptExtender.cpp +++ b/sfall/Modules/ScriptExtender.cpp @@ -24,14 +24,15 @@ #include "..\main.h" #include "..\FalloutEngine\Fallout2.h" #include "..\InputFuncs.h" +#include "..\Logging.h" #include "..\Version.h" +#include "..\Utils.h" #include "BarBoxes.h" #include "Console.h" #include "HookScripts.h" #include "LoadGameHook.h" #include "MainLoopHook.h" #include "Worldmap.h" -#include "..\Logging.h" #include "Scripting\Arrays.h" #include "Scripting\Opcodes.h" #include "Scripting\OpcodeContext.h" @@ -49,14 +50,14 @@ void _stdcall HandleMapUpdateForScripts(DWORD procId); // TODO: move to a better place static char idle; -struct sGlobalScript { +struct GlobalScript { ScriptProgram prog; int count; int repeat; int mode; //0 - local map loop, 1 - input loop, 2 - world map loop, 3 - local and world map loops - sGlobalScript() {} - sGlobalScript(ScriptProgram script) { + GlobalScript() {} + GlobalScript(ScriptProgram script) { prog = script; count = 0; repeat = 0; @@ -64,21 +65,21 @@ struct sGlobalScript { } }; -struct sExportedVar { +struct ExportedVar { int type; // in scripting engine terms, eg. VAR_TYPE_* int val; - sExportedVar() : val(0), type(VAR_TYPE_INT) {} + ExportedVar() : val(0), type(VAR_TYPE_INT) {} }; static std::vector checkedScripts; -static std::vector globalScripts; +static std::vector globalScripts; // a map of all sfall programs (global and hook scripts) by thier scriptPtr typedef std::unordered_map SfallProgsMap; static SfallProgsMap sfallProgsMap; // a map scriptPtr => self_obj to override self_obj for all script types using set_self std::unordered_map selfOverrideMap; -typedef std::tr1::unordered_map ExportedVarsMap; +typedef std::tr1::unordered_map ExportedVarsMap; static ExportedVarsMap globalExportedVars; DWORD isGlobalScriptLoading = 0; DWORD modifiedIni; @@ -185,7 +186,7 @@ static DWORD __stdcall GetGlobalExportedVarPtr(const char* name) { ExportedVarsMap::iterator it = globalExportedVars.find(str); //dlog_f("\n Trying to find exported var %s... ", DL_MAIN, name); if (it != globalExportedVars.end()) { - sExportedVar *ptr = &it->second; + ExportedVar *ptr = &it->second; return (DWORD)ptr; } return 0; @@ -194,7 +195,7 @@ static DWORD __stdcall GetGlobalExportedVarPtr(const char* name) { static DWORD __stdcall CreateGlobalExportedVar(DWORD scr, const char* name) { //dlog_f("\nTrying to export variable %s (%d)\r\n", DL_MAIN, name, isGlobalScriptLoading); std::string str(name); - globalExportedVars[str] = sExportedVar(); // add new + globalExportedVars[str] = ExportedVar(); // add new return 1; } @@ -354,8 +355,11 @@ void _stdcall SetSelfObject(fo::Program* script, fo::GameObject* obj) { } // loads script from .int file into a sScriptProgram struct, filling script pointer and proc lookup table -void LoadScriptProgram(ScriptProgram &prog, const char* fileName) { - fo::Program* scriptPtr = fo::func::loadProgram(fileName); +void LoadScriptProgram(ScriptProgram &prog, const char* fileName, bool fullPath) { + fo::Program* scriptPtr = fullPath + ? fo::func::allocateProgram(fileName) + : fo::func::loadProgram(fileName); + if (scriptPtr) { const char** procTable = fo::var::procTableStrs; prog.ptr = scriptPtr; @@ -382,7 +386,7 @@ void AddProgramToMap(ScriptProgram &prog) { } ScriptProgram* GetGlobalScriptProgram(fo::Program* scriptPtr) { - for (std::vector::iterator it = globalScripts.begin(); it != globalScripts.end(); it++) { + for (std::vector::iterator it = globalScripts.begin(); it != globalScripts.end(); it++) { if (it->prog.ptr == scriptPtr) return &it->prog; } return nullptr; @@ -396,30 +400,29 @@ bool _stdcall IsGameScript(const char* filename) { return false; } -// this runs after the game was loaded/started -void LoadGlobalScripts() { - isGameLoading = false; - LoadHookScripts(); - dlogr("Loading global scripts", DL_SCRIPT|DL_INIT); - - char* name = "scripts\\gl*.int"; +void LoadGLobalScriptsByMask(const std::string& fileMask) { char* *filenames; - int count = fo::func::db_get_file_list(name, &filenames, 0, 0); + auto basePath = fileMask.substr(0, fileMask.find_last_of("\\/") + 1); + ToLowerCase(basePath); + int count = fo::func::db_get_file_list(fileMask.c_str(), &filenames); // TODO: refactor script programs ScriptProgram prog; for (int i = 0; i < count; i++) { - name = _strlwr(filenames[i]); - name[strlen(name) - 4] = 0; - if (!IsGameScript(name)) { + char* name = _strlwr(filenames[i]); + std::string baseName(name); + baseName = baseName.substr(0, baseName.find_last_of('.')); + if (basePath != fo::var::script_path_base || !IsGameScript(baseName.c_str())) { dlog(">", DL_SCRIPT); - dlog(name, DL_SCRIPT); + std::string fullPath(basePath); + fullPath += name; + dlog(fullPath, DL_SCRIPT); isGlobalScriptLoading = 1; - LoadScriptProgram(prog, name); + LoadScriptProgram(prog, fullPath.c_str(), true); if (prog.ptr) { dlogr(" Done", DL_SCRIPT); DWORD idx; - sGlobalScript gscript = sGlobalScript(prog); + GlobalScript gscript = GlobalScript(prog); idx = globalScripts.size(); globalScripts.push_back(gscript); AddProgramToMap(prog); @@ -432,6 +435,17 @@ void LoadGlobalScripts() { } } fo::func::db_free_file_list(&filenames, 0); +} + +// this runs after the game was loaded/started +void LoadGlobalScripts() { + isGameLoading = false; + LoadHookScripts(); + dlogr("Loading global scripts", DL_SCRIPT|DL_INIT); + auto maskList = GetConfigList("Scripts", "GlobalScriptPaths", "scripts\\gl*.int", 255); + for (auto& mask : maskList) { + LoadGLobalScriptsByMask(mask); + } dlogr("Finished loading global scripts", DL_SCRIPT|DL_INIT); //ButtonsReload(); } @@ -515,7 +529,7 @@ void RunScriptProc(ScriptProgram* prog, long procId) { } } -static void RunScript(sGlobalScript* script) { +static void RunScript(GlobalScript* script) { script->count = 0; RunScriptProc(&script->prog, fo::ScriptProc::start); // run "start" } diff --git a/sfall/Modules/ScriptExtender.h b/sfall/Modules/ScriptExtender.h index abc14c81..020752bb 100644 --- a/sfall/Modules/ScriptExtender.h +++ b/sfall/Modules/ScriptExtender.h @@ -72,8 +72,11 @@ void GetAppearanceGlobals(int *race, int *style); void _stdcall RegAnimCombatCheck(DWORD newValue); bool _stdcall ScriptHasLoaded(fo::Program* script); -// loads script from .int file into scripting engine, fill scriptPtr and proc table -void LoadScriptProgram(ScriptProgram &prog, const char* fileName); +// loads script from .int file into a sScriptProgram struct, filling script pointer and proc lookup table +// prog - reference to program structure +// fileName - the script file name without extension (if fullPath is false) or a full file path (if fullPath is true) +// fullPath - controls how fileName is used (see above) +void LoadScriptProgram(ScriptProgram &prog, const char* fileName, bool fullPath = false); // init program after load, needs to be called once void InitScriptProgram(ScriptProgram &prog); // execute script by specific proc name diff --git a/sfall/Utils.cpp b/sfall/Utils.cpp index dc59e126..231866da 100644 --- a/sfall/Utils.cpp +++ b/sfall/Utils.cpp @@ -13,12 +13,16 @@ std::vector split(const std::string &s, char delim) { } std::string trim(const std::string& str) { - size_t first = str.find_first_not_of(' '); - if (std::string::npos == first) { - return str; - } - size_t last = str.find_last_not_of(' '); - return str.substr(first, (last - first + 1)); + size_t first = str.find_first_not_of(' '); + if (std::string::npos == first) { + return str; + } + size_t last = str.find_last_not_of(' '); + return str.substr(first, (last - first + 1)); +} + +void ToLowerCase(std::string& line) { + std::transform(line.begin(), line.end(), line.begin(), ::tolower); } } diff --git a/sfall/Utils.h b/sfall/Utils.h index 64a9bf08..93ba06a5 100644 --- a/sfall/Utils.h +++ b/sfall/Utils.h @@ -26,4 +26,6 @@ std::vector split(const std::string &s, char delim); std::string trim(const std::string& str); +void ToLowerCase(std::string& line); + }