Subversion Repositories Games.Carmageddon

Rev

Rev 15 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #include "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 (was: { 8, 1, 0, 640, 480, 0, 0, "64X48X8", GFX_INIT_STRING_64X48X8, 640, 640 480, NULL })
  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.             gHarness_platform.Renderer_Present(gBack_screen);
  640.         } else {
  641.             DRPixelmapDoubledCopy(gTemp_screen, gBack_screen, 320, 200, 0, 40);
  642.             // BrPixelmapDoubleBuffer(gScreen, gTemp_screen);
  643.             gHarness_platform.Renderer_Present(gTemp_screen);
  644.         }
  645.     }
  646. }
  647.  
  648. 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) {
  649.     LOG_TRACE("(%p, %d, %d, %p, %d, %d, %d, %d)", dst, dx, dy, src, sx, sy, w, h);
  650.     NOT_IMPLEMENTED();
  651. }
  652.  
  653. 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) {
  654.     LOG_TRACE("(%p, %d, %d, %d, %d, %d)", dst, x1, y1, x2, y2, colour);
  655.     NOT_IMPLEMENTED();
  656. }
  657.  
  658. 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) {
  659.     LOG_TRACE("(%p, %d, %d, %d, %d, %d)", dst, x1, y1, x2, y2, colour);
  660.     NOT_IMPLEMENTED();
  661. }
  662.  
  663. void PDInstallErrorHandlers(void) {
  664.     LOG_TRACE("()");
  665.  
  666.     gWin32_br_diaghandler.identifier = "LlantisilioBlahBlahBlahOgOgOch";
  667.     gWin32_br_diaghandler.warning = Win32BRenderWarningFunc;
  668.     gWin32_br_diaghandler.failure = Win32BRenderFailureFunc;
  669.     BrDiagHandlerSet(&gWin32_br_diaghandler);
  670. }
  671.  
  672. void PDSetFileVariables(void) {
  673.  
  674.     // Changed by dethrace for cross-platform
  675.     // strcpy(gDir_separator, "\\");
  676.     strcpy(gDir_separator, "/");
  677. }
  678.  
  679. void PDBuildAppPath(char* pThe_path) {
  680.     GetCurrentDirectoryA_(253, pThe_path);
  681.     // GetShortPathNameA(pThe_path, pThe_path, 253);
  682.     strcat(pThe_path, "/"); // original: strcat(pThe_path, "\\")
  683.     dr_dprintf("Application path '%s'", pThe_path);
  684. }
  685.  
  686. void PDForEveryFile(char* pThe_path, void (*pAction_routine)(char*)) {
  687.     char found_path[256];        // [esp+Ch] [ebp-448h] BYREF
  688.     WIN32_FIND_DATAA_ find_data; // [esp+10Ch] [ebp-348h] BYREF
  689.     HANDLE_ hFindFile;           // [esp+24Ch] [ebp-208h]
  690.     char file_filter[256];       // [esp+250h] [ebp-204h] BYREF
  691.     char current_dir[260];       // [esp+350h] [ebp-104h] BYREF
  692.  
  693.     GetCurrentDirectoryA_(sizeof(current_dir), current_dir);
  694.     if (SetCurrentDirectoryA_(pThe_path)) {
  695.         strcpy(file_filter, "*.???");
  696.         hFindFile = FindFirstFileA_(file_filter, &find_data);
  697.         if (hFindFile != INVALID_HANDLE_VALUE) {
  698.             do {
  699.                 PathCat(found_path, pThe_path, find_data.cFileName);
  700.                 pAction_routine(found_path);
  701.             } while (FindNextFileA_(hFindFile, &find_data));
  702.             FindClose_(hFindFile);
  703.         }
  704.         SetCurrentDirectoryA_(current_dir);
  705.     }
  706. }
  707.  
  708. void PDSetPalette(br_pixelmap* pThe_palette) {
  709.     PDSetPaletteEntries(pThe_palette, 0, 256);
  710. }
  711.  
  712. void Win32SetPaletteEntries(uint8_t* entries, int pFirst_colour, int pCount) {
  713.     int i;           // [esp+Ch] [ebp-Ch]
  714.     int last_colour; // [esp+14h] [ebp-4h]
  715.  
  716.     last_colour = pFirst_colour + pCount - 1;
  717.     if (last_colour > 255) {
  718.         last_colour = 255;
  719.     }
  720.     for (i = pFirst_colour; i <= last_colour; i++) {
  721.         gWin32_palette[i].peFlags = 0;
  722.         gWin32_palette[i].peRed = entries[i * 4 + 2];
  723.         gWin32_palette[i].peGreen = entries[i * 4 + 1];
  724.         gWin32_palette[i].peBlue = entries[i * 4];
  725.     }
  726.     SSDXSetPaleeteEntries(gWin32_palette, 0, 256);
  727. }
  728.  
  729. void PDSetPaletteEntries(br_pixelmap* pPalette, int pFirst_colour, int pCount) {
  730.     Win32SetPaletteEntries(pPalette->pixels, pFirst_colour, pCount);
  731. }
  732.  
  733. void PDSwitchToRealResolution(void) {
  734.     LOG_TRACE("()");
  735. }
  736.  
  737. void PDSwitchToLoresMode(void) {
  738.     LOG_TRACE("()");
  739. }
  740.  
  741. void PDMouseButtons(int* pButton_1, int* pButton_2) {
  742.     //br_uint_32 mouse_buttons; // Pierre-Marie Baty -- unused variable
  743.     //br_int_32 mouse_x; // Pierre-Marie Baty -- unused variable
  744.     //br_int_32 mouse_y; // Pierre-Marie Baty -- unused variable
  745.     LOG_TRACE("(%p, %p)", pButton_1, pButton_2);
  746.  
  747.     // added by dethrace
  748.     gHarness_platform.GetMouseButtons(pButton_1, pButton_2);
  749. }
  750.  
  751. void PDGetMousePosition(int* pX_coord, int* pY_coord) {
  752.     POINT_ p;
  753.     LOG_TRACE("(%p, %p)", pX_coord, pY_coord);
  754.  
  755.     GetCursorPos_(&p);
  756.     ScreenToClient_(gWin32_hwnd, &p);
  757.     *pX_coord = p.x;
  758.     *pY_coord = p.y;
  759. }
  760.  
  761. int PDGetTotalTime(void) {
  762.     return timeGetTime_();
  763. }
  764.  
  765. int PDServiceSystem(tU32 pTime_since_last_call) {
  766.     Win32PumpMessages();
  767.     return 0;
  768. }
  769.  
  770. void Win32InitInputDevice(void) {
  771.     // do directinput stuff
  772.     gJoystick_deadzone = 8000;
  773. }
  774.  
  775. void Win32AllocateActionReplayBuffer(void) {
  776.     MEMORYSTATUS_ mem_status; // [esp+Ch] [ebp-28h] BYREF
  777.     size_t buf_size;          // [esp+2Ch] [ebp-8h]
  778.     void* buf;                // [esp+30h] [ebp-4h]
  779.  
  780.     buf = 0;
  781.     if (gWin32_action_replay_buffer_allocated) {
  782.         return;
  783.     }
  784.     gWin32_action_replay_buffer_allocated = 1;
  785.     mem_status.dwLength = sizeof(mem_status);
  786.     GlobalMemoryStatus_(&mem_status);
  787.     dr_dprintf(
  788.         "Win32AllocateActionReplayBuffer(): Memory Status BEFORE Action Replay Allocation:\n"
  789.         "             dwLength        %u\n"
  790.         "             dwMemoryLoad    %u\n"
  791.         "             dwTotalPhys     %u\n"
  792.         "             dwAvailPhys     %u\n"
  793.         "             dwTotalPageFile %u\n"
  794.         "             dwAvailPageFile %u\n"
  795.         "             dwTotalVirtual  %u\n"
  796.         "             dwAvailVirtual  %u",
  797.         mem_status.dwLength,
  798.         mem_status.dwMemoryLoad,
  799.         mem_status.dwTotalPhys,
  800.         mem_status.dwAvailPhys,
  801.         mem_status.dwTotalPageFile,
  802.         mem_status.dwAvailPageFile,
  803.         mem_status.dwTotalVirtual,
  804.         mem_status.dwAvailVirtual);
  805.  
  806.     buf_size = 20000000;
  807.  
  808.     if (mem_status.dwTotalPhys < 16000000) {
  809.         buf_size = 500000;
  810.     }
  811.     if (mem_status.dwTotalPhys < 24000000) {
  812.         buf_size = 4000000;
  813.     }
  814.     if (mem_status.dwTotalPhys < 32000000) {
  815.         buf_size = 6000000;
  816.     }
  817.     if (mem_status.dwTotalPhys < 48000000) {
  818.         buf_size = 12000000;
  819.     }
  820.  
  821.     dr_dprintf("Win32AllocateActionReplayBuffer(): We want %d bytes...", buf_size);
  822.     if (mem_status.dwAvailPhys + mem_status.dwAvailPageFile < buf_size) {
  823.         buf_size = mem_status.dwAvailPhys + mem_status.dwAvailPageFile - 1048576;
  824.         dr_dprintf("Win32AllocateActionReplayBuffer(): ...but there's only %d bytes available...", buf_size);
  825.     }
  826.     if (buf_size < 65536) {
  827.         buf_size = 65536;
  828.         dr_dprintf("Win32AllocateActionReplayBuffer(): ...but we have to have a minimum size of %d bytes...", 65536);
  829.     }
  830.     while (buf_size >= 65536) {
  831.         buf = malloc(buf_size);
  832.         if (buf) {
  833.             break;
  834.         }
  835.         buf_size -= 65536;
  836.     }
  837.     gWin32_action_replay_buffer = buf;
  838.     if (buf) {
  839.         gWin32_action_replay_buffer_size = buf_size;
  840.         Sleep_(1000u);
  841.     } else {
  842.         gWin32_action_replay_buffer_size = 0;
  843.     }
  844.     dr_dprintf("Win32AllocateActionReplayBuffer(): Actually allocated %d bytes.", buf_size);
  845.     GlobalMemoryStatus_(&mem_status);
  846.     dr_dprintf(
  847.         "Win32AllocateActionReplayBuffer(): Memory Status AFTER Action Replay Allocation:\n"
  848.         "             dwLength        %u\n"
  849.         "             dwMemoryLoad    %u\n"
  850.         "             dwTotalPhys     %u\n"
  851.         "             dwAvailPhys     %u\n"
  852.         "             dwTotalPageFile %u\n"
  853.         "             dwAvailPageFile %u\n"
  854.         "             dwTotalVirtual  %u\n"
  855.         "             dwAvailVirtual  %u",
  856.         mem_status.dwLength,
  857.         mem_status.dwMemoryLoad,
  858.         mem_status.dwTotalPhys,
  859.         mem_status.dwAvailPhys,
  860.         mem_status.dwTotalPageFile,
  861.         mem_status.dwAvailPageFile,
  862.         mem_status.dwTotalVirtual,
  863.         mem_status.dwAvailVirtual);
  864. }
  865.  
  866. void PDAllocateActionReplayBuffer(char** pBuffer, tU32* pBuffer_size) {
  867.     LOG_TRACE("(%p, %p)", pBuffer, pBuffer_size);
  868.  
  869.     if (gReplay_override) {
  870.         *pBuffer = NULL;
  871.         *pBuffer_size = 0;
  872.         return;
  873.     }
  874.     Win32AllocateActionReplayBuffer();
  875.     *pBuffer = gWin32_action_replay_buffer;
  876.     *pBuffer_size = gWin32_action_replay_buffer_size;
  877. }
  878.  
  879. void PDDisposeActionReplayBuffer(char* pBuffer) {
  880.     LOG_TRACE("(\"%s\")", pBuffer);
  881. }
  882.  
  883. // this function is taken from dossys
  884. void Usage(char* pProgpath) {
  885.     char base_name[256]; // fix: changed from 9 to avoid overflow on longer filenames
  886.  
  887.     _splitpath_(pProgpath, NULL, NULL, base_name, NULL);
  888.  
  889.     fprintf(stderr,
  890.         "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",
  891.         base_name,
  892.         "-hires",
  893.         "-yon",
  894.         "-simple",
  895.         "-sound",
  896.         "-robots",
  897.         "-lomem",
  898.         "-nosound",
  899.         "-spamfritter",
  900.         "-nocutscenes",
  901.         "-noreplay",
  902.         CAR_MAX_SIMPLIFICATION_LEVEL);
  903.     exit(1);
  904. }
  905.  
  906. // Renamed from "main" to "original_main" to allow for harness + unit testing
  907. int original_main(int pArgc, char** pArgv) {
  908.     int arg;
  909.     int i;
  910.     float f;
  911.  
  912.     for (i = 1; i < pArgc; i++) {
  913.         if (strcasecmp(pArgv[i], "-hires") == 0) {
  914.             gGraf_spec_index = 1;
  915.         } else if (strcasecmp(pArgv[i], "-yon") == 0 && i < pArgc - 1) {
  916.             i++;
  917.             sscanf(pArgv[i], "%f", &f);
  918.             if (f >= 0.0 && f <= 1.0f) {
  919.                 gYon_multiplier = f;
  920.             }
  921.         } else if (strcasecmp(pArgv[i], "-simple") == 0 && i < pArgc - 1) {
  922.             i++;
  923.             sscanf(pArgv[i], "%d", &arg);
  924.             if (arg >= 0 && arg < 5) {
  925.                 gCar_simplification_level = arg;
  926.             }
  927.         } else if (strcasecmp(pArgv[i], "-sound") == 0 && i < pArgc - 1) {
  928.             i++;
  929.             sscanf(pArgv[i], "%d", &arg);
  930.             gSound_detail_level = arg;
  931.  
  932.         } else if (strcasecmp(pArgv[i], "-robots") == 0 || strcasecmp(pArgv[i], "-german") == 0) {
  933.             gSausage_override = 1;
  934.         } else if (strcasecmp(pArgv[i], "-lomem") == 0) {
  935.             gAustere_override = 1;
  936.         } else if (strcasecmp(pArgv[i], "-nosound") == 0) {
  937.             gSound_override = 1;
  938.         } else if (strcasecmp(pArgv[i], "-spamfritter") == 0) {
  939.             gExtra_mem = 2000000;
  940.         } else if (strcasecmp(pArgv[i], "-nocutscenes") == 0) {
  941.             gCut_scene_override = 1;
  942.         } else if (strcasecmp(pArgv[i], "-noreplay") == 0) {
  943.             gReplay_override = 1;
  944.         } else {
  945.             Usage(pArgv[0]);
  946.         }
  947.     }
  948.  
  949.     gNetwork_profile_fname[0] = 0;
  950.     uint32_t len = GetCurrentDirectoryA_(240, gNetwork_profile_fname);
  951.     if (len > 0 && len == strlen(gNetwork_profile_fname)) {
  952.         gNetwork_profile_file_exists = 1;
  953.         strcat(gNetwork_profile_fname, "/");
  954.         strcat(gNetwork_profile_fname, "NETWORK.INI");
  955.     }
  956.  
  957.     GameMain(pArgc, pArgv);
  958.     return 0;
  959. }
  960.  
  961. int OurGetChar(void) {
  962.     //int key; // Pierre-Marie Baty -- unused variable
  963.     LOG_TRACE("()");
  964.     NOT_IMPLEMENTED();
  965. }
  966.  
  967. void PDEnterDebugger(char* pStr) {
  968.     //static unsigned char* save_it; // Pierre-Marie Baty -- unused variable
  969.     LOG_TRACE("(\"%s\")", pStr);
  970.  
  971.     dr_dprintf("PDEnterDebugger(): %s", pStr);
  972.     ShowCursor_(1);
  973. #ifdef DETHRACE_FIX_BUGS
  974.     if (strcmp(pStr, "Bet you weren't expecting this") != 0
  975. #else
  976.     if (pStr != "Bet you weren't expecting this"
  977. #endif
  978.         && _CrtDbgReport_(_CRT_ASSERT, "C:\\Msdev\\Projects\\DethRace\\Win95sys.c", 437, 0, 0) == 1) {
  979.  
  980.         abort(); // original: __debugbreak();
  981.     }
  982.     ShowCursor_(0);
  983. }
  984.  
  985. // Added function
  986. br_material* PDMissingMaterial(char* name) {
  987.     LOG_TRACE("(\"%s\")", name);
  988.  
  989.     // FIXME: call functiont in harness
  990.     dr_dprintf("SOMETHING MISSING WARNING - Can't find material '%s'", name);
  991.     return NULL;
  992. }
  993.  
  994. // Added function
  995. br_pixelmap* PDMissingTable(char* name) {
  996.     LOG_TRACE("(\"%s\")", name);
  997.  
  998.     // FIXME: call function in harness
  999.     dr_dprintf("SOMETHING MISSING WARNING - Can't find shade table '%s'", name);
  1000.     return NULL;
  1001. }
  1002.  
  1003. // Added function
  1004. br_model* PDMissingModel(char* name) {
  1005.     LOG_TRACE("(\"%s\")", name);
  1006.  
  1007.     // FIXME: call function in harness
  1008.     dr_dprintf("SOMETHING MISSING WARNING - Can't find model '%s'", name);
  1009.     return NULL;
  1010. }
  1011.  
  1012. // Added function
  1013. br_pixelmap* PDMissingMap(char* name) {
  1014.     LOG_TRACE("(\"%s\")", name);
  1015.  
  1016.     // FIXME: call function in harness
  1017.     dr_dprintf("SOMETHING MISSING WARNING - Can't find pixelmap '%s'", name);
  1018.     return NULL;
  1019. }
  1020.  
  1021. void PDEndItAllAndReRunTheBastard(void) {
  1022.     LOG_TRACE("()");
  1023.     NOT_IMPLEMENTED();
  1024. }
  1025.  
  1026. int InitJoysticks(void) {
  1027.     LOG_TRACE("()");
  1028.     NOT_IMPLEMENTED();
  1029. }
  1030.  
  1031. tU32 ReadJoystickAxis(int pBit) {
  1032.     //tU32 val; // Pierre-Marie Baty -- unused variable
  1033.     //tU32 count; // Pierre-Marie Baty -- unused variable
  1034.     LOG_TRACE("(%d)", pBit);
  1035.     NOT_IMPLEMENTED();
  1036. }
  1037.  
  1038. void PDReadJoySticks(void) {
  1039.     //tU32 temp1x; // Pierre-Marie Baty -- unused variable
  1040.     //tU32 temp1y; // Pierre-Marie Baty -- unused variable
  1041.     //tU32 temp2x; // Pierre-Marie Baty -- unused variable
  1042.     //tU32 temp2y; // Pierre-Marie Baty -- unused variable
  1043.     LOG_TRACE("()");
  1044.     NOT_IMPLEMENTED();
  1045. }
  1046.  
  1047. tS32 PDGetJoy1X(void) {
  1048.     //tS32 joy; // Pierre-Marie Baty -- unused variable
  1049.     LOG_TRACE("()");
  1050.     NOT_IMPLEMENTED();
  1051. }
  1052.  
  1053. tS32 PDGetJoy1Y(void) {
  1054.     //tS32 joy; // Pierre-Marie Baty -- unused variable
  1055.     LOG_TRACE("()");
  1056.     NOT_IMPLEMENTED();
  1057. }
  1058.  
  1059. tS32 PDGetJoy2X(void) {
  1060.     //tS32 joy; // Pierre-Marie Baty -- unused variable
  1061.     LOG_TRACE("()");
  1062.     NOT_IMPLEMENTED();
  1063. }
  1064.  
  1065. tS32 PDGetJoy2Y(void) {
  1066.     //tS32 joy; // Pierre-Marie Baty -- unused variable
  1067.     LOG_TRACE("()");
  1068.     NOT_IMPLEMENTED();
  1069. }
  1070.  
  1071. int PDGetJoy1Button1(void) {
  1072.     LOG_TRACE("()");
  1073.     NOT_IMPLEMENTED();
  1074. }
  1075.  
  1076. int PDGetJoy1Button2(void) {
  1077.     LOG_TRACE("()");
  1078.     NOT_IMPLEMENTED();
  1079. }
  1080.  
  1081. int PDGetJoy1Button3(void) {
  1082.     LOG_TRACE("()");
  1083.     NOT_IMPLEMENTED();
  1084. }
  1085.  
  1086. int PDGetJoy1Button4(void) {
  1087.     LOG_TRACE("()");
  1088.     NOT_IMPLEMENTED();
  1089. }
  1090.  
  1091. int PDGetJoy2Button1(void) {
  1092.     LOG_TRACE("()");
  1093.     NOT_IMPLEMENTED();
  1094. }
  1095.  
  1096. int PDGetJoy2Button2(void) {
  1097.     LOG_TRACE("()");
  1098.     NOT_IMPLEMENTED();
  1099. }
  1100.  
  1101. int PDGetJoy2Button3(void) {
  1102.     LOG_TRACE("()");
  1103.     NOT_IMPLEMENTED();
  1104. }
  1105.  
  1106. int PDGetJoy2Button4(void) {
  1107.     LOG_TRACE("()");
  1108.     NOT_IMPLEMENTED();
  1109. }
  1110.  
  1111. int PDFileUnlock(char* pThe_path) {
  1112.     uint32_t dwFileAttributes; // [esp+Ch] [ebp-4h]
  1113.     LOG_TRACE("(\"%s\")", pThe_path);
  1114.  
  1115.     dwFileAttributes = GetFileAttributesA_(pThe_path);
  1116.     return dwFileAttributes != INVALID_FILE_ATTRIBUTES && SetFileAttributesA_(pThe_path, dwFileAttributes & ~FILE_ATTRIBUTE_READONLY);
  1117. }
  1118.  
  1119. int PDCheckDriveExists2(char* pThe_path, char* pFile_name, tU32 pMin_size) {
  1120.  
  1121.     char the_path[256]; // [esp+Ch] [ebp-108h] BYREF
  1122.     tU32 file_size;     // [esp+10Ch] [ebp-8h]
  1123.     HANDLE_ hFile;      // [esp+110h] [ebp-4h]
  1124.     LOG_TRACE("(\"%s\", \"%s\", %d)", pThe_path, pFile_name, pMin_size);
  1125.  
  1126.     file_size = 0;
  1127.     if (pFile_name) {
  1128.         PathCat(the_path, pThe_path, pFile_name);
  1129.     } else {
  1130.         strcpy(the_path, pThe_path);
  1131.     }
  1132.     if (the_path[0] && the_path[1] == ':' && !the_path[2]) {
  1133.         strcat(the_path, gDir_separator);
  1134.     }
  1135.     if (GetFileAttributesA_(pThe_path) == INVALID_FILE_ATTRIBUTES) {
  1136.         return 0;
  1137.     }
  1138.     hFile = CreateFileA_(the_path, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  1139.     if (hFile != INVALID_HANDLE_VALUE) {
  1140.         file_size = GetFileSize_(hFile, 0);
  1141.         CloseHandle_(hFile);
  1142.     }
  1143.     return file_size >= pMin_size;
  1144. }
  1145.  
  1146. int PDDoWeLeadAnAustereExistance(void) {
  1147.     return 0;
  1148. }
  1149.  
  1150. // Windows-specific functions. The only name we know for sure is "Win32AllocateReplayBuffer".
  1151.  
  1152. void Win32BRenderWarningFunc(char* msg) {
  1153.     dr_dprintf("*******************************************************************************");
  1154.     dr_dprintf("BRender WARNING: '%s'", msg);
  1155.     dr_dprintf("*******************************************************************************");
  1156. }
  1157.  
  1158. void Win32BRenderFailureFunc(char* msg) {
  1159.     dr_dprintf("*******************************************************************************");
  1160.     dr_dprintf("BRender FAILURE: '%s'", msg);
  1161.     dr_dprintf("*******************************************************************************");
  1162.     Win32FatalError("BRender error detected:", msg);
  1163. }
  1164.