mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
484 lines
14 KiB
C++
484 lines
14 KiB
C++
/*
|
|
* sfall
|
|
* Copyright (C) 2008-2023 The sfall team
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#pragma comment(lib, "psapi.lib")
|
|
|
|
#include <psapi.h>
|
|
|
|
#include "main.h"
|
|
#include "FalloutEngine\Fallout2.h"
|
|
|
|
#include "Modules\AI.h"
|
|
#include "Modules\Animations.h"
|
|
#include "Modules\BarBoxes.h"
|
|
#include "Modules\Books.h"
|
|
#include "Modules\BugFixes.h"
|
|
#include "Modules\BurstMods.h"
|
|
#include "Modules\Combat.h"
|
|
#include "Modules\Console.h"
|
|
#include "Modules\Credits.h"
|
|
#include "Modules\Criticals.h"
|
|
#include "Modules\DamageMod.h"
|
|
#include "Modules\DebugEditor.h"
|
|
#include "Modules\Elevators.h"
|
|
#include "Modules\EngineTweaks.h"
|
|
#include "Modules\Explosions.h"
|
|
#include "Modules\ExtraSaveSlots.h"
|
|
#include "Modules\FileSystem.h"
|
|
#include "Modules\Graphics.h"
|
|
#include "Modules\HeroAppearance.h"
|
|
#include "Modules\HookScripts.h"
|
|
#include "Modules\Input.h"
|
|
#include "Modules\Interface.h"
|
|
#include "Modules\Inventory.h"
|
|
#include "Modules\Karma.h"
|
|
#include "Modules\KillCounter.h"
|
|
#include "Modules\LoadGameHook.h"
|
|
#include "Modules\LoadOrder.h"
|
|
#include "Modules\MainLoopHook.h"
|
|
#include "Modules\MainMenu.h"
|
|
#include "Modules\Message.h"
|
|
#include "Modules\MetaruleExtender.h"
|
|
#include "Modules\MiscPatches.h"
|
|
#include "Modules\Movies.h"
|
|
#include "Modules\Objects.h"
|
|
#include "Modules\PartyControl.h"
|
|
#include "Modules\Perks.h"
|
|
#include "Modules\PlayerModel.h"
|
|
#include "Modules\Premade.h"
|
|
#include "Modules\QuestList.h"
|
|
#include "Modules\Reputations.h"
|
|
#include "Modules\ScriptExtender.h"
|
|
#include "Modules\ScriptShaders.h"
|
|
#include "Modules\Skills.h"
|
|
#include "Modules\Sound.h"
|
|
#include "Modules\SpeedPatch.h"
|
|
#include "Modules\Stats.h"
|
|
#include "Modules\TalkingHeads.h"
|
|
#include "Modules\Tiles.h"
|
|
#include "Modules\Unarmed.h"
|
|
#include "Modules\Worldmap.h"
|
|
|
|
#include "ConsoleWindow.h"
|
|
#include "CRC.h"
|
|
#include "InputFuncs.h"
|
|
#include "Logging.h"
|
|
#include "ReplacementFuncs.h"
|
|
#include "Translate.h"
|
|
#include "Utils.h"
|
|
#include "version.h"
|
|
#include "WinProc.h"
|
|
|
|
ddrawDll ddraw;
|
|
|
|
namespace sfall
|
|
{
|
|
|
|
bool isDebug = false;
|
|
|
|
bool hrpIsEnabled = false;
|
|
bool hrpVersionValid = false; // HRP 4.1.8 version validation
|
|
|
|
static DWORD hrpDLLBaseAddr = 0; // 0x10000000
|
|
|
|
DWORD HRPAddress(DWORD addr) {
|
|
return (hrpDLLBaseAddr + (addr & 0xFFFFF));
|
|
}
|
|
|
|
char falloutConfigName[65];
|
|
|
|
static void ModuleInitLog(const char* name) {
|
|
dlog_f("Initializing module %s...\n", DL_INIT, name);
|
|
}
|
|
|
|
static void InitModules() {
|
|
dlogr("In InitModules", DL_INIT);
|
|
|
|
// fixes should be applied at the beginning
|
|
ModuleInitLog(BugFixes::name());
|
|
BugFixes::init();
|
|
|
|
ModuleInitLog(SpeedPatch::name());
|
|
SpeedPatch::init();
|
|
|
|
ModuleInitLog(Graphics::name());
|
|
Graphics::init();
|
|
|
|
ModuleInitLog(Input::name());
|
|
Input::init();
|
|
|
|
ModuleInitLog(FileSystem::name());
|
|
FileSystem::init();
|
|
|
|
ModuleInitLog(LoadOrder::name());
|
|
LoadOrder::init();
|
|
|
|
ModuleInitLog(LoadGameHook::name());
|
|
LoadGameHook::init();
|
|
|
|
ModuleInitLog(MainLoopHook::name());
|
|
MainLoopHook::init();
|
|
|
|
ModuleInitLog(EngineTweaks::name());
|
|
EngineTweaks::init();
|
|
|
|
ModuleInitLog(Books::name());
|
|
Books::init();
|
|
|
|
ModuleInitLog(Criticals::name());
|
|
Criticals::init();
|
|
|
|
ModuleInitLog(Elevators::name());
|
|
Elevators::init();
|
|
|
|
ModuleInitLog(Unarmed::name());
|
|
Unarmed::init();
|
|
|
|
ModuleInitLog(Animations::name());
|
|
Animations::init();
|
|
|
|
ModuleInitLog(BarBoxes::name());
|
|
BarBoxes::init();
|
|
|
|
ModuleInitLog(Explosions::name());
|
|
Explosions::init();
|
|
|
|
ModuleInitLog(Message::name());
|
|
Message::init();
|
|
|
|
ModuleInitLog(Interface::name());
|
|
Interface::init();
|
|
|
|
ModuleInitLog(Worldmap::name());
|
|
Worldmap::init();
|
|
|
|
ModuleInitLog(Tiles::name());
|
|
Tiles::init();
|
|
|
|
ModuleInitLog(Movies::name());
|
|
Movies::init();
|
|
|
|
ModuleInitLog(Sound::name());
|
|
Sound::init();
|
|
|
|
ModuleInitLog(MiscPatches::name());
|
|
MiscPatches::init();
|
|
|
|
ModuleInitLog(AI::name());
|
|
AI::init();
|
|
|
|
ModuleInitLog(DamageMod::name());
|
|
DamageMod::init();
|
|
|
|
ModuleInitLog(BurstMods::name());
|
|
BurstMods::init();
|
|
|
|
ModuleInitLog(Inventory::name());
|
|
Inventory::init();
|
|
|
|
ModuleInitLog(Objects::name());
|
|
Objects::init();
|
|
|
|
ModuleInitLog(Stats::name());
|
|
Stats::init();
|
|
|
|
ModuleInitLog(Perks::name());
|
|
Perks::init();
|
|
|
|
ModuleInitLog(Skills::name());
|
|
Skills::init();
|
|
|
|
ModuleInitLog(PartyControl::name());
|
|
PartyControl::init();
|
|
|
|
ModuleInitLog(Combat::name());
|
|
Combat::init();
|
|
|
|
ModuleInitLog(PlayerModel::name());
|
|
PlayerModel::init();
|
|
|
|
ModuleInitLog(Karma::name());
|
|
Karma::init();
|
|
|
|
ModuleInitLog(Premade::name());
|
|
Premade::init();
|
|
|
|
ModuleInitLog(Reputations::name());
|
|
Reputations::init();
|
|
|
|
ModuleInitLog(KillCounter::name());
|
|
KillCounter::init();
|
|
|
|
ModuleInitLog(MainMenu::name());
|
|
MainMenu::init();
|
|
|
|
ModuleInitLog(HeroAppearance::name());
|
|
HeroAppearance::init();
|
|
|
|
ModuleInitLog(TalkingHeads::name());
|
|
TalkingHeads::init();
|
|
|
|
ModuleInitLog(ScriptShaders::name());
|
|
ScriptShaders::init();
|
|
|
|
ModuleInitLog(ExtraSaveSlots::name());
|
|
ExtraSaveSlots::init();
|
|
|
|
ModuleInitLog(QuestList::name());
|
|
QuestList::init();
|
|
|
|
ModuleInitLog(Credits::name());
|
|
Credits::init();
|
|
|
|
ModuleInitLog(Console::name());
|
|
Console::init();
|
|
|
|
// most of modules should be initialized before running the script handlers
|
|
ModuleInitLog(MetaruleExtender::name());
|
|
MetaruleExtender::init();
|
|
|
|
ModuleInitLog(HookScripts::name());
|
|
HookScripts::init();
|
|
|
|
ModuleInitLog(ScriptExtender::name());
|
|
ScriptExtender::init();
|
|
|
|
ModuleInitLog(DebugEditor::name());
|
|
DebugEditor::init();
|
|
|
|
dlogr("Leave InitModules", DL_INIT);
|
|
}
|
|
|
|
static void __stdcall OnExit() {
|
|
SpeedPatch::exit();
|
|
Graphics::exit();
|
|
//EngineTweaks::exit();
|
|
Books::exit();
|
|
//Unarmed::exit();
|
|
//Animations:exit();
|
|
BarBoxes::exit();
|
|
//Message::exit();
|
|
Interface::exit();
|
|
Tiles::exit();
|
|
//Movies::exit();
|
|
Sound::exit();
|
|
MiscPatches::exit();
|
|
Skills::exit();
|
|
Reputations::exit();
|
|
HeroAppearance::exit();
|
|
TalkingHeads::exit();
|
|
ExtraSaveSlots::exit();
|
|
Console::exit();
|
|
}
|
|
|
|
static void __declspec(naked) WinMain_hook() {
|
|
__asm {
|
|
pushad;
|
|
call OnExit;
|
|
popad;
|
|
jmp fo::funcoffs::DOSCmdLineDestroy_;
|
|
}
|
|
}
|
|
|
|
static void GetHRPModule() {
|
|
hrpDLLBaseAddr = (DWORD)GetModuleHandleA("f2_res.dll");
|
|
if (hrpDLLBaseAddr) dlog_f("Loaded f2_res.dll library at the memory address: 0x%x\n", DL_MAIN, hrpDLLBaseAddr);
|
|
}
|
|
|
|
static void CompatModeCheck(HKEY root, const char* filepath, int extra) {
|
|
HKEY key;
|
|
char buf[MAX_PATH];
|
|
DWORD size = MAX_PATH;
|
|
DWORD type;
|
|
if (!(type = RegOpenKeyEx(root, "Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers", 0, extra | STANDARD_RIGHTS_READ | KEY_QUERY_VALUE, &key))) {
|
|
if (!RegQueryValueEx(key, filepath, 0, &type, (BYTE*)buf, &size)) {
|
|
if (size && (type == REG_EXPAND_SZ || type == REG_MULTI_SZ || type == REG_SZ)) {
|
|
if (strstr(buf, "256COLOR") || strstr(buf, "640X480") || strstr(buf, "WIN")) {
|
|
RegCloseKey(key);
|
|
|
|
MessageBoxA(0, "Fallout appears to be running in compatibility mode.\n" //, and sfall was not able to disable it.\n"
|
|
"Please check the compatibility tab of fallout2.exe, and ensure that the following settings are unchecked:\n"
|
|
"Run this program in compatibility mode for..., run in 256 colours, and run in 640x480 resolution.\n"
|
|
"If these options are disabled, click the 'change settings for all users' button and see if that enables them.", 0, MB_TASKMODAL | MB_ICONERROR);
|
|
|
|
ExitProcess(-1);
|
|
}
|
|
}
|
|
}
|
|
RegCloseKey(key);
|
|
}
|
|
}
|
|
|
|
static int CheckEXE() {
|
|
return std::strncmp((const char*)0x53C938, "FALLOUT Mapper", 14);
|
|
}
|
|
|
|
static HMODULE SfallInit() {
|
|
char filepath[MAX_PATH];
|
|
GetModuleFileName(0, filepath, MAX_PATH);
|
|
|
|
SetCursor(LoadCursorA(0, IDC_ARROW));
|
|
ShowCursor(1);
|
|
|
|
if (!CRC(filepath)) return 0;
|
|
|
|
LoggingInit();
|
|
ConsoleWindow::instance().init();
|
|
|
|
HookCall(0x4DE7D2, WinMain_hook);
|
|
|
|
// enabling debugging features
|
|
isDebug = (IniReader::GetIntDefaultConfig("Debugging", "Enable", 0) != 0);
|
|
|
|
if (!ddraw.dll) dlogr("Error: Cannot load the original ddraw.dll library.", DL_MAIN);
|
|
|
|
bool isEnabled = (*(DWORD*)0x4E4480 != 0x278805C7); // check if HRP is enabled
|
|
if (isEnabled) {
|
|
GetHRPModule();
|
|
MODULEINFO info;
|
|
if (hrpDLLBaseAddr && GetModuleInformation(GetCurrentProcess(), (HMODULE)hrpDLLBaseAddr, &info, sizeof(info)) && info.SizeOfImage >= 0x39940 + 7) {
|
|
if (GetByteHRPValue(HRP_VAR_VERSION_STR + 7) == 0 && std::strncmp((const char*)HRPAddress(HRP_VAR_VERSION_STR), "4.1.8", 5) == 0) {
|
|
hrpVersionValid = true;
|
|
}
|
|
}
|
|
}
|
|
hrpIsEnabled = (hrpDLLBaseAddr != 0);
|
|
|
|
if (!hrpIsEnabled) WinProc::init();
|
|
|
|
if (IniReader::GetIntDefaultConfig("Debugging", "SkipCompatModeCheck", 0) == 0) {
|
|
int is64bit;
|
|
typedef int (__stdcall *chk64bitproc)(HANDLE, int*);
|
|
HMODULE h = LoadLibrary("Kernel32.dll");
|
|
chk64bitproc proc = (chk64bitproc)GetProcAddress(h, "IsWow64Process");
|
|
if (proc)
|
|
proc(GetCurrentProcess(), &is64bit);
|
|
else
|
|
is64bit = 0;
|
|
FreeLibrary(h);
|
|
|
|
CompatModeCheck(HKEY_CURRENT_USER, filepath, is64bit ? KEY_WOW64_64KEY : 0);
|
|
CompatModeCheck(HKEY_LOCAL_MACHINE, filepath, is64bit ? KEY_WOW64_64KEY : 0);
|
|
}
|
|
|
|
// ini file override
|
|
std::string overrideIni;
|
|
|
|
std::string cmdline(GetCommandLineA());
|
|
ToLowerCase(cmdline);
|
|
|
|
size_t n = cmdline.find(".ini");
|
|
if (n != std::string::npos && (n + 4) < cmdline.length() && cmdline[n + 4] != ' ') {
|
|
n = cmdline.find(".ini", n + 4);
|
|
}
|
|
if (n != std::string::npos) {
|
|
size_t m = n + 3;
|
|
while (n > 0 && cmdline[n] != ' ') n--;
|
|
if (n > 0) overrideIni = cmdline.substr(n + 1, m - n);
|
|
}
|
|
|
|
if (!overrideIni.empty()) {
|
|
HANDLE h = CreateFileA(overrideIni.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
|
|
if (h != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(h);
|
|
IniReader::SetConfigFile(overrideIni.c_str());
|
|
} else {
|
|
MessageBoxA(0, "You gave a command line argument to Fallout, but the configuration ini file was not found.\n"
|
|
"Using default ddraw.ini instead.", "Warning", MB_TASKMODAL | MB_ICONWARNING);
|
|
goto defaultIni;
|
|
}
|
|
} else {
|
|
defaultIni:
|
|
IniReader::SetDefaultConfigFile();
|
|
}
|
|
//std::srand(GetTickCount());
|
|
|
|
IniReader::init();
|
|
|
|
if (IniReader::GetConfigString("Misc", "ConfigFile", "", falloutConfigName, 65)) {
|
|
dlogr("Applying config file patch.", DL_INIT);
|
|
const DWORD configFileAddr[] = {0x444BA5, 0x444BCA};
|
|
SafeWriteBatch<DWORD>((DWORD)&falloutConfigName, configFileAddr);
|
|
} else {
|
|
// if the ConfigFile is not assigned a value
|
|
std::strcpy(falloutConfigName, (const char*)FO_VAR_fallout_config);
|
|
}
|
|
|
|
Translate::init(falloutConfigName);
|
|
|
|
InitReplacementHacks();
|
|
InitInput();
|
|
InitModules();
|
|
|
|
ShowCursor(0);
|
|
|
|
fo::var::setInt(FO_VAR_GNW95_hDDrawLib) = (long)ddraw.sfall;
|
|
return ddraw.sfall;
|
|
}
|
|
|
|
}
|
|
|
|
static bool LoadOriginalDll(DWORD fdwReason) {
|
|
switch (fdwReason) {
|
|
case DLL_PROCESS_ATTACH:
|
|
char path[MAX_PATH];
|
|
CopyMemory(path + GetSystemDirectoryA(path , MAX_PATH - 10), "\\ddraw.dll", 11); // path to original dll
|
|
ddraw.dll = LoadLibraryA(path);
|
|
if (ddraw.dll) {
|
|
ddraw.AcquireDDThreadLock = GetProcAddress(ddraw.dll, "AcquireDDThreadLock");
|
|
ddraw.CheckFullscreen = GetProcAddress(ddraw.dll, "CheckFullscreen");
|
|
ddraw.CompleteCreateSysmemSurface = GetProcAddress(ddraw.dll, "CompleteCreateSysmemSurface");
|
|
ddraw.D3DParseUnknownCommand = GetProcAddress(ddraw.dll, "D3DParseUnknownCommand");
|
|
ddraw.DDGetAttachedSurfaceLcl = GetProcAddress(ddraw.dll, "DDGetAttachedSurfaceLcl");
|
|
ddraw.DDInternalLock = GetProcAddress(ddraw.dll, "DDInternalLock");
|
|
ddraw.DDInternalUnlock = GetProcAddress(ddraw.dll, "DDInternalUnlock");
|
|
ddraw.DSoundHelp = GetProcAddress(ddraw.dll, "DSoundHelp");
|
|
ddraw.DirectDrawCreateClipper = GetProcAddress(ddraw.dll, "DirectDrawCreateClipper");
|
|
ddraw.DirectDrawCreate = GetProcAddress(ddraw.dll, "DirectDrawCreate");
|
|
ddraw.DirectDrawCreateEx = GetProcAddress(ddraw.dll, "DirectDrawCreateEx");
|
|
ddraw.DirectDrawEnumerateA = GetProcAddress(ddraw.dll, "DirectDrawEnumerateA");
|
|
ddraw.DirectDrawEnumerateExA = GetProcAddress(ddraw.dll, "DirectDrawEnumerateExA");
|
|
ddraw.DirectDrawEnumerateExW = GetProcAddress(ddraw.dll, "DirectDrawEnumerateExW");
|
|
ddraw.DirectDrawEnumerateW = GetProcAddress(ddraw.dll, "DirectDrawEnumerateW");
|
|
ddraw.DllCanUnloadNow = GetProcAddress(ddraw.dll, "DllCanUnloadNow");
|
|
ddraw.DllGetClassObject = GetProcAddress(ddraw.dll, "DllGetClassObject");
|
|
ddraw.GetDDSurfaceLocal = GetProcAddress(ddraw.dll, "GetDDSurfaceLocal");
|
|
ddraw.GetOLEThunkData = GetProcAddress(ddraw.dll, "GetOLEThunkData");
|
|
ddraw.GetSurfaceFromDC = GetProcAddress(ddraw.dll, "GetSurfaceFromDC");
|
|
ddraw.RegisterSpecialCase = GetProcAddress(ddraw.dll, "RegisterSpecialCase");
|
|
ddraw.ReleaseDDThreadLock = GetProcAddress(ddraw.dll, "ReleaseDDThreadLock");
|
|
ddraw.SetAppCompatData = GetProcAddress(ddraw.dll, "SetAppCompatData");
|
|
}
|
|
return true;
|
|
case DLL_PROCESS_DETACH:
|
|
if (ddraw.dll) FreeLibrary(ddraw.dll);
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) {
|
|
if (LoadOriginalDll(fdwReason)) {
|
|
if (sfall::CheckEXE()) {
|
|
ddraw.sfall = hinstDLL;
|
|
sfall::MakeCall(0x4DE8DE, sfall::SfallInit); // LoadDirectX_
|
|
}
|
|
}
|
|
return true;
|
|
}
|