Subversion Repositories Games.Carmageddon

Rev

Rev 18 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #include "brender/brender.h"
  2. #include "car.h"
  3. #include "dinput.h"
  4. #include "errors.h"
  5. #include "globvars.h"
  6. #include "grafdata.h"
  7. #include "graphics.h"
  8. #include "harness/config.h"
  9. #include "harness/hooks.h"
  10. #include "harness/os.h"
  11. #include "harness/trace.h"
  12. #include "input.h"
  13. #include "loadsave.h"
  14. #include "main.h"
  15. #include "pd/sys.h"
  16. #include "sound.h"
  17. #include "ssdx.h"
  18. #include "utility.h"
  19. #include <errno.h>
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <sys/stat.h>
  23. #include <time.h>
  24.  
  25. #include "harness/win95_polyfill.h"
  26.  
  27. #define GFX_INIT_STRING_32X20X8 "320x200 init string"
  28. #define GFX_INIT_STRING_64X48X8 "640x480 init string"
  29.  
  30. #define KEYDOWN(var, key) (var[key] & 0x80)
  31.  
  32. int gExtra_mem;
  33. int gReplay_override;
  34. tGraf_spec gGraf_specs[2] = {
  35.     { 8, 1, 0, 320, 200, 0, 0, "32X20X8", GFX_INIT_STRING_32X20X8, 320, 320, 200, NULL },
  36.     { 8, 1, 0, 640, 480, 0, 0, "64X48X8", GFX_INIT_STRING_64X48X8, 640, 480, 480, NULL } // Pierre-Marie Baty -- fixed yres
  37. };
  38. int gASCII_table[128];
  39. tU32 gKeyboard_bits[8];
  40. int gASCII_shift_table[128];
  41. char gNetwork_profile_fname[256];
  42. tS32 gJoystick_min1y;
  43. tS32 gJoystick_min2y;
  44. tS32 gJoystick_min2x;
  45. tS32 gRaw_joystick2y;
  46. tS32 gRaw_joystick2x;
  47. tS32 gRaw_joystick1y;
  48. tS32 gRaw_joystick1x;
  49. tS32 gJoystick_range2y;
  50. tS32 gJoystick_range2x;
  51. tS32 gJoystick_range1y;
  52. tS32 gJoystick_range1x;
  53. int gNo_voodoo;
  54. int gSwitched_resolution;
  55. br_pixelmap* gReal_back_screen;
  56. tS32 gJoystick_min1x;
  57. br_pixelmap* gTemp_screen;
  58. int gGfx_initialized; // maybe renamed here
  59. tU32 gUpper_loop_limit;
  60. int gReal_back_screen_locked;
  61. tU32 gScan_code[123]; // was tU8 [123][2] in symbol dump
  62.  
  63. // Added by dethrace. Windows-specific. Original variable names unknown.
  64. int gWin32_fatal_error_exit_code;
  65. int gWin32_show_fatal_error_message;
  66. char gWin32_fatal_error_message[512];
  67. int gWin32_action_replay_buffer_allocated;
  68. void* gWin32_action_replay_buffer;
  69. int gWin32_action_replay_buffer_size;
  70. void* gWin32_hwnd;
  71. int gWin32_lbutton_down;
  72. int gWin32_rbutton_down;
  73. PALETTEENTRY_ gWin32_palette[256];
  74. br_diaghandler gWin32_br_diaghandler;
  75. int gWin32_window_has_focus = 1;
  76. int gNetwork_profile_file_exists = 0;
  77.  
  78. char* _unittest_last_fatal_error;
  79.  
  80. int original_main(int pArgc, char** pArgv);
  81.  
  82. /*static*/ void KeyboardHandler(void);
  83. /*static*/ int KeyDown(tU8 pScan_code);
  84. /*static*/ void KeyTranslation(tU8 pKey_index, tU8 pScan_code_1, tU8 pScan_code_2);
  85. /*static*/ void KeyBegin(void);
  86. /*static*/ void KeyEnd(void);
  87. /*static*/ int KeyDown22(int pKey_index);
  88. static void Win32ReleaseInputDevice(void);
  89. static void Win32PumpMessages(void);
  90. static HARNESS_NORETURN void Win32FatalError(char* pStr_1, char* pStr_2);
  91. static void Win32CreateWindow(void);
  92. static void Win32InitScreen(void);
  93. /*static*/ void Copy8BitTo16BitPixelmap(br_pixelmap* pDst, br_pixelmap* pSrc, br_pixelmap* pPalette);
  94. /*static*/ void SwapBackScreen(void);
  95. /*static*/ void ReallyCopyBackScreen(int pRendering_area_only, int pClear_top_and_bottom);
  96. /*static*/ void CopyBackScreen(int pRendering_area_only);
  97. static void Win32SetPaletteEntries(uint8_t* entries, int pFirst_colour, int pCount);
  98. static void Win32InitInputDevice(void);
  99. static void Win32AllocateActionReplayBuffer(void);
  100. static void Usage(char* pProgpath);
  101. /*static*/ int OurGetChar(void);
  102. /*static*/ int InitJoysticks(void);
  103. /*static*/ tU32 ReadJoystickAxis(int pBit);
  104. static void Win32BRenderWarningFunc(char* msg);
  105. static void Win32BRenderFailureFunc(char* msg);
  106.  
  107. extern void QuitGame(void);
  108.  
  109. void KeyboardHandler(void) {
  110.     //tU8 scan_code; // Pierre-Marie Baty -- unused variable
  111.     //tU8 up; // Pierre-Marie Baty -- unused variable
  112.     //static tU8 extended; // Pierre-Marie Baty -- unused variable
  113.     LOG_TRACE("()");
  114.     NOT_IMPLEMENTED();
  115. }
  116.  
  117. int KeyDown(tU8 pScan_code) {
  118.     NOT_IMPLEMENTED();
  119. }
  120.  
  121. void KeyTranslation(tU8 pKey_index, tU8 pScan_code_1, tU8 pScan_code_2) {
  122.     LOG_TRACE("(%d, %d, %d)", pKey_index, pScan_code_1, pScan_code_2);
  123.     NOT_IMPLEMENTED();
  124. }
  125.  
  126. void KeyBegin(void) {
  127.     gScan_code[KEY_0] = DIK_0;
  128.     gScan_code[KEY_1] = DIK_1;
  129.     gScan_code[KEY_2] = DIK_2;
  130.     gScan_code[KEY_3] = DIK_3;
  131.     gScan_code[KEY_4] = DIK_4;
  132.     gScan_code[KEY_5] = DIK_5;
  133.     gScan_code[KEY_6] = DIK_6;
  134.     gScan_code[KEY_7] = DIK_7;
  135.     gScan_code[KEY_8] = DIK_8;
  136.     gScan_code[KEY_9] = DIK_9;
  137.     gScan_code[KEY_A] = DIK_A;
  138.     gScan_code[KEY_B] = DIK_B;
  139.     gScan_code[KEY_C] = DIK_C;
  140.     gScan_code[KEY_D] = DIK_D;
  141.     gScan_code[KEY_E] = DIK_E;
  142.     gScan_code[KEY_F] = DIK_F;
  143.     gScan_code[KEY_G] = DIK_G;
  144.     gScan_code[KEY_H] = DIK_H;
  145.     gScan_code[KEY_I] = DIK_I;
  146.     gScan_code[KEY_J] = DIK_J;
  147.     gScan_code[KEY_K] = DIK_K;
  148.     gScan_code[KEY_L] = DIK_L;
  149.     gScan_code[KEY_M] = DIK_M;
  150.     gScan_code[KEY_N] = DIK_N;
  151.     gScan_code[KEY_O] = DIK_O;
  152.     gScan_code[KEY_P] = DIK_P;
  153.     gScan_code[KEY_Q] = DIK_Q;
  154.     gScan_code[KEY_R] = DIK_R;
  155.     gScan_code[KEY_S] = DIK_S;
  156.     gScan_code[KEY_T] = DIK_T;
  157.     gScan_code[KEY_U] = DIK_U;
  158.     gScan_code[KEY_V] = DIK_V;
  159.     gScan_code[KEY_W] = DIK_W;
  160.     gScan_code[KEY_X] = DIK_X;
  161.     gScan_code[KEY_Y] = DIK_Y;
  162.     gScan_code[KEY_Z] = DIK_Z;
  163.     gScan_code[KEY_GRAVE] = DIK_GRAVE;
  164.     gScan_code[KEY_MINUS] = DIK_MINUS;
  165.     gScan_code[KEY_EQUALS] = DIK_EQUALS;
  166.     gScan_code[KEY_BACKSPACE] = DIK_BACK;
  167.     gScan_code[KEY_RETURN] = DIK_RETURN;
  168.     gScan_code[KEY_KP_ENTER] = DIK_NUMPADENTER;
  169.     gScan_code[KEY_CAPSLOCK] = DIK_CAPSLOCK;
  170.     gScan_code[KEY_TAB] = DIK_TAB;
  171.     gScan_code[KEY_SLASH] = DIK_SLASH;
  172.     gScan_code[KEY_UNKNOWN_55] = 0;
  173.     gScan_code[KEY_SEMICOLON] = DIK_SEMICOLON;
  174.     gScan_code[KEY_APOSTROPHE] = DIK_APOSTROPHE;
  175.     gScan_code[KEY_PERIOD] = DIK_PERIOD;
  176.     gScan_code[KEY_COMMA] = DIK_COMMA;
  177.     gScan_code[KEY_LBRACKET] = DIK_LBRACKET;
  178.     gScan_code[KEY_RBRACKET] = DIK_RBRACKET;
  179.     gScan_code[KEY_ESCAPE] = DIK_ESCAPE;
  180.     gScan_code[KEY_INSERT] = DIK_INSERT;
  181.     gScan_code[KEY_DELETE] = DIK_DELETE;
  182.     gScan_code[KEY_HOME] = DIK_HOME;
  183.     gScan_code[KEY_END] = DIK_END;
  184.     gScan_code[KEY_PAGEUP] = DIK_PGUP;
  185.     gScan_code[KEY_PAGEDOWN] = DIK_PGDN;
  186.     gScan_code[KEY_LEFT] = DIK_LEFT;
  187.     gScan_code[KEY_RIGHT] = DIK_RIGHT;
  188.     gScan_code[KEY_UP] = DIK_UP;
  189.     gScan_code[KEY_DOWN] = DIK_DOWN;
  190.     gScan_code[KEY_KP_NUMLOCK] = DIK_NUMLOCK;
  191.     gScan_code[KEY_KP_DIVIDE] = DIK_DIVIDE;
  192.     gScan_code[KEY_KP_MULTIPLY] = DIK_MULTIPLY;
  193.     gScan_code[KEY_KP_MINUS] = DIK_SUBTRACT;
  194.     gScan_code[KEY_KP_PLUS] = DIK_ADD;
  195.     gScan_code[KEY_KP_PERIOD] = DIK_DECIMAL;
  196.     gScan_code[KEY_KP_0] = DIK_NUMPAD0;
  197.     gScan_code[KEY_KP_1] = DIK_NUMPAD1;
  198.     gScan_code[KEY_KP_2] = DIK_NUMPAD2;
  199.     gScan_code[KEY_KP_3] = DIK_NUMPAD3;
  200.     gScan_code[KEY_KP_4] = DIK_NUMPAD4;
  201.     gScan_code[KEY_KP_5] = DIK_NUMPAD5;
  202.     gScan_code[KEY_KP_6] = DIK_NUMPAD6;
  203.     gScan_code[KEY_KP_7] = DIK_NUMPAD7;
  204.     gScan_code[KEY_KP_8] = DIK_NUMPAD8;
  205.     gScan_code[KEY_KP_9] = DIK_NUMPAD9;
  206.     gScan_code[KEY_F1] = DIK_F1;
  207.     gScan_code[KEY_F2] = DIK_F2;
  208.     gScan_code[KEY_F3] = DIK_F3;
  209.     gScan_code[KEY_F4] = DIK_F4;
  210.     gScan_code[KEY_F5] = DIK_F5;
  211.     gScan_code[KEY_F6] = DIK_F6;
  212.     gScan_code[KEY_F7] = DIK_F7;
  213.     gScan_code[KEY_F8] = DIK_F8;
  214.     gScan_code[KEY_F9] = DIK_F9;
  215.     gScan_code[KEY_F10] = DIK_F10;
  216.     gScan_code[KEY_F11] = DIK_F11;
  217.     gScan_code[KEY_F12] = DIK_F12;
  218.     gScan_code[KEY_PRTSCN] = DIK_SYSRQ;
  219.     gScan_code[KEY_SCRLK] = DIK_SCROLL;
  220.     gScan_code[KEY_SPACE] = DIK_SPACE;
  221.     gScan_code[KEY_RSHIFT] = DIK_RSHIFT;
  222.     gScan_code[KEY_RALT] = DIK_RALT;
  223.     gScan_code[KEY_RCTRL] = DIK_RCONTROL;
  224.     gScan_code[KEY_LSHIFT] = DIK_LSHIFT;
  225.     gScan_code[KEY_LALT] = DIK_LALT;
  226.     gScan_code[KEY_LCTRL] = DIK_LCONTROL;
  227.     gScan_code[KEY_KP_EQUALS] = 0;
  228.     gScan_code[KEY_BACKSLASH] = DIK_BACKSLASH;
  229.     gScan_code[KEY_CTRL_ANY_2] = 0xff;
  230.     gScan_code[KEY_PAUSE] = 0xff;
  231.     gScan_code[KEY_SHIFT_ANY] = 0xff;
  232.     gScan_code[KEY_ALT_ANY] = 0xff;
  233.     gScan_code[KEY_CTRL_ANY] = 0xff;
  234. }
  235.  
  236. void KeyEnd(void) {
  237.     LOG_TRACE("()");
  238.     NOT_IMPLEMENTED();
  239. }
  240.  
  241. int KeyDown22(int pKey_index) {
  242.     LOG_TRACE("(%d)", pKey_index);
  243.     NOT_IMPLEMENTED();
  244. }
  245.  
  246. void PDSetKeyArray(int* pKeys, int pMark) {
  247.     int i;
  248.     uint8_t keystate[256];
  249.     LOG_TRACE10("(%p, %d)", pKeys, pMark);
  250.  
  251.     gKeys_pressed = 0;
  252.     Win32PumpMessages();
  253.     DirectInputDevice_GetDeviceState(COUNT_OF(keystate), keystate);
  254.  
  255.     for (i = 0; i < COUNT_OF(gScan_code); i++) {
  256.         if (gScan_code[i] == 0) {
  257.             continue;
  258.         }
  259.         if (gScan_code[i] == 0xff) {
  260.             switch (i) {
  261.             case KEY_SHIFT_ANY:
  262.                 if (KEYDOWN(keystate, gScan_code[KEY_LSHIFT]) || KEYDOWN(keystate, gScan_code[KEY_RSHIFT])) {
  263.                     pKeys[KEY_SHIFT_ANY] = pMark;
  264.                 } else {
  265.                     if (pKeys[KEY_SHIFT_ANY] == pMark) {
  266.                         pKeys[KEY_SHIFT_ANY] = 0;
  267.                     }
  268.                 }
  269.                 break;
  270.             case KEY_ALT_ANY:
  271.                 if (KEYDOWN(keystate, gScan_code[KEY_LALT]) || KEYDOWN(keystate, gScan_code[KEY_RALT])) {
  272.                     pKeys[KEY_ALT_ANY] = pMark;
  273.                 } else {
  274.                     if (pKeys[KEY_ALT_ANY] == pMark) {
  275.                         pKeys[KEY_ALT_ANY] = 0;
  276.                     }
  277.                 }
  278.                 break;
  279.             case KEY_CTRL_ANY:
  280.             case KEY_CTRL_ANY_2:
  281.                 if (KEYDOWN(keystate, gScan_code[KEY_LCTRL]) || KEYDOWN(keystate, gScan_code[KEY_RCTRL])) {
  282.                     pKeys[KEY_CTRL_ANY] = pMark;
  283.                     pKeys[KEY_CTRL_ANY_2] = pMark;
  284.                 } else {
  285.                     if (pKeys[KEY_CTRL_ANY] == pMark || pKeys[KEY_CTRL_ANY_2] == pMark) {
  286.                         pKeys[KEY_CTRL_ANY] = 0;
  287.                         pKeys[KEY_CTRL_ANY_2] = 0;
  288.                     }
  289.                 }
  290.                 break;
  291.             default:
  292.                 continue;
  293.             }
  294.         } else if (KEYDOWN(keystate, gScan_code[i])) {
  295.             pKeys[i] = pMark;
  296.             gKeys_pressed = i + (gKeys_pressed << 8) + 1;
  297.         } else {
  298.             if (pKeys[i] == pMark) {
  299.                 pKeys[i] = 0;
  300.             }
  301.         }
  302.     }
  303. }
  304.  
  305. void Win32ReleaseInputDevice(void) {
  306. }
  307.  
  308. int PDGetASCIIFromKey(int pKey) {
  309.     LOG_TRACE("(%d)", pKey);
  310.  
  311.     /* The Windows Carmageddon executable uses PDKeyDown here. The German DOS executable uses PDKeyDown3. */
  312.     if (PDKeyDown3(KEY_SHIFT_ANY)) {
  313.         return gASCII_shift_table[pKey];
  314.     } else {
  315.         return gASCII_table[pKey];
  316.     }
  317. }
  318.  
  319. void Win32PumpMessages(void) {
  320.     MSG_ msg; // [esp+Ch] [ebp-20h] BYREF
  321.  
  322.     PDUnlockRealBackScreen();
  323.     while ((!gWin32_window_has_focus || PeekMessageA_(&msg, 0, 0, 0, 1u)) && (gWin32_window_has_focus || GetMessageA_(&msg, 0, 0, 0) != -1)) {
  324.         if (msg.message == WM_QUIT) {
  325.             dr_dprintf("WM_QUIT received.");
  326.             if (gWin32_window_has_focus) {
  327.                 dr_dprintf("Active, so lock the surface");
  328.                 PDLockRealBackScreen();
  329.                 dr_dprintf("QuitGame being called...");
  330.                 QuitGame();
  331.             }
  332.             PDShutdownSystem();
  333.         }
  334.         TranslateMessage_(&msg);
  335.         DispatchMessageA_(&msg);
  336.     }
  337.     PDLockRealBackScreen();
  338. }
  339.  
  340. void PDFatalError(char* pThe_str) {
  341.     LOG_TRACE("(\"%s\")", pThe_str);
  342.  
  343.     dr_dprintf("FATAL ERROR: %s", pThe_str);
  344.     Win32FatalError(pThe_str, "");
  345. }
  346.  
  347. void Win32FatalError(char* pStr_1, char* pStr_2) {
  348.     gWin32_show_fatal_error_message = 1;
  349.     sprintf(gWin32_fatal_error_message, "%s\n%s", pStr_1, pStr_2);
  350.     gWin32_fatal_error_exit_code = 15;
  351.     PDShutdownSystem();
  352. }
  353.  
  354. void PDNonFatalError(char* pThe_str) {
  355.     LOG_TRACE("(\"%s\")", pThe_str);
  356.     NOT_IMPLEMENTED();
  357. }
  358.  
  359. void PDInitialiseSystem(void) {
  360.     tPath_name the_path;
  361.     FILE* f;
  362.     int len;
  363.  
  364.     Win32AllocateActionReplayBuffer();
  365.     gBack_screen = NULL;
  366.     gScreen = NULL;
  367.     Win32CreateWindow();
  368.     ShowCursor_(0);
  369.     KeyBegin();
  370.  
  371.     PathCat(the_path, gApplication_path, "KEYBOARD.COK");
  372.     f = fopen(the_path, "rb");
  373.     if (f == NULL) {
  374.         if (harness_game_info.defines.requires_ascii_table) {
  375. #if !defined(DETHRACE_FIX_BUGS)
  376.             PDFatalError("This .exe must have KEYBOARD.COK in the DATA folder.");
  377. #endif
  378.         }
  379.         // dethrace: demos do not ship with KEYBOARD.COK file
  380.         memcpy(gASCII_table, harness_game_info.defines.ascii_table, sizeof(gASCII_table));
  381.         memcpy(gASCII_shift_table, harness_game_info.defines.ascii_shift_table, sizeof(gASCII_shift_table));
  382.     } else {
  383.         PathCat(the_path, gApplication_path, "KEYBOARD.COK");
  384.         f = fopen(the_path, "rb");
  385.         if (f == NULL) {
  386.             PDFatalError("This .exe must have KEYBOARD.COK in the DATA folder.");
  387.         }
  388.         fseek(f, 0, 2);
  389.         len = ftell(f) / 2;
  390.         rewind(f);
  391.         fread(gASCII_table, len, 1u, f);
  392.         fread(gASCII_shift_table, len, 1u, f);
  393.         fclose(f);
  394.     }
  395.     Win32InitInputDevice();
  396. }
  397.  
  398. void Win32CreateWindow(void) {
  399.     // wnd_class.style = 3;
  400.     // wnd_class.lpfnWndProc = window_proc;
  401.     // wnd_class.cbClsExtra = 0;
  402.     // wnd_class.cbWndExtra = 0;
  403.     // wnd_class.hInstance = gWin32_hinst;
  404.     // wnd_class.hIcon = LoadIconA(0, (LPCSTR)0x7F00);
  405.     // wnd_class.hCursor = LoadCursorA(0, (LPCSTR)0x7F00);
  406.     // wnd_class.hbrBackground = (HBRUSH)GetStockObject(4);
  407.     // wnd_class.lpszMenuName = 0;
  408.     // wnd_class.lpszClassName = "CarmageddonClass";
  409.     // LOWORD(v5) = RegisterClassA(&wnd_class);
  410.     // v5 = (unsigned __int16)v5;
  411.     // v2 = gWin32_hinst;
  412.  
  413.     // int height = GetSystemMetrics(SM_CYSCREEN);
  414.     // int width = GetSystemMetrics(SM_CXSCREEN);
  415.  
  416.     int width = gGraf_specs[gGraf_spec_index].total_width;
  417.     int height = gGraf_specs[gGraf_spec_index].total_height;
  418.     // WS_VISIBLE | WS_POPUP
  419.     gWin32_hwnd = CreateWindowExA_(0, "CarmageddonClass", "Carmageddon", 0x90000000, 0, 0, width, height, 0, NULL, NULL, NULL);
  420.     SSDXGetWindowRect(gWin32_hwnd);
  421.     // hdc = GetDC(gWin32_hwnd);
  422.     // GetSystemPaletteEntries(hdc, 0, 256u, &gWin32_palette);
  423.     // ReleaseDC(gWin32_hwnd, hdc);
  424.     // UpdateWindow(gWin32_hwnd);
  425.     // SetFocus(gWin32_hwnd);
  426. }
  427.  
  428. void PDShutdownSystem(void) {
  429.     static int been_here = 0;
  430.     LOG_TRACE("()");
  431.  
  432.     if (!been_here) {
  433.         been_here = 1;
  434.         dr_dprintf("PDShutdownSystem()...");
  435.         SSDXRelease();
  436.         Win32ReleaseInputDevice();
  437.         ShowCursor_(1);
  438.         if (gWin32_hwnd) {
  439.             dr_dprintf("Resizing main window...");
  440.             SetWindowPos_(gWin32_hwnd, 0, -100, -100, 64, 64, 0x414u);
  441.         }
  442.         dr_dprintf("Servicing messages...");
  443.         Win32PumpMessages();
  444.         dr_dprintf("Sending WM_SHOWWINDOW broadcast message...");
  445.         SendMessageA_(HWND_BROADCAST, 0x18u, 1u, 0);
  446.         if (gWin32_show_fatal_error_message) {
  447.             dr_dprintf("Displaying fatal error...");
  448.             MessageBoxA_(0, gWin32_fatal_error_message, "Carmageddon Fatal Error", MB_ICONERROR);
  449.         }
  450.         if (gWin32_hwnd) {
  451.             dr_dprintf("Destroying window...");
  452.             DestroyWindow_(gWin32_hwnd);
  453.             gWin32_hwnd = 0;
  454.         }
  455.         dr_dprintf("End of PDShutdownSystem().");
  456.         CloseDiagnostics();
  457.         ExitProcess_(gWin32_fatal_error_exit_code);
  458.     }
  459.     ExitProcess_(8u);
  460. }
  461.  
  462. void PDSaveOriginalPalette(void) {
  463.     LOG_TRACE("()");
  464.     NOT_IMPLEMENTED();
  465. }
  466.  
  467. void PDRevertPalette(void) {
  468.     LOG_TRACE("()");
  469.  
  470.     // empty function
  471. }
  472.  
  473. int PDInitScreenVars(int pArgc, char** pArgv) {
  474.     // this codes from dossys
  475.     gGraf_specs[gGraf_spec_index].phys_width = gGraf_specs[gGraf_spec_index].total_width;
  476.     gGraf_specs[gGraf_spec_index].phys_height = gGraf_specs[gGraf_spec_index].total_height;
  477.     return 1;
  478. }
  479.  
  480. void PDInitScreen(void) {
  481.     Win32InitScreen();
  482. }
  483.  
  484. void Win32InitScreen(void) {
  485.     // SWP_NOSENDCHANGING | SWP_NOACTIVATE | SWP_NOZORDER
  486.     SetWindowPos_(gWin32_hwnd, 0, 0, 0, gGraf_specs[gReal_graf_data_index].total_width, gGraf_specs[gReal_graf_data_index].total_height, 0x414u);
  487.     // get_window_rect(gWin32_hwnd);
  488.     Win32PumpMessages();
  489. }
  490.  
  491. void PDLockRealBackScreen(void) {
  492.     LOG_TRACE("()");
  493.  
  494.     // no-op
  495. }
  496.  
  497. void PDUnlockRealBackScreen(void) {
  498.     LOG_TRACE("()");
  499.  
  500.     // no-op
  501. }
  502.  
  503. void PDAllocateScreenAndBack(void) {
  504.     // this is a mix of windows and dos code
  505.  
  506.     dr_dprintf("PDAllocateScreenAndBack() - START...");
  507.     BrMaterialFindHook(PDMissingMaterial);
  508.     BrTableFindHook(PDMissingTable);
  509.     BrModelFindHook(PDMissingModel);
  510.     BrMapFindHook(PDMissingMap);
  511.  
  512.     int row_bytes;
  513.     SSDXInitDirectDraw(gGraf_specs[gGraf_spec_index].total_width, gGraf_specs[gGraf_spec_index].total_height, &row_bytes);
  514.     gScreen = BrPixelmapAllocate(BR_PMT_INDEX_8, gGraf_specs[gGraf_spec_index].total_width, gGraf_specs[gGraf_spec_index].total_height, NULL, BR_PMAF_NORMAL);
  515.  
  516.     gScreen->origin_x = 0;
  517.     gGfx_initialized = 1;
  518.     gScreen->origin_y = 0;
  519.     gBack_screen = BrPixelmapMatch(gScreen, BR_PMMATCH_OFFSCREEN);
  520.     gBack_screen->origin_x = 0;
  521.     gBack_screen->origin_y = 0;
  522.     gTemp_screen = BrPixelmapMatch(gScreen, BR_PMMATCH_OFFSCREEN);
  523.     gTemp_screen->origin_x = 0;
  524.     gTemp_screen->origin_y = 0;
  525.     dr_dprintf("PDAllocateScreenAndBack() - END.");
  526.  
  527.     // dr_dprintf("PDAllocateScreenAndBack() - START...");
  528.     // BrMaterialFindHook(PDMissingMaterial);
  529.     // BrTableFindHook(PDMissingTable);
  530.     // BrModelFindHook(PDMissingModel);
  531.     // BrMapFindHook(PDMissingMap);
  532.     // dr_dprintf("Setting up DirectDraw stuff...");
  533.     // SSDXStart(gWin32_hwnd, 0, 1);
  534.     // dr_dprintf("Setting up DirectSound stuff...");
  535.     // int result = SSDXStart(gWin32_hwnd, 0, 2);
  536.     // int row_bytes;
  537.     // if (result == 0) {
  538.     //     result = SSDXInitDirectDraw(gGraf_specs[gGraf_spec_index].total_width, gGraf_specs[gGraf_spec_index].total_height, &row_bytes);
  539.     // }
  540.     // if (result) {
  541.     //     SSDXHandleError(result);
  542.     //     PDFatalError("Unable to setup DirectDraw - please check that DirectX is installed");
  543.     // }
  544.     // gGraf_specs[gGraf_spec_index].row_bytes = row_bytes;
  545.     // gGraf_specs[gGraf_spec_index].phys_width = gGraf_specs[gGraf_spec_index].row_bytes;
  546.     // gGraf_specs[gGraf_spec_index].phys_height = gGraf_specs[gGraf_spec_index].total_height;
  547.     // dr_dprintf(
  548.     //     "Graf spec info after screen allocation:\n"
  549.     //     "                 Total width:   %d\n"
  550.     //     "                 Total height:  %d\n"
  551.     //     "                 Phys width:    %d\n"
  552.     //     "                 Phys height:   %d\n"
  553.     //     "                 Row bytes:     %d\n",
  554.     //     gGraf_specs[gGraf_spec_index].total_width,
  555.     //     gGraf_specs[gGraf_spec_index].total_height,
  556.     //     gGraf_specs[gGraf_spec_index].phys_width,
  557.     //     gGraf_specs[gGraf_spec_index].phys_height,
  558.     //     gGraf_specs[gGraf_spec_index].row_bytes);
  559.     // dr_dprintf("First attempt at locking surface...");
  560.     // PDLockRealBackScreen();
  561.     // dr_dprintf("Done first surface lock; gOffscreen_pixels 0x%p", gOffscreen_pixels);
  562.     // gBack_screen = BrPixelmapAllocate(
  563.     //     3u,
  564.     //     gGraf_specs[gGraf_spec_index].phys_width,
  565.     //     gGraf_specs[gGraf_spec_index].phys_height,
  566.     //     gOffscreen_pixels,
  567.     //     0);
  568.     // gScreen = gBack_screen;
  569.     // gBack_screen->origin_x = 0;
  570.     // gBack_screen->origin_y = 0;
  571.     // gBack_screen->base_x = 0;
  572.     // gBack_screen->base_y = 0;
  573.     // gBack_screen->row_bytes = gGraf_specs[gGraf_spec_index].row_bytes;
  574.     // gTemp_screen = (br_pixelmap*)BrPixelmapMatch(gBack_screen, 0);
  575.     // gGfx_initialized = 1;
  576.     // memset(gBack_screen->pixels, 0, gBack_screen->row_bytes * gBack_screen->height);
  577.     // PDScreenBufferSwap(0);
  578.     // dr_dprintf("PDAllocateScreenAndBack() - END.");
  579. }
  580.  
  581. void Copy8BitTo16BitPixelmap(br_pixelmap* pDst, br_pixelmap* pSrc, br_pixelmap* pPalette) {
  582.     //int x; // Pierre-Marie Baty -- unused variable
  583.     //int y; // Pierre-Marie Baty -- unused variable
  584.     //tU8* src; // Pierre-Marie Baty -- unused variable
  585.     //tU8 value; // Pierre-Marie Baty -- unused variable
  586.     //tU8 red; // Pierre-Marie Baty -- unused variable
  587.     //tU8 green; // Pierre-Marie Baty -- unused variable
  588.     //tU8 blue; // Pierre-Marie Baty -- unused variable
  589.     //tU16* dst; // Pierre-Marie Baty -- unused variable
  590.     //tU16* palette_entry; // Pierre-Marie Baty -- unused variable
  591.     LOG_TRACE("(%p, %p, %p)", pDst, pSrc, pPalette);
  592.     NOT_IMPLEMENTED();
  593. }
  594.  
  595. void Double8BitTo16BitPixelmap(br_pixelmap* pDst, br_pixelmap* pSrc, br_pixelmap* pPalette, tU16 pOff, tU16 pSrc_width, tU16 pSrc_height) {
  596.     //int x; // Pierre-Marie Baty -- unused variable
  597.     //int y; // Pierre-Marie Baty -- unused variable
  598.     //tU8* src; // Pierre-Marie Baty -- unused variable
  599.     //tU8 value; // Pierre-Marie Baty -- unused variable
  600.     //tU8 red; // Pierre-Marie Baty -- unused variable
  601.     //tU8 green; // Pierre-Marie Baty -- unused variable
  602.     //tU8 blue; // Pierre-Marie Baty -- unused variable
  603.     //tU16* dst0; // Pierre-Marie Baty -- unused variable
  604.     //tU16* dst1; // Pierre-Marie Baty -- unused variable
  605.     //tU16 sixteen; // Pierre-Marie Baty -- unused variable
  606.     //tU16* palette_entry; // Pierre-Marie Baty -- unused variable
  607.     LOG_TRACE("(%p, %p, %p, %d, %d, %d)", pDst, pSrc, pPalette, pOff, pSrc_width, pSrc_height);
  608.     NOT_IMPLEMENTED();
  609. }
  610.  
  611. br_pixelmap* PDInterfacePixelmap(void) {
  612.     LOG_TRACE("()");
  613.     NOT_IMPLEMENTED();
  614. }
  615.  
  616. void SwapBackScreen(void) {
  617.     LOG_TRACE("()");
  618.     NOT_IMPLEMENTED();
  619. }
  620.  
  621. void ReallyCopyBackScreen(int pRendering_area_only, int pClear_top_and_bottom) {
  622.     LOG_TRACE("(%d, %d)", pRendering_area_only, pClear_top_and_bottom);
  623.     NOT_IMPLEMENTED();
  624. }
  625.  
  626. void CopyBackScreen(int pRendering_area_only) {
  627.     LOG_TRACE("(%d)", pRendering_area_only);
  628.     NOT_IMPLEMENTED();
  629. }
  630.  
  631. void PDScreenBufferSwap(int pRendering_area_only) {
  632.     // taken from dossys
  633.  
  634.     if (pRendering_area_only) {
  635.         BrPixelmapRectangleCopy(gScreen, gY_offset, gX_offset, gRender_screen, 0, 0, gWidth, gHeight);
  636.     } else {
  637.         if (gReal_graf_data_index == gGraf_data_index) {
  638.             BrPixelmapDoubleBuffer(gScreen, gBack_screen);
  639.         } else {
  640.             DRPixelmapDoubledCopy(gTemp_screen, gBack_screen, 320, 200, 0, 40);
  641.             BrPixelmapDoubleBuffer(gScreen, gTemp_screen);
  642.         }
  643.     }
  644. }
  645.  
  646. void PDPixelmapToScreenRectangleCopy(br_pixelmap* dst, br_int_16 dx, br_int_16 dy, br_pixelmap* src, br_int_16 sx, br_int_16 sy, br_uint_16 w, br_uint_16 h) {
  647.     LOG_TRACE("(%p, %d, %d, %p, %d, %d, %d, %d)", dst, dx, dy, src, sx, sy, w, h);
  648.     NOT_IMPLEMENTED();
  649. }
  650.  
  651. void PDPixelmapHLineOnScreen(br_pixelmap* dst, br_int_16 x1, br_int_16 y1, br_int_16 x2, br_int_16 y2, br_uint_32 colour) {
  652.     LOG_TRACE("(%p, %d, %d, %d, %d, %d)", dst, x1, y1, x2, y2, colour);
  653.     NOT_IMPLEMENTED();
  654. }
  655.  
  656. void PDPixelmapVLineOnScreen(br_pixelmap* dst, br_int_16 x1, br_int_16 y1, br_int_16 x2, br_int_16 y2, br_uint_32 colour) {
  657.     LOG_TRACE("(%p, %d, %d, %d, %d, %d)", dst, x1, y1, x2, y2, colour);
  658.     NOT_IMPLEMENTED();
  659. }
  660.  
  661. void PDInstallErrorHandlers(void) {
  662.     LOG_TRACE("()");
  663.  
  664.     gWin32_br_diaghandler.identifier = "LlantisilioBlahBlahBlahOgOgOch";
  665.     gWin32_br_diaghandler.warning = Win32BRenderWarningFunc;
  666.     gWin32_br_diaghandler.failure = Win32BRenderFailureFunc;
  667.     BrDiagHandlerSet(&gWin32_br_diaghandler);
  668. }
  669.  
  670. void PDSetFileVariables(void) {
  671.  
  672.     // Changed by dethrace for cross-platform
  673.     // strcpy(gDir_separator, "\\");
  674.     strcpy(gDir_separator, "/");
  675. }
  676.  
  677. void PDBuildAppPath(char* pThe_path) {
  678.     GetCurrentDirectoryA_(253, pThe_path);
  679.     // GetShortPathNameA(pThe_path, pThe_path, 253);
  680.     strcat(pThe_path, "/"); // original: strcat(pThe_path, "\\")
  681.     dr_dprintf("Application path '%s'", pThe_path);
  682. }
  683.  
  684. void PDForEveryFile(char* pThe_path, void (*pAction_routine)(char*)) {
  685.     char found_path[256];        // [esp+Ch] [ebp-448h] BYREF
  686.     WIN32_FIND_DATAA_ find_data; // [esp+10Ch] [ebp-348h] BYREF
  687.     HANDLE_ hFindFile;           // [esp+24Ch] [ebp-208h]
  688.     char file_filter[256];       // [esp+250h] [ebp-204h] BYREF
  689.     char current_dir[260];       // [esp+350h] [ebp-104h] BYREF
  690.  
  691.     GetCurrentDirectoryA_(sizeof(current_dir), current_dir);
  692.     if (SetCurrentDirectoryA_(pThe_path)) {
  693.         strcpy(file_filter, "*.???");
  694.         hFindFile = FindFirstFileA_(file_filter, &find_data);
  695.         if (hFindFile != INVALID_HANDLE_VALUE) {
  696.             do {
  697.                 PathCat(found_path, pThe_path, find_data.cFileName);
  698.                 pAction_routine(found_path);
  699.             } while (FindNextFileA_(hFindFile, &find_data));
  700.             FindClose_(hFindFile);
  701.         }
  702.         SetCurrentDirectoryA_(current_dir);
  703.     }
  704. }
  705.  
  706. void PDSetPalette(br_pixelmap* pThe_palette) {
  707.     PDSetPaletteEntries(pThe_palette, 0, 256);
  708. }
  709.  
  710. void Win32SetPaletteEntries(uint8_t* entries, int pFirst_colour, int pCount) {
  711.     int i;           // [esp+Ch] [ebp-Ch]
  712.     int last_colour; // [esp+14h] [ebp-4h]
  713.  
  714.     last_colour = pFirst_colour + pCount - 1;
  715.     if (last_colour > 255) {
  716.         last_colour = 255;
  717.     }
  718.     for (i = pFirst_colour; i <= last_colour; i++) {
  719.         gWin32_palette[i].peFlags = 0;
  720.         gWin32_palette[i].peRed = entries[i * 4 + 2];
  721.         gWin32_palette[i].peGreen = entries[i * 4 + 1];
  722.         gWin32_palette[i].peBlue = entries[i * 4];
  723.     }
  724.     SSDXSetPaleeteEntries(gWin32_palette, 0, 256);
  725. }
  726.  
  727. void PDSetPaletteEntries(br_pixelmap* pPalette, int pFirst_colour, int pCount) {
  728.     Win32SetPaletteEntries(pPalette->pixels, pFirst_colour, pCount);
  729. }
  730.  
  731. void PDSwitchToRealResolution(void) {
  732.     LOG_TRACE("()");
  733. }
  734.  
  735. void PDSwitchToLoresMode(void) {
  736.     LOG_TRACE("()");
  737. }
  738.  
  739. void PDMouseButtons(int* pButton_1, int* pButton_2) {
  740.     //br_uint_32 mouse_buttons; // Pierre-Marie Baty -- unused variable
  741.     //br_int_32 mouse_x; // Pierre-Marie Baty -- unused variable
  742.     //br_int_32 mouse_y; // Pierre-Marie Baty -- unused variable
  743.     LOG_TRACE("(%p, %p)", pButton_1, pButton_2);
  744.  
  745.     // added by dethrace
  746.     gHarness_platform.GetMouseButtons(pButton_1, pButton_2);
  747. }
  748.  
  749. void PDGetMousePosition(int* pX_coord, int* pY_coord) {
  750.     POINT_ p;
  751.     LOG_TRACE("(%p, %p)", pX_coord, pY_coord);
  752.  
  753.     GetCursorPos_(&p);
  754.     ScreenToClient_(gWin32_hwnd, &p);
  755.     *pX_coord = p.x;
  756.     *pY_coord = p.y;
  757. }
  758.  
  759. int PDGetTotalTime(void) {
  760.     return timeGetTime_();
  761. }
  762.  
  763. int PDServiceSystem(tU32 pTime_since_last_call) {
  764.     Win32PumpMessages();
  765.     return 0;
  766. }
  767.  
  768. void Win32InitInputDevice(void) {
  769.     // do directinput stuff
  770.     gJoystick_deadzone = 8000;
  771. }
  772.  
  773. void Win32AllocateActionReplayBuffer(void) {
  774.     MEMORYSTATUS_ mem_status; // [esp+Ch] [ebp-28h] BYREF
  775.     size_t buf_size;          // [esp+2Ch] [ebp-8h]
  776.     void* buf;                // [esp+30h] [ebp-4h]
  777.  
  778.     buf = 0;
  779.     if (gWin32_action_replay_buffer_allocated) {
  780.         return;
  781.     }
  782.     gWin32_action_replay_buffer_allocated = 1;
  783.     mem_status.dwLength = sizeof(mem_status);
  784.     GlobalMemoryStatus_(&mem_status);
  785.     dr_dprintf(
  786.         "Win32AllocateActionReplayBuffer(): Memory Status BEFORE Action Replay Allocation:\n"
  787.         "             dwLength        %u\n"
  788.         "             dwMemoryLoad    %u\n"
  789.         "             dwTotalPhys     %u\n"
  790.         "             dwAvailPhys     %u\n"
  791.         "             dwTotalPageFile %u\n"
  792.         "             dwAvailPageFile %u\n"
  793.         "             dwTotalVirtual  %u\n"
  794.         "             dwAvailVirtual  %u",
  795.         mem_status.dwLength,
  796.         mem_status.dwMemoryLoad,
  797.         mem_status.dwTotalPhys,
  798.         mem_status.dwAvailPhys,
  799.         mem_status.dwTotalPageFile,
  800.         mem_status.dwAvailPageFile,
  801.         mem_status.dwTotalVirtual,
  802.         mem_status.dwAvailVirtual);
  803.  
  804.     buf_size = 20000000;
  805.  
  806.     if (mem_status.dwTotalPhys < 16000000) {
  807.         buf_size = 500000;
  808.     }
  809.     if (mem_status.dwTotalPhys < 24000000) {
  810.         buf_size = 4000000;
  811.     }
  812.     if (mem_status.dwTotalPhys < 32000000) {
  813.         buf_size = 6000000;
  814.     }
  815.     if (mem_status.dwTotalPhys < 48000000) {
  816.         buf_size = 12000000;
  817.     }
  818.  
  819.     dr_dprintf("Win32AllocateActionReplayBuffer(): We want %d bytes...", buf_size);
  820.     if (mem_status.dwAvailPhys + mem_status.dwAvailPageFile < buf_size) {
  821.         buf_size = mem_status.dwAvailPhys + mem_status.dwAvailPageFile - 1048576;
  822.         dr_dprintf("Win32AllocateActionReplayBuffer(): ...but there's only %d bytes available...", buf_size);
  823.     }
  824.     if (buf_size < 65536) {
  825.         buf_size = 65536;
  826.         dr_dprintf("Win32AllocateActionReplayBuffer(): ...but we have to have a minimum size of %d bytes...", 65536);
  827.     }
  828.     while (buf_size >= 65536) {
  829.         buf = malloc(buf_size);
  830.         if (buf) {
  831.             break;
  832.         }
  833.         buf_size -= 65536;
  834.     }
  835.     gWin32_action_replay_buffer = buf;
  836.     if (buf) {
  837.         gWin32_action_replay_buffer_size = buf_size;
  838.         Sleep_(1000u);
  839.     } else {
  840.         gWin32_action_replay_buffer_size = 0;
  841.     }
  842.     dr_dprintf("Win32AllocateActionReplayBuffer(): Actually allocated %d bytes.", buf_size);
  843.     GlobalMemoryStatus_(&mem_status);
  844.     dr_dprintf(
  845.         "Win32AllocateActionReplayBuffer(): Memory Status AFTER Action Replay Allocation:\n"
  846.         "             dwLength        %u\n"
  847.         "             dwMemoryLoad    %u\n"
  848.         "             dwTotalPhys     %u\n"
  849.         "             dwAvailPhys     %u\n"
  850.         "             dwTotalPageFile %u\n"
  851.         "             dwAvailPageFile %u\n"
  852.         "             dwTotalVirtual  %u\n"
  853.         "             dwAvailVirtual  %u",
  854.         mem_status.dwLength,
  855.         mem_status.dwMemoryLoad,
  856.         mem_status.dwTotalPhys,
  857.         mem_status.dwAvailPhys,
  858.         mem_status.dwTotalPageFile,
  859.         mem_status.dwAvailPageFile,
  860.         mem_status.dwTotalVirtual,
  861.         mem_status.dwAvailVirtual);
  862. }
  863.  
  864. void PDAllocateActionReplayBuffer(char** pBuffer, tU32* pBuffer_size) {
  865.     LOG_TRACE("(%p, %p)", pBuffer, pBuffer_size);
  866.  
  867.     if (gReplay_override) {
  868.         *pBuffer = NULL;
  869.         *pBuffer_size = 0;
  870.         return;
  871.     }
  872.     Win32AllocateActionReplayBuffer();
  873.     *pBuffer = gWin32_action_replay_buffer;
  874.     *pBuffer_size = gWin32_action_replay_buffer_size;
  875. }
  876.  
  877. void PDDisposeActionReplayBuffer(char* pBuffer) {
  878.     LOG_TRACE("(\"%s\")", pBuffer);
  879. }
  880.  
  881. // this function is taken from dossys
  882. void Usage(char* pProgpath) {
  883.     char base_name[256]; // fix: changed from 9 to avoid overflow on longer filenames
  884.  
  885.     _splitpath_(pProgpath, NULL, NULL, base_name, NULL);
  886.  
  887.     fprintf(stderr,
  888.         "Usage: %s [%s] [%s YonFactor] [%s CarSimplificationLevel] [%s SoundDetailLevel] [%s] [%s] [%s] [%s] [%s] [%s]\nWhere YonFactor is between 0 and 1,\nCarSimplificationLevel is a whole number between 0 and %d,\nand SoundDetailLevel is a whole number.\n",
  889.         base_name,
  890.         "-hires",
  891.         "-yon",
  892.         "-simple",
  893.         "-sound",
  894.         "-robots",
  895.         "-lomem",
  896.         "-nosound",
  897.         "-spamfritter",
  898.         "-nocutscenes",
  899.         "-noreplay",
  900.         CAR_MAX_SIMPLIFICATION_LEVEL);
  901.     exit(1);
  902. }
  903.  
  904. // Renamed from "main" to "original_main" to allow for harness + unit testing
  905. int original_main(int pArgc, char** pArgv) {
  906.     int arg;
  907.     int i;
  908.     float f;
  909.  
  910.     for (i = 1; i < pArgc; i++) {
  911.         if (strcasecmp(pArgv[i], "-hires") == 0) {
  912.             gGraf_spec_index = 1;
  913.         } else if (strcasecmp(pArgv[i], "-yon") == 0 && i < pArgc - 1) {
  914.             i++;
  915.             sscanf(pArgv[i], "%f", &f);
  916.             if (f >= 0.0 && f <= 1.0f) {
  917.                 gYon_multiplier = f;
  918.             }
  919.         } else if (strcasecmp(pArgv[i], "-simple") == 0 && i < pArgc - 1) {
  920.             i++;
  921.             sscanf(pArgv[i], "%d", &arg);
  922.             if (arg >= 0 && arg < 5) {
  923.                 gCar_simplification_level = arg;
  924.             }
  925.         } else if (strcasecmp(pArgv[i], "-sound") == 0 && i < pArgc - 1) {
  926.             i++;
  927.             sscanf(pArgv[i], "%d", &arg);
  928.             gSound_detail_level = arg;
  929.  
  930.         } else if (strcasecmp(pArgv[i], "-robots") == 0 || strcasecmp(pArgv[i], "-german") == 0) {
  931.             gSausage_override = 1;
  932.         } else if (strcasecmp(pArgv[i], "-lomem") == 0) {
  933.             gAustere_override = 1;
  934.         } else if (strcasecmp(pArgv[i], "-nosound") == 0) {
  935.             gSound_override = 1;
  936.         } else if (strcasecmp(pArgv[i], "-spamfritter") == 0) {
  937.             gExtra_mem = 2000000;
  938.         } else if (strcasecmp(pArgv[i], "-nocutscenes") == 0) {
  939.             gCut_scene_override = 1;
  940.         } else if (strcasecmp(pArgv[i], "-noreplay") == 0) {
  941.             gReplay_override = 1;
  942.         } else {
  943.             Usage(pArgv[0]);
  944.         }
  945.     }
  946.  
  947.     gNetwork_profile_fname[0] = 0;
  948.     uint32_t len = GetCurrentDirectoryA_(240, gNetwork_profile_fname);
  949.     if (len > 0 && len == strlen(gNetwork_profile_fname)) {
  950.         gNetwork_profile_file_exists = 1;
  951.         strcat(gNetwork_profile_fname, "/");
  952.         strcat(gNetwork_profile_fname, "NETWORK.INI");
  953.     }
  954.  
  955.     GameMain(pArgc, pArgv);
  956.     return 0;
  957. }
  958.  
  959. int OurGetChar(void) {
  960.     //int key; // Pierre-Marie Baty -- unused variable
  961.     LOG_TRACE("()");
  962.     NOT_IMPLEMENTED();
  963. }
  964.  
  965. void PDEnterDebugger(char* pStr) {
  966.     //static unsigned char* save_it; // Pierre-Marie Baty -- unused variable
  967.     LOG_TRACE("(\"%s\")", pStr);
  968.  
  969.     dr_dprintf("PDEnterDebugger(): %s", pStr);
  970.     ShowCursor_(1);
  971. #ifdef DETHRACE_FIX_BUGS
  972.     if (strcmp(pStr, "Bet you weren't expecting this") != 0
  973. #else
  974.     if (pStr != "Bet you weren't expecting this"
  975. #endif
  976.         && _CrtDbgReport_(_CRT_ASSERT, "C:\\Msdev\\Projects\\DethRace\\Win95sys.c", 437, 0, 0) == 1) {
  977.  
  978.         abort(); // original: __debugbreak();
  979.     }
  980.     ShowCursor_(0);
  981. }
  982.  
  983. // Added function
  984. br_material* PDMissingMaterial(char* name) {
  985.     LOG_TRACE("(\"%s\")", name);
  986.  
  987.     // FIXME: call functiont in harness
  988.     dr_dprintf("SOMETHING MISSING WARNING - Can't find material '%s'", name);
  989.     return NULL;
  990. }
  991.  
  992. // Added function
  993. br_pixelmap* PDMissingTable(char* name) {
  994.     LOG_TRACE("(\"%s\")", name);
  995.  
  996.     // FIXME: call function in harness
  997.     dr_dprintf("SOMETHING MISSING WARNING - Can't find shade table '%s'", name);
  998.     return NULL;
  999. }
  1000.  
  1001. // Added function
  1002. br_model* PDMissingModel(char* name) {
  1003.     LOG_TRACE("(\"%s\")", name);
  1004.  
  1005.     // FIXME: call function in harness
  1006.     dr_dprintf("SOMETHING MISSING WARNING - Can't find model '%s'", name);
  1007.     return NULL;
  1008. }
  1009.  
  1010. // Added function
  1011. br_pixelmap* PDMissingMap(char* name) {
  1012.     LOG_TRACE("(\"%s\")", name);
  1013.  
  1014.     // FIXME: call function in harness
  1015.     dr_dprintf("SOMETHING MISSING WARNING - Can't find pixelmap '%s'", name);
  1016.     return NULL;
  1017. }
  1018.  
  1019. void PDEndItAllAndReRunTheBastard(void) {
  1020.     LOG_TRACE("()");
  1021.     NOT_IMPLEMENTED();
  1022. }
  1023.  
  1024. int InitJoysticks(void) {
  1025.     LOG_TRACE("()");
  1026.     NOT_IMPLEMENTED();
  1027. }
  1028.  
  1029. tU32 ReadJoystickAxis(int pBit) {
  1030.     //tU32 val; // Pierre-Marie Baty -- unused variable
  1031.     //tU32 count; // Pierre-Marie Baty -- unused variable
  1032.     LOG_TRACE("(%d)", pBit);
  1033.     NOT_IMPLEMENTED();
  1034. }
  1035.  
  1036. void PDReadJoySticks(void) {
  1037.     //tU32 temp1x; // Pierre-Marie Baty -- unused variable
  1038.     //tU32 temp1y; // Pierre-Marie Baty -- unused variable
  1039.     //tU32 temp2x; // Pierre-Marie Baty -- unused variable
  1040.     //tU32 temp2y; // Pierre-Marie Baty -- unused variable
  1041.     LOG_TRACE("()");
  1042.     NOT_IMPLEMENTED();
  1043. }
  1044.  
  1045. tS32 PDGetJoy1X(void) {
  1046.     //tS32 joy; // Pierre-Marie Baty -- unused variable
  1047.     LOG_TRACE("()");
  1048.     NOT_IMPLEMENTED();
  1049. }
  1050.  
  1051. tS32 PDGetJoy1Y(void) {
  1052.     //tS32 joy; // Pierre-Marie Baty -- unused variable
  1053.     LOG_TRACE("()");
  1054.     NOT_IMPLEMENTED();
  1055. }
  1056.  
  1057. tS32 PDGetJoy2X(void) {
  1058.     //tS32 joy; // Pierre-Marie Baty -- unused variable
  1059.     LOG_TRACE("()");
  1060.     NOT_IMPLEMENTED();
  1061. }
  1062.  
  1063. tS32 PDGetJoy2Y(void) {
  1064.     //tS32 joy; // Pierre-Marie Baty -- unused variable
  1065.     LOG_TRACE("()");
  1066.     NOT_IMPLEMENTED();
  1067. }
  1068.  
  1069. int PDGetJoy1Button1(void) {
  1070.     LOG_TRACE("()");
  1071.     NOT_IMPLEMENTED();
  1072. }
  1073.  
  1074. int PDGetJoy1Button2(void) {
  1075.     LOG_TRACE("()");
  1076.     NOT_IMPLEMENTED();
  1077. }
  1078.  
  1079. int PDGetJoy1Button3(void) {
  1080.     LOG_TRACE("()");
  1081.     NOT_IMPLEMENTED();
  1082. }
  1083.  
  1084. int PDGetJoy1Button4(void) {
  1085.     LOG_TRACE("()");
  1086.     NOT_IMPLEMENTED();
  1087. }
  1088.  
  1089. int PDGetJoy2Button1(void) {
  1090.     LOG_TRACE("()");
  1091.     NOT_IMPLEMENTED();
  1092. }
  1093.  
  1094. int PDGetJoy2Button2(void) {
  1095.     LOG_TRACE("()");
  1096.     NOT_IMPLEMENTED();
  1097. }
  1098.  
  1099. int PDGetJoy2Button3(void) {
  1100.     LOG_TRACE("()");
  1101.     NOT_IMPLEMENTED();
  1102. }
  1103.  
  1104. int PDGetJoy2Button4(void) {
  1105.     LOG_TRACE("()");
  1106.     NOT_IMPLEMENTED();
  1107. }
  1108.  
  1109. int PDFileUnlock(char* pThe_path) {
  1110.     uint32_t dwFileAttributes; // [esp+Ch] [ebp-4h]
  1111.     LOG_TRACE("(\"%s\")", pThe_path);
  1112.  
  1113.     dwFileAttributes = GetFileAttributesA_(pThe_path);
  1114.     return dwFileAttributes != INVALID_FILE_ATTRIBUTES && SetFileAttributesA_(pThe_path, dwFileAttributes & ~FILE_ATTRIBUTE_READONLY);
  1115. }
  1116.  
  1117. int PDCheckDriveExists2(char* pThe_path, char* pFile_name, tU32 pMin_size) {
  1118.  
  1119.     char the_path[256]; // [esp+Ch] [ebp-108h] BYREF
  1120.     tU32 file_size;     // [esp+10Ch] [ebp-8h]
  1121.     HANDLE_ hFile;      // [esp+110h] [ebp-4h]
  1122.     LOG_TRACE("(\"%s\", \"%s\", %d)", pThe_path, pFile_name, pMin_size);
  1123.  
  1124.     file_size = 0;
  1125.     if (pFile_name) {
  1126.         PathCat(the_path, pThe_path, pFile_name);
  1127.     } else {
  1128.         strcpy(the_path, pThe_path);
  1129.     }
  1130.     if (the_path[0] && the_path[1] == ':' && !the_path[2]) {
  1131.         strcat(the_path, gDir_separator);
  1132.     }
  1133.     if (GetFileAttributesA_(pThe_path) == INVALID_FILE_ATTRIBUTES) {
  1134.         return 0;
  1135.     }
  1136.     hFile = CreateFileA_(the_path, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  1137.     if (hFile != INVALID_HANDLE_VALUE) {
  1138.         file_size = GetFileSize_(hFile, 0);
  1139.         CloseHandle_(hFile);
  1140.     }
  1141.     return file_size >= pMin_size;
  1142. }
  1143.  
  1144. int PDDoWeLeadAnAustereExistance(void) {
  1145.     return 0;
  1146. }
  1147.  
  1148. // Windows-specific functions. The only name we know for sure is "Win32AllocateReplayBuffer".
  1149.  
  1150. void Win32BRenderWarningFunc(char* msg) {
  1151.     dr_dprintf("*******************************************************************************");
  1152.     dr_dprintf("BRender WARNING: '%s'", msg);
  1153.     dr_dprintf("*******************************************************************************");
  1154. }
  1155.  
  1156. void Win32BRenderFailureFunc(char* msg) {
  1157.     dr_dprintf("*******************************************************************************");
  1158.     dr_dprintf("BRender FAILURE: '%s'", msg);
  1159.     dr_dprintf("*******************************************************************************");
  1160.     Win32FatalError("BRender error detected:", msg);
  1161. }
  1162.