Subversion Repositories Games.Carmageddon

Rev

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

  1. #include "newgame.h"
  2. #include "cutscene.h"
  3. #include "displays.h"
  4. #include "drmem.h"
  5. #include "errors.h"
  6. #include "flicplay.h"
  7. #include "globvars.h"
  8. #include "globvrpb.h"
  9. #include "grafdata.h"
  10. #include "graphics.h"
  11. #include "harness/config.h"
  12. #include "harness/hooks.h"
  13. #include "harness/trace.h"
  14. #include "init.h"
  15. #include "input.h"
  16. #include "intrface.h"
  17. #include "loading.h"
  18. #include "network.h"
  19. #include "pd/sys.h"
  20. #include "racestrt.h"
  21. #include "sound.h"
  22. #include "structur.h"
  23. #include "utility.h"
  24. #include "world.h"
  25. #include <stdlib.h>
  26. #include <string.h>
  27.  
  28. tU8* gFrank_flic_data;
  29. tU8* gAnne_flic_data;
  30. int gNet_storage_allocated;
  31. // clang-format off
  32. tRadio_bastards gRadio_bastards__newgame[11] = { // suffix added to avoid duplicate symbol
  33.     { 1,  32, 0, { 245,   0,   0,   0,   0, }, },
  34.     { 1,  43, 0, { 245,   0,   0,   0,   0, }, },
  35.     { 1,  54, 0, { 245,   0,   0,   0,   0, }, },
  36.     { 1,  65, 0, { 245,   0,   0,   0,   0, }, },
  37.     { 1,  76, 0, { 245,   0,   0,   0,   0, }, },
  38.     { 2,  86, 0, {  81, 150,   0,   0,   0, }, },
  39.     { 2,  97, 0, {  81, 150,   0,   0,   0, }, },
  40.     { 2, 108, 0, {  81, 150,   0,   0,   0, }, },
  41.     { 2, 119, 0, { 150, 201,   0,   0,   0, }, },
  42.     { 4, 130, 0, { 115, 150, 183, 215,   0, }, },
  43.     { 5, 141, 0, { 142, 160, 182, 204, 230, }, },
  44. };
  45. // clang-format on
  46. char _name1[] = "xxxxxxxx.TXT"; // keep compiler happy
  47. char _name2[] = "yyyyyyyy.TXT"; // keep compiler happy
  48. char* gBasic_car_names[2] = { _name1, _name2 };
  49. tNet_game_options gNet_settings[8];
  50. tJoinable_game gGames_to_join[6];
  51. tNet_game_options* gOptions;
  52. int gNet_target[7];
  53. int gLast_graph_sel__newgame;                   // suffix added to avoid duplicate symbol
  54. tInterface_spec* gThe_interface_spec__newgame;  // suffix added to avoid duplicate symbol
  55. tNet_sequence_type gNet_race_sequence__newgame; // suffix added to avoid duplicate symbol
  56. tNet_game_type gLast_game_type;
  57. int gCurrent_net_game_count;
  58. tU32 gAnne_flic_data_length;
  59. int gShifted_default_yet;
  60. char* gNet_name;
  61. tU32 gFrank_flic_data_length;
  62. int gLast_net_choose_box;
  63. int gCurrent_game_selection;
  64. int gRace_index;
  65. int gRadio_selected;
  66.  
  67. // IDA: void __cdecl StartRollingPlayerNamesIn()
  68. void StartRollingPlayerNamesIn(void) {
  69.     int i;
  70.     LOG_TRACE("()");
  71.  
  72.     for (i = 0; i < COUNT_OF(gCurrent_graf_data->player_name_x); i++) {
  73.         SetSlotXY(i, gCurrent_graf_data->player_name_x[i], gCurrent_graf_data->player_name_y);
  74.         AddRollingString(gProgram_state.player_name[i], gCurrent_graf_data->player_name_x[i], gCurrent_graf_data->player_name_y, eRT_alpha);
  75.     }
  76. }
  77.  
  78. // IDA: void __cdecl FrankAnneStart1()
  79. void FrankAnneStart1(void) {
  80.     LOG_TRACE("()");
  81.  
  82.     StartRollingPlayerNamesIn();
  83.     if (gFrank_flic_data == NULL) {
  84.         if (!LoadFlicData("FRANK.FLI", &gFrank_flic_data, &gFrank_flic_data_length)) {
  85.             FatalError(kFatalError_LoadOpponentMugShotFile);
  86.         }
  87.     } else {
  88.         MAMSLock((void**)&gFrank_flic_data);
  89.     }
  90.     if (!gAnne_flic_data) {
  91.         if (!LoadFlicData("ANNIE.FLI", &gAnne_flic_data, &gAnne_flic_data_length)) {
  92.             FatalError(kFatalError_LoadOpponentMugShotFile);
  93.         }
  94.     } else {
  95.         MAMSLock((void**)&gAnne_flic_data);
  96.     }
  97.     InitialiseFlicPanel(0,
  98.         gCurrent_graf_data->frank_panel_left,
  99.         gCurrent_graf_data->frank_panel_top,
  100.         gCurrent_graf_data->frank_panel_right - gCurrent_graf_data->frank_panel_left,
  101.         gCurrent_graf_data->frank_panel_bottom - gCurrent_graf_data->frank_panel_top);
  102.     InitialiseFlicPanel(1,
  103.         gCurrent_graf_data->anne_panel_left,
  104.         gCurrent_graf_data->anne_panel_top,
  105.         gCurrent_graf_data->anne_panel_right - gCurrent_graf_data->anne_panel_left,
  106.         gCurrent_graf_data->anne_panel_bottom - gCurrent_graf_data->anne_panel_top);
  107. }
  108.  
  109. // IDA: void __cdecl FrankAnneStart2()
  110. void FrankAnneStart2(void) {
  111.     LOG_TRACE("()");
  112.  
  113.     ChangePanelFlic(0, gFrank_flic_data, gFrank_flic_data_length);
  114.     ChangePanelFlic(1, gAnne_flic_data, gAnne_flic_data_length);
  115.     TellyInImage(GetPanelPixelmap(0), gCurrent_graf_data->frank_panel_left, gCurrent_graf_data->frank_panel_top);
  116.     TellyInImage(GetPanelPixelmap(1), gCurrent_graf_data->anne_panel_left, gCurrent_graf_data->anne_panel_top);
  117. }
  118.  
  119. // IDA: void __usercall GetPlayerName(int pStarting_to_type@<EAX>, int pCurrent_choice@<EDX>, char *pString@<EBX>, int *pMax_length@<ECX>)
  120. void GetPlayerName(int pStarting_to_type, int pCurrent_choice, char* pString, int* pMax_length) {
  121.     LOG_TRACE("(%d, %d, \"%s\", %p)", pStarting_to_type, pCurrent_choice, pString, pMax_length);
  122.  
  123.     strcpy(pString, gProgram_state.player_name[pCurrent_choice]);
  124.     *pMax_length = PLAYER_NAME_MAX_LENGTH;
  125. }
  126.  
  127. // IDA: int __usercall FrankAnneDone@<EAX>(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>, int pGo_ahead@<EBX>, int pEscaped@<ECX>, int pTimed_out)
  128. int FrankAnneDone(int pCurrent_choice, int pCurrent_mode, int pGo_ahead, int pEscaped, int pTimed_out) {
  129.     LOG_TRACE("(%d, %d, %d, %d, %d)", pCurrent_choice, pCurrent_mode, pGo_ahead, pEscaped, pTimed_out);
  130.  
  131.     RemoveTransientBitmaps(1);
  132.     TellyOutImage(GetPanelPixelmap(1), gCurrent_graf_data->anne_panel_left, gCurrent_graf_data->anne_panel_top);
  133.     TellyOutImage(GetPanelPixelmap(0), gCurrent_graf_data->frank_panel_left, gCurrent_graf_data->frank_panel_top);
  134.     if (gFrank_flic_data) {
  135.         MAMSUnlock((void**)&gFrank_flic_data);
  136.     }
  137.     if (gAnne_flic_data) {
  138.         MAMSUnlock((void**)&gAnne_flic_data);
  139.     }
  140.     gProgram_state.frank_or_anniness = pCurrent_choice;
  141.     GetTypedName(gProgram_state.player_name[pCurrent_choice], PLAYER_NAME_MAX_LENGTH);
  142.     return pCurrent_choice;
  143. }
  144.  
  145. // IDA: void __usercall FrankAnneDraw(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>)
  146. void FrankAnneDraw(int pCurrent_choice, int pCurrent_mode) {
  147.     LOG_TRACE9("(%d, %d)", pCurrent_choice, pCurrent_mode);
  148.  
  149.     if (gTyping) {
  150.         if (GetTotalTime() & 0x100) {
  151.             if (pCurrent_choice < 2) {
  152.                 TransDRPixelmapText(
  153.                     gBack_screen,
  154.                     gCurrent_graf_data->enter_name_x[pCurrent_choice],
  155.                     gCurrent_graf_data->enter_name_y,
  156.                     &gFonts[FONT_GRNLIT],
  157.                     GetMiscString(kMiscString_ENTER_NAME),
  158.                     gBack_screen->width);
  159.             }
  160.         }
  161.     }
  162. }
  163.  
  164. // IDA: int __cdecl FrankieOrAnnie()
  165. int FrankieOrAnnie(void) {
  166.     static tFlicette flicker_on[3] = {
  167.         { 83, { 61, 122 }, { 52, 125 } },
  168.         { 83, { 184, 398 }, { 52, 125 } },
  169.         { 43, { 215, 430 }, { 158, 379 } }
  170.     };
  171.     static tFlicette flicker_off[3] = {
  172.         { 82, { 61, 122 }, { 52, 125 } },
  173.         { 82, { 184, 398 }, { 52, 125 } },
  174.         { 42, { 215, 430 }, { 158, 379 } }
  175.     };
  176.     static tFlicette push[3] = {
  177.         { 83, { 61, 122 }, { 52, 125 } },
  178.         { 83, { 184, 398 }, { 52, 125 } },
  179.         { 45, { 215, 430 }, { 158, 379 } }
  180.     };
  181.     static tMouse_area mouse_areas[3] = {
  182.         { { 55, 110 }, { 52, 125 }, { 161, 322 }, { 154, 370 }, 0, 0, 0, NULL },
  183.         { { 178, 356 }, { 52, 125 }, { 295, 596 }, { 154, 370 }, 1, 0, 0, NULL },
  184.         { { 215, 430 }, { 158, 379 }, { 278, 556 }, { 179, 430 }, 2, 1, 1, NULL }
  185.     };
  186.     static tRectile recopy_areas[2] = {
  187.         { { 55, 110 }, { 132, 317 }, { 161, 322 }, { 154, 370 } },
  188.         { { 178, 356 }, { 132, 317 }, { 295, 590 }, { 154, 370 } }
  189.     };
  190.     static tInterface_spec interface_spec = {
  191.         0,               // initial_imode
  192.         80,              // first_opening_flic
  193.         0,               // second_opening_flic
  194.         81,              // end_flic_go_ahead
  195.         81,              // end_flic_escaped
  196.         81,              // end_flic_otherwise
  197.         0,               // flic_bunch_to_load
  198.         { -1, -1 },      // move_left_new_mode
  199.         { -1, 0 },       // move_left_delta
  200.         { 0, 2 },        // move_left_min
  201.         { 1, 2 },        // move_left_max
  202.         { NULL, NULL },  // move_left_proc
  203.         { -1, -1 },      // move_right_new_mode
  204.         { 1, 0 },        // move_right_delta
  205.         { 0, 2 },        // move_right_min
  206.         { 1, 2 },        // move_right_max
  207.         { NULL, NULL },  // move_right_proc
  208.         { 1, 0 },        // move_up_new_mode
  209.         { -2, -1 },      // move_up_delta
  210.         { 2, 1 },        // move_up_min
  211.         { 2, 1 },        // move_up_max
  212.         { NULL, NULL },  // move_up_proc
  213.         { 1, 0 },        // move_down_new_mode
  214.         { 2, -1 },       // move_down_delta
  215.         { 2, 1 },        // move_down_min
  216.         { 2, 1 },        // move_down_max
  217.         { NULL, NULL },  // move_down_proc
  218.         { 1, 1 },        // go_ahead_allowed
  219.         { NULL, NULL },  // go_ahead_proc
  220.         { 1, 1 },        // escape_allowed
  221.         { NULL, NULL },  // escape_proc
  222.         NULL,            // exit_proc
  223.         FrankAnneDraw,   // draw_proc
  224.         0,               // time_out
  225.         FrankAnneStart1, // start_proc1
  226.         FrankAnneStart2, // start_proc2
  227.         FrankAnneDone,   // done_proc
  228.         1,               // font_needed
  229.         { 1, 0 },        // typeable
  230.         GetPlayerName,   // get_original_string
  231.         2,               // escape_code
  232.         1,               // dont_save_or_load
  233.         3,               // number_of_button_flics
  234.         flicker_on,      // flicker_on_flics
  235.         flicker_off,     // flicker_off_flics
  236.         push,            // pushed_flics
  237.         3,               // number_of_mouse_areas
  238.         mouse_areas,     // mouse_areas
  239.         2,               // number_of_recopy_areas
  240.         recopy_areas     // recopy_areas
  241.     };
  242.  
  243.     int result;
  244.     LOG_TRACE("()");
  245.  
  246.     LoadFont(FONT_GRNLIT);
  247.     result = DoInterfaceScreen(&interface_spec, 0, gProgram_state.frank_or_anniness);
  248.     DisposeFlicPanel(1);
  249.     DisposeFlicPanel(0);
  250.     DisposeFont(FONT_GRNLIT);
  251.     return result < 2;
  252. }
  253.  
  254. // IDA: int __cdecl SelectSkillLevel()
  255. int SelectSkillLevel(void) {
  256.     static tFlicette flicker_on[4] = {
  257.         { 116, { 38, 76 }, { 55, 132 } },
  258.         { 119, { 36, 72 }, { 83, 199 } },
  259.         { 121, { 38, 76 }, { 111, 266 } },
  260.         { 43, { 227, 454 }, { 158, 379 } }
  261.     };
  262.  
  263.     static tFlicette flicker_off[4] = {
  264.         { 115, { 38, 76 }, { 55, 132 } },
  265.         { 118, { 36, 72 }, { 83, 199 } },
  266.         { 120, { 38, 76 }, { 111, 266 } },
  267.         { 42, { 227, 454 }, { 158, 379 } }
  268.     };
  269.  
  270.     static tFlicette push[4] = {
  271.         { 117, { 38, 76 }, { 55, 132 } },
  272.         { 117, { 36, 72 }, { 83, 199 } },
  273.         { 117, { 38, 76 }, { 111, 266 } },
  274.         { 45, { 227, 454 }, { 158, 379 } }
  275.     };
  276.     static tMouse_area mouse_areas[4] = {
  277.         { { 38, 76 }, { 55, 132 }, { 205, 410 }, { 69, 166 }, 0, 0, 0, NULL },
  278.         { { 36, 72 }, { 83, 199 }, { 205, 410 }, { 98, 235 }, 1, 0, 0, NULL },
  279.         { { 38, 76 }, { 111, 266 }, { 205, 410 }, { 125, 300 }, 2, 0, 0, NULL },
  280.         { { 227, 454 }, { 158, 379 }, { 290, 580 }, { 178, 427 }, 3, 0, 0, NULL }
  281.     };
  282.  
  283.     static tInterface_spec interface_spec = {
  284.         0,              // initial_imode
  285.         110,            // first_opening_flic
  286.         0,              // second_opening_flic
  287.         -1,             // end_flic_go_ahead
  288.         111,            // end_flic_escaped
  289.         -1,             // end_flic_otherwise
  290.         0,              // flic_bunch_to_load
  291.         { -1, 0 },      // move_left_new_mode
  292.         { 0, 0 },       // move_left_delta
  293.         { 0, 0 },       // move_left_min
  294.         { 0, 0 },       // move_left_max
  295.         { NULL, NULL }, // move_left_proc
  296.         { -1, 0 },      // move_right_new_mode
  297.         { 0, 0 },       // move_right_delta
  298.         { 0, 0 },       // move_right_min
  299.         { 0, 0 },       // move_right_max
  300.         { NULL, NULL }, // move_right_proc
  301.         { -1, 0 },      // move_up_new_mode
  302.         { -1, 0 },      // move_up_delta
  303.         { 0, 0 },       // move_up_min
  304.         { 3, 0 },       // move_up_max
  305.         { NULL, NULL }, // move_up_proc
  306.         { -1, 0 },      // move_down_new_mode
  307.         { 1, 0 },       // move_down_delta
  308.         { 0, 0 },       // move_down_min
  309.         { 3, 0 },       // move_down_max
  310.         { NULL, NULL }, // move_down_proc
  311.         { 1, 1 },       // go_ahead_allowed
  312.         { NULL, NULL }, // go_ahead_proc
  313.         { 1, 1 },       // escape_allowed
  314.         { NULL, NULL }, // escape_proc
  315.         NULL,           // exit_proc
  316.         NULL,           // draw_proc
  317.         0u,             // time_out
  318.         NULL,           // start_proc1
  319.         NULL,           // start_proc2
  320.         NULL,           // done_proc
  321.         0,              // font_needed
  322.         { 0, 0 },       // typeable
  323.         NULL,           // get_original_string
  324.         3,              // escape_code
  325.         1,              // dont_save_or_load
  326.         4,              // number_of_button_flics
  327.         flicker_on,     // flicker_on_flics
  328.         flicker_off,    // flicker_off_flics
  329.         push,           // pushed_flics
  330.         4,              // number_of_mouse_areas
  331.         mouse_areas,    // mouse_areas
  332.         0,              // number_of_recopy_areas
  333.         NULL            // recopy_areas
  334.     };
  335.  
  336.     int result;
  337.     LOG_TRACE("()");
  338.  
  339.     result = DoInterfaceScreen(&interface_spec, 0, gProgram_state.skill_level);
  340.     if (result > 2) {
  341.         return 0;
  342.     }
  343.     gProgram_state.skill_level = result;
  344.     return 1;
  345. }
  346.  
  347. // IDA: int __cdecl DoOnePlayerStart()
  348. int DoOnePlayerStart(void) {
  349.     int merrily_looping;
  350.     tProgram_state saved_state;
  351.     LOG_TRACE("()");
  352.  
  353.     if (OriginalCarmaCDinDrive()) {
  354.         memcpy(&saved_state, &gProgram_state, sizeof(tProgram_state));
  355.         do {
  356.             merrily_looping = FrankieOrAnnie();
  357.             if (!merrily_looping) {
  358.                 memcpy(&gProgram_state, &saved_state, sizeof(tProgram_state));
  359.                 return 0;
  360.             }
  361.             if ((harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo || harness_game_info.mode == eGame_splatpack_xmas_demo) && gProgram_state.frank_or_anniness != eFrankie) {
  362.                 DoFeatureUnavailableInDemo();
  363.                 memset(&gProgram_state, 0, sizeof(gProgram_state));
  364.                 return 0;
  365.             }
  366.  
  367.             if (SelectSkillLevel()) {
  368.                 DoGoToRaceAnimation();
  369.                 StartLoadingScreen();
  370.                 AboutToLoadFirstCar();
  371.                 PrintMemoryDump(0, "JUST BEFORE LOADING YOUR CAR");
  372.                 SwitchToRealResolution();
  373.                 LoadCar(
  374.                     gBasic_car_names[gProgram_state.frank_or_anniness],
  375.                     eDriver_local_human,
  376.                     &gProgram_state.current_car,
  377.                     gProgram_state.frank_or_anniness,
  378.                     gProgram_state.player_name[gProgram_state.frank_or_anniness],
  379.                     &gOur_car_storage_space);
  380.                 SwitchToLoresMode();
  381.                 SetCarStorageTexturingLevel(&gOur_car_storage_space, GetCarTexturingLevel(), eCTL_full);
  382.                 PrintMemoryDump(0, "IMMEDIATELY AFTER LOADING YOUR CAR");
  383.                 gNet_mode = eNet_mode_none;
  384.                 InitGame(0);
  385.                 merrily_looping = 0;
  386.             }
  387.         } while (merrily_looping);
  388.         UnlockBunchOfFlics(4);
  389.         return 1;
  390.     } else {
  391.         DoErrorInterface(kMiscString_PLEASE_INSERT_THE_CARMAGEDDON_CD);
  392.         return 0;
  393.     }
  394. }
  395.  
  396. // IDA: int __usercall NewNetGameUp@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
  397. int NewNetGameUp(int* pCurrent_choice, int* pCurrent_mode) {
  398.     int new_sel;
  399.     int i;
  400.     LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
  401.  
  402.     DRS3StartSound(gEffects_outlet, 3000);
  403.     if (*pCurrent_mode == 0) {
  404.         gLast_graph_sel__newgame = COUNT_OF(gGames_to_join);
  405.     }
  406.     new_sel = -1;
  407.     for (i = gLast_graph_sel__newgame - 1; i >= 0; i--) {
  408.         gLast_graph_sel__newgame = i;
  409.         if (gGames_to_join[i].game == NULL) {
  410.             continue;
  411.         }
  412.         if (!gGames_to_join[i].game->options.open_game && !gGames_to_join[i].game->no_races_yet) {
  413.             continue;
  414.         }
  415.         if (gGames_to_join[i].game->num_players > 5) {
  416.             continue;
  417.         }
  418.         new_sel = i;
  419.         break;
  420.     }
  421.     if (new_sel < 0) {
  422.         gLast_graph_sel__newgame = -1;
  423.         *pCurrent_choice = 0;
  424.         *pCurrent_mode = 0;
  425.     } else {
  426.         gLast_graph_sel__newgame = new_sel;
  427.         *pCurrent_choice = 2;
  428.         *pCurrent_mode = 1;
  429.     }
  430.     return 1;
  431. }
  432.  
  433. // IDA: int __usercall NewNetGameDown@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
  434. int NewNetGameDown(int* pCurrent_choice, int* pCurrent_mode) {
  435.     int new_sel;
  436.     int i;
  437.     LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
  438.  
  439.     DRS3StartSound(gEffects_outlet, 3000);
  440.     if (*pCurrent_mode == 0) {
  441.         gLast_graph_sel__newgame = -1;
  442.     }
  443.  
  444.     new_sel = -1;
  445.     for (i = gLast_graph_sel__newgame - 1; i < COUNT_OF(gGames_to_join); i++) {
  446.         gLast_graph_sel__newgame = i;
  447.         if (gGames_to_join[i].game == NULL) {
  448.             continue;
  449.         }
  450.         if (!gGames_to_join[i].game->options.open_game && !gGames_to_join[i].game->no_races_yet) {
  451.             continue;
  452.         }
  453.         if (gGames_to_join[i].game->num_players > 5) {
  454.             continue;
  455.         }
  456.         new_sel = i;
  457.         break;
  458.     }
  459.     if (new_sel < 0) {
  460.         gLast_graph_sel__newgame = -1;
  461.         *pCurrent_choice = 0;
  462.         *pCurrent_mode = 0;
  463.     } else {
  464.         gLast_graph_sel__newgame = new_sel;
  465.         *pCurrent_choice = 2;
  466.         *pCurrent_mode = 1;
  467.     }
  468.     return 1;
  469. }
  470.  
  471. // IDA: void __usercall DisposeJoinableGame(int pIndex@<EAX>)
  472. void DisposeJoinableGame(int pIndex) {
  473.     LOG_TRACE("(%d)", pIndex);
  474.  
  475.     NetDisposeGameDetails(gGames_to_join[pIndex].game);
  476.     gGames_to_join[pIndex].game = NULL;
  477. }
  478.  
  479. // IDA: void __usercall DrawAnItem(int pX@<EAX>, int pY_index@<EDX>, int pFont_index@<EBX>, char *pText@<ECX>)
  480. void DrawAnItem__newgame(int pX, int pY_index, int pFont_index, char* pText) {
  481.     LOG_TRACE("(%d, %d, %d, \"%s\")", pX, pY_index, pFont_index, pText);
  482.  
  483.     TransDRPixelmapText(gBack_screen,
  484.         pX,
  485.         gCurrent_graf_data->joinable_games_y + gCurrent_graf_data->joinable_games_y_pitch * pY_index,
  486.         &gFonts[pFont_index],
  487.         pText,
  488.         pX + DRTextWidth(&gFonts[pFont_index], pText));
  489. }
  490.  
  491. // IDA: void __usercall DrawColumnHeading(int pStr_index@<EAX>, int pX@<EDX>)
  492. void DrawColumnHeading__newgame(int pStr_index, int pX) {
  493.     LOG_TRACE("(%d, %d)", pStr_index, pX);
  494.  
  495.     TransDRPixelmapText(gBack_screen,
  496.         pX,
  497.         gCurrent_graf_data->joinable_games_y - gCurrent_graf_data->joinable_games_y_pitch,
  498.         &gFonts[kFont_GRYLIT],
  499.         GetMiscString(pStr_index),
  500.         pX + DRTextWidth(&gFonts[kFont_GRYLIT], GetMiscString(pStr_index)));
  501. }
  502.  
  503. // IDA: void __usercall DrawGames(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>)
  504. void DrawGames(int pCurrent_choice, int pCurrent_mode) {
  505.     int i;
  506.     int font_index;
  507.     int current_index;
  508.     int x_coord;
  509.     int y_coord;
  510.     char s[256];
  511.     //char* s2; // Pierre-Marie Baty -- unused variable
  512.     //char* s3; // Pierre-Marie Baty -- unused variable
  513.     LOG_TRACE("(%d, %d)", pCurrent_choice, pCurrent_mode);
  514.  
  515.     current_index = 0;
  516.     BrPixelmapRectangleFill(gBack_screen,
  517.         gCurrent_graf_data->joinable_games_sel_left,
  518.         gCurrent_graf_data->joinable_games_sel_top_marg + gCurrent_graf_data->joinable_games_y,
  519.         gCurrent_graf_data->joinable_games_sel_right - gCurrent_graf_data->joinable_games_sel_left,
  520.         (COUNT_OF(gGames_to_join) + 1) * gCurrent_graf_data->joinable_games_y_pitch + gCurrent_graf_data->joinable_games_sel_bot_marg,
  521.         0);
  522.     if (gMouse_in_use && pCurrent_mode) {
  523.         GetMousePosition(&x_coord, &y_coord);
  524.         gLast_graph_sel__newgame = -1;
  525.     }
  526.     DrawColumnHeading__newgame(kMiscString_NetworkGamesTableHeading_HOST, gCurrent_graf_data->joinable_games_x_1);
  527.     DrawColumnHeading__newgame(kMiscString_NetworkGamesTableHeading_GAME_TYPE, gCurrent_graf_data->joinable_games_x_2);
  528.     DrawColumnHeading__newgame(kMiscString_NetworkGamesTableHeading_PLAYERS, gCurrent_graf_data->joinable_games_x_3);
  529.     DrawColumnHeading__newgame(kMiscString_NetworkGamesTableHeading_STATUS, gCurrent_graf_data->joinable_games_x_4);
  530.     BrPixelmapLine(gBack_screen,
  531.         gCurrent_graf_data->joinable_games_sel_left,
  532.         gCurrent_graf_data->joinable_games_y + gFonts[kFont_GRYLIT].height + 1 - (TranslationMode() ? 2 : 0) - gCurrent_graf_data->joinable_games_y_pitch,
  533.         gCurrent_graf_data->joinable_games_sel_right - 1,
  534.         gCurrent_graf_data->joinable_games_y + gFonts[kFont_GRYLIT].height + 1 - (TranslationMode() ? 2 : 0) - gCurrent_graf_data->joinable_games_y_pitch,
  535.         6);
  536.     for (i = 0; i < COUNT_OF(gGames_to_join); i++) {
  537.         if (gGames_to_join[i].game == NULL) {
  538.             continue;
  539.         }
  540.         if (gGames_to_join[i].game->type < 0 || gGames_to_join[i].game->type >= eNet_game_type_count) {
  541.             continue;
  542.         }
  543.         if ((PDGetTotalTime() - gGames_to_join[i].time) >= 15000) {
  544.             DisposeJoinableGame(i);
  545.             continue;
  546.         }
  547.         if (gMouse_in_use
  548.             && pCurrent_mode != 0
  549.             && gGames_to_join[i].game != NULL
  550.             && (gGames_to_join[i].game->options.open_game || gGames_to_join[i].game->no_races_yet)
  551.             && gGames_to_join[i].game->num_players <= 5
  552.             && x_coord >= gCurrent_graf_data->joinable_games_sel_left
  553.             && x_coord <= gCurrent_graf_data->joinable_games_sel_right
  554.             && y_coord >= (gCurrent_graf_data->joinable_games_y + gCurrent_graf_data->joinable_games_sel_top_marg + current_index * gCurrent_graf_data->joinable_games_y_pitch)
  555.             && y_coord <= (gCurrent_graf_data->joinable_games_y + gCurrent_graf_data->joinable_games_sel_bot_marg + current_index * gCurrent_graf_data->joinable_games_y_pitch - 1)) {
  556.             gLast_graph_sel__newgame = i;
  557.         }
  558.         if (i == gLast_graph_sel__newgame) {
  559.             font_index = 10;
  560.         } else {
  561.             font_index = 9;
  562.         }
  563.         sprintf(s, "%s", gGames_to_join[i].game->host_name);
  564.         DrawAnItem__newgame(gCurrent_graf_data->joinable_games_x_1, current_index, font_index, s);
  565.         sprintf(s, "%s", GetMiscString(kMiscString_NetworkGameTypeNames_START + gGames_to_join[i].game->type));
  566.         DrawAnItem__newgame(gCurrent_graf_data->joinable_games_x_2, current_index, font_index, s);
  567.         sprintf(s, "%d", gGames_to_join[i].game->num_players);
  568.         DrawAnItem__newgame(gCurrent_graf_data->joinable_games_x_3, current_index, font_index, s);
  569.         sprintf(s, "%s, %s",
  570.             GetMiscString(kMiscString_NetworkGameStage_START + gGames_to_join[i].game->status.stage),
  571.             GetMiscString(kMiscString_NetworkGameOpenGame_START + gGames_to_join[i].game->options.open_game));
  572.         DrawAnItem__newgame(gCurrent_graf_data->joinable_games_x_4, current_index, font_index, s);
  573.         if (i == gLast_graph_sel__newgame) {
  574.             DrawRectangle(gBack_screen,
  575.                 gCurrent_graf_data->joinable_games_sel_left,
  576.                 gCurrent_graf_data->joinable_games_y + gCurrent_graf_data->joinable_games_sel_top_marg + gCurrent_graf_data->joinable_games_y_pitch * current_index,
  577.                 gCurrent_graf_data->joinable_games_sel_right - 1,
  578.                 gCurrent_graf_data->joinable_games_y + gCurrent_graf_data->joinable_games_sel_bot_marg + gCurrent_graf_data->joinable_games_y_pitch * current_index - 1,
  579.                 45);
  580.         }
  581.         current_index++;
  582.     }
  583.  
  584.     if (current_index != 0 && (gCurrent_game_selection == 0 || (gLast_graph_sel__newgame >= 0 && (gGames_to_join[gLast_graph_sel__newgame].game == NULL || (!gGames_to_join[gLast_graph_sel__newgame].game->options.open_game && !gGames_to_join[gLast_graph_sel__newgame].game->no_races_yet) || gGames_to_join[gLast_graph_sel__newgame].game->num_players > 5)))) {
  585.         gCurrent_game_selection = 1;
  586.         for (i = 0; i < COUNT_OF(gGames_to_join); i++) {
  587.             if (gGames_to_join[i].game != NULL && (gGames_to_join[i].game->options.open_game || gGames_to_join[i].game->no_races_yet) && gGames_to_join[i].game->num_players <= 5) {
  588.                 gLast_graph_sel__newgame = i;
  589.                 ChangeSelectionTo(2, 1);
  590.                 return;
  591.             }
  592.         }
  593.     }
  594.     if (pCurrent_mode != 0 &&
  595. #if defined(DETHRACE_FIX_BUGS)
  596.         (gLast_graph_sel__newgame >= 0) &&
  597. #endif
  598.         (current_index == 0
  599.             || gGames_to_join[gLast_graph_sel__newgame].game == NULL
  600.             || (!gGames_to_join[gLast_graph_sel__newgame].game->options.open_game && !gGames_to_join[gLast_graph_sel__newgame].game->no_races_yet)
  601.             || gGames_to_join[gLast_graph_sel__newgame].game->num_players > 5)) {
  602.         gLast_graph_sel__newgame = -1;
  603.         ChangeSelectionTo(0, 0);
  604.     }
  605. }
  606.  
  607. // IDA: void __cdecl InitGamesToJoin()
  608. void InitGamesToJoin(void) {
  609.     int i;
  610.     LOG_TRACE("()");
  611.  
  612.     for (i = 0; i < COUNT_OF(gGames_to_join); i++) {
  613.         gGames_to_join[i].game = NULL;
  614.     }
  615.     gLast_graph_sel__newgame = -1;
  616. }
  617.  
  618. // IDA: void __usercall DisposeJoinList(int pExemption@<EAX>)
  619. void DisposeJoinList(int pExemption) {
  620.     int i;
  621.     LOG_TRACE("(%d)", pExemption);
  622.  
  623.     for (i = 0; i < COUNT_OF(gGames_to_join); i++) {
  624.         if (i == pExemption) {
  625.             continue;
  626.         }
  627.         if (gGames_to_join[i].game != NULL) {
  628.             DisposeJoinableGame(i);
  629.         }
  630.     }
  631. }
  632.  
  633. // IDA: void __usercall AddToJoinList(tNet_game_details *pGame@<EAX>)
  634. void AddToJoinList(tNet_game_details* pGame) {
  635.     int i;
  636.     int slot_to_use;
  637.     tU32 this_game_ID;
  638.     LOG_TRACE("(%p)", pGame);
  639.  
  640.     slot_to_use = -1;
  641.     this_game_ID = NetExtractGameID(pGame);
  642.     for (i = 0; i < COUNT_OF(gGames_to_join); i++) {
  643.         if (gGames_to_join[i].game != NULL) {
  644.             if (NetExtractGameID(gGames_to_join[i].game) == this_game_ID) {
  645.                 DisposeJoinableGame(i);
  646.                 slot_to_use = i;
  647.                 break;
  648.             }
  649.         }
  650.     }
  651.     if (slot_to_use < 0) {
  652.         for (i = 0; i < COUNT_OF(gGames_to_join); i++) {
  653.             if (gGames_to_join[i].game == NULL) {
  654.                 slot_to_use = i;
  655.                 break;
  656.             }
  657.         }
  658.     }
  659.     if (slot_to_use >= 0) {
  660.         gGames_to_join[slot_to_use].game = pGame;
  661.         gGames_to_join[slot_to_use].time = PDGetTotalTime();
  662.     }
  663. }
  664.  
  665. // IDA: void __cdecl NewNetStart1()
  666. void NewNetStart1(void) {
  667.     LOG_TRACE("()");
  668.  
  669.     gTyping = 1;
  670.     SetSlotXY(0, gCurrent_graf_data->net_player_name_x, gCurrent_graf_data->net_player_name_y);
  671.     AddRollingString(gNet_player_name,
  672.         gCurrent_graf_data->net_player_name_x, gCurrent_graf_data->net_player_name_y, eRT_alpha);
  673. }
  674.  
  675. // IDA: void __cdecl NewNetStart2()
  676. void NewNetStart2(void) {
  677.     LOG_TRACE("()");
  678.  
  679.     gTyping_slot = 0;
  680.     StartTyping(0, gNet_player_name, 11);
  681. }
  682.  
  683. // IDA: void __usercall NewNetGetName(int pStarting_to_type@<EAX>, int pCurrent_choice@<EDX>, char *pString@<EBX>, int *pMax_length@<ECX>)
  684. void NewNetGetName(int pStarting_to_type, int pCurrent_choice, char* pString, int* pMax_length) {
  685.     LOG_TRACE("(%d, %d, \"%s\", %p)", pStarting_to_type, pCurrent_choice, pString, pMax_length);
  686.  
  687.     strcpy(pString, gNet_player_name);
  688.     *pMax_length = 10;
  689. }
  690.  
  691. // IDA: int __usercall NewNetDone@<EAX>(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>, int pGo_ahead@<EBX>, int pEscaped@<ECX>, int pTimed_out)
  692. int NewNetDone(int pCurrent_choice, int pCurrent_mode, int pGo_ahead, int pEscaped, int pTimed_out) {
  693.     LOG_TRACE("(%d, %d, %d, %d, %d)", pCurrent_choice, pCurrent_mode, pGo_ahead, pEscaped, pTimed_out);
  694.  
  695.     if (pCurrent_choice != 1) {
  696.         GetTypedName(gNet_player_name, 10);
  697.     }
  698.     return pCurrent_choice;
  699. }
  700.  
  701. // IDA: int __usercall NewNetGoAhead@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
  702. int NewNetGoAhead(int* pCurrent_choice, int* pCurrent_mode) {
  703.     LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
  704.  
  705.     return gLast_graph_sel__newgame >= 0;
  706. }
  707.  
  708. // IDA: tJoin_or_host_result __usercall JoinOrHostGame@<EAX>(tNet_game_details **pGame_to_join@<EAX>)
  709. tJoin_or_host_result JoinOrHostGame(tNet_game_details** pGame_to_join) {
  710.     static tFlicette flicker_on[2] = {
  711.         { 43, { 41, 122 }, { 164, 370 } },
  712.         { 43, { 230, 440 }, { 164, 370 } },
  713.     };
  714.     static tFlicette flicker_off[2] = {
  715.         { 42, { 41, 122 }, { 164, 370 } },
  716.         { 42, { 230, 440 }, { 164, 370 } },
  717.     };
  718.     static tFlicette push[2] = {
  719.         { 90, { 41, 122 }, { 164, 370 } },
  720.         { 45, { 230, 440 }, { 164, 370 } },
  721.     };
  722.     static tMouse_area mouse_areas[3] = {
  723.         { { 41, 122 }, { 164, 370 }, { 104, 326 }, { 184, 422 }, 0, 0, 1, NULL },
  724.         { { 230, 440 }, { 164, 370 }, { 293, 568 }, { 184, 422 }, 1, 0, 1, NULL },
  725.         { { 42, 94 }, { 57, 137 }, { 290, 556 }, { 150, 341 }, 2, 1, 1, NULL },
  726.     };
  727.     static tRectile recopy_areas[1] = {
  728.         {
  729.             { 124, 110 },
  730.             { 163, 317 },
  731.             { 212, 322 },
  732.             { 180, 370 },
  733.         },
  734.     };
  735.     static tInterface_spec interface_spec = {
  736.         0,
  737.         100,
  738.         0,
  739.         101,
  740.         101,
  741.         101,
  742.         -1,
  743.         { 0, -1 },
  744.         { -1, -1 },
  745.         { 0, 2 },
  746.         { 1, 2 },
  747.         { NULL, NULL },
  748.         { 0, -1 },
  749.         { 1, -1 },
  750.         { 0, 2 },
  751.         { 1, 2 },
  752.         { NULL, NULL },
  753.         { 1, -1 },
  754.         { 0, 0 },
  755.         { 2, 0 },
  756.         { 2, 0 },
  757.         { NewNetGameUp, NewNetGameUp },
  758.         { 1, -1 },
  759.         { 0, 0 },
  760.         { 2, 0 },
  761.         { 2, 0 },
  762.         { NewNetGameDown, NewNetGameDown },
  763.         { 1, 1 },
  764.         { NULL, NewNetGoAhead },
  765.         { 1, 1 },
  766.         { NULL, NULL },
  767.         NULL,
  768.         DrawGames,
  769.         0,
  770.         NewNetStart1,
  771.         NewNetStart2,
  772.         NewNetDone,
  773.         1,
  774.         { 1, 1 },
  775.         NewNetGetName,
  776.         1,
  777.         1,
  778.         COUNT_OF(flicker_on),
  779.         flicker_on,
  780.         flicker_off,
  781.         push,
  782.         COUNT_OF(mouse_areas),
  783.         mouse_areas,
  784.         COUNT_OF(recopy_areas),
  785.         recopy_areas,
  786.     };
  787.     int result;
  788.     LOG_TRACE("(%p)", pGame_to_join);
  789.  
  790.     gCurrent_game_selection = 0;
  791.     LoadFont(kFont_GRNDK);
  792.     LoadFont(kFont_GRNLIT);
  793.     LoadFont(kFont_GREENHED);
  794.     LoadFont(kFont_GRYLIT);
  795.     SetAlwaysTyping();
  796.     InitGamesToJoin();
  797.     NetStartProducingJoinList(AddToJoinList);
  798.     result = DoInterfaceScreen(&interface_spec, 0, 0);
  799.     ClearAlwaysTyping();
  800.     NetEndJoinList();
  801.     DisposeJoinList(gLast_graph_sel__newgame);
  802.     DisposeFont(kFont_GRNDK); // Pierre-Marie Baty -- replaced font number with symbol
  803.     DisposeFont(kFont_GRNLIT); // Pierre-Marie Baty -- replaced font number with symbol
  804.     DisposeFont(kFont_GREENHED); // Pierre-Marie Baty -- replaced font number with symbol
  805.     DisposeFont(kFont_GRYLIT); // Pierre-Marie Baty -- replaced font number with symbol
  806.     strcpy(gProgram_state.player_name[0], gNet_player_name);
  807.     SaveOptions();
  808.     switch (result) {
  809.     case 0:
  810.         return eJoin_or_host_host;
  811.     case 1:
  812.         return eJoin_or_host_cancel;
  813.     case 2:
  814.         *pGame_to_join = gGames_to_join[gLast_graph_sel__newgame].game;
  815.         return eJoin_or_host_join;
  816.     default:
  817.         return eJoin_or_host_cancel;
  818.     }
  819. }
  820.  
  821. // IDA: void __usercall GetNetOptions(tNet_game_options *pGame_options@<EAX>)
  822. void GetNetOptions(tNet_game_options* pGame_options) {
  823.     LOG_TRACE("(%p)", pGame_options);
  824.  
  825.     pGame_options->enable_text_messages = gRadio_bastards__newgame[0].current_value;
  826.     pGame_options->show_players_on_map = gRadio_bastards__newgame[1].current_value;
  827.     pGame_options->show_peds_on_map = gRadio_bastards__newgame[2].current_value;
  828.     pGame_options->show_powerups_on_map = gRadio_bastards__newgame[3].current_value;
  829.     pGame_options->powerup_respawn = gRadio_bastards__newgame[4].current_value;
  830.     pGame_options->open_game = !gRadio_bastards__newgame[5].current_value;
  831.     pGame_options->grid_start = !gRadio_bastards__newgame[6].current_value;
  832.     pGame_options->race_sequence_type = gRadio_bastards__newgame[7].current_value ? eNet_sequence_sequential : eNet_sequence_random;
  833.     pGame_options->random_car_choice = gRadio_bastards__newgame[8].current_value;
  834.     pGame_options->car_choice = gRadio_bastards__newgame[9].current_value;
  835.     pGame_options->starting_money_index = gRadio_bastards__newgame[10].current_value;
  836. }
  837.  
  838. // IDA: void __usercall SetNetOptions(tNet_game_options *pGame_options@<EAX>)
  839. void SetNetOptions(tNet_game_options* pGame_options) {
  840.     LOG_TRACE("(%p)", pGame_options);
  841.  
  842.     gRadio_bastards__newgame[0].current_value = pGame_options->enable_text_messages;
  843.     gRadio_bastards__newgame[1].current_value = pGame_options->show_players_on_map;
  844.     gRadio_bastards__newgame[2].current_value = pGame_options->show_peds_on_map;
  845.     gRadio_bastards__newgame[3].current_value = pGame_options->show_powerups_on_map;
  846.     gRadio_bastards__newgame[4].current_value = pGame_options->powerup_respawn;
  847.     gRadio_bastards__newgame[5].current_value = !pGame_options->open_game;
  848.     gRadio_bastards__newgame[6].current_value = !pGame_options->grid_start;
  849.     gRadio_bastards__newgame[7].current_value = pGame_options->race_sequence_type == eNet_sequence_sequential;
  850.     gRadio_bastards__newgame[8].current_value = pGame_options->random_car_choice;
  851.     gRadio_bastards__newgame[9].current_value = pGame_options->car_choice;
  852.     gRadio_bastards__newgame[10].current_value = pGame_options->starting_money_index;
  853. }
  854.  
  855. // IDA: void __usercall NetPlayCheckboxOn2(int pIndex@<EAX>)
  856. void NetPlayCheckboxOn2(int pIndex) {
  857.     LOG_TRACE("(%d)", pIndex);
  858.  
  859.     RunFlicAt(95,
  860.         gRadio_bastards__newgame[pIndex].left[0],
  861.         gRadio_bastards__newgame[pIndex].top + 1);
  862. }
  863.  
  864. // IDA: void __usercall NetPlayCheckboxOff2(int pIndex@<EAX>)
  865. void NetPlayCheckboxOff2(int pIndex) {
  866.     LOG_TRACE("(%d)", pIndex);
  867.  
  868.     RunFlicAt(96,
  869.         gRadio_bastards__newgame[pIndex].left[0],
  870.         gRadio_bastards__newgame[pIndex].top + 1);
  871. }
  872.  
  873. // IDA: void __usercall NetPlayCheckboxOn(int pIndex@<EAX>)
  874. void NetPlayCheckboxOn(int pIndex) {
  875.     LOG_TRACE("(%d)", pIndex);
  876.  
  877.     RemoveTransientBitmaps(1);
  878.     DontLetFlicFuckWithPalettes();
  879.     TurnFlicTransparencyOn();
  880.     NetPlayCheckboxOn2(pIndex);
  881.     TurnFlicTransparencyOff();
  882.     LetFlicFuckWithPalettes();
  883. }
  884.  
  885. // IDA: void __usercall NetPlayCheckboxOff(int pIndex@<EAX>)
  886. void NetPlayCheckboxOff(int pIndex) {
  887.     LOG_TRACE("(%d)", pIndex);
  888.  
  889.     RemoveTransientBitmaps(1);
  890.     DontLetFlicFuckWithPalettes();
  891.     TurnFlicTransparencyOn();
  892.     NetPlayCheckboxOff2(pIndex);
  893.     TurnFlicTransparencyOff();
  894.     LetFlicFuckWithPalettes();
  895. }
  896.  
  897. // IDA: void __usercall NetPlayRadioOn2(int pIndex@<EAX>, int pValue@<EDX>)
  898. void NetPlayRadioOn2(int pIndex, int pValue) {
  899.     LOG_TRACE("(%d, %d)", pIndex, pValue);
  900.  
  901.     RunFlicAt(288,
  902.         gRadio_bastards__newgame[pIndex].left[pValue],
  903.         gRadio_bastards__newgame[pIndex].top + 1);
  904. }
  905.  
  906. // IDA: void __usercall NetPlayRadioOff2(int pIndex@<EAX>, int pValue@<EDX>)
  907. void NetPlayRadioOff2(int pIndex, int pValue) {
  908.     LOG_TRACE("(%d, %d)", pIndex, pValue);
  909.  
  910.     RunFlicAt(287,
  911.         gRadio_bastards__newgame[pIndex].left[pValue],
  912.         gRadio_bastards__newgame[pIndex].top + 1);
  913. }
  914.  
  915. // IDA: void __usercall NetPlayRadioOn(int pIndex@<EAX>, int pValue@<EDX>)
  916. void NetPlayRadioOn(int pIndex, int pValue) {
  917.     LOG_TRACE("(%d, %d)", pIndex, pValue);
  918.  
  919.     RemoveTransientBitmaps(1);
  920.     DontLetFlicFuckWithPalettes();
  921.     TurnFlicTransparencyOn();
  922.     NetPlayRadioOn2(pIndex, pValue);
  923.     TurnFlicTransparencyOff();
  924.     LetFlicFuckWithPalettes();
  925. }
  926.  
  927. // IDA: void __usercall NetPlayRadioOff(int pIndex@<EAX>, int pValue@<EDX>)
  928. void NetPlayRadioOff(int pIndex, int pValue) {
  929.     LOG_TRACE("(%d, %d)", pIndex, pValue);
  930.  
  931.     RemoveTransientBitmaps(1);
  932.     DontLetFlicFuckWithPalettes();
  933.     TurnFlicTransparencyOn();
  934.     NetPlayRadioOff2(pIndex, pValue);
  935.     TurnFlicTransparencyOff();
  936.     LetFlicFuckWithPalettes();
  937. }
  938.  
  939. // IDA: void __cdecl DrawNOptInitialRadios()
  940. void DrawNOptInitialRadios(void) {
  941.     int i;
  942.     int j;
  943.     LOG_TRACE("()");
  944.  
  945.     RemoveTransientBitmaps(1);
  946.     DontLetFlicFuckWithPalettes();
  947.     TurnFlicTransparencyOn();
  948.     for (i = 0; i < COUNT_OF(gRadio_bastards__newgame); i++) {
  949.         if (gRadio_bastards__newgame[i].count < 2) {
  950.             if (gRadio_bastards__newgame[i].current_value) {
  951.                 NetPlayCheckboxOn2(i);
  952.             } else {
  953.                 NetPlayCheckboxOff2(i);
  954.             }
  955.         } else {
  956.             NetPlayRadioOn2(i, gRadio_bastards__newgame[i].current_value);
  957.             for (j = 0; j < gRadio_bastards__newgame[i].count; j++) {
  958.                 if (j != gRadio_bastards__newgame[i].current_value) {
  959.                     NetPlayRadioOff2(i, j);
  960.                 }
  961.             }
  962.         }
  963.     }
  964.     TurnFlicTransparencyOff();
  965.     LetFlicFuckWithPalettes();
  966. }
  967.  
  968. // IDA: void __usercall NetRadioChanged(int pIndex@<EAX>, int pNew_value@<EDX>)
  969. void NetRadioChanged(int pIndex, int pNew_value) {
  970.     LOG_TRACE("(%d, %d)", pIndex, pNew_value);
  971.  
  972.     NetPlayRadioOff(pIndex, gRadio_bastards__newgame[pIndex].current_value);
  973.     NetPlayRadioOn(pIndex, pNew_value);
  974.     gRadio_bastards__newgame[pIndex].current_value = pNew_value;
  975. }
  976.  
  977. // IDA: void __usercall NetCheckboxChanged(int pIndex@<EAX>)
  978. void NetCheckboxChanged(int pIndex) {
  979.     LOG_TRACE("(%d)", pIndex);
  980.  
  981.     if (gRadio_bastards__newgame[pIndex].current_value) {
  982.         NetPlayCheckboxOff(pIndex);
  983.     } else {
  984.         NetPlayCheckboxOn(pIndex);
  985.     }
  986.     gRadio_bastards__newgame[pIndex].current_value = !gRadio_bastards__newgame[pIndex].current_value;
  987. }
  988.  
  989. // IDA: int __usercall NetOptLeft@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
  990. int NetOptLeft(int* pCurrent_choice, int* pCurrent_mode) {
  991.     int new_value;
  992.     LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
  993.  
  994.     DRS3StartSound(gEffects_outlet, 3000);
  995.     if (gRadio_bastards__newgame[*pCurrent_choice - 3].count < 2) {
  996.         NetCheckboxChanged(*pCurrent_choice - 3);
  997.     } else {
  998.         new_value = gRadio_bastards__newgame[*pCurrent_choice - 3].current_value - 1;
  999.         if (new_value < 0) {
  1000.             new_value = gRadio_bastards__newgame[*pCurrent_choice - 3].count - 1;
  1001.         }
  1002.         NetRadioChanged(*pCurrent_choice - 3, new_value);
  1003.     }
  1004.     return 1;
  1005. }
  1006.  
  1007. // IDA: int __usercall NetOptRight@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
  1008. int NetOptRight(int* pCurrent_choice, int* pCurrent_mode) {
  1009.     int new_value;
  1010.     LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
  1011.  
  1012.     DRS3StartSound(gEffects_outlet, 3000);
  1013.     if (gRadio_bastards__newgame[*pCurrent_choice - 3].count < 2) {
  1014.         NetCheckboxChanged(*pCurrent_choice - 3);
  1015.     } else {
  1016.         new_value = gRadio_bastards__newgame[*pCurrent_choice - 3].current_value + 1;
  1017.         if (new_value == gRadio_bastards__newgame[*pCurrent_choice - 3].count) {
  1018.             new_value = 0;
  1019.         }
  1020.         NetRadioChanged(*pCurrent_choice - 3, new_value);
  1021.     }
  1022.     return 1;
  1023. }
  1024.  
  1025. // IDA: int __usercall NetOptUp@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
  1026. int NetOptUp(int* pCurrent_choice, int* pCurrent_mode) {
  1027.     LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
  1028.  
  1029.     if (*pCurrent_mode == 0) {
  1030.         *pCurrent_mode = 1;
  1031.         *pCurrent_choice = 13;
  1032.         DRS3StartSound(gEffects_outlet, 3000);
  1033.         return 1;
  1034.     } else if (*pCurrent_choice == 2) {
  1035.         *pCurrent_mode = 0;
  1036.         *pCurrent_choice = 0;
  1037.         DRS3StartSound(gEffects_outlet, 3000);
  1038.         return 1;
  1039.     } else {
  1040.         return 0;
  1041.     }
  1042. }
  1043.  
  1044. // IDA: int __usercall NetOptDown@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
  1045. int NetOptDown(int* pCurrent_choice, int* pCurrent_mode) {
  1046.     LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
  1047.  
  1048.     if (*pCurrent_mode == 0) {
  1049.         *pCurrent_mode = 1;
  1050.         *pCurrent_choice = 3;
  1051.         DRS3StartSound(gEffects_outlet, 3000);
  1052.         return 1;
  1053.     } else if (*pCurrent_choice == 14) {
  1054.         *pCurrent_mode = 0;
  1055.         *pCurrent_choice = 0;
  1056.         DRS3StartSound(gEffects_outlet, 3000);
  1057.         return 1;
  1058.     } else {
  1059.         return 0;
  1060.     }
  1061. }
  1062.  
  1063. // IDA: int __usercall NetRadioClick@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>, int pX_offset@<EBX>, int pY_offset@<ECX>)
  1064. int NetRadioClick(int* pCurrent_choice, int* pCurrent_mode, int pX_offset, int pY_offset) {
  1065.     int i;
  1066.     LOG_TRACE("(%p, %p, %d, %d)", pCurrent_choice, pCurrent_mode, pX_offset, pY_offset);
  1067.  
  1068.     if (gRadio_bastards__newgame[*pCurrent_choice - 3].count < 2) {
  1069.         NetCheckboxChanged(*pCurrent_choice - 3);
  1070.     } else {
  1071.         for (i = gRadio_bastards__newgame[*pCurrent_choice - 3].count - 1; i >= 0; i--) {
  1072.             if (gThe_interface_spec__newgame->mouse_areas[3].left[gGraf_data_index] + pX_offset + 3 >= gRadio_bastards__newgame[*pCurrent_choice - 3].left[i]) {
  1073.                 DRS3StartSound(gEffects_outlet, 3000);
  1074.                 NetRadioChanged(*pCurrent_choice - 3, i);
  1075.                 break;
  1076.             }
  1077.         }
  1078.     }
  1079.     return 0;
  1080. }
  1081.  
  1082. // IDA: void __cdecl RevertToDefaults()
  1083. void RevertToDefaults(void) {
  1084.     tPath_name the_path;
  1085.     FILE* f;
  1086.     tNet_game_options net_options;
  1087.     int i;
  1088.     LOG_TRACE("()");
  1089.  
  1090.     PathCat(the_path, gApplication_path, "NETDEFLT.TXT");
  1091.     f = DRfopen(the_path, "rt");
  1092.     if (f == NULL) {
  1093.         return;
  1094.     }
  1095.     for (i = 0; i < gLast_game_type + 1; i++) {
  1096.         ReadNetworkSettings(f, &net_options);
  1097.     }
  1098.     SetNetOptions(&net_options);
  1099.     DrawNOptInitialRadios();
  1100.     fclose(f);
  1101. }
  1102.  
  1103. // IDA: void __cdecl DefaultNetSettings()
  1104. void DefaultNetSettings(void) {
  1105.     FILE* f;
  1106.     int i;
  1107.     tPath_name the_path; // added
  1108.  
  1109.     PathCat(the_path, gApplication_path, "NETDEFLT.TXT");
  1110.     f = DRfopen(the_path, "rt");
  1111.     if (f == NULL) {
  1112.         return;
  1113.     }
  1114.     ReadNetworkSettings(f, gNet_settings);
  1115.     rewind(f);
  1116.     for (i = 0; i < COUNT_OF(gNet_settings) - 1; i++) {
  1117.         ReadNetworkSettings(f, &gNet_settings[i + 1]);
  1118.     }
  1119.     fclose(f);
  1120. }
  1121.  
  1122. // IDA: int __usercall NetOptGoAhead@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
  1123. int NetOptGoAhead(int* pCurrent_choice, int* pCurrent_mode) {
  1124.     LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
  1125.  
  1126.     if (*pCurrent_mode == 0) {
  1127.         if (*pCurrent_choice == 2) {
  1128.             RevertToDefaults();
  1129.             return 0;
  1130.         } else {
  1131.             return 1;
  1132.         }
  1133.     } else {
  1134.         NetOptRight(pCurrent_choice, pCurrent_mode);
  1135.         return 0;
  1136.     }
  1137. }
  1138.  
  1139. // IDA: void __usercall NetPlotAGraphBox(int pIndex@<EAX>, int pColour_value@<EDX>)
  1140. void NetPlotAGraphBox(int pIndex, int pColour_value) {
  1141.     LOG_TRACE("(%d, %d)", pIndex, pColour_value);
  1142.  
  1143.     if (pIndex >= 0) {
  1144.         DrawRRectangle(gBack_screen,
  1145.             gThe_interface_spec__newgame->mouse_areas[pIndex + 3].left[gGraf_data_index],
  1146.             gThe_interface_spec__newgame->mouse_areas[pIndex + 3].top[gGraf_data_index],
  1147.             gThe_interface_spec__newgame->mouse_areas[pIndex + 3].right[gGraf_data_index],
  1148.             gThe_interface_spec__newgame->mouse_areas[pIndex + 3].bottom[gGraf_data_index],
  1149.             pColour_value);
  1150.     }
  1151. }
  1152.  
  1153. // IDA: void __usercall NetDrawAGraphBox(int pIndex@<EAX>)
  1154. void NetDrawAGraphBox(int pIndex) {
  1155.     LOG_TRACE("(%d)", pIndex);
  1156.  
  1157.     NetPlotAGraphBox(pIndex, 45);
  1158. }
  1159.  
  1160. // IDA: void __usercall NetEraseAGraphBox(int pIndex@<EAX>)
  1161. void NetEraseAGraphBox(int pIndex) {
  1162.     LOG_TRACE("(%d)", pIndex);
  1163.  
  1164.     NetPlotAGraphBox(pIndex, 0);
  1165. }
  1166.  
  1167. // IDA: void __usercall DrawNetOptBox(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>)
  1168. void DrawNetOptBox(int pCurrent_choice, int pCurrent_mode) {
  1169.     LOG_TRACE("(%d, %d)", pCurrent_choice, pCurrent_mode);
  1170.  
  1171.     if (gRadio_selected != pCurrent_choice) {
  1172.         NetEraseAGraphBox(gRadio_selected - 3);
  1173.         NetDrawAGraphBox(pCurrent_choice - 3);
  1174.         gRadio_selected = pCurrent_choice;
  1175.     }
  1176. }
  1177.  
  1178. // IDA: void __usercall DoNetOptions(tNet_game_options *pGame_options@<EAX>)
  1179. void DoNetOptions(tNet_game_options* pGame_options) {
  1180.     static tFlicette flicker_on[14] = {
  1181.         { 43, { 169, 90 }, { 156, 398 } },
  1182.         { 43, { 236, 440 }, { 156, 398 } },
  1183.         { 43, { 37, 440 }, { 156, 398 } },
  1184.         { 68, { 81, 98 }, { 32, 86 } },
  1185.         { 75, { 81, 98 }, { 43, 108 } },
  1186.         { 77, { 81, 98 }, { 54, 130 } },
  1187.         { 79, { 81, 98 }, { 65, 161 } },
  1188.         { 112, { 81, 98 }, { 76, 182 } },
  1189.         { 127, { 81, 98 }, { 86, 214 } },
  1190.         { 129, { 81, 98 }, { 97, 235 } },
  1191.         { 134, { 81, 98 }, { 108, 266 } },
  1192.         { 137, { 81, 98 }, { 119, 288 } },
  1193.         { 139, { 81, 98 }, { 130, 310 } },
  1194.         { 143, { 81, 98 }, { 141, 331 } },
  1195.     };
  1196.     static tFlicette flicker_off[14] = {
  1197.         { 42, { 169, 90 }, { 156, 398 } },
  1198.         { 42, { 236, 440 }, { 156, 398 } },
  1199.         { 42, { 37, 440 }, { 156, 398 } },
  1200.         { 69, { 81, 98 }, { 32, 86 } },
  1201.         { 76, { 81, 98 }, { 43, 108 } },
  1202.         { 78, { 81, 98 }, { 54, 130 } },
  1203.         { 109, { 81, 98 }, { 65, 161 } },
  1204.         { 113, { 81, 98 }, { 76, 182 } },
  1205.         { 128, { 81, 98 }, { 86, 214 } },
  1206.         { 133, { 81, 98 }, { 97, 235 } },
  1207.         { 136, { 81, 98 }, { 108, 266 } },
  1208.         { 138, { 81, 98 }, { 119, 288 } },
  1209.         { 142, { 81, 98 }, { 130, 310 } },
  1210.         { 148, { 81, 98 }, { 141, 331 } },
  1211.     };
  1212.     static tFlicette push[14] = {
  1213.         { 154, { 169, 90 }, { 156, 398 } },
  1214.         { 45, { 236, 440 }, { 156, 398 } },
  1215.         { 67, { 37, 440 }, { 156, 398 } },
  1216.         { 68, { 81, 98 }, { 32, 86 } },
  1217.         { 75, { 81, 98 }, { 43, 108 } },
  1218.         { 77, { 81, 98 }, { 54, 130 } },
  1219.         { 79, { 81, 98 }, { 65, 161 } },
  1220.         { 112, { 81, 98 }, { 76, 182 } },
  1221.         { 127, { 81, 98 }, { 86, 214 } },
  1222.         { 129, { 81, 98 }, { 97, 235 } },
  1223.         { 134, { 81, 98 }, { 108, 266 } },
  1224.         { 137, { 81, 98 }, { 119, 288 } },
  1225.         { 139, { 81, 98 }, { 130, 310 } },
  1226.         { 143, { 81, 98 }, { 141, 331 } },
  1227.     };
  1228.     static tMouse_area mouse_areas[14] = {
  1229.         { { 169, 90 }, { 156, 396 }, { 232, 214 }, { 176, 444 }, 0, 0, 0, NULL },
  1230.         { { 236, 440 }, { 156, 396 }, { 299, 552 }, { 176, 444 }, 1, 0, 0, NULL },
  1231.         { { 37, 98 }, { 156, 84 }, { 100, 568 }, { 176, 103 }, 2, 0, 0, NULL },
  1232.         { { 61, 98 }, { 30, 106 }, { 270, 568 }, { 40, 125 }, 3, 1, 0, NetRadioClick },
  1233.         { { 61, 98 }, { 41, 127 }, { 270, 568 }, { 51, 146 }, 4, 1, 0, NetRadioClick },
  1234.         { { 61, 98 }, { 52, 158 }, { 270, 568 }, { 62, 178 }, 5, 1, 0, NetRadioClick },
  1235.         { { 61, 98 }, { 63, 180 }, { 270, 568 }, { 73, 199 }, 6, 1, 0, NetRadioClick },
  1236.         { { 61, 98 }, { 74, 192 }, { 270, 568 }, { 84, 230 }, 7, 1, 0, NetRadioClick },
  1237.         { { 61, 98 }, { 84, 233 }, { 270, 568 }, { 94, 252 }, 8, 1, 0, NetRadioClick },
  1238.         { { 61, 98 }, { 95, 264 }, { 270, 568 }, { 105, 283 }, 9, 1, 0, NetRadioClick },
  1239.         { { 61, 98 }, { 106, 286 }, { 270, 568 }, { 116, 305 }, 10, 1, 0, NetRadioClick },
  1240.         { { 61, 98 }, { 117, 307 }, { 270, 322 }, { 127, 326 }, 11, 1, 0, NetRadioClick },
  1241.         { { 61, 98 }, { 128, 329 }, { 270, 322 }, { 138, 348 }, 12, 1, 0, NetRadioClick },
  1242.         { { 61, 98 }, { 139, 358 }, { 270, 322 }, { 149, 377 }, 13, 1, 0, NetRadioClick },
  1243.     };
  1244.     static tInterface_spec interface_spec = {
  1245.         0, 65, 0, 66, 66, 66, -1,
  1246.         { -1, 0 }, { -1, 0 }, { 0, 3 }, { 2, 13 }, { NULL, NetOptLeft },
  1247.         { -1, 0 }, { 1, 0 }, { 0, 3 }, { 2, 13 }, { NULL, NetOptRight },
  1248.         { -1, -1 }, { 0, -1 }, { 0, 2 }, { 0, 13 }, { NetOptUp, NetOptUp },
  1249.         { -1, -1 }, { 1, 1 }, { 0, 3 }, { 0, 14 }, { NetOptDown, NetOptDown },
  1250.         { 1, 1 }, { NetOptGoAhead, NetOptGoAhead }, { 1, 1 }, { NULL, NULL },
  1251.         NULL, DrawNetOptBox, 0,
  1252.         NULL, DrawNOptInitialRadios, NULL, 0, { 0, 0 }, NULL, 1, 1,
  1253.         COUNT_OF(flicker_on), flicker_on, flicker_off, push,
  1254.         COUNT_OF(mouse_areas), mouse_areas,
  1255.         0, NULL
  1256.     };
  1257.     LOG_TRACE("(%p)", pGame_options);
  1258.  
  1259.     gThe_interface_spec__newgame = &interface_spec;
  1260.     gRadio_selected = -1;
  1261.     LoadFont(kFont_GRYLIT);
  1262.     SetNetOptions(pGame_options);
  1263.     if (DoInterfaceScreen(&interface_spec, 0, 0) == 0) {
  1264.         GetNetOptions(pGame_options);
  1265.     }
  1266.     DisposeFont(kFont_GRYLIT); // Pierre-Marie Baty -- replaced font number with symbol
  1267. }
  1268.  
  1269. // IDA: void __usercall PlayRadioOn(int pIndex@<EAX>)
  1270. //  Suffix added to avoid duplicate symbol
  1271. void PlayRadioOn__newgame(int pIndex) {
  1272.     LOG_TRACE("(%d)", pIndex);
  1273.  
  1274.     RunFlicAt(288,
  1275.         gThe_interface_spec__newgame->pushed_flics[pIndex + 4].x[gGraf_data_index],
  1276.         gThe_interface_spec__newgame->pushed_flics[pIndex + 4].y[gGraf_data_index]);
  1277. }
  1278.  
  1279. // IDA: void __usercall PlayRadioOff(int pIndex@<EAX>)
  1280. //  Suffix added to avoid duplicate symbol
  1281. void PlayRadioOff__newgame(int pIndex) {
  1282.     LOG_TRACE("(%d)", pIndex);
  1283.  
  1284.     RunFlicAt(287,
  1285.         gThe_interface_spec__newgame->pushed_flics[pIndex + 4].x[gGraf_data_index],
  1286.         gThe_interface_spec__newgame->pushed_flics[pIndex + 4].y[gGraf_data_index]);
  1287. }
  1288.  
  1289. // IDA: void __usercall SetOptions(tNet_game_type pGame_type@<EAX>, tNet_game_options *pGame_options@<EDX>)
  1290. void SetOptions(tNet_game_type pGame_type, tNet_game_options* pGame_options) {
  1291.     LOG_TRACE("(%d, %p)", pGame_type, pGame_options);
  1292.  
  1293.     pGame_options->show_players_on_map = gNet_settings[0].show_players_on_map;
  1294.     pGame_options->show_peds_on_map = gNet_settings[pGame_type + 1].show_peds_on_map;
  1295.     pGame_options->enable_text_messages = gNet_settings[0].enable_text_messages;
  1296.     pGame_options->powerup_respawn = gNet_settings[0].powerup_respawn;
  1297.     pGame_options->show_powerups_on_map = gNet_settings[0].show_powerups_on_map;
  1298.     pGame_options->open_game = gNet_settings[pGame_type + 1].open_game;
  1299.     pGame_options->grid_start = gNet_settings[pGame_type + 1].grid_start;
  1300.     pGame_options->random_car_choice = gNet_settings[0].random_car_choice;
  1301.     pGame_options->car_choice = gNet_settings[0].car_choice;
  1302.     pGame_options->starting_money_index = gNet_settings[0].starting_money_index;
  1303.     pGame_options->race_sequence_type = gNet_settings[0].race_sequence_type;
  1304. }
  1305.  
  1306. // IDA: void __cdecl DrawNetChooseInitial()
  1307. void DrawNetChooseInitial(void) {
  1308.     LOG_TRACE("()");
  1309.  
  1310.     PlayRadioOn__newgame(gLast_game_type);
  1311. }
  1312.  
  1313. // IDA: int __usercall NetChooseGoAhead@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
  1314. int NetChooseGoAhead(int* pCurrent_choice, int* pCurrent_mode) {
  1315.     LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
  1316.  
  1317.     if (*pCurrent_mode == 0) {
  1318.         return 1;
  1319.     } else {
  1320.         if (*pCurrent_choice - 4 != gLast_game_type) {
  1321.             RemoveTransientBitmaps(1);
  1322.             DontLetFlicFuckWithPalettes();
  1323.             TurnFlicTransparencyOn();
  1324.             PlayRadioOff__newgame(gLast_game_type);
  1325.             gLast_game_type = *pCurrent_choice - 4;
  1326.             PlayRadioOn__newgame(gLast_game_type);
  1327.             LoadRaces(gRace_list, &gNumber_of_races, gLast_game_type);
  1328.             SetOptions(gLast_game_type, gOptions);
  1329.             TurnFlicTransparencyOff();
  1330.             LetFlicFuckWithPalettes();
  1331.             if (gRace_index >= gNumber_of_races) {
  1332.                 gRace_index = PickNetRace(-1, gNet_race_sequence__newgame);
  1333.             }
  1334.             if (!gMouse_in_use) {
  1335.                 *pCurrent_mode = 0;
  1336.                 *pCurrent_choice = 0;
  1337.             }
  1338.         }
  1339.         return 0;
  1340.     }
  1341. }
  1342.  
  1343. // IDA: void __usercall PlotAGraphBox(int pIndex@<EAX>, int pColour_value@<EDX>)
  1344. // Suffix added to avoid duplicate symbol
  1345. void PlotAGraphBox__newgame(int pIndex, int pColour_value) {
  1346.     LOG_TRACE("(%d, %d)", pIndex, pColour_value);
  1347.  
  1348.     if (pIndex >= 0) {
  1349.         DrawRRectangle(gBack_screen,
  1350.             gThe_interface_spec__newgame->mouse_areas[pIndex].left[gGraf_data_index],
  1351.             gThe_interface_spec__newgame->mouse_areas[pIndex].top[gGraf_data_index],
  1352.             gThe_interface_spec__newgame->mouse_areas[pIndex].right[gGraf_data_index],
  1353.             gThe_interface_spec__newgame->mouse_areas[pIndex].bottom[gGraf_data_index],
  1354.             pColour_value);
  1355.     }
  1356. }
  1357.  
  1358. // IDA: void __usercall DrawAGraphBox(int pIndex@<EAX>)
  1359. // Suffix added to avoid duplicate symbol
  1360. void DrawAGraphBox__newgame(int pIndex) {
  1361.     LOG_TRACE("(%d)", pIndex);
  1362.  
  1363.     PlotAGraphBox__newgame(pIndex, 45);
  1364. }
  1365.  
  1366. // IDA: void __usercall EraseAGraphBox(int pIndex@<EAX>)
  1367. // Suffix added to avoid duplicate symbol
  1368. void EraseAGraphBox__newgame(int pIndex) {
  1369.     LOG_TRACE("(%d)", pIndex);
  1370.  
  1371.     PlotAGraphBox__newgame(pIndex, 0);
  1372. }
  1373.  
  1374. // IDA: void __usercall DrawNetChoose(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>)
  1375. void DrawNetChoose(int pCurrent_choice, int pCurrent_mode) {
  1376.     char s[256];
  1377.     tU32* k;
  1378.     int i;
  1379.     LOG_TRACE("(%d, %d)", pCurrent_choice, pCurrent_mode);
  1380.  
  1381.     if (gLast_net_choose_box >= 0) {
  1382.         EraseAGraphBox__newgame(gLast_net_choose_box);
  1383.     }
  1384.     if (pCurrent_mode != 0) {
  1385.         gLast_net_choose_box = pCurrent_choice;
  1386.         DrawAGraphBox__newgame(pCurrent_choice);
  1387.     } else {
  1388.         gLast_net_choose_box = -1;
  1389.     }
  1390.     BrPixelmapRectangleFill(gBack_screen,
  1391.         gCurrent_graf_data->net_descr_race_l,
  1392.         gCurrent_graf_data->net_choose_race_y,
  1393.         gCurrent_graf_data->net_descr_race_r - gCurrent_graf_data->net_descr_race_l,
  1394.         gFonts[kFont_GRNLIT].height + 1 - (TranslationMode() ? 2 : 0), 0);
  1395.     sprintf(s, "%s %s", GetMiscString(kMiscString_FIRST_RACE), gRace_list[gRace_index].name);
  1396.     DRPixelmapCentredText(gBack_screen,
  1397.         gCurrent_graf_data->net_choose_race_x,
  1398.         gCurrent_graf_data->net_choose_race_y,
  1399.         &gFonts[kFont_GRNLIT], s);
  1400.     BrPixelmapRectangleFill(gBack_screen,
  1401.         gCurrent_graf_data->net_descr_race_l,
  1402.         gCurrent_graf_data->net_descr_race_top - (TranslationMode() ? 2 : 0),
  1403.         gCurrent_graf_data->net_descr_race_r - gCurrent_graf_data->net_descr_race_l,
  1404.         gCurrent_graf_data->net_descr_race_bot - gCurrent_graf_data->net_descr_race_top,
  1405.         0);
  1406.     OoerrIveGotTextInMeBoxMissus(9,
  1407.         GetMiscString(kMiscString_NetworkGameTypeDescriptions_START + (pCurrent_mode ? pCurrent_choice - 4 : gLast_game_type)),
  1408.         gBack_screen,
  1409.         gCurrent_graf_data->net_descr_race_l,
  1410.         gCurrent_graf_data->net_descr_race_top,
  1411.         gCurrent_graf_data->net_descr_race_r,
  1412.         gCurrent_graf_data->net_descr_race_bot,
  1413.         1);
  1414.     k = KevKeyService();
  1415.     if (k[0] == 0x2212d981 && k[1] == 0x90e8cf51) {
  1416.         DRS3StartSound(gEffects_outlet, 3202);
  1417.         DRS3StartSound(gEffects_outlet, 3202);
  1418.         for (i = 0; i < gNumber_of_racers; i++) {
  1419.             if (gOpponents[i].network_availability == eNet_avail_never) {
  1420.                 gOpponents[i].network_availability = eNet_avail_all;
  1421.             }
  1422.         }
  1423.     }
  1424. }
  1425.  
  1426. // IDA: int __usercall NetChooseLR@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
  1427. int NetChooseLR(int* pCurrent_choice, int* pCurrent_mode) {
  1428.     LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
  1429.  
  1430.     *pCurrent_choice = gLast_game_type + 4;
  1431.     return 0;
  1432. }
  1433.  
  1434. // IDA: void __usercall SetGameTarget(tNet_game_type *pGame_type@<EAX>, tNet_game_options *pGame_options@<EDX>)
  1435. void SetGameTarget(tNet_game_type* pGame_type, tNet_game_options* pGame_options) {
  1436.     LOG_TRACE("(%p, %p)", pGame_type, pGame_options);
  1437.  
  1438.     pGame_options->race_end_target = gNet_target[*pGame_type];
  1439.     switch (*pGame_type) {
  1440.     case eNet_game_type_car_crusher:
  1441.         pGame_options->race_end_target = gNet_target[*pGame_type];
  1442.         break;
  1443.     case eNet_game_type_tag:
  1444.         pGame_options->race_end_target = 1000 * gNet_target[*pGame_type];
  1445.         break;
  1446.     case eNet_game_type_foxy:
  1447.         pGame_options->race_end_target = 1000 * gNet_target[*pGame_type];
  1448.         break;
  1449.     default:
  1450.         pGame_options->race_end_target = gNet_target[*pGame_type];
  1451.         break;
  1452.     }
  1453. }
  1454.  
  1455. // IDA: int __usercall NetGameChoices@<EAX>(tNet_game_type *pGame_type@<EAX>, tNet_game_options *pGame_options@<EDX>, int *pRace_index@<EBX>)
  1456. int NetGameChoices(tNet_game_type* pGame_type, tNet_game_options* pGame_options, int* pRace_index) {
  1457.     static tFlicette flicker_on[11] = {
  1458.         { 43, { 226, 90 }, { 117, 398 } },
  1459.         { 43, { 226, 440 }, { 148, 398 } },
  1460.         { 43, { 226, 98 }, { 42, 86 } },
  1461.         { 43, { 226, 98 }, { 74, 108 } },
  1462.         { 162, { 74, 98 }, { 73, 130 } },
  1463.         { 163, { 74, 98 }, { 83, 161 } },
  1464.         { 164, { 74, 98 }, { 93, 182 } },
  1465.         { 165, { 74, 98 }, { 103, 214 } },
  1466.         { 166, { 74, 98 }, { 113, 235 } },
  1467.         { 167, { 74, 98 }, { 123, 266 } },
  1468.         { 168, { 74, 98 }, { 133, 288 } },
  1469.     };
  1470.     static tFlicette flicker_off[11] = {
  1471.         { 42, { 226, 90 }, { 117, 398 } },
  1472.         { 42, { 226, 440 }, { 148, 398 } },
  1473.         { 42, { 226, 98 }, { 42, 86 } },
  1474.         { 42, { 226, 98 }, { 74, 108 } },
  1475.         { 182, { 74, 98 }, { 73, 130 } },
  1476.         { 183, { 74, 98 }, { 83, 161 } },
  1477.         { 184, { 74, 98 }, { 93, 182 } },
  1478.         { 185, { 74, 98 }, { 103, 214 } },
  1479.         { 186, { 74, 98 }, { 113, 235 } },
  1480.         { 187, { 74, 98 }, { 123, 266 } },
  1481.         { 188, { 74, 98 }, { 133, 288 } },
  1482.     };
  1483.     static tFlicette push[11] = {
  1484.         { 88, { 227, 90 }, { 117, 398 } },
  1485.         { 45, { 226, 440 }, { 148, 398 } },
  1486.         { 195, { 227, 98 }, { 42, 86 } },
  1487.         { 124, { 226, 98 }, { 74, 108 } },
  1488.         { 162, { 74, 98 }, { 73, 130 } },
  1489.         { 163, { 74, 98 }, { 83, 161 } },
  1490.         { 164, { 74, 98 }, { 93, 182 } },
  1491.         { 165, { 74, 98 }, { 103, 214 } },
  1492.         { 166, { 74, 98 }, { 113, 235 } },
  1493.         { 167, { 74, 98 }, { 123, 266 } },
  1494.         { 168, { 74, 98 }, { 133, 288 } },
  1495.     };
  1496.     static tMouse_area mouse_areas[11] = {
  1497.         { { 226, 90 }, { 117, 396 }, { 290, 214 }, { 137, 444 }, 0, 0, 0, NULL },
  1498.         { { 226, 440 }, { 148, 396 }, { 290, 552 }, { 168, 444 }, 1, 0, 0, NULL },
  1499.         { { 226, 98 }, { 42, 84 }, { 290, 568 }, { 62, 103 }, 2, 0, 0, NULL },
  1500.         { { 226, 98 }, { 74, 106 }, { 290, 568 }, { 94, 125 }, 3, 0, 0, NULL },
  1501.         { { 53, 98 }, { 71, 127 }, { 211, 568 }, { 79, 146 }, 4, 1, 0, NULL },
  1502.         { { 53, 98 }, { 81, 158 }, { 211, 568 }, { 89, 178 }, 5, 1, 0, NULL },
  1503.         { { 53, 98 }, { 91, 180 }, { 211, 568 }, { 99, 199 }, 6, 1, 0, NULL },
  1504.         { { 53, 98 }, { 101, 192 }, { 211, 568 }, { 109, 230 }, 7, 1, 0, NULL },
  1505.         { { 53, 98 }, { 111, 233 }, { 211, 568 }, { 119, 252 }, 8, 1, 0, NULL },
  1506.         { { 53, 98 }, { 121, 264 }, { 211, 568 }, { 129, 283 }, 9, 1, 0, NULL },
  1507.         { { 53, 98 }, { 131, 264 }, { 211, 568 }, { 139, 283 }, 10, 1, 0, NULL },
  1508.     };
  1509.     static tInterface_spec interface_spec = {
  1510.         0, 122, 0, 0, 0, 0, -1,
  1511.         { 1, 0 }, { 4, -10 }, { 4, 0 }, { 4, 0 }, { NetChooseLR, NULL },
  1512.         { 1, 0 }, { 3, -10 }, { 4, 0 }, { 4, 0 }, { NetChooseLR, NULL },
  1513.         { -1, -1 }, { -1, -1 }, { 0, 4 }, { 3, 10 }, { NULL, NULL },
  1514.         { -1, -1 }, { 1, 1 }, { 0, 4 }, { 3, 10 }, { NULL, NULL },
  1515.         { 1, 1 }, { NetChooseGoAhead, NetChooseGoAhead }, { 1, 1 }, { NULL, NULL },
  1516.         NULL, DrawNetChoose, 0, NULL, DrawNetChooseInitial, NULL, 0, { 0, 0 }, NULL,
  1517.         1, 1,
  1518.         COUNT_OF(flicker_on), flicker_on, flicker_off, push,
  1519.         COUNT_OF(mouse_areas), mouse_areas,
  1520.         0, NULL
  1521.  
  1522.     };
  1523.     int result;
  1524.     LOG_TRACE("(%p, %p, %p)", pGame_type, pGame_options, pRace_index);
  1525.  
  1526.     gRace_index = *pRace_index;
  1527.     gLast_game_type = *pGame_type;
  1528.     do {
  1529.         LoadFont(kFont_GRNLIT);
  1530.         LoadFont(kFont_GRNDK);
  1531.         gThe_interface_spec__newgame = &interface_spec;
  1532.         gLast_net_choose_box = -1;
  1533.         gOptions = pGame_options;
  1534.         gNet_race_sequence__newgame = pGame_options->race_sequence_type;
  1535.         result = DoInterfaceScreen(&interface_spec, 0, 0);
  1536.         if (result || !pGame_options->random_car_choice) {
  1537.             RunFlic(123);
  1538.         } else {
  1539.             FadePaletteDown();
  1540.         }
  1541.         DisposeFont(kFont_GRNDK); // Pierre-Marie Baty -- replaced font number with symbol
  1542.         DisposeFont(kFont_GRNLIT); // Pierre-Marie Baty -- replaced font number with symbol
  1543.         switch (result) {
  1544.         case 0:
  1545.             *pGame_type = gLast_game_type;
  1546.             *pRace_index = gRace_index;
  1547.             break;
  1548.         case 2:
  1549.             ChangeRace(&gRace_index, 1, pGame_options->race_sequence_type);
  1550.             break;
  1551.         case 3:
  1552.             DoNetOptions(pGame_options);
  1553.             break;
  1554.         }
  1555.     } while (result > 1);
  1556.     gLast_game_type = *pGame_type;
  1557.     gNet_settings[0] = *pGame_options;
  1558.     gNet_settings[gLast_game_type + 1] = *pGame_options;
  1559.     SaveOptions();
  1560.     SetGameTarget(pGame_type, pGame_options);
  1561.     return result == 0;
  1562. }
  1563.  
  1564. // IDA: void __usercall ReadNetGameChoices(tNet_game_type *pGame_type@<EAX>, tNet_game_options *pGame_options@<EDX>, int *pRace_index@<EBX>)
  1565. void ReadNetGameChoices(tNet_game_type* pGame_type, tNet_game_options* pGame_options, int* pRace_index) {
  1566.     LOG_TRACE("(%p, %p, %p)", pGame_type, pGame_options, pRace_index);
  1567.  
  1568.     *pGame_type = gLast_game_type;
  1569.     SetOptions(*pGame_type, pGame_options);
  1570.     SetGameTarget(pGame_type, pGame_options);
  1571.     *pRace_index = PickNetRace(-1, pGame_options->race_sequence_type);
  1572. }
  1573.  
  1574. // IDA: int __usercall ChooseStartRace@<EAX>(int *pRank@<EAX>)
  1575. int ChooseStartRace(int* pRank) {
  1576.     LOG_TRACE("(%p)", pRank);
  1577.  
  1578.     *pRank = 0;
  1579.     return 1;
  1580. }
  1581.  
  1582. // IDA: void __usercall SetUpOtherNetThings(tNet_game_details *pNet_game@<EAX>)
  1583. void SetUpOtherNetThings(tNet_game_details* pNet_game) {
  1584.     LOG_TRACE("(%p)", pNet_game);
  1585.  
  1586.     StartLoadingScreen();
  1587.     gProgram_state.skill_level = 1;
  1588.     InitGame(pNet_game->start_race);
  1589. }
  1590.  
  1591. // IDA: void __usercall RequestCarDetails(tNet_game_details *pNet_game@<EAX>)
  1592. void RequestCarDetails(tNet_game_details* pNet_game) {
  1593.     tNet_message* message;
  1594.     LOG_TRACE("(%p)", pNet_game);
  1595.  
  1596.     gReceived_car_details = 0;
  1597.     if (gNet_mode == eNet_mode_none) {
  1598.         gNet_mode = eNet_mode_thinking_about_it;
  1599.     }
  1600.     message = NetBuildMessage(NETMSGID_CARDETAILSREQ, 0);
  1601.     NetGuaranteedSendMessageToAddress(pNet_game, message, &pNet_game->pd_net_info.addr_in, NULL);
  1602. }
  1603.  
  1604. // IDA: int __cdecl PickARandomCar()
  1605. int PickARandomCar(void) {
  1606.     int i;
  1607.     int cars[120];
  1608.     int array_size;
  1609.     LOG_TRACE("()");
  1610.  
  1611.     array_size = 0;
  1612.     for (i = 0; i < gNumber_of_racers; i++) {
  1613.         if (gCar_details[i].ownership == eCar_owner_none) {
  1614.             cars[array_size] = i;
  1615.             array_size++;
  1616.             if (gOpponents[i].network_availability == eNet_avail_all) {
  1617.                 cars[array_size] = i;
  1618.                 array_size++;
  1619.             }
  1620.         }
  1621.     }
  1622.     return cars[IRandomBetween(0, array_size - 1)];
  1623. }
  1624.  
  1625. // IDA: void __usercall PollCarDetails(tNet_game_details *pNet_game@<EAX>)
  1626. void PollCarDetails(tNet_game_details* pNet_game) {
  1627.     LOG_TRACE("(%p)", pNet_game);
  1628.  
  1629.     if (gReceived_car_details) {
  1630.         RequestCarDetails(pNet_game);
  1631.     }
  1632. }
  1633.  
  1634. // IDA: void __usercall SetNetAvailability(tNet_game_options *pOptions@<EAX>)
  1635. void SetNetAvailability(tNet_game_options* pOptions) {
  1636.     int i;
  1637.     LOG_TRACE("(%p)", pOptions);
  1638.  
  1639.     for (i = 0; i < gNumber_of_racers; i++) {
  1640.         switch (gOpponents[i].network_availability) {
  1641.         case eNet_avail_never:
  1642.             gCar_details[i].ownership = eCar_owner_not_allowed;
  1643.             break;
  1644.         case eNet_avail_eagle:
  1645.             if (pOptions->car_choice == eNet_car_annie) {
  1646.                 gCar_details[i].ownership = eCar_owner_not_allowed;
  1647.             } else {
  1648.                 gCar_details[i].ownership = eCar_owner_none;
  1649.             }
  1650.             break;
  1651.         case eNet_avail_hawk:
  1652.             if (pOptions->car_choice == eNet_car_frankie) {
  1653.                 gCar_details[i].ownership = eCar_owner_not_allowed;
  1654.             } else {
  1655.                 gCar_details[i].ownership = eCar_owner_none;
  1656.             }
  1657.             break;
  1658.         case eNet_avail_all:
  1659.             if (pOptions->car_choice == eNet_car_all) {
  1660.                 gCar_details[i].ownership = eCar_owner_none;
  1661.             } else {
  1662.                 gCar_details[i].ownership = eCar_owner_not_allowed;
  1663.             }
  1664.         }
  1665.     }
  1666. }
  1667.  
  1668. // IDA: int __usercall ChooseNetCar@<EAX>(tNet_game_details *pNet_game@<EAX>, tNet_game_options *pOptions@<EDX>, int *pCar_index@<EBX>, int pIm_the_host_so_fuck_off@<ECX>)
  1669. int ChooseNetCar(tNet_game_details* pNet_game, tNet_game_options* pOptions, int* pCar_index, int pIm_the_host_so_fuck_off) {
  1670.     tS32 start_time;
  1671.     int i;
  1672.     int result;
  1673.     int car_index;
  1674.     //int the_car_index; // Pierre-Marie Baty -- unused variable
  1675.     LOG_TRACE("(%p, %p, %p, %d)", pNet_game, pOptions, pCar_index, pIm_the_host_so_fuck_off);
  1676.  
  1677.     if (!pOptions->random_car_choice || pIm_the_host_so_fuck_off) {
  1678.         gNet_options = pOptions;
  1679.         if (pIm_the_host_so_fuck_off) {
  1680.             SetNetAvailability(pOptions);
  1681.         } else {
  1682.             RequestCarDetails(pNet_game);
  1683.             start_time = PDGetTotalTime();
  1684.             while (!gReceived_car_details && PDGetTotalTime() - start_time < 10000) {
  1685.                 NetService(0);
  1686.             }
  1687.             gNet_mode = eNet_mode_none;
  1688.             if (!gReceived_car_details) {
  1689.                 gNet_mode = eNet_mode_none;
  1690.                 return 0;
  1691.             }
  1692.         }
  1693.         if (pOptions->random_car_choice) {
  1694.             *pCar_index = PickARandomCar();
  1695.             if (pIm_the_host_so_fuck_off && *pCar_index >= 0) {
  1696.                 gCar_details[*pCar_index].ownership = eCar_owner_someone;
  1697.             }
  1698.             result = 1;
  1699.         } else {
  1700.             if (*pCar_index < 0) {
  1701.                 *pCar_index = PickARandomCar();
  1702.                 car_index = 0;
  1703.                 for (i = 0; i < gNumber_of_racers; i++) {
  1704.                     if (gCar_details[i].ownership < eCar_owner_not_allowed) {
  1705.                         gProgram_state.cars_available[car_index] = i;
  1706.                         car_index++;
  1707.                     }
  1708.                 }
  1709.                 gProgram_state.number_of_cars = car_index;
  1710.             }
  1711.             result = ChangeCar(1, pCar_index, pNet_game);
  1712.             gNet_mode = eNet_mode_none;
  1713.             if (pIm_the_host_so_fuck_off) {
  1714.                 gCar_details[*pCar_index].ownership = eCar_owner_someone;
  1715.             }
  1716.         }
  1717.     } else {
  1718.         result = 1;
  1719.     }
  1720.     return result;
  1721. }
  1722.  
  1723. // IDA: void __cdecl InitNetStorageSpace()
  1724. void InitNetStorageSpace(void) {
  1725.     int i;
  1726.     LOG_TRACE("()");
  1727.  
  1728.     for (i = 0; i < COUNT_OF(gNet_players); i++) {
  1729.         gCurrent_race.opponent_list[i].car_spec = NULL;
  1730.     }
  1731.     gNet_storage_allocated = 1;
  1732.     InitialiseStorageSpace(&gNet_cars_storage_space, 500, 50, 500, 300);
  1733. }
  1734.  
  1735. // IDA: void __cdecl DisposeNetStorageSpace()
  1736. void DisposeNetStorageSpace(void) {
  1737.     LOG_TRACE("()");
  1738.  
  1739.     if (gNet_storage_allocated) {
  1740.         DisposeStorageSpace(&gNet_cars_storage_space);
  1741.     }
  1742.     gNet_storage_allocated = 0;
  1743. }
  1744.  
  1745. // IDA: int __cdecl DoMultiPlayerStart()
  1746. int DoMultiPlayerStart(void) {
  1747.     tJoin_or_host_result result;
  1748.     tNet_game_details* game_to_join;
  1749.     char s[256];
  1750.     //char* s2; // Pierre-Marie Baty -- unused variable
  1751.     tNet_game_type new_game_type;
  1752.     tNet_game_options new_game_options;
  1753.     int start_rank;
  1754.     int car_index;
  1755.     //int race_index; // added by dethrace // Pierre-Marie Baty -- unused variable
  1756.     LOG_TRACE("()");
  1757.  
  1758.     if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo || harness_game_info.mode == eGame_splatpack_xmas_demo) {
  1759.         SuspendPendingFlic();
  1760.         DoFeatureUnavailableInDemo();
  1761.         return 0;
  1762.     }
  1763.  
  1764.     if (gAusterity_mode) {
  1765.         NetFullScreenMessage(kMiscString_NOT_ENOUGH_MEMORY, 0);
  1766.         return 0;
  1767.     }
  1768.     if (NetInitialise()) {
  1769.         SuspendPendingFlic();
  1770.         DoErrorInterface(kMiscString_NetworkPlayIsNotAvailable);
  1771.         return 0;
  1772.     }
  1773.     gSynch_race_start = 0;
  1774.     gPending_race = -1;
  1775.     gCurrent_race.number_of_racers = 0;
  1776.     gAsk_time = 0;
  1777.     AboutToLoadFirstCar();
  1778.     result = JoinOrHostGame(&game_to_join);
  1779.     switch (result) {
  1780.     case eJoin_or_host_cancel:
  1781.         return 0;
  1782.     case eJoin_or_host_join:
  1783.         gProgram_state.frank_or_anniness = eFrankie;
  1784.         if (!CarmaCDinDriveOrFullGameInstalled()) {
  1785.             DoErrorInterface(kMiscString_PLEASE_INSERT_THE_CARMAGEDDON_CD);
  1786.             return 0;
  1787.         }
  1788.         car_index = -1;
  1789.         // Abusing 'start_rank' here, it's probably better to introduce a new variable name (e.g. join_result)
  1790.         start_rank = -4;
  1791.         while (start_rank == -4) {
  1792.             start_rank = 0;
  1793.             if (!ChooseNetCar(game_to_join, &game_to_join->options, &car_index, 0)) {
  1794.                 continue;
  1795.             }
  1796.             StartLoadingScreen();
  1797.             InitNetStorageSpace();
  1798.             start_rank = NetJoinGame(game_to_join, gProgram_state.player_name[0], car_index);
  1799.             if (start_rank == 0) {
  1800.                 LoadRaces(gRace_list, &gNumber_of_races, gCurrent_net_game->type);
  1801.                 SetUpOtherNetThings(game_to_join);
  1802.                 ReenableNetService();
  1803.                 strcpy(s, gProgram_state.player_name[0]);
  1804.                 strcat(s, " ");
  1805.                 strcat(s, GetMiscString(kMiscString_HasJoinedTheGame));
  1806.                 NetSendHeadupToAllPlayers(s);
  1807.                 start_rank = 1;
  1808.             } else {
  1809.                 DisposeNetStorageSpace();
  1810.             }
  1811.         }
  1812.         if (start_rank <= 0) {
  1813.             NetDisposeGameDetails(game_to_join);
  1814.             return 0;
  1815.         } else {
  1816.             return 1;
  1817.         }
  1818.     case eJoin_or_host_host:
  1819. #if defined(DETHRACE_FIX_BUGS)
  1820.         /* Don't allow hosting a game when the game is launched with --no-bind */
  1821.         if (harness_game_config.no_bind) {
  1822.             DoErrorInterface(76);
  1823.             return 0;
  1824.         }
  1825. #endif
  1826.         gProgram_state.frank_or_anniness = eFrankie;
  1827.         if (!OriginalCarmaCDinDrive()) {
  1828.             DoErrorInterface(kMiscString_PLEASE_INSERT_THE_CARMAGEDDON_CD);
  1829.             return 0;
  1830.         }
  1831.         car_index = -1;
  1832.         ReadNetGameChoices(&new_game_type, &new_game_options, &start_rank);
  1833.         LoadRaces(gRace_list, &gNumber_of_races, new_game_type);
  1834.         start_rank = PickNetRace(-1, new_game_options.race_sequence_type);
  1835.         if (NetGameChoices(&new_game_type, &new_game_options, &start_rank) != 0
  1836.             && ChooseNetCar(gCurrent_net_game, &new_game_options, &car_index, 1) != 0) {
  1837.             StartLoadingScreen();
  1838.             InitNetStorageSpace();
  1839.             if (NetHostGame(new_game_type, &new_game_options, start_rank, gProgram_state.player_name[0], car_index) != NULL) {
  1840.                 SetUpOtherNetThings(gCurrent_net_game);
  1841.                 ReenableNetService();
  1842.                 return 1;
  1843.             } else {
  1844.                 DisposeNetStorageSpace();
  1845.                 ReenableNetService();
  1846.                 NetLeaveGame(gCurrent_net_game);
  1847.                 return 0;
  1848.             }
  1849.         }
  1850.     default:
  1851.         return 0;
  1852.     }
  1853. }
  1854.