Added support for closing the game by Alt+F4

Moved some code from Graphics.cpp to new WinProc files.
Patched dead code in memory in DamageMod.cpp.
This commit is contained in:
NovaRain
2023-03-16 10:55:05 +08:00
parent f6675cf241
commit 0c3d6004a7
9 changed files with 305 additions and 110 deletions
@@ -235,6 +235,7 @@ FUNC(frame_ptr_, 0x419880)
FUNC(game_exit_, 0x442C34)
FUNC(game_get_global_var_, 0x443C68)
FUNC(game_help_, 0x443F74)
FUNC(game_quit_with_confirm_, 0x4440B8)
FUNC(game_reset_, 0x442B84)
FUNC(game_screendump_, 0x443EF0)
FUNC(game_set_global_var_, 0x443C98)
@@ -457,6 +458,7 @@ FUNC(main_init_system_, 0x480CC0)
FUNC(main_load_new_, 0x480D4C)
FUNC(main_menu_create_, 0x481650)
FUNC(main_menu_hide_, 0x481A00)
FUNC(main_menu_is_shown_, 0x481A8C)
FUNC(main_menu_loop_, 0x481AEC)
// (int aObjFrom<eax>, int aTileFrom<edx>, char* aPathPtr<ecx>, int aTileTo<ebx>, int a5, int (__fastcall *a6)(_DWORD, _DWORD))
// - path is saved in ecx as a sequence of tile directions (0..5) to move on each step,
+1
View File
@@ -119,6 +119,7 @@
#define FO_VAR_GNW95_hDDrawLib 0x51E44C
#define FO_VAR_GNW95_hwnd 0x51E434 // main hwnd window
#define FO_VAR_GNW95_isActive 0x51E444
#define FO_VAR_GNW95_keyboardHandle 0x6AC758
#define FO_VAR_GNW95_repeat_delay 0x51E240
#define FO_VAR_GNW95_repeat_rate 0x51E23C
#define FO_VAR_GNWWin 0x5195B8
+2 -2
View File
@@ -501,12 +501,12 @@ void DamageMod::init() {
switch (formula) {
case 1:
case 2:
MakeJump(0x424995, DamageGlovz);
MakeJump(0x424995, DamageGlovz, 2);
MakeCall(0x49B54A, AmmoInfoPrintGlovz, 2); // Dmg Mod (obj_examine_func_)
Translate::Get("sfall", "AmmoInfoGlovz", "Div: DR/%d, DT/%d", ammoInfoFmt, 32);
break;
case 5:
MakeJump(0x424995, DamageYAAM);
MakeJump(0x424995, DamageYAAM, 2);
MakeCall(0x49B4EB, AmmoInfoPrintYAAM, 2); // DR Mod (obj_examine_func_)
Translate::Get("sfall", "AmmoInfoYAAM", "DT Mod: %d", ammoInfoFmt, 32);
break;
+9 -108
View File
@@ -20,6 +20,7 @@
#include "..\FalloutEngine\Fallout2.h"
#include "..\InputFuncs.h"
#include "..\version.h"
#include "..\WinProc.h"
#include "LoadGameHook.h"
#include "ScriptShaders.h"
#include "Movies.h"
@@ -95,13 +96,8 @@ static struct PALCOLOR {
static bool paletteInit = false;
static long windowLeft = 0;
static long windowTop = 0;
static HWND window;
static long moveWindowKey[2];
static long windowData;
static DWORD ShaderVersion;
IDirect3D9* d3d9;
@@ -165,14 +161,6 @@ static void WindowInit() {
ScriptShaders::LoadGlobalShader();
}
static void SetWindowToCenter() {
RECT desktop;
GetWindowRect(GetDesktopWindow(), &desktop);
windowLeft = (desktop.right / 2) - (gWidth / 2);
windowTop = (desktop.bottom / 2) - (gHeight / 2);
}
// pixel size for the current game resolution
const float* Graphics::rcpresGet() {
return rcpres;
@@ -374,46 +362,7 @@ static void DrawFPS() {}
#endif
static void Present() {
if (moveWindowKey[0] != 0 && (KeyDown(moveWindowKey[0]) || (moveWindowKey[1] != 0 && KeyDown(moveWindowKey[1])))) {
int mx, my;
GetMouse(&mx, &my);
windowLeft += mx;
windowTop += my;
RECT toRect, curRect;
toRect.left = windowLeft;
toRect.right = windowLeft + gWidth;
toRect.top = windowTop;
toRect.bottom = windowTop + gHeight;
AdjustWindowRect(&toRect, WS_CAPTION, false);
toRect.right -= (toRect.left - windowLeft);
toRect.left = windowLeft;
toRect.bottom -= (toRect.top - windowTop);
toRect.top = windowTop;
if (GetWindowRect(GetShellWindow(), &curRect)) {
if (toRect.right > curRect.right) {
DWORD move = toRect.right - curRect.right;
windowLeft -= move;
toRect.right -= move;
} else if (toRect.left < curRect.left) {
DWORD move = curRect.left - toRect.left;
windowLeft += move;
toRect.right += move;
}
if (toRect.bottom > curRect.bottom) {
DWORD move = toRect.bottom - curRect.bottom;
windowTop -= move;
toRect.bottom -= move;
} else if (toRect.top < curRect.top) {
DWORD move = curRect.top - toRect.top;
windowTop += move;
toRect.bottom += move;
}
}
MoveWindow(window, windowLeft, windowTop, toRect.right - windowLeft, toRect.bottom - windowTop, true);
}
WinProc::Moving();
if (d3d9Device->Present(0, 0, 0, 0) == D3DERR_DEVICELOST) {
#ifndef NDEBUG
@@ -1036,27 +985,12 @@ public:
HRESULT __stdcall SetCooperativeLevel(HWND a, DWORD b) { // called 0x4CB005 GNW95_init_DirectDraw_
window = a;
char windowTitle[128];
if (ResWidth != gWidth || ResHeight != gHeight) {
std::sprintf(windowTitle, "%s @sfall " VERSION_STRING " : %ix%i >> %ix%i", (const char*)0x50AF08, ResWidth, ResHeight, gWidth, gHeight);
} else {
std::sprintf(windowTitle, "%s @sfall " VERSION_STRING " : %ix%i", (const char*)0x50AF08, ResWidth, ResHeight);
}
SetWindowTextA(a, windowTitle);
WinProc::SetHWND(window);
WinProc::SetTitle(ResWidth, ResHeight, gWidth, gHeight);
if (Graphics::mode >= 5) {
long windowStyle = (Graphics::mode == 5) ? (WS_VISIBLE | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU) : WS_OVERLAPPED;
SetWindowLongA(a, GWL_STYLE, windowStyle);
RECT r;
r.left = 0;
r.right = gWidth;
r.top = 0;
r.bottom = gHeight;
AdjustWindowRect(&r, windowStyle, false);
r.right -= r.left;
r.bottom -= r.top;
SetWindowPos(a, HWND_NOTOPMOST, windowLeft, windowTop, r.right, r.bottom, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOCOPYBITS);
WinProc::SetStyle(windowStyle);
}
if (!d3d9Device) {
@@ -1120,15 +1054,8 @@ HRESULT __stdcall InitFakeDirectDrawCreate(void*, IDirectDraw** b, void*) {
Graphics::GPUBlt = 2; // Swap them around to keep compatibility with old ddraw.ini
else if (Graphics::GPUBlt == 2) Graphics::GPUBlt = 0; // Use CPU
if (Graphics::mode == 5) {
windowData = IniReader::GetConfigInt("Graphics", "WindowData", -1);
if (windowData > 0) {
windowLeft = windowData >> 16;
windowTop = windowData & 0xFFFF;
} else if (windowData == -1) {
SetWindowToCenter();
}
}
WinProc::SetSize(gWidth, gHeight);
if (Graphics::mode == 5) WinProc::LoadPosition();
rcpres[0] = 1.0f / (float)gWidth;
rcpres[1] = 1.0f / (float)gHeight;
@@ -1310,29 +1237,7 @@ void Graphics::init() {
dShowMovies = Movies::DirectShowMovies();
}
if (Graphics::mode == 5) {
moveWindowKey[0] = IniReader::GetConfigInt("Input", "WindowScrollKey", 0);
if (moveWindowKey[0] < 0) {
switch (moveWindowKey[0]) {
case -1:
moveWindowKey[0] = DIK_LCONTROL;
moveWindowKey[1] = DIK_RCONTROL;
break;
case -2:
moveWindowKey[0] = DIK_LMENU;
moveWindowKey[1] = DIK_RMENU;
break;
case -3:
moveWindowKey[0] = DIK_LSHIFT;
moveWindowKey[1] = DIK_RSHIFT;
break;
default:
moveWindowKey[0] = 0;
}
} else {
moveWindowKey[0] &= 0xFF;
}
}
if (Graphics::mode == 5) WinProc::SetMoveKeys();
// Set the maximum number of BMP screenshots to 10k (was 100k)
const DWORD screendumpMaxAddr[] = {0x4C908B, 0x4C9093}; // default_screendump_
@@ -1343,11 +1248,7 @@ void Graphics::init() {
void Graphics::exit() {
if (Graphics::mode >= 4) {
RECT rect;
if (Graphics::mode == 5 && GetWindowRect(window, &rect)) {
int data = rect.top | (rect.left << 16);
if (data >= 0 && data != windowData) IniReader::SetConfigInt("Graphics", "WindowData", data);
}
WinProc::SavePosition(Graphics::mode);
CoUninitialize();
}
}
+241
View File
@@ -0,0 +1,241 @@
/*
* 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/>.
*/
#include "main.h"
#include "FalloutEngine\Fallout2.h"
#include "InputFuncs.h"
#include "version.h"
#include "WinProc.h"
namespace sfall
{
static HWND window;
static Rectangle win;
static long moveWindowKey[2];
static long windowData;
static long reqGameQuit = 0;
static bool isClosing = false;
static void __declspec(naked) WindowProc_hack() {
static const DWORD WindowProc_hack_Ret = 0x4DEAA5;
static const DWORD WindowProc_hack_End = 0x4DEAFA;
__asm {
cmp ebx, WM_PAINT;
je wmPaint;
cmp ebx, WM_CLOSE;
je wmClose;
retn;
wmPaint:
add esp, 4;
jmp WindowProc_hack_Ret;
wmClose:
call fo::funcoffs::main_menu_is_shown_;
test eax, eax;
jnz skip;
cmp isClosing, 0;
jnz end;
mov isClosing, 1;
call fo::funcoffs::game_quit_with_confirm_;
mov isClosing, al;
skip:
mov reqGameQuit, eax;
end:
xor eax, eax; // return 0
add esp, 4;
jmp WindowProc_hack_End;
}
}
static long __stdcall GNW95_keyboard_hook(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode < 0) {
goto callNext;
}
switch (wParam) {
case VK_DELETE:
if (!(lParam & 0x20000000)) {
break;
}
case VK_ESCAPE:
if (GetAsyncKeyState(VK_CONTROL) < 0) {
return 0;
}
break;
case VK_TAB:
if ((lParam & 0x20000000)) {
return 0;
}
break;
case VK_NUMLOCK:
case VK_CAPITAL:
case VK_SCROLL:
case VK_F4:
callNext:
return CallNextHookEx((HHOOK)fo::var::getInt(FO_VAR_GNW95_keyboardHandle), nCode, wParam, lParam);
default:
break;
}
return 1;
}
static long __stdcall main_menu_loop_hook() {
return (!reqGameQuit) ? fo::func::get_input() : VK_ESCAPE;
}
void WinProc::SetHWND(HWND _window) {
window = _window;
}
void WinProc::SetSize(long w, long h) {
win.width = w;
win.height = h;
}
// Sets the window style and its position/size
void WinProc::SetStyle(long windowStyle) {
SetWindowLongA(window, GWL_STYLE, windowStyle);
RECT r;
r.left = 0;
r.right = win.width;
r.top = 0;
r.bottom = win.height;
AdjustWindowRect(&r, windowStyle, false);
r.right -= r.left;
r.bottom -= r.top;
SetWindowPos(window, HWND_NOTOPMOST, win.x, win.y, r.right, r.bottom, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOCOPYBITS);
}
void WinProc::SetTitle(long resWidth, long resHeight, long wWidth, long wHeight) {
char windowTitle[128];
if (resWidth != wWidth || resHeight != wHeight) {
std::sprintf(windowTitle, "%s @sfall " VERSION_STRING " : %ix%i >> %ix%i [DX9]", (const char*)0x50AF08, resWidth, resHeight, wWidth, wHeight);
} else {
std::sprintf(windowTitle, "%s @sfall " VERSION_STRING " : %ix%i [DX9]", (const char*)0x50AF08, resWidth, resHeight);
}
SetWindowTextA(window, windowTitle);
}
void WinProc::SetMoveKeys() {
moveWindowKey[0] = IniReader::GetConfigInt("Input", "WindowScrollKey", 0);
if (moveWindowKey[0] < 0) {
switch (moveWindowKey[0]) {
case -1:
moveWindowKey[0] = DIK_LCONTROL;
moveWindowKey[1] = DIK_RCONTROL;
break;
case -2:
moveWindowKey[0] = DIK_LMENU;
moveWindowKey[1] = DIK_RMENU;
break;
case -3:
moveWindowKey[0] = DIK_LSHIFT;
moveWindowKey[1] = DIK_RSHIFT;
break;
default:
moveWindowKey[0] = 0;
}
} else {
moveWindowKey[0] &= 0xFF;
}
}
void WinProc::Moving() {
if (moveWindowKey[0] != 0 && (KeyDown(moveWindowKey[0]) || (moveWindowKey[1] != 0 && KeyDown(moveWindowKey[1])))) {
int mx, my;
GetMouse(&mx, &my);
win.x += mx;
win.y += my;
RECT toRect, curRect;
toRect.left = win.x;
toRect.right = win.x + win.width;
toRect.top = win.y;
toRect.bottom = win.y + win.height;
AdjustWindowRect(&toRect, WS_CAPTION, false);
toRect.right -= (toRect.left - win.x);
toRect.left = win.x;
toRect.bottom -= (toRect.top - win.y);
toRect.top = win.y;
if (GetWindowRect(GetShellWindow(), &curRect)) {
if (toRect.right > curRect.right) {
DWORD move = toRect.right - curRect.right;
win.x -= move;
toRect.right -= move;
} else if (toRect.left < curRect.left) {
DWORD move = curRect.left - toRect.left;
win.x += move;
toRect.right += move;
}
if (toRect.bottom > curRect.bottom) {
DWORD move = toRect.bottom - curRect.bottom;
win.y -= move;
toRect.bottom -= move;
} else if (toRect.top < curRect.top) {
DWORD move = curRect.top - toRect.top;
win.y += move;
toRect.bottom += move;
}
}
MoveWindow(window, win.x, win.y, toRect.right - win.x, toRect.bottom - win.y, true);
}
}
void WinProc::SetToCenter(long wWidth, long wHeight, long* outX, long* outY) {
RECT desktop;
GetWindowRect(GetDesktopWindow(), &desktop);
*outX = (desktop.right / 2) - (wWidth / 2);
*outY = (desktop.bottom / 2) - (wHeight / 2);
}
void WinProc::LoadPosition() {
windowData = IniReader::GetConfigInt("Graphics", "WindowData", -1);
if (windowData > 0) {
win.x = windowData >> 16;
win.y = windowData & 0xFFFF;
} else if (windowData == -1) {
SetToCenter(win.width, win.height, &win.x, &win.y);
}
}
void WinProc::SavePosition(long mode) {
RECT rect;
if (mode == 5 && GetWindowRect(window, &rect)) {
int data = rect.top | (rect.left << 16);
if (data >= 0 && data != windowData) IniReader::SetConfigInt("Graphics", "WindowData", data);
}
}
void WinProc::init() {
// Add WM_CLOSE message check to WindowProc_ engine function
MakeCall(0x4DEA47, WindowProc_hack);
// Replace the engine GNW95_keyboard_hook_ with sfall implementation
SafeWrite32(0x4C9BD9, (DWORD)&GNW95_keyboard_hook); // GNW95_hook_keyboard_
HookCall(0x481B2A, main_menu_loop_hook);
}
}
+43
View File
@@ -0,0 +1,43 @@
/*
* 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 once
namespace sfall
{
class WinProc {
public:
static void init();
static void SetHWND(HWND _window);
static void SetTitle(long resWidth, long resHeight, long wWidth, long wHeight);
static void SetSize(long w, long h);
// Sets the window style and its position
static void SetStyle(long windowStyle);
static void SetMoveKeys();
static void Moving();
static void SetToCenter(long wWidth, long wHeight, long* outX, long* outY);
static void LoadPosition();
static void SavePosition(long mode);
};
}
+2
View File
@@ -348,6 +348,7 @@
<ClInclude Include="Translate.h" />
<ClInclude Include="Utils.h" />
<ClInclude Include="version.h" />
<ClInclude Include="WinProc.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="CRC.cpp" />
@@ -458,6 +459,7 @@
</ClCompile>
<ClCompile Include="Translate.cpp" />
<ClCompile Include="Utils.cpp" />
<ClCompile Include="WinProc.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="exports.def" />
+2
View File
@@ -340,6 +340,7 @@
<ClInclude Include="Translate.h" />
<ClInclude Include="Utils.h" />
<ClInclude Include="version.h" />
<ClInclude Include="WinProc.h" />
<ClInclude Include="HLSL\A8PixelShader.h">
<Filter>HLSL</Filter>
</ClInclude>
@@ -640,6 +641,7 @@
<ClCompile Include="stdafx.cpp" />
<ClCompile Include="Translate.cpp" />
<ClCompile Include="Utils.cpp" />
<ClCompile Include="WinProc.cpp" />
<ClCompile Include="Modules\SubModules\CombatBlock.cpp">
<Filter>Modules\SubModules</Filter>
</ClCompile>
+3
View File
@@ -81,6 +81,7 @@
#include "Translate.h"
#include "Utils.h"
#include "version.h"
#include "WinProc.h"
ddrawDll ddraw;
@@ -356,6 +357,8 @@ static HMODULE SfallInit() {
}
hrpIsEnabled = (hrpDLLBaseAddr != 0);
if (!hrpIsEnabled) WinProc::init();
if (IniReader::GetIntDefaultConfig("Debugging", "SkipCompatModeCheck", 0) == 0) {
int is64bit;
typedef int (__stdcall *chk64bitproc)(HANDLE, int*);