#include #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_Console.h" #include "Oni.h" #include "Oni_GL.h" #include "Daodan_GL.h" #include "Inifile_Reader.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_optionsvisible = true; bool patch_binkplay = true; bool patch_safeprintf = true; bool patch_daodandisplayenum = true; bool patch_usegettickcount = true; bool patch_cheatsenabled = true; bool patch_usedaodangl = true; bool patch_clipcursor = true; bool patch_daodaninit = true; bool patch_bsl = true; bool patch_cheater = true; bool patch_newweapon = true; bool opt_usedaodanbsl = true; bool opt_border = true; bool opt_topmost = false; bool opt_gamma = true; typedef int (__cdecl *CHINESEPROC)(DWORD ThreadId); bool patch_chinese = true; // Hooked WMrSlider_SetRange() in ONiOGU_Options_InitDialog. Disables a gamma // slider in windowed mode. static void ONICALL DD_ONiOGU_GammaSlider_SetRange(WMtWindow* window, int min_value, int max_value) { WMrWindow_SetEnabled(window, M3gResolutionSwitch && opt_gamma); WMrSlider_SetRange(window, min_value, max_value); } void ONICALL DDrShowResumeButton(WMtWindow* window, int visibility) { if (visibility) WMrWindow_SetLocation(window, 150, 350); WMrWindow_SetVisible(window, visibility); } /* Options always visible patch */ void ONICALL DDrShowOptionsButton(WMtWindow* window, int visibility) { WMrWindow_SetVisible(window, 1); } bool DDrPatch_Init() { DDrStartupMessage("Daodan: Patching engine"); // Font texture cache doubled if (patch_fonttexturecache) { DDrPatch_Byte((char*)(OniExe + 0x00020ea7), 0x20); DDrPatch_Byte((char*)(OniExe + 0x00020f4a), 0x40); } // Now supports textures up to 512x512 if (patch_largetextures) DDrPatch_Byte ((char*)(OniExe + 0x00005251), 0x10); // Non-"_Final" levels are now valid if (patch_levelplugins) DDrPatch_Byte ((char*)(OniExe + 0x000206a8), 0x01); // Pathfinding grid cache size x8 if (patch_pathfinding) { const unsigned char pathfinding[2] = {0x90 , 0xE9 }; DDrPatch_Byte ((char*)(OniExe + 0x0010b03b), 0x20); DDrPatch_Byte ((char*)(OniExe + 0x0010b04c), 0x20); //other stuff DDrPatch_Const((char*)(OniExe + 0x00040789), pathfinding); } // Projectile awareness fixed if (patch_projaware) { DDrPatch_Byte ((char*)(OniExe + 0x0009c07c), 0x6c); DDrPatch_Byte ((char*)(OniExe + 0x0009c080), 0x70); DDrPatch_Byte ((char*)(OniExe + 0x0009c084), 0x74); DDrPatch_Byte ((char*)(OniExe + 0x0009c110), 0x6c); } // Forced DirectInput (for Windows NT) if (patch_directinput) DDrPatch_Byte((char*)(OniExe + 0x00002e6d), 0xeb); if (patch_wpfadetime) { // Makes wp_fadetime actually have a function const unsigned char fadetime_patch[] = { 0x66, 0x8B, 0x1D, 0xC4, 0x7D, 0x62, 0x00, 0x66, 0x89, 0x5E, 0x46, 0x5B, 0x5E, 0x83, 0xC4, 0x14, 0xC3 }; DDrPatch_Const ((char*)(OniExe + 0x0011a889), fadetime_patch); DDrPatch_Byte ((char*)(OniExe + 0x0011a560), 0x31); // Sets the fadetime to 4800 by default DDrPatch_Int16 ((short*)(OniExe + 0x0011ab0e), 0x12c0); } // FIXME: add switches //pathfinding fix // Hackish fix for Konoko not kicking guns // Don't use this, it breaks stairs. if (patch_kickguns) { const unsigned 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 ((char*)(OniExe + 0x000dc420), kickgun_patch); } // Cooldown timer exploit fix ^_^ if (patch_cooldowntimer) { const unsigned 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 ((char*)(OniExe + 0x0011a825), cooldown_patch); } if (patch_throwtest) { const unsigned char throwtest_patch[] = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }; DDrPatch_Const((char*)(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) { // 0xC3 = ret, so makes those functions just have a "ret" instruction at their start DDrPatch_Byte ((char*)UUrPlatform_Initialize, 0xC3); DDrPatch_Byte ((char*)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 ((short*)(OniExe + 0x001b184), 0x9090); // Multi-byte patch (multiple language support) if (!patch_multibyte) { DDrPatch_Byte ((char*)(OniExe + 0x0002d8f8), 0xeb); DDrPatch_Byte ((char*)(OniExe + 0x0002d9ad), 0xeb); DDrPatch_Byte ((char*)(OniExe + 0x0002dbe2), 0xeb); DDrPatch_Byte ((char*)(OniExe + 0x0002dec3), 0xeb); DDrPatch_Byte ((char*)(OniExe + 0x0002e2ab), 0xeb); DDrPatch_Byte ((char*)(OniExe + 0x0002e2c4), 0xeb); DDrPatch_Byte ((char*)(OniExe + 0x0002e379), 0xeb); DDrPatch_Byte ((char*)(OniExe + 0x0002e48c), 0xeb); DDrPatch_Byte ((char*)(OniExe + 0x0002e4d0), 0xeb); DDrPatch_Byte ((char*)(OniExe + 0x0002e4f4), 0xeb); DDrPatch_Byte ((char*)(OniExe + 0x0002e646), 0xeb); DDrPatch_Byte ((char*)(OniExe + 0x0002e695), 0xeb); DDrPatch_Byte ((char*)(OniExe + 0x0002e944), 0xeb); DDrPatch_Byte ((char*)(OniExe + 0x0002e95d), 0xeb); DDrPatch_Byte ((char*)(OniExe + 0x0002e98e), 0xeb); DDrPatch_Byte ((char*)(OniExe + 0x0002e9dc), 0xeb); } // Cheat table patch if (patch_cheattable) { DDrPatch_Int32 ((int*)(OniExe + 0x000f616b), (int)&DDr_CheatTable[0].name); DDrPatch_Int32 ((int*)(OniExe + 0x000f617a), (int)&DDr_CheatTable[0].message_on); } // ARGB8888 textures if (patch_argb8888) { DDrPatch_Byte ((char*)(OniExe + 0x00135af0), 0x07); DDrPatch_Byte ((char*)(OniExe + 0x00135af4), 0x0B); } //Test newweap patch if (patch_newweapon) { //Makes it always say "Received weapon_name." //Needs check for loc_4DFC66 //DDrPatch_NOOP((char*)(OniExe + 0x000E4DF8),2); //Adds Weapon name and ammo meter to pickup autoprompt DDrPatch_NOOP((char*)(OniExe + 0x000FAC73), 9); DDrPatch_NOOP((char*)(OniExe + 0x000FAC80), 5); DDrPatch_MakeCall((void*)(OniExe + 0xFAC85), (void*)DDrWeapon2Message); //Moves location of colors //DDrPatch_Int32((int*)(OniExe + 0x0002E3D5), (int)&DDrDSayColors ); //DDrPatch_Int32((int*)(OniExe + 0x0002E3DA), (int)&DDrDSayColors ); } // Disable loading the vtuneapi.dll //if (patch_killvtune) //DDrPatch_Byte ((char*)(OniExe + 0x00026340), 0xC3); // Disable Oni's internal CLrGetCommandLine function (to eventually replace it with our own) if (patch_getcmdline) DDrPatch_NOOP ((char*)(OniExe + 0x000d3280), 51); // Disable Oni's command line parser so it doesn't interfere with ours if (patch_disablecmdline) DDrPatch_Int32 ((int*)(OniExe + 0x000d3570), 0xc3c03366); if (patch_bsl) { //Calculating the value of the needed offset is much more reliable when the compiler does it for you. //TODO: fix moonshadow. Character * Chr = 0; int NoPath = (int)&(Chr[0].RegenHax) & 0x000000FF; const unsigned char regen_patch[] = {0x90, 0x90, 0x90, 0x90, 0x90, // mov al, _WPgRegenerationCheat -> NOOP 0x90, 0x90, // test al, al -> NOOP 0x90, 0x90, // jz short loc_51BB98 -> NOOP 0x8B, 0x86, (char)NoPath, 0x01, 0x00, 0x00, // mov eax, [esi+Character.field_1E8] // -> mov eax, [esi+Character.RegenHax] 0x85, 0xC0, // test eax, eax 0x74, 0x21 // jnz 0x21 -> jz 0x21 }; DDrPatch_Const((char*)(OniExe + 0x0011BB64), regen_patch); } if(patch_chinese) { if (GetFileAttributes("xfhsm_oni.dll") != INVALID_FILE_ATTRIBUTES) { HMODULE dll; DWORD err; DDrStartupMessage("Daodan: Loading chinese DLL"); dll = LoadLibrary("xfhsm_oni.dll"); err = GetLastError(); if( dll ) { void* proc = GetProcAddress( dll, "InstallHook" ); if(proc) { ((CHINESEPROC)proc)(GetCurrentThreadId()); } } else { char msg[100]; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, msg, 100, NULL); DDrStartupMessage("Daodan: Loading DLL failed with error %i: %s", err, msg); } } } //Fix crappy ai2_shownames if(1) { //Set distance above head to 4.0 DDrPatch_Int32((int*)(OniExe + 0x0008C998), 0x005296C8); //texture height DDrPatch_Byte((char*)(OniExe + 0x0008C9DF), 0x3F ); //texture width DDrPatch_NOOP((char*)(OniExe + 0x0008C9CA), 6 ); //Set the text color to whatever we like ;) DDrPatch_NOOP((char*)(OniExe + 0x0008C898), 6 ); DDrPatch_Byte((char*)(OniExe + 0x0008C898), 0x8B ); DDrPatch_Byte((char*)(OniExe + 0x0008C899), 0xCE ); //FLATLINE? DDrPatch_MakeCall((void*)(OniExe + 0x0008C8A3), FLrHook_DebugNameShadeHack); //Make the background black for additive blending //FLATLINE? DDrPatch_MakeCall((void*)(OniExe + 0x0008C802), FLrHook_DebugNameTextureInit ); } if(1) { //DDrPatch_NOOP((char*)(OniExe + 0x000E1957), 6 ); //DDrPatch_MakeCall((void*)(OniExe + 0x000E17F6), FLrHook_Lasers ); } //Flatline related stuff // DDrPatch_MakeCall((void*)(OniExe + 0x000FBCEA), DDrText_Hook); //FLATLINE? DDrPatch_Int32((int*)(OniExe + 0x000B24D2), FLrSpawnHack); //FLATLINE? DDrPatch_NOOP((char*)(OniExe + 0x000C26CB), 6); //FLATLINE? DDrPatch_MakeCall((void*)(OniExe + 0x000C26CB), FLrHook_DoorOpen); //FLATLINE? DDrPatch_MakeCall((void*)(OniExe + 0x000EE3CF), FLrHook_ConsoleActivate); // Fix options not visible in main menu when a game was started if(patch_optionsvisible) { DDrPatch_MakeCall((void*)(OniExe + 0x000d2d2d), DDrShowOptionsButton); DDrPatch_MakeCall((void*)(OniExe + 0x000d2d43), DDrShowResumeButton); } // Fix BinkBufferInit() call in BKrMovie_Play() to use GDI (DIB) blitting // instead of DirectDraw; patch ONiRunGame to use the same method to play // outro (ie., BKrMovie_Play() instead of ONrMovie_Play_Hardware() as the // latter has problems on WINE). if (patch_binkplay) { // push BINKBUFFERAUTO -> push BINKBUFFERDIBSECTION. DDrPatch_Byte((void*)(OniExe + 0x0008829b + 1), 0x02); // call ONrMovie_Play_Hardware -> call ONrMovie_Play DDrPatch_MakeCall((void*)(OniExe + 0x000d496f), ONrMovie_Play); } // Patch a gamma slider in Options dialog (unconditionally). // ONiOGU_Options_InitDialog: replace WMrSlider_SetRange(gammaSliderWindow, ...) // call with our hook function. DDrPatch_MakeCall((void*)(OniExe + 0x000d262c), (void*)DD_ONiOGU_GammaSlider_SetRange); 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("Daodan: Unrecognised ini 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, "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 if (!_stricmp(name, "gamma")) opt_gamma = !_stricmp(inifile_cleanstr(value), "true"); else DDrStartupMessage("Daodan: Unrecognised ini 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, "clipcursor")) patch_clipcursor = !_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 if (!_stricmp(name, "newweap")) patch_newweapon = !_stricmp(inifile_cleanstr(value), "true"); else if (!_stricmp(name, "optionsvisible")) patch_optionsvisible = !_stricmp(inifile_cleanstr(value), "true"); else if (!_stricmp(name, "binkplay")) patch_binkplay = !_stricmp(inifile_cleanstr(value), "true"); else DDrStartupMessage("Daodan: Unrecognised ini patch \"%s\"", name); break; case s_language: if (!_stricmp(name, "chinese")) patch_chinese = true; else if (!_stricmp(name, "savepoint")) { char* str = _strdup(value); DDrPatch_Int32((int*)(OniExe + 0x000fd730), (int)str); DDrPatch_Int32((int*)(OniExe + 0x000fd738), (int)str); } else if (!_stricmp(name, "syndicatewarehouse")) { char* str = _strdup(value); DDrPatch_Int32((int*)(OniExe + 0x000fd71a), (int)str); DDrPatch_Int32((int*)(OniExe + 0x0010ef75), (int)str); } else if (!_stricmp(name, "damn")) DDrPatch__strdup((int*)(OniExe + 0x0010fb6e), value); else if (!_stricmp(name, "blam")) DDrPatch__strdup((int*)(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("Daodan: Unrecognised ini language item \"%s\"", name); break; case s_bsl: default: break; } return true; } void DDrConfig() { if (GetFileAttributes("daodan.ini") == INVALID_FILE_ATTRIBUTES) { FILE* fp; DDrStartupMessage("Daodan: daodan.ini doesn't exist, creating"); fp = fopen("daodan.ini", "w"); if (fp) { fputs("[Options]\n", fp); fclose(fp); } } DDrStartupMessage("Daodan: Parsing daodan.ini..."); if (!inifile_read("daodan.ini", DDrIniCallback)) DDrStartupMessage("Daodan: Error reading daodan.ini, check your syntax!"); DDrStartupMessage("Daodan: Finished parsing"); } void ONICALL DDrGame_Init() { if (opt_usedaodanbsl) SLrDaodan_Initialize(); } void DDrException() { int* i = 0; *i = 1; } #include //this was broken FILE** _UUgError_WarningFile = (FILE**)0x005711B4; FILE *__fastcall DDrPrintWarning(int filename, int linenumber, unsigned __int16 errornum, int message) { FILE *v4; // eax@1 FILE *result; // eax@4 char v6[512]; // [sp+0h] [bp-100h]@1 FILE* UUgError_WarningFile = *_UUgError_WarningFile; if (filename && message && (strlen((const char*)filename)+strlen((const char*)message))<420) { sprintf( v6, "Error %x reported from File: %s, Line: %d (message follows) \r\n%s", errornum, (const char*)filename, linenumber, (const char*)message); if ( UUgError_WarningFile || (UUgError_WarningFile = oni_fopen("debugger.txt", "wb"), UUgError_WarningFile ) ) { oni_fprintf(UUgError_WarningFile, "%s\r\n", v6); oni_fflush(UUgError_WarningFile); } } //oni_fprintf(stdout, v6); //sprintf(&v6, "%s", message); *_UUgError_WarningFile = UUgError_WarningFile; result = UUgError_WarningFile; return result; } void __cdecl DDrMain(int argc, char* argv[]) { int i; char* section; char* option; bool falseoption; DDrStartupMessage("Daodan: Daodan attached!"); // Tell Oni to not load non levelX_final-files by default: opt_ignore_private_data = false; // Enable sound by default: opt_sound = true; DDrConfig(); DDrStartupMessage("Daodan: Parsing command line..."); 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("Daodan: Parse error \"%s\"", argv[i]); break; } } DDrStartupMessage("Daodan: Finished parsing"); DDrPatch_Init(); // Safe startup message printer if (patch_safeprintf) DDrPatch_MakeJump((void*)UUrStartupMessage, (void*)DDrStartupMessage); // Daodan device mode enumeration function if (patch_daodandisplayenum) DDrPatch_MakeJump((void*)gl_enumerate_valid_display_modes, (void*)DD_GLrEnumerateDisplayModes); // Performance patch if (patch_usegettickcount) { DDrPatch_MakeJump((void*)UUrMachineTime_High, (void*)DDrMachineTime_High); DDrPatch_MakeJump((void*)UUrMachineTime_High_Frequency, (void*)DDrMachineTime_High_Frequency); DDrPatch_MakeJump((void*)UUrMachineTime_Sixtieths, (void*)DDrMachineTime_Sixtieths); } // Cheats always enabled if (patch_cheatsenabled) DDrPatch_MakeJump((void*)ONrPersist_GetWonGame, (void*)DDrPersist_GetWonGame); // DaodanGL with windowed mode support. if (patch_usedaodangl) { // LIrPlatform_Mode_Set: GetWindowRect -> GetClientRect. DDrPatch_NOOP((char*) OniExe + 0x00002dd6, 6); DDrPatch_MakeCall((char*) OniExe + 0x00002dd6, (void*) GetClientRect); // UUrWindow_GetSize: GetWindowRect -> GetClientRect. DDrPatch_NOOP((char*) OniExe + 0x0002651c, 6); DDrPatch_MakeCall((char*) OniExe + 0x0002651c, (void*) GetClientRect); // LIrPlatform_PollInputForAction: fix GetCursorPos call to return client coordinates. DDrPatch_NOOP((char*) OniExe + 0x000032cc, 6); DDrPatch_MakeCall((char*) OniExe + 0x000032cc, (void*) DD_GetCursorPos); // LIrPlatform_InputEvent_GetMouse: fix GetCursorPos call to return client coordinates. DDrPatch_NOOP((char*) OniExe + 0x00002cc2, 6); DDrPatch_MakeCall((char*) OniExe + 0x00002cc2, (void*) DD_GetCursorPos); // LIrPlatform_PollInputForAction: translate SetCursorPos position to screen coordinates. DDrPatch_NOOP((char*) OniExe + 0x000032b7, 6); DDrPatch_MakeCall((char*) OniExe + 0x000032b7, (void*) DD_SetCursorPos); // LIrPlatform_PollInputForAction: translate SetCursorPos position to screen coordinates. DDrPatch_NOOP((char*) OniExe + 0x00003349, 6); DDrPatch_MakeCall((char*) OniExe + 0x00003349, (void*) DD_SetCursorPos); // Replace ONrPlatformInitialize. DDrPatch_MakeJump((void*) ONrPlatform_Initialize, (void*) DD_ONrPlatform_Initialize); // Replace gl_platform_initialize. DDrPatch_MakeJump((void*) gl_platform_initialize, (void*) DD_GLrPlatform_Initialize); // Replace gl_platform_dispose. DDrPatch_MakeJump((void *) gl_platform_dispose, (void*) DD_GLrPlatform_Dispose); } if (patch_clipcursor) { // LIrMode_Set: replace LIrPlatform_Mode_Set call with our hook. DDrPatch_MakeCall((void*)(OniExe + 0x00003f9f), (void*) DD_LIrPlatform_Mode_Set); // LIrMode_Set_Internal: replace LIrPlatform_Mode_Set call with our hook. DDrPatch_MakeCall((void*)(OniExe + 0x00003fff), (void*) DD_LIrPlatform_Mode_Set); // LIrTermiante: replace LIrPlatform_Terminate call with our hook. DDrPatch_MakeCall((void*)(OniExe + 0x000004cb8), (void*) DD_LIrPlatform_Terminate); } if (patch_daodaninit) DDrPatch_MakeCall((void*)(OniExe + 0x000d345a), (void*)DDrGame_Init); // Patches for existing BSL functions if (patch_bsl) SLrDaodan_Patch(); if (patch_cheater) { DDrPatch_MakeCall((void*)(OniExe + 0x000f618f), (void*)DDrCheater); DDrPatch_Int16((short*)(OniExe + 0x000deb45), 0x5590); #if 1 DDrPatch_MakeCall((void*)(OniExe + 0x000deb47), (void*)FallingFrames); #endif DDrPatch_MakeJump((void*)(OniExe + 0x0010f021), (void*)DDrCheater_LevelLoad); } DDrPatch_MakeJump((void*)(OniExe + 0x000245A0), (void*)DDrPrintWarning); 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*)(OniExe + 0x0011acd0) == 0x09d36852) DDrPatch_MakeCall((void*)(OniExe + 0x0010fb49), (void*)DDrMain); else ExitProcess(0); break; } return TRUE; }