#include #include "Daodan.h" #include "Daodan_Patch.h" #include "Daodan_Utility.h" #include "Daodan_Win32.h" #include "Daodan_Cheater.h" #include "Daodan_Persistence.h" #include "Daodan_BSL.h" #include "Daodan_WindowHack.h" #include "Oni.h" #include "Oni_Persistence.h" #include "BFW_Utility.h" #include "oni_gl.h" #include "daodan_gl.h" #include "inifile.h" HMODULE DDrDLLModule; HMODULE DDrONiModule; bool patch_fonttexturecache = true; bool patch_largetextures = true; bool patch_levelplugins = true; bool patch_pathfinding = true; bool patch_projaware = true; bool patch_directinput = true; bool patch_wpfadetime = true; bool patch_kickguns = false; bool patch_cooldowntimer = true; bool patch_throwtest = false; bool patch_alttab = true; bool patch_particledisablebit = false; bool patch_multibyte = false; bool patch_cheattable = true; bool patch_argb8888 = true; bool patch_killvtune = true; bool patch_getcmdline = true; bool patch_disablecmdline = true; bool patch_safeprintf = true; bool patch_daodandisplayenum = true; bool patch_usegettickcount = true; bool patch_cheatsenabled = true; bool patch_usedaodangl = false; bool patch_windowhack = true; bool patch_daodaninit = true; bool patch_bsl = true; bool patch_cheater = true; bool opt_usedaodanbsl = true; bool opt_border = true; bool opt_shadow = true; bool opt_topmost = false; bool DDrPatch_Init() { DDrStartupMessage("patching engine"); // Font texture cache doubled if (patch_fonttexturecache) { DDrPatch_Byte (OniExe + 0x00020ea7, 0x20); DDrPatch_Byte (OniExe + 0x00020f4a, 0x40); } // Now supports textures up to 512x512 if (patch_largetextures) DDrPatch_Byte (OniExe + 0x00005251, 0x10); // Non-"_Final" levels are now valid if (patch_levelplugins) DDrPatch_Byte (OniExe + 0x000206a8, 0x01); // Pathfinding grid cache size x8 if (patch_pathfinding) { DDrPatch_Byte (OniExe + 0x0010b03b, 0x20); DDrPatch_Byte (OniExe + 0x0010b04c, 0x20); } // Projectile awareness fixed if (patch_projaware) { DDrPatch_Byte (OniExe + 0x0009c07c, 0x6c); DDrPatch_Byte (OniExe + 0x0009c080, 0x70); DDrPatch_Byte (OniExe + 0x0009c084, 0x74); DDrPatch_Byte (OniExe + 0x0009c110, 0x6c); } // Forced DirectInput (for Windows NT) if (patch_directinput) DDrPatch_Byte (OniExe + 0x00002e6d, 0xeb); if (patch_wpfadetime) { // Makes wp_fadetime actually have a function const char fadetime_patch[] = { 0x66, 0x8B, 0x1D, 0xC4, 0x7D, 0x62, 0x00, 0x66, 0x89, 0x5E, 0x46, 0x5B, 0x5E, 0x83, 0xC4, 0x14, 0xC3 }; DDrPatch_Const (OniExe + 0x0011a889, fadetime_patch); DDrPatch_Byte (OniExe + 0x0011a560, 0x31); // Sets the fadetime to 4800 by default DDrPatch_Int16 (OniExe + 0x0011ab0e, 0x12c0); } // Hackish fix for Konoko not kicking guns if (patch_kickguns) { const char kickgun_patch[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0xC7, 0x05, 0x1C, 0xC9, 0x5E, 0x00, 0x70, 0xB8, 0x43, 0x00, 0xC7, 0x05, 0x20, 0xC9, 0x5E, 0x00, 0x20, 0xBE, 0x43 }; DDrPatch_Const (OniExe + 0x000dc420, kickgun_patch); } // Cooldown timer exploit fix ^_^ if (patch_cooldowntimer) { const char cooldown_patch[] = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }; DDrPatch_Const (OniExe + 0x0011a825, cooldown_patch); } if (patch_throwtest) { const char throwtest_patch[] = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }; DDrPatch_Const(OniExe + 0x000dc190, throwtest_patch); } // Disable UUrPlatform_Initalize/Terminate, this enables the Alt-Tab and the Windows key but has the possible side effect of allowing the screensaver to enable itself in-game. if (patch_alttab) { DDrPatch_Byte ((void*)UUrPlatform_Initialize, 0xC3); DDrPatch_Byte ((void*)UUrPlatform_Terminate, 0xC3); } // Unlocks particle action disabling/enabling bits for all events. (Will be controlled by a command line switch when I figure out how to do that without Win32 hacks.) if (patch_particledisablebit) DDrPatch_Int16 (OniExe + 0x001b184, 0x9090); // Multi-byte patch (multiple language support) if (!patch_multibyte) { DDrPatch_Byte (OniExe + 0x0002d8f8, 0xeb); DDrPatch_Byte (OniExe + 0x0002d9ad, 0xeb); DDrPatch_Byte (OniExe + 0x0002dbe2, 0xeb); DDrPatch_Byte (OniExe + 0x0002dec3, 0xeb); DDrPatch_Byte (OniExe + 0x0002e2ab, 0xeb); DDrPatch_Byte (OniExe + 0x0002e2c4, 0xeb); DDrPatch_Byte (OniExe + 0x0002e379, 0xeb); DDrPatch_Byte (OniExe + 0x0002e48c, 0xeb); DDrPatch_Byte (OniExe + 0x0002e4d0, 0xeb); DDrPatch_Byte (OniExe + 0x0002e4f4, 0xeb); DDrPatch_Byte (OniExe + 0x0002e646, 0xeb); DDrPatch_Byte (OniExe + 0x0002e695, 0xeb); DDrPatch_Byte (OniExe + 0x0002e944, 0xeb); DDrPatch_Byte (OniExe + 0x0002e95d, 0xeb); DDrPatch_Byte (OniExe + 0x0002e98e, 0xeb); DDrPatch_Byte (OniExe + 0x0002e9dc, 0xeb); } // Cheat table patch if (patch_cheattable) { DDrPatch_Int32 (OniExe + 0x000f616b, (int)&DDr_CheatTable[0].name); DDrPatch_Int32 (OniExe + 0x000f617a, (int)&DDr_CheatTable[0].message_on); } // ARGB8888 textures if (patch_argb8888) { DDrPatch_Byte (OniExe + 0x00135af0, 0x07); DDrPatch_Byte (OniExe + 0x00135af4, 0x0B); } // Disable loading the vtuneapi.dll if (patch_killvtune) DDrPatch_Byte (OniExe + 0x00026340, 0xC3); // Disable Oni's internal CLrGetCommandLine function (to eventually replace it with our own) if (patch_getcmdline) DDrPatch_NOOP (OniExe + 0x000d3280, 51); // Disable Oni's command line parser so it doesn't interfere with ours if (patch_disablecmdline) DDrPatch_Int32 (OniExe + 0x000d3570, 0xc3c03366); return true; } enum {s_unknown, s_options, s_patch, s_bsl, s_language} ini_section; bool DDrIniCallback(char* section, bool newsection, char* name, char* value) { if (newsection) { if (!stricmp(section, "options")) ini_section = s_options; else if (!stricmp(section, "patch")) ini_section = s_patch; else if (!stricmp(section, "bsl")) ini_section = s_bsl; else if (!stricmp(section, "language")) ini_section = s_language; else { ini_section = s_unknown; DDrStartupMessage("unrecognised section \"%s\"", section); } } switch (ini_section) { case s_options: if (!stricmp(name, "usedaodanbsl")) opt_usedaodanbsl = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "border")) opt_border = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "shadow")) opt_shadow = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "topmost")) opt_topmost = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "multibyte")) patch_multibyte = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "debug")) AKgDebug_DebugMaps = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "debugfiles")) BFgDebugFileEnable = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "findsounds")) SSgSearchOnDisk = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "ignore_private_data")) opt_ignore_private_data = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "sound")) opt_sound = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "switch")) M3gResolutionSwitch = !stricmp(inifile_cleanstr(value), "true"); else DDrStartupMessage("unrecognised option \"%s\"", name); break; case s_patch: if (!stricmp(name, "fonttexturecache")) patch_fonttexturecache = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "largetextures")) patch_largetextures = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "levelplugins")) patch_levelplugins = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "pathfinding")) patch_pathfinding = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "projaware")) patch_projaware = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "directinput")) patch_directinput = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "wpfadetime")) patch_wpfadetime = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "kickguns")) patch_kickguns = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "cooldowntimer")) patch_cooldowntimer = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "throwtest")) patch_throwtest = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "alttab")) patch_alttab = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "particledisablebit")) patch_particledisablebit = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "multibyte")) patch_multibyte = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "cheattable")) patch_cheattable = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "argb8888")) patch_argb8888 = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "killvtune")) patch_killvtune = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "getcmdline")) patch_getcmdline = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "disablecmdline")) patch_disablecmdline = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "safeprintf")) patch_safeprintf = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "daodandisplayenum")) patch_daodandisplayenum = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "usegettickcount")) patch_usegettickcount = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "cheatsenabled")) patch_cheatsenabled = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "usedaodangl")) patch_usedaodangl = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "windowhack")) patch_windowhack = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "daodaninit")) patch_daodaninit = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "bsl")) patch_bsl = !stricmp(inifile_cleanstr(value), "true"); else if (!stricmp(name, "cheater")) patch_cheater = !stricmp(inifile_cleanstr(value), "true"); else DDrStartupMessage("unrecognised patch \"%s\"", name); break; case s_language: if (!stricmp(name, "savepoint")) { char* str = strdup(value); DDrPatch_Int32(OniExe + 0x000fd730, (int)str); DDrPatch_Int32(OniExe + 0x000fd738, (int)str); } else if (!stricmp(name, "syndicatewarehouse")) { char* str = strdup(value); DDrPatch_Int32(OniExe + 0x000fd71a, (int)str); DDrPatch_Int32(OniExe + 0x0010ef75, (int)str); } else if (!stricmp(name, "damn")) DDrPatch_StrDup(OniExe + 0x0010fb6e, value); else if (!stricmp(name, "blam")) DDrPatch_StrDup(OniExe + 0x0010fb73, value); else if (!stricmp(name, "shapeshifter_on")) DDr_CheatTable[0].message_on = strdup(value); else if (!stricmp(name, "shapeshifter_off")) DDr_CheatTable[0].message_off = strdup(value); else if (!stricmp(name, "liveforever_on")) DDr_CheatTable[1].message_on = strdup(value); else if (!stricmp(name, "liveforever_off")) DDr_CheatTable[1].message_off = strdup(value); else if (!stricmp(name, "touchofdeath_on")) DDr_CheatTable[2].message_on = strdup(value); else if (!stricmp(name, "touchofdeath_off")) DDr_CheatTable[2].message_off = strdup(value); else if (!stricmp(name, "canttouchthis_on")) DDr_CheatTable[3].message_on = strdup(value); else if (!stricmp(name, "canttouchthis_off")) DDr_CheatTable[3].message_off = strdup(value); else if (!stricmp(name, "fatloot_on")) DDr_CheatTable[4].message_on = strdup(value); else if (!stricmp(name, "glassworld_on")) DDr_CheatTable[5].message_on = strdup(value); else if (!stricmp(name, "glassworld_off")) DDr_CheatTable[5].message_off = strdup(value); else if (!stricmp(name, "winlevel_on")) DDr_CheatTable[6].message_on = strdup(value); else if (!stricmp(name, "loselevel_on")) DDr_CheatTable[7].message_on = strdup(value); else if (!stricmp(name, "bighead_on")) DDr_CheatTable[8].message_on = strdup(value); else if (!stricmp(name, "bighead_off")) DDr_CheatTable[8].message_off = strdup(value); else if (!stricmp(name, "minime_on")) DDr_CheatTable[9].message_on = strdup(value); else if (!stricmp(name, "minime_off")) DDr_CheatTable[9].message_off = strdup(value); else if (!stricmp(name, "superammo_on")) DDr_CheatTable[10].message_on = strdup(value); else if (!stricmp(name, "superammo_off")) DDr_CheatTable[10].message_off = strdup(value); else if (!stricmp(name, "devmode_on")) { char* str = strdup(value); DDr_CheatTable[11].message_on = str; DDr_CheatTable[cheat_x].message_on = str; } else if (!stricmp(name, "devmode_off")) { char* str = strdup(value); DDr_CheatTable[11].message_off = str; DDr_CheatTable[cheat_x].message_off = str; } else if (!stricmp(name, "reservoirdogs_on")) DDr_CheatTable[12].message_on = strdup(value); else if (!stricmp(name, "reservoirdogs_off")) DDr_CheatTable[12].message_off = strdup(value); else if (!stricmp(name, "roughjustice_on")) DDr_CheatTable[13].message_on = strdup(value); else if (!stricmp(name, "roughjustice_off")) DDr_CheatTable[13].message_off = strdup(value); else if (!stricmp(name, "chenille_on")) DDr_CheatTable[14].message_on = strdup(value); else if (!stricmp(name, "chenille_off")) DDr_CheatTable[14].message_off = strdup(value); else if (!stricmp(name, "behemoth_on")) DDr_CheatTable[15].message_on = strdup(value); else if (!stricmp(name, "behemoth_off")) DDr_CheatTable[15].message_off = strdup(value); else if (!stricmp(name, "elderrune_on")) DDr_CheatTable[16].message_on = strdup(value); else if (!stricmp(name, "elderrune_off")) DDr_CheatTable[16].message_off = strdup(value); else if (!stricmp(name, "moonshadow_on")) DDr_CheatTable[17].message_on = strdup(value); else if (!stricmp(name, "moonshadow_off")) DDr_CheatTable[17].message_off = strdup(value); else if (!stricmp(name, "munitionfrenzy_on")) DDr_CheatTable[18].message_on = strdup(value); else if (!stricmp(name, "fistsoflegend_on")) DDr_CheatTable[19].message_on = strdup(value); else if (!stricmp(name, "fistsoflegend_off")) DDr_CheatTable[19].message_off = strdup(value); else if (!stricmp(name, "killmequick_on")) DDr_CheatTable[20].message_on = strdup(value); else if (!stricmp(name, "killmequick_off")) DDr_CheatTable[20].message_off = strdup(value); else if (!stricmp(name, "carousel_on")) DDr_CheatTable[21].message_on = strdup(value); else if (!stricmp(name, "carousel_off")) DDr_CheatTable[21].message_off = strdup(value); else DDrStartupMessage("unrecognised language item \"%s\"", name); break; case s_bsl: default: break; } return true; } void DDrConfig() { if (GetFileAttributes("daodan.ini") == INVALID_FILE_ATTRIBUTES) { DDrStartupMessage("daodan.ini doesn't exist, creating"); FILE* fp = fopen("daodan.ini", "w"); if (fp) { fputs("[Options]\n", fp); fclose(fp); } } DDrStartupMessage("parsing daodan.ini..."); if (!inifile_read("daodan.ini", DDrIniCallback)) DDrStartupMessage("error reading daodan.ini, check your syntax!"); DDrStartupMessage("finished parsing"); } void ONICALL DDrGame_Init() { if (opt_usedaodanbsl) SLrDaodan_Initalize(); } void __cdecl DDrMain(int argc, char* argv[]) { DDrStartupMessage("daodan attached!"); opt_ignore_private_data = false; opt_sound = true; DDrConfig(); DDrStartupMessage("parsing command line..."); int i; char* section; char* option; bool falseoption; for (i = 1; i < argc; i ++) { if (argv[i][0] == '-') { section = argv[i] + 1; if ((option = strchr(argv[i], '.'))) { *option = '\0'; falseoption = (option[1] == 'n' || option[1] == 'N') && (option[2] = 'o' || option[2] == 'O'); if (i < (argc - 1) && argv[i + 1][0] != '-') DDrIniCallback(section, true, option + 1, argv[++i]); else DDrIniCallback(section, true, option + (falseoption ? 3 : 1), (falseoption ? "false" : "true")); *option = '.'; } else { falseoption = (section[0] == 'n' || section[0] == 'N') && (section[1] = 'o' || section[1] == 'O'); ini_section = s_options; if (i < (argc - 1) && argv[i + 1][0] != '-') DDrIniCallback(NULL, false, section, argv[++i]); else DDrIniCallback(NULL, false, section + (falseoption ? 2 : 0), (falseoption ? "false" : "true")); } } else { DDrStartupMessage("parse error \"%s\"", argv[i]); break; } } DDrStartupMessage("finished parsing"); DDrPatch_Init(); // Safe startup message printer if (patch_safeprintf) DDrPatch_MakeJump(UUrStartupMessage, DDrStartupMessage); // Daodan device mode enumeration function if (patch_daodandisplayenum) DDrPatch_MakeJump(gl_enumerate_valid_display_modes, daodan_enumerate_valid_display_modes); // Performance patch if (patch_usegettickcount) { DDrPatch_MakeJump(UUrMachineTime_High, DDrMachineTime_High); DDrPatch_MakeJump(UUrMachineTime_High_Frequency, DDrMachineTime_High_Frequency); DDrPatch_MakeJump(UUrMachineTime_Sixtieths, DDrMachineTime_Sixtieths); } // Cheats always enabled if (patch_cheatsenabled) DDrPatch_MakeJump(ONrPersist_GetWonGame, DDrPersist_GetWonGame); // Windowed mode if (patch_usedaodangl) { DDrPatch_MakeJump(ONrPlatform_Initialize, DDrPlatform_Initialize); DDrPatch_MakeJump(gl_platform_initialize, daodangl_platform_initialize); } // Hacked windowed mode (for when daodangl isn't working properly) if (patch_windowhack) DDrWindowHack_Install(); if (patch_daodaninit) DDrPatch_MakeCall(OniExe + 0x000d345a, DDrGame_Init); // Patches for existing BSL functions if (patch_bsl) SLrDaodan_Patch(); if (patch_cheater) { DDrPatch_MakeCall(OniExe + 0x000f618f, DDrCheater); DDrPatch_Int16(OniExe + 0x000deb45, 0x5590); DDrPatch_MakeCall(OniExe + 0x000deb47, FallingFrames); DDrPatch_MakeJump(OniExe + 0x0010f021, DDrCheater_LevelLoad); } init_daodan_gl(); ONiMain(argc, argv); } /* void DDrWrongExe() { switch (MessageBox(NULL, "This version of the Daodan DLL is incompatible with your Oni.exe.\n" "Click OK for more information. To continue using Oni without the patch, replace the downloaded binkw32.dll with the original.", "Daodan", MB_OKCANCEL | MB_ICONERROR)) { case IDOK: { STARTUPINFO si; PROCESS_INFORMATION pi; FillMemory(&si, 0, sizeof(si)); FillMemory(&pi, 0, sizeof(pi)); si.cb = sizeof(si); if (!CreateProcess(NULL, "cmd /c \"start http://wiki.oni2.net/Daodan_DLL\"", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) MessageBox(NULL, "", "", 0); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } default: ExitProcess(0); } } */ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) { switch (fdwReason) { case DLL_PROCESS_ATTACH: DDrDLLModule = hinstDLL; DDrONiModule = GetModuleHandle(NULL); if (*(uint32_t*)((void*)OniExe + 0x0011acd0) == 0x09d36852) DDrPatch_MakeCall(OniExe + 0x0010fb49, DDrMain); else ExitProcess(0); break; } return TRUE; }