/* * Rollcage Stage II Bump Map Fix - by InDigo176 * 2009-12-29 * * This patch basically just adds * if (esi == 9) { * esi--; * } * to be run before every call to SetTextureStageState(ecx, edx, esi); * * The problem is that the game is using D3DTOP_ADDSIGNED2X (9) instead of * just D3DTOP_ADDSIGNED (8). * */ #include #include #include #define WIN32_LEAN_AND_MEAN /* skip rarely used stuff */ #include #define TITLE "Rollcage Stage II Bump Map Fix - by InDigo176" char *get_path(size_t *maxlen); void show_error(const char *msg); int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { size_t maxlen = 32768; /* max path length */ char *path = NULL; FILE *fd = NULL; /* this is the jump to the payload we're going to add * JMP 004B3C2E */ const unsigned char jump_to_hack[5] = {0xE9, 0xBB, 0x8C, 0x02, 0x00}; /* this is the payload placed below the original code * it also contains operations that got overwritten by the jump */ const unsigned char hack[16] = {0x83, 0xFE, 0x09, /* CMP ESI,9 */ 0x75, 0x01, /* JNZ SHORT +01 */ 0x4E, /* DEC ESI */ /* these below got overwritten by the * jump and need to be placed back */ 0x56, /* PUSH ESI */ 0x52, /* PUSH EDX */ 0x51, /* PUSH ECX */ 0x8B, 0x18, /* MOV EBX,[EAX] */ /* JMP 0048AF73 (jump back) */ 0xE9, 0x35, 0x73, 0xFD, 0xFF}; path = get_path(&maxlen); if (!path) { show_error("Cannot locate Rollcage Stage II!\n" "Please make sure it is installed."); return FALSE; } strcpy(path+maxlen-1, "\\BIN\\Rollcage D3D.exe"); fd = fopen(path, "r+b"); if (!fd) { show_error("Cannot open file!\nTry running this patch as " "Administrator and make sure Rollcage Stage " "II is installed correctly."); return FALSE; } free(path); /* add the jump */ if (fseek(fd, 0x0008AF6EL, SEEK_SET) != 0) { show_error("Unexpected read error."); return FALSE; } switch (fgetc(fd)) { case 0x56: /* PUSH ESI */ break; case 0xE9: /* JMP */ MessageBoxA(NULL, "Patch already applied.", TITLE, MB_ICONINFORMATION|MB_OK); return FALSE; default: show_error("Wrong version of Rollcage Stage II installed.\n" "Please install v1.0c patch first!"); return FALSE; } if (fseek(fd, -1L, SEEK_CUR) != 0) { show_error("Unexpected read error."); return FALSE; } if (fwrite(jump_to_hack, 1, 5, fd) != 5 || fflush(fd) != 0) { show_error("Unexpected write error."); return FALSE; } /* add the payload */ if (fseek(fd, 0x000B3C2EL, SEEK_SET) != 0) { show_error("Unexpected read error."); return FALSE; } if (fgetc(fd) != 0x00) { /* just an extra check */ show_error("Wrong version of Rollcage Stage II installed.\n" "Please install v1.0c patch first!"); return FALSE; } if (fseek(fd, -1L, SEEK_CUR) != 0) { show_error("Unexpected read error."); return FALSE; } if (fwrite(hack, 1, 16, fd) != 16 || fflush(fd) != 0) { show_error("Unexpected write error."); return FALSE; } if (fclose(fd) != 0) { MessageBoxA(NULL, "Something went wrong!\n" "The patch maybe didn't get applied.", TITLE, MB_ICONWARNING|MB_OK); return FALSE; } MessageBoxA(NULL, "Patch applied successfully!", TITLE, MB_ICONINFORMATION|MB_OK); return FALSE; } char *get_path(size_t *maxlen) { HKEY hkey; char *path; if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Psygnosis\\Rollcage Stage II\\Installer", 0, KEY_READ, &hkey) != ERROR_SUCCESS) { return NULL; } path = malloc(*maxlen); if (!path) { return NULL; } *maxlen -= 21; /* ensure there's space for "\BIN\Rollcage D3D.exe" */ if (RegQueryValueExA(hkey, "Destination", NULL, NULL, (LPBYTE)path, (LPDWORD)maxlen) != ERROR_SUCCESS) { free(path); path = NULL; } RegCloseKey(hkey); return path; } void show_error(const char *msg) { MessageBoxA(NULL, msg, TITLE, MB_ICONERROR|MB_OK); }