Skip to content

Commit

Permalink
add 'Marvel Ultimate Alliance' support
Browse files Browse the repository at this point in the history
  • Loading branch information
anzz1 committed Oct 10, 2023
1 parent 7520c8d commit e85c1c6
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 17 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ Please note that the GameSpy protocol is old and does not meet modern password e
| James Bond 007: Nightfire | <picture><img src="./.github/img/disc.png" title="Retail" alt="(Retail)" /></picture> | `dsound.dll` | n/a | |
| Jet Fighter IV | <picture><img src="./.github/img/disc.png" title="Retail" alt="(Retail)" /></picture> | `dinput.dll` | n/a | |
| Magic: The Gathering - Battlegrounds | <picture><img src="./.github/img/disc.png" title="Retail" alt="(Retail)" /></picture> | `dinput8.dll` | n/a | |
| Marvel: Ultimate Alliance | <picture><img src="./.github/img/disc.png" title="Retail" alt="(Retail)" /></picture> | `winmm.dll` | n/a | <sub><sup>[1]</sup> Requires [No-CD patch](https://taco.cab/files/games/mua/Marvel.Ultimate.Alliance.v1.0.NoCD.zip) to remove SafeDisc (V4) protection</sub> |
| Medal of Honor: Allied Assault | <picture><img src="./.github/img/disc.png" title="Retail" alt="(Retail)" /></picture>&nbsp;<a href="https://www.gog.com/en/game/medal_of_honor_allied_assault_war_chest"><img src="./.github/img/gog.png" title="GOG" alt="(GOG)" /></a> | `dinput.dll` | n/a | |
| Midnight Club 2 | <picture><img src="./.github/img/disc.png" title="Retail" alt="(Retail)" /></picture>&nbsp;<a href="https://store.steampowered.com/app/12160/Midnight_Club_2/"><img src="./.github/img/steam.png" title="Steam" alt="(Steam)" /></a> | `dinput8.dll` | n/a | |
| MX vs. ATV Unleashed | <picture><img src="./.github/img/disc.png" title="Retail" alt="(Retail)" /></picture>&nbsp;<a href="https://www.gog.com/en/game/mx_vs_atv_unleashed"><img src="./.github/img/gog.png" title="GOG" alt="(GOG)" /></a>&nbsp;<a href="https://store.steampowered.com/app/359220/MX_vs_ATV_Unleashed/"><img src="./.github/img/steam.png" title="Steam" alt="(Steam)" /></a> | `dsound.dll` | n/a | |
Expand Down
15 changes: 11 additions & 4 deletions dllmain.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include "include/game_ts.h"
#include "include/game_gt.h"
#include "include/game_sof2.h"
#include "include/game_mua.h"
#endif // !_WIN64

#include "include/picoupnp.h"
Expand Down Expand Up @@ -187,7 +188,6 @@ int __stdcall DllMain(HINSTANCE hInstDLL, DWORD dwReason, LPVOID lpReserved) {
if (dwReason == DLL_PROCESS_ATTACH && !initialized) {
HMODULE hm = 0;
char* p = 0;
char* p2 = 0;
char s[512];

initialized = 1;
Expand Down Expand Up @@ -234,7 +234,6 @@ int __stdcall DllMain(HINSTANCE hInstDLL, DWORD dwReason, LPVOID lpReserved) {
patch_cry();
}
#else // !_WIN64
p2 = GetModExpName(GetModuleHandleA(0));
if (!__stricmp(p, "sr2_pc.exe")) { // Saints Row 2
patch_sr2();
} else if (!__stricmp(p, "cmr5.exe")) { // Colin McRae Rally 2005
Expand Down Expand Up @@ -280,8 +279,6 @@ int __stdcall DllMain(HINSTANCE hInstDLL, DWORD dwReason, LPVOID lpReserved) {
patch_gt();
} else if (!__stricmp(p, "sof2mp.exe")) { // Soldier of Fortune 2
patch_sof2();
} else if (!__stricmp(p, "game.dat") && p2 && !__strcmp(p2, "RTS.exe")) { // Battle for Middle-earth II
patch_bfme2();
} else if (!__stricmp(p, "serioussam.exe") || !__stricmp(p, "sam2.exe") || !__stricmp(p, "dedicatedserver.exe")) { // Serious Sam 1 & 2
force_bind_ip = 0;
patch_sam();
Expand All @@ -306,6 +303,16 @@ int __stdcall DllMain(HINSTANCE hInstDLL, DWORD dwReason, LPVOID lpReserved) {
ue2_patch_ipdrv();
} else if (!__stricmp(p, "fear2.exe")) { // FEAR 2
gs_replace_pubkey(0);
} else if (!__stricmp(p, "game.dat")) {
char* p2 = GetModExpName(GetModuleHandleA(0));
if (p2) {
if (!__strcmp(p2, "RTS.exe")) patch_bfme2(); // Battle for Middle-earth II
}
} else if (!__stricmp(p, "game.exe")) {
LPGUID pguid = GetModPdbGuid(GetModuleHandleA(0));
if (pguid) {
if (!__memcmp(pguid, &mua_guid, sizeof(GUID))) patch_mua(); // Marvel Ultimate Alliance
}
}
#endif // _WIN64 || !_WIN64
}
Expand Down
20 changes: 20 additions & 0 deletions include/game_mua.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// game_mua.h

#ifndef __GAME_MUA_H
#define __GAME_MUA_H

#include "include/global.h"

static char mua_key[] = "SOFTWARE\\Activision\\Marvel Ultimate Alliance\\Settings\\Display";
static GUID mua_guid = {0xA5B4AF14, 0xA34F, 0x4677, {0xBE, 0x65, 0x95, 0x52, 0xDC, 0x25, 0x6D, 0x3A}};

// missing registry key causes crash on startup
__forceinline static void mua_create_key() {
CreateRegKey(HKEY_CURRENT_USER, mua_key);
}

__noinline static void patch_mua() {
mua_create_key();
}

#endif // __GAME_MUA_H
66 changes: 53 additions & 13 deletions include/global.h
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,21 @@ __forceinline static int FileExistsA(const char* path) {
return 1;
}

static BOOL CreateRegKey(HKEY hKeyRoot, char* subKey) {
HKEY hKey;
char *p = subKey;
while (*++p) {
if (*p == '\\') {
*p = 0;
if (!RegCreateKeyExA(hKeyRoot, subKey, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL)) RegCloseKey(hKey);
*p = '\\';
}
}
if (RegCreateKeyExA(hKeyRoot, subKey, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL)) return FALSE;
RegCloseKey(hKey);
return TRUE;
}

static char* GetModExpName(HMODULE hModule) {
PIMAGE_DOS_HEADER img_dos_headers;
PIMAGE_NT_HEADERS img_nt_headers;
Expand Down Expand Up @@ -448,19 +463,44 @@ static char* GetModExpName(HMODULE hModule) {
return (img_exp_dir->Name ? (char*)((size_t)img_dos_headers + img_exp_dir->Name) : 0);
}

static BOOL CreateRegKey(HKEY hKeyRoot, char* subKey) {
HKEY hKey;
char *p = subKey;
while (*++p) {
if (*p == '\\') {
*p = 0;
if (!RegCreateKeyExA(hKeyRoot, subKey, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL)) RegCloseKey(hKey);
*p = '\\';
}
}
if (RegCreateKeyExA(hKeyRoot, subKey, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL)) return FALSE;
RegCloseKey(hKey);
return TRUE;
typedef struct _RSDS_DEBUG_FORMAT {
DWORD Signature;
GUID Guid;
DWORD Age;
CHAR Path[ANYSIZE_ARRAY];
} RSDS_DEBUG_FORMAT, *PRSDS_DEBUG_FORMAT;

static LPGUID GetModPdbGuid(HMODULE hModule) {
PIMAGE_DOS_HEADER img_dos_headers;
PIMAGE_NT_HEADERS img_nt_headers;
PIMAGE_DATA_DIRECTORY img_dir_debug;
PIMAGE_DEBUG_DIRECTORY img_dbg_dir;
PRSDS_DEBUG_FORMAT img_codeview;

if (!hModule)
return 0;
img_dos_headers = (PIMAGE_DOS_HEADER)hModule;
if (img_dos_headers->e_magic != IMAGE_DOS_SIGNATURE)
return 0;
img_nt_headers = (PIMAGE_NT_HEADERS)((size_t)img_dos_headers + img_dos_headers->e_lfanew);
if (img_nt_headers->Signature != IMAGE_NT_SIGNATURE)
return 0;
if (img_nt_headers->FileHeader.SizeOfOptionalHeader < 4) // OptionalHeader.Magic
return 0;
if (img_nt_headers->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC || img_nt_headers->OptionalHeader.NumberOfRvaAndSizes < 7)
return 0;

img_dir_debug = (PIMAGE_DATA_DIRECTORY)(&(img_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]));
if (!img_dir_debug->VirtualAddress || img_dir_debug->Size < sizeof(IMAGE_DEBUG_DIRECTORY))
return 0;

img_dbg_dir = (PIMAGE_DEBUG_DIRECTORY)((size_t)img_dos_headers + img_dir_debug->VirtualAddress);
if (img_dbg_dir->Type != IMAGE_DEBUG_TYPE_CODEVIEW || !img_dbg_dir->PointerToRawData) // img_dbg_dir->AddressOfRawData ?
return 0;

img_codeview = (PRSDS_DEBUG_FORMAT)((size_t)img_dos_headers + img_dbg_dir->PointerToRawData);

return ((img_codeview->Signature == 0x53445352) ? &(img_codeview->Guid) : 0);
}

#endif // __GLOBAL_H

0 comments on commit e85c1c6

Please sign in to comment.