source: Daodan/src/Daodan.c@ 838

Last change on this file since 838 was 838, checked in by alloc, 12 years ago

Daodan:

  • Fixes #40
  • Moved configuration parsing (ini, command line) into its own file
File size: 16.5 KB
Line 
1#include <windows.h>
2#include <string.h>
3#include <stdio.h>
4
5#include "Daodan.h"
6#include "Daodan_Patch.h"
7#include "Daodan_Utility.h"
8#include "Daodan_Win32.h"
9#include "Daodan_Cheater.h"
10#include "Daodan_Persistence.h"
11#include "Daodan_BSL.h"
12#include "Daodan_Console.h"
13#include "Daodan_Config.h"
14
15#include "Oni.h"
16
17#include "Oni_GL.h"
18#include "Daodan_GL.h"
19
20HMODULE DDrDLLModule;
21HMODULE DDrONiModule;
22
23typedef int (__cdecl *CHINESEPROC)(DWORD ThreadId);
24
25// Hooked WMrSlider_SetRange() in ONiOGU_Options_InitDialog. Disables a gamma
26// slider in windowed mode.
27static void ONICALL DD_ONiOGU_GammaSlider_SetRange(WMtWindow* window, int min_value, int max_value)
28{
29 WMrWindow_SetEnabled(window, M3gResolutionSwitch && opt_gamma);
30 WMrSlider_SetRange(window, min_value, max_value);
31}
32
33void ONICALL DDrShowResumeButton(WMtWindow* window, int visibility)
34{
35 if (visibility)
36 WMrWindow_SetLocation(window, 150, 350);
37 WMrWindow_SetVisible(window, visibility);
38}
39
40
41/* Options always visible patch */
42void ONICALL DDrShowOptionsButton(WMtWindow* window, int visibility)
43{
44 WMrWindow_SetVisible(window, 1);
45}
46
47void ONICALL DDrGame_Init()
48{
49 if (opt_usedaodanbsl)
50 SLrDaodan_Initialize();
51}
52
53
54//this was broken
55FILE** _UUgError_WarningFile = (FILE**)0x005711B4;
56FILE *__fastcall DDrPrintWarning(int filename, int linenumber, unsigned __int16 errornum, int message)
57{
58
59 FILE *v4; // eax@1
60 FILE *result; // eax@4
61 char v6[512]; // [sp+0h] [bp-100h]@1
62 FILE* UUgError_WarningFile = *_UUgError_WarningFile;
63
64 if (filename && message && (strlen((const char*)filename)+strlen((const char*)message))<420) {
65 sprintf(
66 v6,
67 "Error %x reported from File: %s, Line: %d (message follows) \r\n%s",
68 errornum,
69 (const char*)filename,
70 linenumber,
71 (const char*)message);
72
73 if ( UUgError_WarningFile
74 || (UUgError_WarningFile = oni_fopen("debugger.txt", "wb"), UUgError_WarningFile ) )
75 {
76 oni_fprintf(UUgError_WarningFile, "%s\r\n", v6);
77 oni_fflush(UUgError_WarningFile);
78 }
79 }
80 //oni_fprintf(stdout, v6);
81 //sprintf(&v6, "%s", message);
82 *_UUgError_WarningFile = UUgError_WarningFile;
83 result = UUgError_WarningFile;
84 return result;
85}
86
87
88bool DDrPatch_Init()
89{
90 DDrStartupMessage("Daodan: Patching engine");
91
92 // Font texture cache doubled
93 if (patch_fonttexturecache)
94 {
95 DDrPatch_Byte((char*)(OniExe + 0x00020ea7), 0x20);
96 DDrPatch_Byte((char*)(OniExe + 0x00020f4a), 0x40);
97 }
98
99 // Now supports textures up to 512x512
100 if (patch_largetextures)
101 DDrPatch_Byte ((char*)(OniExe + 0x00005251), 0x10);
102
103 // Non-"_Final" levels are now valid
104 if (patch_levelplugins)
105 DDrPatch_Byte ((char*)(OniExe + 0x000206a8), 0x01);
106
107 // Pathfinding grid cache size x8
108 if (patch_pathfinding)
109 {
110 const unsigned char pathfinding[2] = {0x90 , 0xE9 };
111 DDrPatch_Byte ((char*)(OniExe + 0x0010b03b), 0x20);
112 DDrPatch_Byte ((char*)(OniExe + 0x0010b04c), 0x20);
113
114 //other stuff
115 DDrPatch_Const((char*)(OniExe + 0x00040789), pathfinding);
116 }
117
118 // Projectile awareness fixed
119 if (patch_projaware)
120 {
121 DDrPatch_Byte ((char*)(OniExe + 0x0009c07c), 0x6c);
122 DDrPatch_Byte ((char*)(OniExe + 0x0009c080), 0x70);
123 DDrPatch_Byte ((char*)(OniExe + 0x0009c084), 0x74);
124 DDrPatch_Byte ((char*)(OniExe + 0x0009c110), 0x6c);
125 }
126
127 // Forced DirectInput (for Windows NT)
128 if (patch_directinput)
129 DDrPatch_Byte((char*)(OniExe + 0x00002e6d), 0xeb);
130
131 if (patch_wpfadetime)
132 {
133 // Makes wp_fadetime actually have a function
134 const unsigned char fadetime_patch[] = { 0x66, 0x8B, 0x1D, 0xC4, 0x7D, 0x62, 0x00, 0x66, 0x89, 0x5E, 0x46, 0x5B, 0x5E, 0x83, 0xC4, 0x14, 0xC3 };
135 DDrPatch_Const ((char*)(OniExe + 0x0011a889), fadetime_patch);
136 DDrPatch_Byte ((char*)(OniExe + 0x0011a560), 0x31);
137
138 // Sets the fadetime to 4800 by default
139 DDrPatch_Int16 ((short*)(OniExe + 0x0011ab0e), 0x12c0);
140 }
141
142 // FIXME: add switches
143 //pathfinding fix
144
145
146
147
148 // Hackish fix for Konoko not kicking guns
149 // Don't use this, it breaks stairs.
150 if (patch_kickguns)
151 {
152 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 };
153 DDrPatch_Const ((char*)(OniExe + 0x000dc420), kickgun_patch);
154 }
155
156 // Cooldown timer exploit fix ^_^
157 if (patch_cooldowntimer)
158 {
159 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 };
160 DDrPatch_Const ((char*)(OniExe + 0x0011a825), cooldown_patch);
161 }
162
163 if (patch_throwtest)
164 {
165 const unsigned char throwtest_patch[] = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 };
166 DDrPatch_Const((char*)(OniExe + 0x000dc190), throwtest_patch);
167 }
168
169 // 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.
170 if (patch_alttab)
171 {
172 // 0xC3 = ret, so makes those functions just have a "ret" instruction at their start
173 DDrPatch_Byte ((char*)UUrPlatform_Initialize, 0xC3);
174 DDrPatch_Byte ((char*)UUrPlatform_Terminate, 0xC3);
175 }
176
177 // 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.)
178 if (patch_particledisablebit)
179 DDrPatch_Int16 ((short*)(OniExe + 0x001b184), 0x9090);
180
181 // Multi-byte patch (multiple language support)
182 if (!patch_multibyte)
183 {
184 DDrPatch_Byte ((char*)(OniExe + 0x0002d8f8), 0xeb);
185 DDrPatch_Byte ((char*)(OniExe + 0x0002d9ad), 0xeb);
186 DDrPatch_Byte ((char*)(OniExe + 0x0002dbe2), 0xeb);
187 DDrPatch_Byte ((char*)(OniExe + 0x0002dec3), 0xeb);
188 DDrPatch_Byte ((char*)(OniExe + 0x0002e2ab), 0xeb);
189 DDrPatch_Byte ((char*)(OniExe + 0x0002e2c4), 0xeb);
190 DDrPatch_Byte ((char*)(OniExe + 0x0002e379), 0xeb);
191 DDrPatch_Byte ((char*)(OniExe + 0x0002e48c), 0xeb);
192 DDrPatch_Byte ((char*)(OniExe + 0x0002e4d0), 0xeb);
193 DDrPatch_Byte ((char*)(OniExe + 0x0002e4f4), 0xeb);
194 DDrPatch_Byte ((char*)(OniExe + 0x0002e646), 0xeb);
195 DDrPatch_Byte ((char*)(OniExe + 0x0002e695), 0xeb);
196 DDrPatch_Byte ((char*)(OniExe + 0x0002e944), 0xeb);
197 DDrPatch_Byte ((char*)(OniExe + 0x0002e95d), 0xeb);
198 DDrPatch_Byte ((char*)(OniExe + 0x0002e98e), 0xeb);
199 DDrPatch_Byte ((char*)(OniExe + 0x0002e9dc), 0xeb);
200 }
201
202 // Cheat table patch
203 if (patch_cheattable)
204 {
205 DDrPatch_Int32 ((int*)(OniExe + 0x000f616b), (int)&DDr_CheatTable[0].name);
206 DDrPatch_Int32 ((int*)(OniExe + 0x000f617a), (int)&DDr_CheatTable[0].message_on);
207 }
208
209 // ARGB8888 textures
210 if (patch_argb8888)
211 {
212 DDrPatch_Byte ((char*)(OniExe + 0x00135af0), 0x07);
213 DDrPatch_Byte ((char*)(OniExe + 0x00135af4), 0x0B);
214 }
215
216 //Test newweap patch
217 if (patch_newweapon) {
218
219 //Makes it always say "Received weapon_name."
220 //Needs check for loc_4DFC66
221 //DDrPatch_NOOP((char*)(OniExe + 0x000E4DF8),2);
222
223 //Adds Weapon name and ammo meter to pickup autoprompt
224 DDrPatch_NOOP((char*)(OniExe + 0x000FAC73), 9);
225 DDrPatch_NOOP((char*)(OniExe + 0x000FAC80), 5);
226 DDrPatch_MakeCall((void*)(OniExe + 0xFAC85), (void*)DDrWeapon2Message);
227
228 //Moves location of colors
229 //DDrPatch_Int32((int*)(OniExe + 0x0002E3D5), (int)&DDrDSayColors );
230 //DDrPatch_Int32((int*)(OniExe + 0x0002E3DA), (int)&DDrDSayColors );
231 }
232
233 // Disable loading the vtuneapi.dll
234 //if (patch_killvtune)
235 //DDrPatch_Byte ((char*)(OniExe + 0x00026340), 0xC3);
236
237 // Disable Oni's internal CLrGetCommandLine function (to eventually replace it with our own)
238 if (patch_getcmdline)
239 DDrPatch_NOOP ((char*)(OniExe + 0x000d3280), 51);
240
241 // Disable Oni's command line parser so it doesn't interfere with ours
242 if (patch_disablecmdline)
243 DDrPatch_Int32 ((int*)(OniExe + 0x000d3570), 0xc3c03366);
244
245 if (patch_bsl)
246 {
247 //Calculating the value of the needed offset is much more reliable when the compiler does it for you.
248
249 //TODO: fix moonshadow.
250 Character * Chr = 0;
251 int NoPath = (int)&(Chr[0].RegenHax) & 0x000000FF;
252 const unsigned char regen_patch[] =
253 {0x90, 0x90, 0x90, 0x90, 0x90, // mov al, _WPgRegenerationCheat -> NOOP
254 0x90, 0x90, // test al, al -> NOOP
255 0x90, 0x90, // jz short loc_51BB98 -> NOOP
256 0x8B, 0x86, (char)NoPath, 0x01, 0x00, 0x00, // mov eax, [esi+Character.field_1E8]
257 // -> mov eax, [esi+Character.RegenHax]
258 0x85, 0xC0, // test eax, eax
259 0x74, 0x21 // jnz 0x21 -> jz 0x21
260 };
261 DDrPatch_Const((char*)(OniExe + 0x0011BB64), regen_patch);
262 }
263
264 if(patch_chinese)
265 {
266 if (GetFileAttributes("xfhsm_oni.dll") != INVALID_FILE_ATTRIBUTES)
267 {
268 HMODULE dll;
269 DWORD err;
270
271 DDrStartupMessage("Daodan: Loading chinese DLL");
272 dll = LoadLibrary("xfhsm_oni.dll");
273 err = GetLastError();
274 if( dll )
275 {
276 void* proc = GetProcAddress( dll, "InstallHook" );
277 if(proc)
278 {
279 ((CHINESEPROC)proc)(GetCurrentThreadId());
280 }
281 } else {
282 char msg[100];
283 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, msg, 100, NULL);
284 DDrStartupMessage("Daodan: Loading DLL failed with error %i: %s", err, msg);
285 }
286 }
287 }
288
289 //Fix crappy ai2_shownames
290 if(1)
291 {
292 //Set distance above head to 4.0
293 DDrPatch_Int32((int*)(OniExe + 0x0008C998), 0x005296C8);
294 //texture height
295 DDrPatch_Byte((char*)(OniExe + 0x0008C9DF), 0x3F );
296 //texture width
297 DDrPatch_NOOP((char*)(OniExe + 0x0008C9CA), 6 );
298 //Set the text color to whatever we like ;)
299 DDrPatch_NOOP((char*)(OniExe + 0x0008C898), 6 );
300 DDrPatch_Byte((char*)(OniExe + 0x0008C898), 0x8B );
301 DDrPatch_Byte((char*)(OniExe + 0x0008C899), 0xCE );
302//FLATLINE? DDrPatch_MakeCall((void*)(OniExe + 0x0008C8A3), FLrHook_DebugNameShadeHack);
303
304 //Make the background black for additive blending
305//FLATLINE? DDrPatch_MakeCall((void*)(OniExe + 0x0008C802), FLrHook_DebugNameTextureInit );
306 }
307
308 if(1)
309 {
310 //DDrPatch_NOOP((char*)(OniExe + 0x000E1957), 6 );
311 //DDrPatch_MakeCall((void*)(OniExe + 0x000E17F6), FLrHook_Lasers );
312 }
313
314 //Flatline related stuff
315// DDrPatch_MakeCall((void*)(OniExe + 0x000FBCEA), DDrText_Hook);
316
317//FLATLINE? DDrPatch_Int32((int*)(OniExe + 0x000B24D2), FLrSpawnHack);
318
319//FLATLINE? DDrPatch_NOOP((char*)(OniExe + 0x000C26CB), 6);
320
321//FLATLINE? DDrPatch_MakeCall((void*)(OniExe + 0x000C26CB), FLrHook_DoorOpen);
322//FLATLINE? DDrPatch_MakeCall((void*)(OniExe + 0x000EE3CF), FLrHook_ConsoleActivate);
323
324
325 // Fix options not visible in main menu when a game was started
326 if(patch_optionsvisible)
327 {
328 DDrPatch_MakeCall((void*)(OniExe + 0x000d2d2d), DDrShowOptionsButton);
329 DDrPatch_MakeCall((void*)(OniExe + 0x000d2d43), DDrShowResumeButton);
330 }
331
332 // Fix BinkBufferInit() call in BKrMovie_Play() to use GDI (DIB) blitting
333 // instead of DirectDraw; patch ONiRunGame to use the same method to play
334 // outro (ie., BKrMovie_Play() instead of ONrMovie_Play_Hardware() as the
335 // latter has problems on WINE).
336 if (patch_binkplay)
337 {
338 // push BINKBUFFERAUTO -> push BINKBUFFERDIBSECTION.
339 DDrPatch_Byte((void*)(OniExe + 0x0008829b + 1), 0x02);
340 // call ONrMovie_Play_Hardware -> call ONrMovie_Play
341 DDrPatch_MakeCall((void*)(OniExe + 0x000d496f), ONrMovie_Play);
342 }
343
344 // Patch a gamma slider in Options dialog (unconditionally).
345 // ONiOGU_Options_InitDialog: replace WMrSlider_SetRange(gammaSliderWindow, ...)
346 // call with our hook function.
347 DDrPatch_MakeCall((void*)(OniExe + 0x000d262c), (void*)DD_ONiOGU_GammaSlider_SetRange);
348
349 // Safe startup message printer
350 if (patch_safeprintf)
351 DDrPatch_MakeJump((void*)UUrStartupMessage, (void*)DDrStartupMessage);
352
353 // Daodan device mode enumeration function
354 if (patch_daodandisplayenum)
355 DDrPatch_MakeJump((void*)gl_enumerate_valid_display_modes, (void*)DD_GLrEnumerateDisplayModes);
356
357 // Performance patch
358 if (patch_usegettickcount)
359 {
360 DDrPatch_MakeJump((void*)UUrMachineTime_High, (void*)DDrMachineTime_High);
361 DDrPatch_MakeJump((void*)UUrMachineTime_High_Frequency, (void*)DDrMachineTime_High_Frequency);
362 DDrPatch_MakeJump((void*)UUrMachineTime_Sixtieths, (void*)DDrMachineTime_Sixtieths);
363 }
364
365 // Cheats always enabled
366 if (patch_cheatsenabled)
367 DDrPatch_MakeJump((void*)ONrPersist_GetWonGame, (void*)DDrPersist_GetWonGame);
368
369 // DaodanGL with windowed mode support.
370 if (patch_usedaodangl)
371 {
372 // LIrPlatform_Mode_Set: GetWindowRect -> GetClientRect.
373 DDrPatch_NOOP((char*) OniExe + 0x00002dd6, 6);
374 DDrPatch_MakeCall((char*) OniExe + 0x00002dd6, (void*) GetClientRect);
375
376 // UUrWindow_GetSize: GetWindowRect -> GetClientRect.
377 DDrPatch_NOOP((char*) OniExe + 0x0002651c, 6);
378 DDrPatch_MakeCall((char*) OniExe + 0x0002651c, (void*) GetClientRect);
379
380 // LIrPlatform_PollInputForAction: fix GetCursorPos call to return client coordinates.
381 DDrPatch_NOOP((char*) OniExe + 0x000032cc, 6);
382 DDrPatch_MakeCall((char*) OniExe + 0x000032cc, (void*) DD_GetCursorPos);
383
384 // LIrPlatform_InputEvent_GetMouse: fix GetCursorPos call to return client coordinates.
385 DDrPatch_NOOP((char*) OniExe + 0x00002cc2, 6);
386 DDrPatch_MakeCall((char*) OniExe + 0x00002cc2, (void*) DD_GetCursorPos);
387
388 // LIrPlatform_PollInputForAction: translate SetCursorPos position to screen coordinates.
389 DDrPatch_NOOP((char*) OniExe + 0x000032b7, 6);
390 DDrPatch_MakeCall((char*) OniExe + 0x000032b7, (void*) DD_SetCursorPos);
391
392 // LIrPlatform_PollInputForAction: translate SetCursorPos position to screen coordinates.
393 DDrPatch_NOOP((char*) OniExe + 0x00003349, 6);
394 DDrPatch_MakeCall((char*) OniExe + 0x00003349, (void*) DD_SetCursorPos);
395
396 // Replace ONrPlatformInitialize.
397 DDrPatch_MakeJump((void*) ONrPlatform_Initialize, (void*) DD_ONrPlatform_Initialize);
398
399 // Replace gl_platform_initialize.
400 DDrPatch_MakeJump((void*) gl_platform_initialize, (void*) DD_GLrPlatform_Initialize);
401
402 // Replace gl_platform_dispose.
403 DDrPatch_MakeJump((void *) gl_platform_dispose, (void*) DD_GLrPlatform_Dispose);
404 }
405
406 if (patch_clipcursor)
407 {
408 // LIrMode_Set: replace LIrPlatform_Mode_Set call with our hook.
409 DDrPatch_MakeCall((void*)(OniExe + 0x00003f9f), (void*) DD_LIrPlatform_Mode_Set);
410
411 // LIrMode_Set_Internal: replace LIrPlatform_Mode_Set call with our hook.
412 DDrPatch_MakeCall((void*)(OniExe + 0x00003fff), (void*) DD_LIrPlatform_Mode_Set);
413
414 // LIrTermiante: replace LIrPlatform_Terminate call with our hook.
415 DDrPatch_MakeCall((void*)(OniExe + 0x000004cb8), (void*) DD_LIrPlatform_Terminate);
416 }
417
418
419 if (patch_daodaninit)
420 DDrPatch_MakeCall((void*)(OniExe + 0x000d345a), (void*)DDrGame_Init);
421
422 // Patches for existing BSL functions
423 if (patch_bsl)
424 SLrDaodan_Patch();
425
426 if (patch_cheater)
427 {
428 DDrPatch_MakeCall((void*)(OniExe + 0x000f618f), (void*)DDrCheater);
429 DDrPatch_Int16((short*)(OniExe + 0x000deb45), 0x5590);
430#if 1
431 DDrPatch_MakeCall((void*)(OniExe + 0x000deb47), (void*)FallingFrames);
432#endif
433 DDrPatch_MakeJump((void*)(OniExe + 0x0010f021), (void*)DDrCheater_LevelLoad);
434 }
435
436 DDrPatch_MakeJump((void*)(OniExe + 0x000245A0), (void*)DDrPrintWarning);
437
438
439 return true;
440}
441
442
443void DDrException() {
444 int* i = 0;
445 *i = 1;
446}
447
448void __cdecl DDrMain(int argc, char* argv[])
449{
450 DDrStartupMessage("Daodan: Daodan attached!");
451
452 // Tell Oni to not load non levelX_final-files by default:
453 opt_ignore_private_data = false;
454
455 // Enable sound by default:
456 opt_sound = true;
457
458 DDrConfig(argc, argv);
459
460 DDrPatch_Init();
461
462
463 ONiMain(argc, argv);
464}
465/*
466void DDrWrongExe()
467{
468 switch (MessageBox(NULL, "This version of the Daodan DLL is incompatible with your Oni.exe.\n"
469 "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))
470 {
471 case IDOK:
472 {
473 STARTUPINFO si;
474 PROCESS_INFORMATION pi;
475 FillMemory(&si, 0, sizeof(si));
476 FillMemory(&pi, 0, sizeof(pi));
477 si.cb = sizeof(si);
478 if (!CreateProcess(NULL, "cmd /c \"start http://wiki.oni2.net/Daodan_DLL\"", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
479 MessageBox(NULL, "", "", 0);
480 CloseHandle(pi.hProcess);
481 CloseHandle(pi.hThread);
482 }
483 default:
484 ExitProcess(0);
485 }
486}
487*/
488BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
489{
490 switch (fdwReason)
491 {
492 case DLL_PROCESS_ATTACH:
493 DDrDLLModule = hinstDLL;
494 DDrONiModule = GetModuleHandle(NULL);
495
496 if (*(uint32_t*)(OniExe + 0x0011acd0) == 0x09d36852)
497 DDrPatch_MakeCall((void*)(OniExe + 0x0010fb49), (void*)DDrMain);
498 else
499 ExitProcess(0);
500 break;
501 }
502 return TRUE;
503}
Note: See TracBrowser for help on using the repository browser.