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);