Files
sfall/sfall/HRP/Init.cpp
T
2022-02-20 08:05:27 +08:00

357 lines
13 KiB
C++

/*
* sfall
* Copyright (C) 2008-2021 The sfall team
*
*/
#pragma comment(lib, "psapi.lib")
#include <psapi.h>
#include "..\main.h"
#include "..\FalloutEngine\Fallout2.h"
#include "..\Translate.h"
#include "..\Utils.h"
#include "..\WinProc.h"
#include "..\Modules\Graphics.h"
#include "..\Modules\LoadOrder.h"
#include "..\Modules\MiscPatches.h"
#include "..\Modules\SubModules\WindowRender.h"
#include "..\Game\tilemap.h"
#include "viewmap\ViewMap.h"
#include "SplashScreen.h"
#include "MainMenu.h"
#include "InterfaceBar.h"
#include "Dialog.h"
#include "Inventory.h"
#include "Character.h"
#include "LoadSave.h"
#include "MiscInterface.h"
#include "Worldmap.h"
#include "HelpScreen.h"
#include "DeathScreen.h"
#include "SlidesScreen.h"
#include "CreditsScreen.h"
#include "MoviesScreen.h"
#include "Init.h"
namespace HRP
{
namespace sf = sfall;
static const char* f2ResIni = ".\\f2_res.ini";
static DWORD baseDLLAddr = 0; // 0x10000000
bool Setting::VersionIsValid = false;
static bool enabled;
static long SCR_WIDTH = 640;
static long SCR_HEIGHT = 480;
static long COLOUR_BITS = 32;
static char SCALE_2X;
bool Setting::IsEnabled() { return enabled; }
long Setting::ScreenWidth() { return SCR_WIDTH; }
long Setting::ScreenHeight() { return SCR_HEIGHT; }
long Setting::ColorBits() { return COLOUR_BITS; }
char Setting::ScaleX2() { return SCALE_2X; }
static void GetHRPModule() {
baseDLLAddr = (DWORD)GetModuleHandleA("f2_res.dll");
if (baseDLLAddr) sf::dlog_f("Loaded f2_res.dll library at the memory address: 0x%x\n", DL_MAIN, baseDLLAddr);
}
bool Setting::CheckExternalPatch() {
bool isEnabled = (*(DWORD*)0x4E4480 != 0x278805C7); // check if Mash's HRP is enabled
if (isEnabled) {
GetHRPModule();
MODULEINFO info;
if (baseDLLAddr && GetModuleInformation(GetCurrentProcess(), (HMODULE)baseDLLAddr, &info, sizeof(info)) && info.SizeOfImage >= 0x39940 + 7) {
if (sf::GetByteHRPValue(HRP_VAR_VERSION_STR + 7) == 0 && std::strncmp((const char*)GetAddress(HRP_VAR_VERSION_STR), "4.1.8", 5) == 0) {
VersionIsValid = true;
}
}
}
return ExternalEnabled();
}
DWORD Setting::GetAddress(DWORD addr) {
return (baseDLLAddr + (addr & 0xFFFFF));
}
bool Setting::ExternalEnabled() {
return (baseDLLAddr != 0);
}
static std::string GetBackupFileName(const char* runFileName, bool wait) {
std::string bakExeName(runFileName);
size_t n = bakExeName.rfind('.');
if (n == std::string::npos) return std::string(); // empty
bakExeName.replace(n, 4, ".hrp");
char c = 10;
while (std::remove(bakExeName.c_str()) != 0 && wait && --c) Sleep(1000); // delete .hrp (if it exists)
return bakExeName;
}
static bool DisableExtHRP(const char* runFileName, std::string &cmdline) {
std::string bakExeName = std::move(GetBackupFileName(runFileName, false));
if (bakExeName.empty()) return false;
std::rename(runFileName, bakExeName.c_str()); // rename the process file to .hrp
CopyFileA(bakExeName.c_str(), runFileName, 0); // restore .exe (already unoccupied by a running process)
FILE* ft = std::fopen(runFileName,"r+b");
if (!ft) return false;
std::fseek(ft, 0xD4880, SEEK_SET); // 0x4E4480
BYTE restore[] = {0xC7, 0x05, 0x88, 0x27, 0x6B, 0x00, 0x00, 0xE7, 0x4D, 0x00};
_fwrite_nolock(restore, 1, 10, ft);
// 0x4FE1C0 - 0x4FE1E7
std::fseek(ft, 0xEE5C0, SEEK_SET);
DWORD restore1[10] = {0};
_fwrite_nolock(restore1, 4, 10, ft);
std::fclose(ft);
cmdline.append(" -restart");
//MessageBoxA(0, "High Resolution Patch has been successfully deactivated.", "sfall", MB_TASKMODAL | MB_ICONINFORMATION);
ShellExecuteA(0, 0, runFileName, cmdline.c_str(), 0, SW_SHOWDEFAULT); // restart game
return true;
}
static __declspec(naked) void fadeSystemPalette_hook() {
__asm {
call fo::funcoffs::setSystemPalette_;
jmp sfall::WinProc::MessageWindow;
}
}
static __declspec(naked) void combat_turn_run_hook() {
__asm {
push edx;
push ecx;
call sfall::WinProc::WaitMessageWindow;
pop ecx;
pop edx;
jmp fo::funcoffs::process_bk_;
}
}
static __declspec(naked) void gmouse_bk_process() {
__asm {
push edx;
push ecx;
call sfall::WinProc::WaitMessageWindow;
pop ecx;
pop edx;
jmp fo::funcoffs::gmouse_bk_process_;
}
}
/*
static __declspec(naked) void GNW95_process_message_hack() {
__asm {
call sfall::WinProc::WaitMessageWindow;
xor eax, eax;
retn
}
}
*/
void Setting::init(const char* exeFileName, std::string &cmdline) {
ViewMap::RedrawFix();
bool hiResMode = sf::IniReader::GetIntDefaultConfig("Main", "HiResMode", 1) != 0;
if (!Setting::ExternalEnabled() && !hiResMode) return; // vanilla game mode
SCR_WIDTH = sf::IniReader::GetInt("Main", "SCR_WIDTH", 0, f2ResIni);
SCR_HEIGHT = sf::IniReader::GetInt("Main", "SCR_HEIGHT", 0, f2ResIni);
if (SCR_WIDTH == 0 || SCR_HEIGHT == 0) {
SCR_WIDTH = sf::IniReader::GetConfigInt("Graphics", "GraphicsWidth", 640);
SCR_HEIGHT = sf::IniReader::GetConfigInt("Graphics", "GraphicsHeight", 480);
}
if (SCR_WIDTH < 640) SCR_WIDTH = 640;
if (SCR_HEIGHT < 480) SCR_HEIGHT = 480;
if (cmdline.find(" -restart") != std::string::npos) {
GetBackupFileName(exeFileName, true); // delete after restart
}
if (hiResMode == false) return;
if (Setting::ExternalEnabled()) {
char infoMsg[512];
sf::Translate::Get("sfall", "HiResInfo",
"This version of sfall has its own integrated High Resolution Patch mode, which is compatible with the settings of the High Resolution Patch by Mash.\n\n"
"If you want to continue using the Hi-Res Patch by Mash without seeing this message, disable the 'HiResMode' option in ddraw.ini.\n"
"Or you can disable the external Hi-Res Patch to get new graphics improvements from sfall.\n\n"
"Do you want to disable the High Resolution Patch by Mash?", infoMsg, 512);
// replace \n for translated message
for (size_t i = 0; i < sizeof(infoMsg); i++) {
if (infoMsg[i] == '\n' || infoMsg[i] == '\0') break;
if (infoMsg[i] == '\\' && infoMsg[i + 1] == 'n') {
infoMsg[i] = ' ';
infoMsg[++i] = '\n';
}
}
if (MessageBoxA(0, infoMsg, "sfall: Conflict of High Resolution patches", MB_TASKMODAL | MB_ICONWARNING | MB_YESNO) == IDYES) {
if (!DisableExtHRP(exeFileName, cmdline)) {
MessageBoxA(0, "An error occurred while trying to deactivate the High Resolution Patch.", "sfall", MB_TASKMODAL | MB_ICONERROR);
} else {
ExitProcess(EXIT_SUCCESS); //std::exit(EXIT_SUCCESS);
}
}
return;
}
enabled = true;
sf::dlog("Applying built-in High Resolution Patch.", DL_MAIN);
// Read High Resolution config
int windowed = (sf::IniReader::GetInt("Main", "WINDOWED", 0, f2ResIni) != 0) ? 1 : 0;
if (windowed && sf::IniReader::GetInt("Main", "WINDOWED_FULLSCREEN", 0, f2ResIni)) {
windowed += 1;
SCR_WIDTH = GetSystemMetrics(SM_CXSCREEN);
SCR_HEIGHT = GetSystemMetrics(SM_CYSCREEN);
}
int gMode = sf::IniReader::GetInt("Main", "GRAPHICS_MODE", 2, f2ResIni);
if (gMode < 0 || gMode > 2) gMode = 2;
if (gMode <= 1) sf::Graphics::mode = 1 + windowed; // DD7: 1 or 2/3 (vanilla)
if (gMode == 2) sf::Graphics::mode = 4 + windowed; // DX9: 4 or 5/6 (sfall)
if (sf::Graphics::mode == 1) {
COLOUR_BITS = sf::IniReader::GetInt("Main", "COLOUR_BITS", 32, f2ResIni);
if (COLOUR_BITS != 32 && COLOUR_BITS != 24 && COLOUR_BITS != 16) COLOUR_BITS = 32;
}
if (sf::IniReader::GetInt("Main", "SCALE_2X", 0, f2ResIni)) {
if (SCR_HEIGHT < 960 && SCR_WIDTH < 1280) {
SCR_WIDTH = 640;
SCR_HEIGHT = 480;
} else {
SCR_WIDTH /= 2;
SCR_HEIGHT /= 2;
}
SCALE_2X = 1;
}
MainMenuScreen::SCALE_BUTTONS_AND_TEXT_MENU = (sf::IniReader::GetInt("MAINMENU", "SCALE_BUTTONS_AND_TEXT_MENU", 0, f2ResIni) != 0);
MainMenuScreen::USE_HIRES_IMAGES = (sf::IniReader::GetInt("MAINMENU", "USE_HIRES_IMAGES", 1, f2ResIni) != 0);
MainMenuScreen::MENU_BG_OFFSET_X += sf::IniReader::GetInt("MAINMENU", "MENU_BG_OFFSET_X", -14, f2ResIni);
MainMenuScreen::MENU_BG_OFFSET_Y += sf::IniReader::GetInt("MAINMENU", "MENU_BG_OFFSET_Y", -4, f2ResIni);
MainMenuScreen::MAIN_MENU_SIZE = sf::IniReader::GetInt("MAINMENU", "MAIN_MENU_SIZE", 1, f2ResIni);
SplashScreen::SPLASH_SCRN_SIZE = sf::IniReader::GetInt("STATIC_SCREENS", "SPLASH_SCRN_SIZE", 1, f2ResIni);
HelpScreen::HELP_SCRN_SIZE = sf::IniReader::GetInt("STATIC_SCREENS", "HELP_SCRN_SIZE", 0, f2ResIni);
DeathScreen::DEATH_SCRN_SIZE = sf::IniReader::GetInt("STATIC_SCREENS", "DEATH_SCRN_SIZE", 1, f2ResIni);
SlidesScreen::END_SLIDE_SIZE = sf::IniReader::GetInt("STATIC_SCREENS", "END_SLIDE_SIZE", 1, f2ResIni);
MoviesScreen::MOVIE_SIZE = sf::IniReader::GetInt("MOVIES", "MOVIE_SIZE", 1, f2ResIni);
std::string x = sf::trim(sf::IniReader::GetString("MAPS", "SCROLL_DIST_X", "480", 16, f2ResIni));
std::string y = sf::trim(sf::IniReader::GetString("MAPS", "SCROLL_DIST_Y", "400", 16, f2ResIni));
ViewMap::SCROLL_DIST_X = (!x.compare(0, 9, "HALF_SCRN")) ? (SCR_WIDTH / 2) + 32 : std::atol(x.c_str());
ViewMap::SCROLL_DIST_Y = (!y.compare(0, 9, "HALF_SCRN")) ? (SCR_HEIGHT / 2) + 24 : std::atol(y.c_str());
ViewMap::IGNORE_PLAYER_SCROLL_LIMITS = (sf::IniReader::GetInt("MAPS", "IGNORE_PLAYER_SCROLL_LIMITS", 0, f2ResIni) != 0);
ViewMap::IGNORE_MAP_EDGES = (sf::IniReader::GetInt("MAPS", "IGNORE_MAP_EDGES", 0, f2ResIni) != 0);
ViewMap::EDGE_CLIPPING_ON = (sf::IniReader::GetInt("MAPS", "EDGE_CLIPPING_ON", 1, f2ResIni) != 0);
IFaceBar::IFACE_BAR_MODE = sf::IniReader::GetInt("IFACE", "IFACE_BAR_MODE", 0, f2ResIni);
IFaceBar::IFACE_BAR_SIDE_ART = sf::IniReader::GetInt("IFACE", "IFACE_BAR_SIDE_ART", 2, f2ResIni);
IFaceBar::IFACE_BAR_WIDTH = sf::IniReader::GetInt("IFACE", "IFACE_BAR_WIDTH", (!sf::versionCHI && SCR_WIDTH >= 800) ? 800 : 640, f2ResIni);
IFaceBar::IFACE_BAR_SIDES_ORI = (sf::IniReader::GetInt("IFACE", "IFACE_BAR_SIDES_ORI", 0, f2ResIni) != 0);
IFaceBar::ALTERNATE_AMMO_METRE = sf::IniReader::GetInt("IFACE", "ALTERNATE_AMMO_METRE", 0, f2ResIni);
IFaceBar::ALTERNATE_AMMO_LIGHT = (BYTE)sf::IniReader::GetInt("IFACE", "ALTERNATE_AMMO_LIGHT", 196, f2ResIni);
IFaceBar::ALTERNATE_AMMO_DARK = (BYTE)sf::IniReader::GetInt("IFACE", "ALTERNATE_AMMO_DARK", 75, f2ResIni);
Dialog::DIALOG_SCRN_ART_FIX = (sf::IniReader::GetInt("OTHER_SETTINGS", "DIALOG_SCRN_ART_FIX", 1, f2ResIni) != 0);
Dialog::DIALOG_SCRN_BACKGROUND = (sf::IniReader::GetInt("OTHER_SETTINGS", "DIALOG_SCRN_BACKGROUND", 0, f2ResIni) != 0);
if (sf::IniReader::GetInt("OTHER_SETTINGS", "FADE_TIME_RECALCULATE_ON_FADE", 0, f2ResIni)) {
sf::WindowRender::EnableRecalculateFadeSteps();
}
int nodes = sf::IniReader::GetInt("MAPS", "NumPathNodes", 1, f2ResIni);
if (nodes > 1) game::Tilemap::SetPathMaxNodes((nodes < 20) ? nodes * 2000 : 40000);
// add: patchXXX.dat > sfall.dat > [add here] > critter.dat > master.dat
sf::LoadOrder::AddResourcePatches(
sf::IniReader::GetString("Main", "f2_res_dat", "f2_res.dat", MAX_PATH, f2ResIni),
sf::IniReader::GetString("Main", "f2_res_patches", "", MAX_PATH, f2ResIni)
);
/* Inject hacks */
if (sf::IniReader::GetInt("INPUT", "EXTRA_WIN_MSG_CHECKS", 0, f2ResIni)) {
sf::HookCall(0x4C73B1, fadeSystemPalette_hook);
sf::HookCall(0x4227E5, combat_turn_run_hook);
sf::HookCalls(gmouse_bk_process, {
0x460EB0, 0x460EFE, 0x460F54, 0x460FAD, 0x46101D, 0x4610F9, // intface_rotate_numbers_
0x45FA4D, // intface_end_window_open_
0x45FBA6, // intface_end_window_close_
});
}
if (sf::IniReader::GetInt("OTHER_SETTINGS", "CPU_USAGE_FIX", 1, f2ResIni) != 0) {
//sf::MakeCall(0x4C9DA9, GNW95_process_message_hack, 11); // implementation by Mash
sf::MiscPatches::SetIdle(1);
}
sf::SafeWrite32(0x482E30, FO_VAR_mapEntranceTileNum); // map_load_file_ (_tile_center_tile to _mapEntranceTileNum)
if (SCR_WIDTH != 640 || SCR_HEIGHT != 480) {
// Set the resolution for GNW95_init_mode_ex_
sf::SafeWrite32(0x4CAD6B, SCR_WIDTH); // 640
sf::SafeWrite32(0x4CAD66, SCR_HEIGHT); // 480
// initWindow_ "Error initializing video mode ..."
sf::SafeWrite32(0x4B9245, (DWORD)&SCR_WIDTH);
sf::SafeWrite32(0x4B923F, (DWORD)&SCR_HEIGHT);
// Set the resolution for the overlapping temporary black window when loading/starting the game
// main_load_new_
sf::SafeWrite32(0x480D6C, SCR_HEIGHT);
sf::SafeWrite32(0x480D84, SCR_WIDTH);
// gnw_main_
sf::SafeWrite32(0x480AFA, SCR_HEIGHT);
sf::SafeWrite32(0x480B04, SCR_WIDTH);
// LoadGame_
sf::SafeWrite32(0x47C6E0, SCR_HEIGHT);
sf::SafeWrite32(0x47C6E5, SCR_WIDTH);
sf::SafeWrite32(0x47C703, SCR_WIDTH);
sf::SafeWrite32(0x47C70D, SCR_HEIGHT);
}
if (sf::isDebug) sf::SafeWrite8(0x480AF6, fo::WinFlags::Hidden); // gnw_main_
// Inits
SplashScreen::init();
MainMenuScreen::init();
ViewMap::init();
Worldmap::init();
IFaceBar::init();
Dialog::init();
Inventory::init();
Character::init();
LoadSave::init();
MiscInterface::init();
HelpScreen::init();
DeathScreen::init();
SlidesScreen::init();
CreditsScreen::init();
MoviesScreen::init();
sf::dlogr(" Done", DL_MAIN);
}
}