mirror of
https://github.com/isledecomp/LEGOIslandRebuilder.git
synced 2024-11-27 09:35:41 -05:00
Merge branch 'mfc' of https://github.com/itsmattkc/LEGOIslandRebuilder into mfc
This commit is contained in:
commit
d4b2bd04e9
11 changed files with 460 additions and 45 deletions
|
@ -5,8 +5,6 @@ project(Rebuilder LANGUAGES CXX)
|
|||
set(CMAKE_MFC_FLAG 2)
|
||||
add_compile_definitions(_AFXDLL)
|
||||
|
||||
option(BUILD_UNICODE "Build with Unicode support" ON)
|
||||
|
||||
#
|
||||
# Build our code injected DLL
|
||||
#
|
||||
|
@ -51,12 +49,6 @@ add_executable(Rebuilder WIN32
|
|||
src/window.h
|
||||
)
|
||||
|
||||
if (BUILD_UNICODE)
|
||||
target_compile_definitions(Rebuilder PRIVATE UNICODE _UNICODE)
|
||||
target_compile_definitions(Rebld PRIVATE UNICODE _UNICODE)
|
||||
target_link_options(Rebuilder PRIVATE /entry:wWinMainCRTStartup)
|
||||
endif()
|
||||
|
||||
target_link_libraries(Rebuilder PRIVATE shlwapi.lib PropertyGrid)
|
||||
|
||||
# Ensure DLL is compiled before resource is built into executable
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#include "config.h"
|
||||
|
||||
#include <SHLWAPI.H>
|
||||
#include <SSTREAM>
|
||||
#include <STRING>
|
||||
|
||||
#include "../cmn/path.h"
|
||||
|
||||
|
@ -22,3 +24,29 @@ UINT Config::GetInt(LPCTSTR name, UINT defaultValue)
|
|||
{
|
||||
return GetPrivateProfileInt(appName, name, defaultValue, m_configFile.c_str());
|
||||
}
|
||||
|
||||
float Config::GetFloat(LPCTSTR name, float defaultValue)
|
||||
{
|
||||
// Convert float to string
|
||||
std::ostringstream oss;
|
||||
oss << defaultValue;
|
||||
std::string defaultStr = oss.str();
|
||||
|
||||
std::string currentStr = GetString(name, defaultStr);
|
||||
|
||||
// Convert to float
|
||||
return atof(currentStr.c_str());
|
||||
}
|
||||
|
||||
std::string Config::GetString(LPCTSTR name, const std::string &defaultValue)
|
||||
{
|
||||
const int max_string_sz = 100;
|
||||
std::string s;
|
||||
s.resize(max_string_sz);
|
||||
|
||||
DWORD count = GetPrivateProfileString(appName, name, defaultValue.c_str(), &s[0], max_string_sz, m_configFile.c_str());
|
||||
|
||||
s.resize(count);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,10 @@ public:
|
|||
|
||||
UINT GetInt(LPCTSTR name, UINT defaultValue = 0);
|
||||
|
||||
float GetFloat(LPCTSTR name, float defaultValue = 0.0f);
|
||||
|
||||
std::string GetString(LPCTSTR name, const std::string &defaultValue = std::string());
|
||||
|
||||
private:
|
||||
std::basic_string<TCHAR> m_configFile;
|
||||
|
||||
|
|
209
lib/hooks.cpp
209
lib/hooks.cpp
|
@ -1,5 +1,6 @@
|
|||
#include "hooks.h"
|
||||
|
||||
#include <MATH.H>
|
||||
#include <STDIO.H>
|
||||
|
||||
#include "../cmn/path.h"
|
||||
|
@ -53,7 +54,7 @@ HRESULT WINAPI InterceptSurfaceGetDesc(LPDIRECTDRAWSURFACE lpDDSurface, LPDDSURF
|
|||
HRESULT res = originalDDSurfaceGetDescFunction(lpDDSurface, lpDDSurfaceDesc);
|
||||
|
||||
if (res == DD_OK) {
|
||||
ForceDDSurfaceDescTo16(lpDDSurfaceDesc);
|
||||
//ForceDDSurfaceDescTo16(lpDDSurfaceDesc);
|
||||
}
|
||||
|
||||
return res;
|
||||
|
@ -172,9 +173,213 @@ LONG WINAPI InterceptRegQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpR
|
|||
// Pass through
|
||||
|
||||
} else {
|
||||
MessageBoxA(isleWindow, lpValueName, "ISLE asked for...", 0);
|
||||
|
||||
printf("Passed through requested registry key \"%s\"\n", lpValueName);
|
||||
|
||||
}
|
||||
|
||||
// Pass these through
|
||||
return RegQueryValueExA(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData);
|
||||
}
|
||||
|
||||
void WINAPI InterceptSleep(DWORD dwMilliseconds)
|
||||
{
|
||||
// Do nothing
|
||||
std::string fps_behavior = config.GetString(_T("FPSLimit"));
|
||||
|
||||
// If uncapped, do nothing
|
||||
if (fps_behavior != "Uncapped") {
|
||||
// If not default, pass through new FPS
|
||||
if (fps_behavior == "Limited") {
|
||||
dwMilliseconds = 1000.0f / config.GetFloat(_T("CustomFPS"));
|
||||
}
|
||||
|
||||
Sleep(dwMilliseconds);
|
||||
}
|
||||
}
|
||||
|
||||
LPDIRECT3DRMVIEWPORT last_viewport = NULL;
|
||||
D3DVALUE last_fov = 0.0f;
|
||||
typedef HRESULT (WINAPI *d3drmViewportSetFieldFunction)(LPDIRECT3DRMVIEWPORT viewport, D3DVALUE field);
|
||||
d3drmViewportSetFieldFunction d3drmViewportSetFieldOriginal = NULL;
|
||||
HRESULT WINAPI InterceptD3DRMViewportSetField(LPDIRECT3DRMVIEWPORT viewport, D3DVALUE field)
|
||||
{
|
||||
last_viewport = viewport;
|
||||
last_fov = field;
|
||||
|
||||
return d3drmViewportSetFieldOriginal(viewport, field);
|
||||
}
|
||||
|
||||
typedef HRESULT (WINAPI *d3drmCreateViewportFunction)(LPDIRECT3DRM d3drm, LPDIRECT3DRMDEVICE device, LPDIRECT3DRMFRAME frame, DWORD x, DWORD y, DWORD w, DWORD h, LPDIRECT3DRMVIEWPORT *viewport);
|
||||
d3drmCreateViewportFunction d3drmCreateViewportOriginal = NULL;
|
||||
HRESULT WINAPI InterceptD3DRMCreateViewport(LPDIRECT3DRM d3drm, LPDIRECT3DRMDEVICE device, LPDIRECT3DRMFRAME frame, DWORD x, DWORD y, DWORD w, DWORD h, LPDIRECT3DRMVIEWPORT *viewport)
|
||||
{
|
||||
HRESULT res = d3drmCreateViewportOriginal(d3drm, device, frame, x, y, w, h, viewport);
|
||||
|
||||
if (res == DD_OK) {
|
||||
if (!d3drmViewportSetFieldOriginal) {
|
||||
d3drmViewportSetFieldOriginal = (d3drmViewportSetFieldFunction)OverwriteVirtualTable(*viewport, 0x10, (LPVOID)InterceptD3DRMViewportSetField);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
d3drmCreateFunction d3drmCreateOriginal = NULL;
|
||||
HRESULT WINAPI InterceptDirect3DRMCreate(LPDIRECT3DRM FAR *lplpDirect3DRM)
|
||||
{
|
||||
HRESULT result = d3drmCreateOriginal(lplpDirect3DRM);
|
||||
|
||||
if (result == DD_OK) {
|
||||
if (!d3drmCreateViewportOriginal) {
|
||||
d3drmCreateViewportOriginal = (d3drmCreateViewportFunction)OverwriteVirtualTable(*lplpDirect3DRM, 0x38, (LPVOID)InterceptD3DRMCreateViewport);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef WM_MOUSEWHEEL
|
||||
#define WM_MOUSEWHEEL 0x020A
|
||||
#endif
|
||||
|
||||
#ifndef WHEEL_DELTA
|
||||
#define WHEEL_DELTA 120
|
||||
#endif
|
||||
|
||||
WNDPROC originalWndProc = NULL;
|
||||
LRESULT CALLBACK InterceptWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (uMsg == WM_MOUSEWHEEL) {
|
||||
SHORT distance = HIWORD(wParam);
|
||||
distance /= WHEEL_DELTA;
|
||||
|
||||
float multiplier = 0.005 * distance;
|
||||
|
||||
InterceptD3DRMViewportSetField(last_viewport, last_fov + multiplier);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return originalWndProc(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
ATOM WINAPI InterceptRegisterClassA(const WNDCLASSA *c)
|
||||
{
|
||||
WNDCLASSA copy = *c;
|
||||
originalWndProc = copy.lpfnWndProc;
|
||||
copy.lpfnWndProc = InterceptWindowProc;
|
||||
|
||||
return RegisterClassA(©);
|
||||
}
|
||||
|
||||
typedef HRESULT (WINAPI *dsCreateSoundBufferFunction)(LPDIRECTSOUND lpDS, LPCDSBUFFERDESC desc, LPDIRECTSOUNDBUFFER *buffer, LPUNKNOWN unk);
|
||||
dsCreateSoundBufferFunction dsCreateSoundBufferOriginal = NULL;
|
||||
HRESULT WINAPI InterceptDirectSoundCreateSoundBuffer(LPDIRECTSOUND lpDS, LPCDSBUFFERDESC desc, LPDIRECTSOUNDBUFFER *buffer, LPUNKNOWN unk)
|
||||
{
|
||||
DSBUFFERDESC copy = *desc;
|
||||
|
||||
if (config.GetInt(_T("StayActiveWhenDefocused")) && !(copy.dwFlags & DSBCAPS_PRIMARYBUFFER)) {
|
||||
copy.dwFlags |= DSBCAPS_GLOBALFOCUS;
|
||||
}
|
||||
|
||||
return dsCreateSoundBufferOriginal(lpDS, ©, buffer, unk);
|
||||
}
|
||||
|
||||
dsCreateFunction dsCreateOriginal = NULL;
|
||||
HRESULT WINAPI InterceptDirectSoundCreate(LPGUID lpGuid, LPDIRECTSOUND* ppDS, LPUNKNOWN pUnkOuter )
|
||||
{
|
||||
HRESULT res = dsCreateOriginal(lpGuid, ppDS, pUnkOuter);
|
||||
|
||||
if (res == DD_OK) {
|
||||
if (!dsCreateSoundBufferOriginal) {
|
||||
dsCreateSoundBufferOriginal = (dsCreateSoundBufferFunction)OverwriteVirtualTable(*ppDS, 0x3, (LPVOID)InterceptDirectSoundCreateSoundBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
SHORT WINAPI InterceptGetAsyncKeyState(int vKey)
|
||||
{
|
||||
if (config.GetInt("UseWASD")) {
|
||||
switch (vKey) {
|
||||
case VK_UP:
|
||||
vKey = 'W';
|
||||
break;
|
||||
case VK_LEFT:
|
||||
vKey = 'A';
|
||||
break;
|
||||
case VK_DOWN:
|
||||
vKey = 'S';
|
||||
break;
|
||||
case VK_RIGHT:
|
||||
vKey = 'D';
|
||||
break;
|
||||
case 'W':
|
||||
vKey = VK_UP;
|
||||
break;
|
||||
case 'A':
|
||||
vKey = VK_LEFT;
|
||||
break;
|
||||
case 'S':
|
||||
vKey = VK_DOWN;
|
||||
break;
|
||||
case 'D':
|
||||
vKey = VK_RIGHT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return GetAsyncKeyState(vKey);
|
||||
}
|
||||
|
||||
typedef HRESULT (WINAPI *dinputGetDeviceStateFunction)(LPDIRECTINPUTDEVICEA lpDevice, DWORD cbData, LPVOID lpvData);
|
||||
dinputGetDeviceStateFunction dinputGetDeviceStateOriginal = NULL;
|
||||
HRESULT WINAPI InterceptDirectInputGetDeviceStateA(LPDIRECTINPUTDEVICEA lpDevice, DWORD cbData, LPVOID lpvData)
|
||||
{
|
||||
HRESULT res = dinputGetDeviceStateOriginal(lpDevice, cbData, lpvData);
|
||||
|
||||
if (config.GetInt("UseWASD") && res == DD_OK) {
|
||||
if (cbData == 256) {
|
||||
unsigned char *keys = (unsigned char *)lpvData;
|
||||
|
||||
// Swap state of WASD with arrow keys
|
||||
std::swap(keys[DIK_W], keys[DIK_UP]);
|
||||
std::swap(keys[DIK_A], keys[DIK_LEFT]);
|
||||
std::swap(keys[DIK_S], keys[DIK_DOWN]);
|
||||
std::swap(keys[DIK_D], keys[DIK_RIGHT]);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
typedef HRESULT (WINAPI *dinputCreateDeviceFunction)(LPDIRECTINPUTA lpDI, REFGUID, LPDIRECTINPUTDEVICEA *, LPUNKNOWN);
|
||||
dinputCreateDeviceFunction dinputCreateDeviceOriginal = NULL;
|
||||
HRESULT WINAPI InterceptDirectInputCreateDeviceA(LPDIRECTINPUTA lpDI, REFGUID guid, LPDIRECTINPUTDEVICEA *ppDevice, LPUNKNOWN unk)
|
||||
{
|
||||
HRESULT res = dinputCreateDeviceOriginal(lpDI, guid, ppDevice, unk);
|
||||
|
||||
if (res == DD_OK) {
|
||||
if (!dinputGetDeviceStateOriginal) {
|
||||
dinputGetDeviceStateOriginal = (dinputGetDeviceStateFunction)OverwriteVirtualTable(*ppDevice, 0x9, (LPVOID)InterceptDirectInputGetDeviceStateA);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
dinputCreateFunction dinputCreateOriginal = NULL;
|
||||
HRESULT WINAPI InterceptDirectInputCreateA(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter)
|
||||
{
|
||||
HRESULT res = dinputCreateOriginal(hinst, dwVersion, ppDI, punkOuter);
|
||||
|
||||
if (res == DD_OK) {
|
||||
if (!dinputCreateDeviceOriginal) {
|
||||
dinputCreateDeviceOriginal = (dinputCreateDeviceFunction)OverwriteVirtualTable(*ppDI, 0x3, (LPVOID)InterceptDirectInputCreateDeviceA);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
23
lib/hooks.h
23
lib/hooks.h
|
@ -1,7 +1,10 @@
|
|||
#ifndef HOOKS_H
|
||||
#define HOOKS_H
|
||||
|
||||
#include <D3DRM.H>
|
||||
#include <DDRAW.H>
|
||||
#include <DINPUT.H>
|
||||
#include <DSOUND.H>
|
||||
#include <WINDOWS.H>
|
||||
|
||||
void InterceptOutputDebugStringA(LPCSTR s);
|
||||
|
@ -21,6 +24,8 @@ HWND WINAPI InterceptCreateWindowExA(
|
|||
LPVOID lpParam
|
||||
);
|
||||
|
||||
|
||||
|
||||
LONG
|
||||
APIENTRY
|
||||
InterceptRegQueryValueExA (
|
||||
|
@ -32,6 +37,8 @@ InterceptRegQueryValueExA (
|
|||
LPDWORD lpcbData
|
||||
);
|
||||
|
||||
ATOM WINAPI InterceptRegisterClassA(const WNDCLASSA *c);
|
||||
|
||||
HWND WINAPI InterceptFindWindowA(LPCSTR lpClassName, LPCSTR lpWindowName);
|
||||
|
||||
typedef HRESULT (WINAPI *ddCreateFunction)(GUID *lpGUID, LPDIRECTDRAW *lplpDD, IUnknown *pUnkOuterS);
|
||||
|
@ -40,4 +47,20 @@ HRESULT WINAPI InterceptDirectDrawCreate(GUID *lpGUID, LPDIRECTDRAW *lplpDD, IUn
|
|||
|
||||
HRESULT WINAPI InterceptSurfaceGetDesc(LPDIRECTDRAWSURFACE lpDDSurface, LPDDSURFACEDESC lpDDSurfaceDesc);
|
||||
|
||||
VOID WINAPI InterceptSleep(DWORD dwMilliseconds);
|
||||
|
||||
typedef HRESULT (WINAPI *d3drmCreateFunction)(LPDIRECT3DRM FAR *lplpDirect3DRM);
|
||||
extern d3drmCreateFunction d3drmCreateOriginal;
|
||||
HRESULT WINAPI InterceptDirect3DRMCreate(LPDIRECT3DRM FAR *lplpDirect3DRM);
|
||||
|
||||
typedef HRESULT (WINAPI *dsCreateFunction)(LPGUID lpGuid, LPDIRECTSOUND* ppDS, LPUNKNOWN pUnkOuter );
|
||||
extern dsCreateFunction dsCreateOriginal;
|
||||
HRESULT WINAPI InterceptDirectSoundCreate(LPGUID lpGuid, LPDIRECTSOUND* ppDS, LPUNKNOWN pUnkOuter );
|
||||
|
||||
SHORT WINAPI InterceptGetAsyncKeyState(int vKey);
|
||||
|
||||
typedef HRESULT (WINAPI *dinputCreateFunction)(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter);
|
||||
extern dinputCreateFunction dinputCreateOriginal;
|
||||
HRESULT WINAPI InterceptDirectInputCreateA(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter);
|
||||
|
||||
#endif // HOOKS_H
|
||||
|
|
12
lib/util.cpp
12
lib/util.cpp
|
@ -95,8 +95,9 @@ LPVOID OverwriteImport(LPVOID imageBase, LPCSTR overrideFunction, LPVOID overrid
|
|||
PIMAGE_IMPORT_BY_NAME functionName = (PIMAGE_IMPORT_BY_NAME)((UINT_PTR)imageBase + (UINT_PTR)originalFirstThunk->u1.AddressOfData);
|
||||
|
||||
if (!strcmp((const char*)functionName->Name, overrideFunction)) {
|
||||
LPVOID originalFunction = (LPVOID)firstThunk->u1.Function;
|
||||
firstThunk->u1.Function = (PDWORD)override;
|
||||
// Write to memory
|
||||
LPVOID originalFunction;
|
||||
WriteMemory(&firstThunk->u1.Function, &override, sizeof(LPVOID), &originalFunction);
|
||||
|
||||
// Return original function and end loop here
|
||||
printf("Hooked %s\n", overrideFunction);
|
||||
|
@ -117,12 +118,9 @@ LPVOID OverwriteVirtualTable(LPVOID object, SIZE_T methodIndex, LPVOID overrideF
|
|||
{
|
||||
LPVOID *vtable = ((LPVOID**)(object))[0];
|
||||
LPVOID &functionAddress = vtable[methodIndex];
|
||||
LPVOID originalFunction = functionAddress;
|
||||
LPVOID originalFunction = NULL;
|
||||
|
||||
if (overrideFunction) {
|
||||
functionAddress = overrideFunction;
|
||||
printf("Hooked vtable %p+%lu\n", vtable, methodIndex);
|
||||
}
|
||||
WriteMemory(&functionAddress, overrideFunction ? &overrideFunction : NULL, sizeof(LPVOID), &originalFunction);
|
||||
|
||||
return originalFunction;
|
||||
}
|
||||
|
|
|
@ -22,22 +22,23 @@ DWORD WINAPI Patch()
|
|||
OverwriteImport(exeBase, "CreateWindowExA", (LPVOID)InterceptCreateWindowExA);
|
||||
OverwriteImport(dllBase, "OutputDebugStringA", (LPVOID)InterceptOutputDebugStringA);
|
||||
OverwriteImport(exeBase, "RegQueryValueExA", (LPVOID)InterceptRegQueryValueExA);
|
||||
OverwriteImport(exeBase, "RegisterClassA", (LPVOID)InterceptRegisterClassA);
|
||||
OverwriteImport(dllBase, "Sleep", (LPVOID)InterceptSleep);
|
||||
OverwriteImport(exeBase, "Sleep", (LPVOID)InterceptSleep);
|
||||
OverwriteImport(dllBase, "GetAsyncKeyState", (LPVOID)InterceptGetAsyncKeyState);
|
||||
ddCreateOriginal = (ddCreateFunction)OverwriteImport(dllBase, "DirectDrawCreate", (LPVOID)InterceptDirectDrawCreate);
|
||||
d3drmCreateOriginal = (d3drmCreateFunction)OverwriteImport(dllBase, "Direct3DRMCreate", (LPVOID)InterceptDirect3DRMCreate);
|
||||
dsCreateOriginal = (dsCreateFunction)OverwriteImport(dllBase, "DirectSoundCreate", (LPVOID)InterceptDirectSoundCreate);
|
||||
dinputCreateOriginal = (dinputCreateFunction)OverwriteImport(dllBase, "DirectInputCreateA", (LPVOID)InterceptDirectInputCreateA);
|
||||
|
||||
// Stay active when defocused
|
||||
if (config.GetInt(_T("StayActiveWhenDefocused"))) {
|
||||
// Patch jump if window isn't active
|
||||
// Patch jump if window isn't active (TODO: Replace with C++ patch)
|
||||
SearchReplacePattern(exeBase, "\x89\x58\x70", "\x90\x90\x90", 3);
|
||||
|
||||
// Patch DirectSound flags so that sound doesn't mute when inactive
|
||||
SearchReplacePattern(dllBase, "\xC7\x44\x24\x24\xE0\x00\x00\x00", "\xC7\x44\x24\x24\xE0\x80\x00\x00", 8);
|
||||
SearchReplacePattern(dllBase, "\xC7\x44\x24\x24\xB0\x00\x00\x00", "\xC7\x44\x24\x24\xB0\x80\x00\x00", 8);
|
||||
SearchReplacePattern(dllBase, "\xC7\x45\xCC\x11\x00\x00\x00", "\xC7\x45\xCC\x11\x80\x00\x00", 7);
|
||||
SearchReplacePattern(dllBase, "\xC7\x45\xCC\xE0\x00\x00\x00", "\xC7\x45\xCC\xE0\x80\x00\x00", 7);
|
||||
}
|
||||
|
||||
// Allow multiple instances
|
||||
if (config.GetInt(_T("AllowMultipleInstances"))) {
|
||||
if (config.GetInt(_T("MultipleInstances"))) {
|
||||
// Patch FindWindowA import to always tell ISLE that no other ISLE window exists
|
||||
OverwriteImport(exeBase, "FindWindowA", (LPVOID)InterceptFindWindowA);
|
||||
}
|
||||
|
@ -50,12 +51,87 @@ DWORD WINAPI Patch()
|
|||
SearchReplacePattern(dllBase, "OGEL", "\x0GEL", 4, TRUE);
|
||||
}
|
||||
|
||||
// Disable auto-finish in build sections
|
||||
if (config.GetInt(_T("DisableAutoFinishBuilding"))) {
|
||||
// Pattern used in August build (jump is much shorter so it uses a different opcode)
|
||||
const char *autofinish_pattern = "\x66\x39\x90\xBE\x00\x00\x00\x75";
|
||||
const char *autofinish_replace = "\x66\x39\x90\xBE\x00\x00\x00\xEB";
|
||||
|
||||
if (SearchReplacePattern(dllBase, autofinish_pattern, autofinish_replace, 8) == 0) {
|
||||
// Pattern used in September build (jump is much longer)
|
||||
autofinish_pattern = "\x66\x39\x90\xBE\x00\x00\x00\x0F\x85\x86\x00\x00\x00";
|
||||
autofinish_replace = "\x66\x39\x90\xBE\x00\x00\x00\xE9\x87\x00\x00\x00\x90";
|
||||
SearchReplacePattern(dllBase, autofinish_pattern, autofinish_replace, 13);
|
||||
}
|
||||
}
|
||||
|
||||
// Patch navigation
|
||||
{
|
||||
const int nav_block_sz = 0x30;
|
||||
const char *nav_block_src = "\x28\x00\x00\x00\x6F\x12\x83\x3A\x00\x00\x20\x42\x00\x00\xA0\x41\x00\x00\x70\x41\x00\x00\xF0\x41\x00\x00\x80\x40\x00\x00\x70\x41\x00\x00\x48\x42\x00\x00\x48\x42\xCD\xCC\xCC\x3E\x00\x00\x00\x00";
|
||||
char nav_block_dst[nav_block_sz];
|
||||
memcpy(nav_block_dst, nav_block_src, nav_block_sz);
|
||||
|
||||
UINT32 mouse_deadzone = config.GetInt(_T("MouseDeadzone"), 40);
|
||||
memcpy(nav_block_dst+0x0, &mouse_deadzone, sizeof(mouse_deadzone));
|
||||
|
||||
// DDRAW GetSurfaceDesc Override
|
||||
OverwriteCall((LPVOID) ((UINT_PTR)dllBase+0xBA7D5), (LPVOID)InterceptSurfaceGetDesc);
|
||||
float movement_max_spd = config.GetFloat(_T("MovementMaxSpeed"), 40.0f);
|
||||
memcpy(nav_block_dst+0x8, &movement_max_spd, sizeof(movement_max_spd));
|
||||
|
||||
float turn_max_spd = config.GetFloat(_T("TurnMaxSpeed"), 20.0f);
|
||||
memcpy(nav_block_dst+0xC, &turn_max_spd, sizeof(turn_max_spd));
|
||||
|
||||
float movement_max_accel = config.GetFloat(_T("MovementMaxAcceleration"), 15.0f);
|
||||
memcpy(nav_block_dst+0x10, &movement_max_accel, sizeof(movement_max_accel));
|
||||
|
||||
float turn_max_accel = config.GetFloat(_T("TurnMaxAcceleration"), 30.0f);
|
||||
memcpy(nav_block_dst+0x14, &turn_max_accel, sizeof(turn_max_accel));
|
||||
|
||||
float movement_min_accel = config.GetFloat(_T("MovementMinAcceleration"), 4.0f);
|
||||
memcpy(nav_block_dst+0x18, &movement_min_accel, sizeof(movement_min_accel));
|
||||
|
||||
float turn_min_accel = config.GetFloat(_T("TurnMinAcceleration"), 15.0f);
|
||||
memcpy(nav_block_dst+0x1C, &turn_min_accel, sizeof(turn_min_accel));
|
||||
|
||||
float movement_decel = config.GetFloat(_T("MovementDeceleration"), 50.0f);
|
||||
memcpy(nav_block_dst+0x20, &movement_decel, sizeof(movement_decel));
|
||||
|
||||
float turn_decel = config.GetFloat(_T("TurnDeceleration"), 50.0f);
|
||||
memcpy(nav_block_dst+0x24, &turn_decel, sizeof(turn_decel));
|
||||
|
||||
UINT32 turn_use_velocity = config.GetInt(_T("TurnUseVelocity"), FALSE);
|
||||
memcpy(nav_block_dst+0x2C, &turn_use_velocity, sizeof(turn_use_velocity));
|
||||
|
||||
SearchReplacePattern(dllBase, nav_block_src, nav_block_dst, nav_block_sz);
|
||||
}
|
||||
|
||||
// Model Quality
|
||||
std::string model_quality = config.GetString("ModelQuality");
|
||||
float mq_val = 3.6f;
|
||||
if (model_quality == "Infinite") {
|
||||
mq_val = 999999.0f;
|
||||
} else if (model_quality == "High") {
|
||||
mq_val = 5.0f;
|
||||
} else if (model_quality == "Medium") {
|
||||
mq_val = 3.6f;
|
||||
} else if (model_quality == "Low") {
|
||||
mq_val = 0.0f;
|
||||
}
|
||||
const char *mq_pattern = "\x00\x00\x80\x40\x66\x66\x66\x40";
|
||||
char mq_replace[8];
|
||||
memcpy(mq_replace, mq_pattern, 8);
|
||||
memcpy(mq_replace+4, &mq_val, sizeof(mq_val));
|
||||
SearchReplacePattern(dllBase, mq_pattern, mq_replace, 8);
|
||||
|
||||
// Field of view
|
||||
const char *fov_pattern = "\x00\x00\x00\x3F\x17\x6C\xC1\x16\x6C\xC1\x76\x3F";
|
||||
char fov_replace[12];
|
||||
float fov;
|
||||
memcpy(fov_replace, fov_pattern, 12); // Make editable copy of pattern
|
||||
memcpy(&fov, fov_replace, sizeof(fov)); // Get float from bytes
|
||||
fov *= 1.0f/config.GetFloat(_T("FOVMultiplier")); // Multiply FOV
|
||||
memcpy(fov_replace, &fov, sizeof(fov)); // Store back into bytes
|
||||
SearchReplacePattern(dllBase, fov_pattern, fov_replace, 12);
|
||||
|
||||
// Window size hack
|
||||
/*SearchReplacePattern(exeBase,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "patchgrid.h"
|
||||
|
||||
#include <SHLWAPI.H>
|
||||
#include <SSTREAM>
|
||||
|
||||
#include "../cmn/path.h"
|
||||
|
@ -123,8 +124,8 @@ PatchGrid::PatchGrid()
|
|||
|
||||
AddPatch("FOVMultiplier",
|
||||
_T("Globally adjusts the field of view by a multiplier\n\n"
|
||||
"0.1 = Default (smaller than 0.1 is more zoomed in, larger than 0.1 is more zoomed out"),
|
||||
AddDoubleItem(sectionGraphics, _T("Field of View Adjustment"), 0.1));
|
||||
"1.0 = Default (greater than 1.0 is zoomed in, less than 1.0 is zoomed out)"),
|
||||
AddDoubleItem(sectionGraphics, _T("Field of View Adjustment"), 1.0));
|
||||
|
||||
// Audio section
|
||||
HSECTION sectionMusic = AddSection(_T("Audio"));
|
||||
|
@ -142,6 +143,61 @@ std::string toString(const T &value)
|
|||
return oss.str();
|
||||
}
|
||||
|
||||
void PatchGrid::LoadConfiguration(LPCTSTR filename)
|
||||
{
|
||||
for (std::map<std::string, HITEM>::const_iterator it=m_mPatchItems.begin(); it!=m_mPatchItems.end(); it++) {
|
||||
CItem *item = FindItem(it->second);
|
||||
|
||||
std::string value;
|
||||
value.resize(1024);
|
||||
|
||||
char buf[1024];
|
||||
|
||||
DWORD sz = GetPrivateProfileString(appName, it->first.c_str(), NULL, &value[0], value.size(), filename);
|
||||
|
||||
// If this entry wasn't in the profile, skip it
|
||||
if (!sz) {
|
||||
continue;
|
||||
}
|
||||
|
||||
value.resize(sz);
|
||||
|
||||
// Convert value to string
|
||||
switch (item->m_type) {
|
||||
case IT_STRING:
|
||||
case IT_TEXT:
|
||||
case IT_FILE:
|
||||
case IT_FOLDER:
|
||||
case IT_COMBO:
|
||||
SetItemValue(it->second, value);
|
||||
break;
|
||||
case IT_BOOLEAN:
|
||||
SetItemValue(it->second, (bool)StrToIntA(value.c_str()));
|
||||
break;
|
||||
case IT_INTEGER:
|
||||
SetItemValue(it->second, StrToIntA(value.c_str()));
|
||||
break;
|
||||
case IT_DOUBLE:
|
||||
SetItemValue(it->second, atof(value.c_str()));
|
||||
break;
|
||||
case IT_COLOR:
|
||||
SetItemValue(it->second, (COLORREF) StrToIntA(value.c_str()));
|
||||
break;
|
||||
case IT_CUSTOM:
|
||||
case IT_DATE:
|
||||
case IT_DATETIME:
|
||||
case IT_FONT:
|
||||
{
|
||||
// Report inability to serialize
|
||||
TCHAR buf[200];
|
||||
sprintf(buf, "Failed to serialize %s from string.", it->first.c_str());
|
||||
MessageBox(buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOL PatchGrid::SaveConfiguration(LPCTSTR filename)
|
||||
{
|
||||
for (std::map<std::string, HITEM>::const_iterator it=m_mPatchItems.begin(); it!=m_mPatchItems.end(); it++) {
|
||||
|
@ -155,20 +211,30 @@ BOOL PatchGrid::SaveConfiguration(LPCTSTR filename)
|
|||
case IT_TEXT:
|
||||
case IT_FILE:
|
||||
case IT_FOLDER:
|
||||
value = item->m_strValue;
|
||||
case IT_COMBO:
|
||||
GetItemValue(it->second, value);
|
||||
break;
|
||||
case IT_BOOLEAN:
|
||||
value = toString(item->m_bValue);
|
||||
{
|
||||
bool b;
|
||||
GetItemValue(it->second, b);
|
||||
value = toString(b);
|
||||
break;
|
||||
case IT_COMBO:
|
||||
}
|
||||
case IT_INTEGER:
|
||||
value = toString(item->m_nValue);
|
||||
int i;
|
||||
GetItemValue(it->second, i);
|
||||
value = toString(i);
|
||||
break;
|
||||
case IT_DOUBLE:
|
||||
value = toString(item->m_dValue);
|
||||
double d;
|
||||
GetItemValue(it->second, d);
|
||||
value = toString(d);
|
||||
break;
|
||||
case IT_COLOR:
|
||||
value = toString(item->m_clrValue);
|
||||
COLORREF c;
|
||||
GetItemValue(it->second, c);
|
||||
value = toString(c);
|
||||
break;
|
||||
case IT_CUSTOM:
|
||||
case IT_DATE:
|
||||
|
@ -183,7 +249,6 @@ BOOL PatchGrid::SaveConfiguration(LPCTSTR filename)
|
|||
}
|
||||
}
|
||||
|
||||
this->GetItemValue(it->second, value);
|
||||
if (!WritePrivateProfileString(appName, it->first.c_str(), value.c_str(), filename)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ class PatchGrid : public CPropertyGrid
|
|||
public:
|
||||
PatchGrid();
|
||||
|
||||
void LoadConfiguration(LPCTSTR filename);
|
||||
BOOL SaveConfiguration(LPCTSTR filename);
|
||||
|
||||
private:
|
||||
|
|
|
@ -78,6 +78,16 @@ CRebuilderWindow::CRebuilderWindow()
|
|||
RECT patchGridClientRect;
|
||||
m_cPatchGrid.GetClientRect(&patchGridClientRect);
|
||||
m_cPatchGrid.SetGutterWidth((patchGridClientRect.right - patchGridClientRect.left) / 2);
|
||||
|
||||
TCHAR configPath[MAX_PATH];
|
||||
if (GetConfigFilename(configPath)) {
|
||||
m_cPatchGrid.LoadConfiguration(configPath);
|
||||
}
|
||||
}
|
||||
|
||||
CRebuilderWindow::~CRebuilderWindow()
|
||||
{
|
||||
TrySaving();
|
||||
}
|
||||
|
||||
DWORD WINAPI WaitForProcessToClose(HANDLE hProcess)
|
||||
|
@ -88,26 +98,35 @@ DWORD WINAPI WaitForProcessToClose(HANDLE hProcess)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void CRebuilderWindow::OnRunClick()
|
||||
BOOL CRebuilderWindow::TrySaving()
|
||||
{
|
||||
TCHAR configPath[MAX_PATH];
|
||||
|
||||
if (GetConfigFilename(configPath)) {
|
||||
if (m_cPatchGrid.SaveConfiguration(configPath)) {
|
||||
if (HANDLE proc = Launcher::Launch(this->GetSafeHwnd())) {
|
||||
m_lProcesses.push_back(proc);
|
||||
SwitchButtonMode(TRUE);
|
||||
|
||||
// Register callback when process exits
|
||||
DWORD threadId; // We don't use this, but Windows 95 will fail without it
|
||||
CloseHandle(CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WaitForProcessToClose, proc, 0, &threadId));
|
||||
}
|
||||
return TRUE;
|
||||
} else {
|
||||
MessageBox(_T("Failed to save configuration file."));
|
||||
}
|
||||
} else {
|
||||
MessageBox(_T("Failed to determine configuration path."));
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void CRebuilderWindow::OnRunClick()
|
||||
{
|
||||
if (TrySaving()) {
|
||||
if (HANDLE proc = Launcher::Launch(this->GetSafeHwnd())) {
|
||||
m_lProcesses.push_back(proc);
|
||||
SwitchButtonMode(TRUE);
|
||||
|
||||
// Register callback when process exits
|
||||
DWORD threadId; // We don't use this, but Windows 95 will fail without it
|
||||
CloseHandle(CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WaitForProcessToClose, proc, 0, &threadId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CRebuilderWindow::OnKillClick()
|
||||
|
|
|
@ -13,6 +13,8 @@ class CRebuilderWindow : public CFrameWnd
|
|||
public:
|
||||
CRebuilderWindow();
|
||||
|
||||
~CRebuilderWindow();
|
||||
|
||||
afx_msg void OnRunClick();
|
||||
|
||||
afx_msg void OnKillClick();
|
||||
|
@ -34,6 +36,8 @@ private:
|
|||
|
||||
void SwitchButtonMode(BOOL running);
|
||||
|
||||
BOOL TrySaving();
|
||||
|
||||
enum {
|
||||
ID_RUN = 1000,
|
||||
ID_KILL,
|
||||
|
|
Loading…
Reference in a new issue