From a9ad1a62eb44db6f2258522f24ae65afb3461452 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Sun, 15 Dec 2019 10:31:50 +0800 Subject: [PATCH] Tweaked the path to load global shaders in the previous commit * although 3.8 doesn't have the path issue as 4.x due to the lack of loading custom .dat, it's better to unify the path in this case. Refactored the code for DataLoadOrderPatch in the same way as 4.x. --- artifacts/ddraw.ini | 2 +- artifacts/scripting/sfall function notes.txt | 2 +- sfall/FalloutEngine.cpp | 4 +- sfall/FalloutEngine.h | 5 +- sfall/Graphics.cpp | 8 +- sfall/LoadOrder.cpp | 84 +++++++++++--------- 6 files changed, 57 insertions(+), 48 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index ce87de8b..7cdb9c60 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -65,7 +65,7 @@ GraphicsWidth=0 GraphicsHeight=0 ;Uncomment the option to use a hardware shader (requires DX9 graphics mode 4 or 5) -;The shader file .fx must be placed in data\shaders\ and must contain one technique with one or more passes +;The shader file .fx must be placed in \\shaders\ and must contain one technique with one or more passes ;GlobalShaderFile=global.fx ;Set to 1 to do the palette conversion on the GPU diff --git a/artifacts/scripting/sfall function notes.txt b/artifacts/scripting/sfall function notes.txt index 4ee95be1..e0dcad85 100644 --- a/artifacts/scripting/sfall function notes.txt +++ b/artifacts/scripting/sfall function notes.txt @@ -24,7 +24,7 @@ The input functions are only available if the user has the input hook turned on The graphics functions are only available if the user is using graphics mode 4 or 5. Use graphics_funcs_available to check; it returns 1 if you can use them or 0 if you can't. Calling graphics functions when graphics_funcs_available returns 0 will do nothing. -load_shader takes a path relative to the data\shaders\ directory as an argument and returns a shader ID. That ID should be passed as the first argument to all other shader functions, and is valid until free_shader is called on the ID, the player loads a saved game or the player quits to the main menu. +load_shader takes a path relative to the \\shaders\ directory as an argument and returns a shader ID. That ID should be passed as the first argument to all other shader functions, and is valid until free_shader is called on the ID, the player loads a saved game or the player quits to the main menu. get_shader_version gives you the highest shader version supported by the player's graphics cards. Possible return values are 11, 12, 13, 14, 20, 21 and 30. diff --git a/sfall/FalloutEngine.cpp b/sfall/FalloutEngine.cpp index 1f1b2a71..ed6199d1 100644 --- a/sfall/FalloutEngine.cpp +++ b/sfall/FalloutEngine.cpp @@ -46,7 +46,7 @@ DWORD* ptr_combat_state = reinterpret_cast(_combat_state); DWORD* ptr_combat_turn_running = reinterpret_cast(_combat_turn_running); DWORD* ptr_combatNumTurns = reinterpret_cast(_combatNumTurns); DWORD* ptr_crit_succ_eff = reinterpret_cast(_crit_succ_eff); -DWORD* ptr_critter_db_handle = reinterpret_cast(_critter_db_handle); +PathNode** ptr_critter_db_handle = reinterpret_cast(_critter_db_handle); DWORD* ptr_critterClearObj = reinterpret_cast(_critterClearObj); DWORD* ptr_crnt_func = reinterpret_cast(_crnt_func); DWORD* ptr_curr_font_num = reinterpret_cast(_curr_font_num); @@ -123,7 +123,7 @@ DWORD* ptr_main_ctd = reinterpret_cast(_main_ctd); DWORD* ptr_main_window = reinterpret_cast(_main_window); DWORD* ptr_map_elevation = reinterpret_cast(_map_elevation); DWORD* ptr_map_global_vars = reinterpret_cast(_map_global_vars); -DWORD* ptr_master_db_handle = reinterpret_cast(_master_db_handle); +PathNode** ptr_master_db_handle = reinterpret_cast(_master_db_handle); DWORD* ptr_max = reinterpret_cast(_max); long* ptr_maxScriptNum = reinterpret_cast(_maxScriptNum); DWORD* ptr_Meet_Frank_Horrigan = reinterpret_cast(_Meet_Frank_Horrigan); diff --git a/sfall/FalloutEngine.h b/sfall/FalloutEngine.h index 24d3d958..33271dc8 100644 --- a/sfall/FalloutEngine.h +++ b/sfall/FalloutEngine.h @@ -94,6 +94,7 @@ #define _game_global_vars 0x5186C0 #define _game_ui_disabled 0x5186B4 #define _game_user_wants_to_quit 0x5186CC +#define _gconfig_file_name 0x58E978 #define _gcsd 0x51094C #define _gdBarterMod 0x51873C #define _gDialogMusicVol 0x5187D8 @@ -300,7 +301,7 @@ extern DWORD* ptr_combat_state; extern DWORD* ptr_combat_turn_running; extern DWORD* ptr_combatNumTurns; extern DWORD* ptr_crit_succ_eff; -extern DWORD* ptr_critter_db_handle; +extern PathNode** ptr_critter_db_handle; extern DWORD* ptr_critterClearObj; extern DWORD* ptr_crnt_func; extern DWORD* ptr_curr_font_num; @@ -377,7 +378,7 @@ extern DWORD* ptr_main_ctd; extern DWORD* ptr_main_window; extern DWORD* ptr_map_elevation; extern DWORD* ptr_map_global_vars; -extern DWORD* ptr_master_db_handle; +extern PathNode** ptr_master_db_handle; extern DWORD* ptr_max; extern long* ptr_maxScriptNum; extern DWORD* ptr_Meet_Frank_Horrigan; diff --git a/sfall/Graphics.cpp b/sfall/Graphics.cpp index 8256cfc8..9dc55080 100644 --- a/sfall/Graphics.cpp +++ b/sfall/Graphics.cpp @@ -196,8 +196,8 @@ void _stdcall SetShaderMode(DWORD d, DWORD mode) { int _stdcall LoadShader(const char* file) { if (!GraphicsMode || strstr(file, "..") || strstr(file, ":")) return -1; char buf[MAX_PATH]; - PathNode* pathsPtr = *ptr_paths; - sprintf_s(buf, "%s\\shaders\\%s", pathsPtr->path, file); + PathNode* masterPtr = *ptr_master_db_handle; + sprintf_s(buf, "%s\\shaders\\%s", masterPtr->path, file); // *ptr_patches for (DWORD d = 0; d < shadersSize; d++) { if (!shaders[d].Effect) { if (FAILED(D3DXCreateEffectFromFile(d3d9Device, buf, 0, 0, 0, 0, &shaders[d].Effect, 0))) { @@ -218,7 +218,7 @@ int _stdcall LoadShader(const char* file) { sprintf(buf, "texname%d", i); if (FAILED(shader.Effect->GetString(buf, &name))) break; - sprintf_s(buf, "%s\\art\\stex\\%s", *ptr_patches, name); + sprintf_s(buf, "%s\\art\\stex\\%s", masterPtr->path, name); // *ptr_patches if (FAILED(D3DXCreateTextureFromFileA(d3d9Device, buf, &tex))) continue; sprintf(buf, "tex%d", i); shader.Effect->SetTexture(buf, tex); @@ -1123,11 +1123,11 @@ void GraphicsInit() { if (!h) { MessageBoxA(0, "You have selected graphics mode 4 or 5, but " _DLL_NAME " is missing.\n" "Switch back to mode 0, or install an up to date version of DirectX.", "Error", MB_TASKMODAL | MB_ICONERROR); +#undef _DLL_NAME ExitProcess(-1); } else { FreeLibrary(h); } -#undef _DLL_NAME SafeWrite8(0x50FB6B, '2'); // Set call DirectDrawCreate2 HookCall(0x44260C, game_init_hook); dlogr(" Done", DL_INIT); diff --git a/sfall/LoadOrder.cpp b/sfall/LoadOrder.cpp index fd1f7d78..c829ab5a 100644 --- a/sfall/LoadOrder.cpp +++ b/sfall/LoadOrder.cpp @@ -21,37 +21,34 @@ static std::vector savPrototypes; -static void __declspec(naked) RemoveDatabase() { - __asm { - cmp eax, -1; - je end; - mov ebx, ds:[_paths]; - mov ecx, ebx; -nextPath: - mov edx, [esp + 0x104 + 4 + 4]; // path_patches - mov eax, [ebx]; // database.path - call stricmp_; - test eax, eax; // found path? - jz skip; // Yes - mov ecx, ebx; - mov ebx, [ebx + 0xC]; // database.next - jmp nextPath; -skip: - mov eax, [ebx + 0xC]; // database.next - mov [ecx + 0xC], eax; // database.next - xchg ebx, eax; - cmp eax, ecx; - jne end; - mov ds:[_paths], ebx; -end: - retn; +static PathNode* __fastcall RemoveDatabase(const char* pathPatches) { + PathNode* paths = *ptr_paths; // curr.node (beginning of the chain of paths) + PathNode* pPaths = paths; // prev.node + + while (paths) { + if (_stricmp(paths->path, pathPatches) == 0) { // found path + PathNode* nextPaths = paths->next; // pointer to the node of the next path +// TODO: need to check if this condition is used correctly + if (paths != pPaths) + pPaths->next = nextPaths; // replace the pointer in the previous node, removing the current(found) path from the chain + else // if the current node is equal to the previous node + *ptr_paths = nextPaths; // set the next node at the beginning of the chain + return paths; // return the pointer of the current removed node (save the pointer) + } + pPaths = paths; // prev.node <- curr.node + paths = paths->next; // take a pointer to the next path from the current node } + return nullptr; // it's possible that this will create an exceptional situation for the game, although such a situation should not arise } // Remove master_patches from the chain static void __declspec(naked) game_init_databases_hack1() { __asm { + cmp eax, -1; + je skip; + mov ecx, [esp + 0x104 + 4]; // path_patches call RemoveDatabase; +skip: mov ds:[_master_db_handle], eax; // the pointer of master_patches node will be saved here retn; } @@ -67,7 +64,7 @@ static void __declspec(naked) game_init_databases_hack2() { call xremovepath_; dec eax; // remove path (critter_patches == master_patches)? jz end; // Yes (jump if 0) - inc eax; + mov ecx, [esp + 0x104 + 4]; // path_patches call RemoveDatabase; end: mov ds:[_critter_db_handle], eax; // the pointer of critter_patches node will be saved here @@ -75,20 +72,29 @@ end: } } -static void __declspec(naked) game_init_databases_hook() { - // eax = _master_db_handle - __asm { - mov ecx, ds:[_critter_db_handle]; - mov edx, ds:[_paths]; - test ecx, ecx; - jz skip; - mov [ecx + 0xC], edx; // critter_patches.next->_paths - mov edx, ecx; -skip: - mov [eax + 0xC], edx; // master_patches.next - mov ds:[_paths], eax; - retn; +static void __fastcall game_init_databases_hook() { // eax = _master_db_handle + PathNode* master_patches = *ptr_master_db_handle; + PathNode* critter_patches = *ptr_critter_db_handle; + PathNode* paths = *ptr_paths; // beginning of the chain of paths + // insert master_patches/critter_patches at the beginning of the chain of paths + if (critter_patches) { + critter_patches->next = paths; // critter_patches.next -> paths + paths = critter_patches; } + master_patches->next = paths; // master_patches.next -> paths + *ptr_paths = master_patches; // set master_patches node at the beginning of the chain of paths +} + +static void __fastcall game_init_databases_hook1() { + char masterPatch[MAX_PATH]; + iniGetString("system", "master_patches", "", masterPatch, MAX_PATH - 1, (const char*)_gconfig_file_name); + + PathNode* node = *ptr_paths; + while (node->next) { + if (!_stricmp(node->path, masterPatch)) break; + node = node->next; + } + *ptr_master_db_handle = node; // set pointer to master_patches node } static void MultiPatchesPatch() { @@ -251,6 +257,8 @@ void LoadOrderInit() { HookCall(0x44436D, game_init_databases_hook); SafeWrite8(0x4DFAEC, 0x1D); // error correction (ecx > ebx) dlogr(" Done", DL_INIT); + } else { + HookCall(0x44436D, game_init_databases_hook1); } dlog("Applying party member protos save/load patch.", DL_INIT);