Subversion Repositories Games.Carmageddon

Rev

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

  1. #include "network.h"
  2. #include "brender/brender.h"
  3. #include "car.h"
  4. #include "controls.h"
  5. #include "displays.h"
  6. #include "errors.h"
  7. #include "globvars.h"
  8. #include "globvrpb.h"
  9. #include "graphics.h"
  10. #include "harness/hooks.h"
  11. #include "harness/trace.h"
  12. #include "loading.h"
  13. #include "netgame.h"
  14. #include "newgame.h"
  15. #include "oil.h"
  16. #include "opponent.h"
  17. #include "pd/net.h"
  18. #include "pd/sys.h"
  19. #include "pedestrn.h"
  20. #include "piping.h"
  21. #include "powerup.h"
  22. #include "replay.h"
  23. #include "spark.h"
  24. #include "structur.h"
  25. #include "utility.h"
  26. #include "world.h"
  27. #include <stdlib.h>
  28.  
  29. tU32 gMess_max_flags;
  30. tU32 gMess_mid_flags;
  31. tU32 gMess_min_flags;
  32. tU32 gGuarantee_number;
  33. int gNet_service_disable = 0;
  34. int gIn_net_service = 0;
  35. int gPlayer_list_batch_number = 0;
  36. int gOnly_receive_guarantee_replies = 0;
  37. void* gMessage_to_free;
  38. tNet_message* gBroadcast_stack;
  39. tNet_message* gTo_host_stack;
  40. tU32 gLast_flush_message = 0;
  41. int gRace_only_flags[33] = {
  42.     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
  43.     1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1,
  44.     0
  45. };
  46. int gJoin_list_mode;
  47. tNet_game_player_info gNew_net_players[6];
  48. tGuaranteed_message gGuarantee_list[100]; // DOS debug symbols has this as [150]
  49. tMid_message* gMid_messages;
  50. tU32 gLast_player_list_received;
  51. tMin_message* gMin_messages;
  52. void (*gAdd_proc)(tNet_game_details*);
  53. int gReceiving_batch_number;
  54. int gReceiving_new_players;
  55. tMax_message* gMax_messages;
  56. int gNext_guarantee;
  57. tU32 gAsk_time;
  58. int gNet_initialised;
  59. int gDont_allow_joiners;
  60. tNet_game_details* gCurrent_join_poll_game;
  61. int gMessage_header_size;
  62. int gJoin_poll_index;
  63. int gJoin_request_denied;
  64. int gHost_died;
  65. int gCar_was_taken;
  66. int gBastard_has_answered;
  67. int gTime_for_next_one;
  68. int gReceived_game_scores;
  69.  
  70. #define MIN_MESSAGES_CAPACITY 20
  71. #define MID_MESSAGES_CAPACITY 10
  72. #define MAX_MESSAGES_CAPACITY 20
  73.  
  74. #define MAX_MESAGE_STACK_SIZE 512
  75.  
  76. // IDA: int __cdecl NetInitialise()
  77. int NetInitialise(void) {
  78.     int i;
  79.     LOG_TRACE("()");
  80.  
  81.     SwitchToRealResolution();
  82.     InitAbuseomatic();
  83.     gNet_service_disable = 0;
  84.     gIn_net_service = 0;
  85.     gMessage_header_size = PDNetGetHeaderSize();
  86.     gOnly_receive_guarantee_replies = 0;
  87.     gMin_messages = BrMemAllocate(MIN_MESSAGES_CAPACITY * (gMessage_header_size + sizeof(tMin_message)), kMem_net_min_messages);
  88.     gMid_messages = BrMemAllocate(MID_MESSAGES_CAPACITY * (gMessage_header_size + sizeof(tMid_message)), kMem_net_mid_messages);
  89.     gMax_messages = BrMemAllocate(MAX_MESSAGES_CAPACITY * (gMessage_header_size + sizeof(tMax_message)), kMem_net_max_messages);
  90.     for (i = 0; i < MIN_MESSAGES_CAPACITY; i++) {
  91.         ((tNet_message*)&gMin_messages[i])->contents.header.type = NETMSGID_NONE;
  92.     }
  93.     for (i = 0; i < MID_MESSAGES_CAPACITY; i++) {
  94.         ((tNet_message*)&gMid_messages[i])->contents.header.type = NETMSGID_NONE;
  95.     }
  96.     for (i = 0; i < MAX_MESSAGES_CAPACITY; i++) {
  97.         ((tNet_message*)&gMax_messages[i])->contents.header.type = NETMSGID_NONE;
  98.     }
  99.     gNet_initialised = PDNetInitialise() == 0;
  100.     if (gNet_initialised) {
  101.         InitNetHeadups();
  102.     }
  103.     GenerateItFoxShadeTable();
  104.     gDont_allow_joiners = 0;
  105.     SwitchToLoresMode();
  106.     return !gNet_initialised;
  107. }
  108.  
  109. // IDA: int __cdecl NetShutdown()
  110. int NetShutdown(void) {
  111.     int err;
  112.     //int i; // Pierre-Marie Baty -- unused variable
  113.     LOG_TRACE("()");
  114.  
  115.     err = PDNetShutdown();
  116.     DisposeAbuseomatic();
  117.     BrMemFree(gMin_messages);
  118.     BrMemFree(gMid_messages);
  119.     BrMemFree(gMax_messages);
  120.     DisposeNetHeadups();
  121.     return err;
  122. }
  123.  
  124. // IDA: void __cdecl ShutdownNetIfRequired()
  125. void ShutdownNetIfRequired(void) {
  126.     LOG_TRACE("()");
  127.  
  128.     if (gNet_initialised) {
  129.         NetShutdown();
  130.         gNet_initialised = 0;
  131.     }
  132. }
  133.  
  134. // IDA: void __cdecl DisableNetService()
  135. void DisableNetService(void) {
  136.     LOG_TRACE("()");
  137.  
  138.     gNet_service_disable = 1;
  139. }
  140.  
  141. // IDA: void __cdecl ReenableNetService()
  142. void ReenableNetService(void) {
  143.     LOG_TRACE("()");
  144.  
  145.     gNet_service_disable = 0;
  146. }
  147.  
  148. // IDA: int __cdecl PermitNetServiceReentrancy()
  149. int PermitNetServiceReentrancy(void) {
  150.     int prev;
  151.     LOG_TRACE("()");
  152.  
  153.     prev = !!gIn_net_service;
  154.     if (prev) {
  155.         gIn_net_service = 0;
  156.     }
  157.     return prev;
  158. }
  159.  
  160. // IDA: void __cdecl HaltNetServiceReentrancy()
  161. void HaltNetServiceReentrancy(void) {
  162.     LOG_TRACE("()");
  163.     NOT_IMPLEMENTED();
  164. }
  165.  
  166. // IDA: void __usercall NetSendHeadupToAllPlayers(char *pMessage@<EAX>)
  167. void NetSendHeadupToAllPlayers(char* pMessage) {
  168.     tNet_contents* the_contents;
  169.     LOG_TRACE("(\"%s\")", pMessage);
  170.  
  171.     if (gNet_mode) {
  172.         the_contents = NetGetBroadcastContents(NETMSGID_HEADUP, 0);
  173.         strcpy(the_contents->data.headup.text, pMessage);
  174.     }
  175. }
  176.  
  177. // IDA: void __usercall NetSendHeadupToEverybody(char *pMessage@<EAX>)
  178. void NetSendHeadupToEverybody(char* pMessage) {
  179.     //tNet_contents* the_contents; // Pierre-Marie Baty -- unused variable
  180.     LOG_TRACE("(\"%s\")", pMessage);
  181.     NOT_IMPLEMENTED();
  182. }
  183.  
  184. // IDA: void __usercall NetSendHeadupToPlayer(char *pMessage@<EAX>, tPlayer_ID pPlayer@<EDX>)
  185. void NetSendHeadupToPlayer(char* pMessage, tPlayer_ID pPlayer) {
  186.     //tNet_message* message; // Pierre-Marie Baty -- unused variable
  187.     LOG_TRACE("(\"%s\", %d)", pMessage, pPlayer);
  188.     NOT_IMPLEMENTED();
  189. }
  190.  
  191. // IDA: void __cdecl InitialisePlayerStati()
  192. void InitialisePlayerStati(void) {
  193.     int i;
  194.     LOG_TRACE("()");
  195.  
  196.     for (i = 0; i < COUNT_OF(gNet_players); i++) {
  197.         gNet_players[i].last_heard_from_him = PDGetTotalTime();
  198.         gNet_players[i].player_status = ePlayer_status_loading;
  199.     }
  200. }
  201.  
  202. // IDA: void __cdecl LeaveTempGame()
  203. void LeaveTempGame(void) {
  204.     LOG_TRACE("()");
  205.  
  206.     if (gCurrent_join_poll_game != NULL) {
  207.         NetLeaveGameLowLevel(gCurrent_join_poll_game);
  208.     }
  209.     gTime_for_next_one = 1;
  210.     gCurrent_join_poll_game = NULL;
  211. }
  212.  
  213. // IDA: void __cdecl DisposeCurrentJoinPollGame()
  214. void DisposeCurrentJoinPollGame(void) {
  215.     LOG_TRACE("()");
  216.  
  217.     if (gCurrent_join_poll_game != NULL) {
  218.         NetDisposeGameDetails(gCurrent_join_poll_game);
  219.         gCurrent_join_poll_game = NULL;
  220.     }
  221. }
  222.  
  223. // IDA: void __cdecl DoNextJoinPoll()
  224. void DoNextJoinPoll(void) {
  225.     tNet_message* the_message;
  226.     LOG_TRACE("()");
  227.  
  228.     if (gTime_for_next_one) {
  229.         gCurrent_join_poll_game = NetAllocatePIDGameDetails();
  230.         if (gCurrent_join_poll_game != NULL) {
  231.             if (PDNetGetNextJoinGame(gCurrent_join_poll_game, gJoin_poll_index)) {
  232.                 if (NetJoinGameLowLevel(gCurrent_join_poll_game, "!TEMP!")) {
  233.                     DisposeCurrentJoinPollGame();
  234.                 } else {
  235.                     gTime_for_next_one = 0;
  236.                     the_message = NetBuildMessage(NETMSGID_SENDMEDETAILS, 0);
  237.                     NetSendMessageToAddress(gCurrent_join_poll_game, the_message, gCurrent_join_poll_game);
  238.                     gBastard_has_answered = 0;
  239.                     gAsk_time = PDGetTotalTime();
  240.                 }
  241.                 gJoin_poll_index++;
  242.             } else {
  243.                 gJoin_poll_index = 0;
  244.                 if (gCurrent_join_poll_game != NULL) {
  245.                     DisposeCurrentJoinPollGame();
  246.                 }
  247.             }
  248.         }
  249.     } else {
  250.         if (gBastard_has_answered) {
  251.             gAdd_proc(gCurrent_join_poll_game);
  252.             LeaveTempGame();
  253.         } else {
  254.             if (PDGetTotalTime() - gAsk_time > 10000) {
  255.                 LeaveTempGame();
  256.                 DisposeCurrentJoinPollGame();
  257.             }
  258.         }
  259.     }
  260. }
  261.  
  262. // IDA: void __usercall NetStartProducingJoinList(void (*pAdd_proc)(tNet_game_details*)@<EAX>)
  263. void NetStartProducingJoinList(void (*pAdd_proc)(tNet_game_details*)) {
  264.     LOG_TRACE("(%p)", pAdd_proc);
  265.  
  266.     gAdd_proc = pAdd_proc;
  267.     gJoin_list_mode = 1;
  268.     gBastard_has_answered = 0;
  269.     gTime_for_next_one = 1;
  270.     gJoin_poll_index = 0;
  271.     gCurrent_join_poll_game = NULL;
  272.     PDNetStartProducingJoinList();
  273. }
  274.  
  275. // IDA: void __cdecl NetEndJoinList()
  276. void NetEndJoinList(void) {
  277.     LOG_TRACE("()");
  278.  
  279.     gJoin_list_mode = 0;
  280.     DisposeCurrentJoinPollGame();
  281.     LeaveTempGame();
  282.     PDNetEndJoinList();
  283. }
  284.  
  285. // IDA: void __usercall NetDisposePIDGameInfo(tNet_game_details *pDetails@<EAX>)
  286. void NetDisposePIDGameInfo(tNet_game_details* pDetails) {
  287.     LOG_TRACE("(%p)", pDetails);
  288.  
  289.     if (pDetails != NULL) {
  290.         BrMemFree(pDetails);
  291.     }
  292. }
  293.  
  294. // IDA: void __usercall NetDisposeGameDetails(tNet_game_details *pDetails@<EAX>)
  295. void NetDisposeGameDetails(tNet_game_details* pDetails) {
  296.     LOG_TRACE("(%p)", pDetails);
  297.  
  298.     // LOG_WARN("NetDisposeGameDetails(%p)", pDetails);
  299.     if (pDetails != NULL) {
  300.         NetDisposePIDGameInfo(pDetails);
  301.     }
  302. }
  303.  
  304. // IDA: tNet_game_details* __cdecl NetAllocatePIDGameDetails()
  305. tNet_game_details* NetAllocatePIDGameDetails(void) {
  306.     //tNet_game_details* game; // Pierre-Marie Baty -- unused variable
  307.     LOG_TRACE("()");
  308.  
  309.     return BrMemAllocate(sizeof(tNet_game_details), kMem_net_pid_details);
  310. }
  311.  
  312. // IDA: void __usercall NetLeaveGameLowLevel(tNet_game_details *pDetails@<EAX>)
  313. void NetLeaveGameLowLevel(tNet_game_details* pDetails) {
  314.     LOG_TRACE("(%p)", pDetails);
  315.  
  316.     if (gNet_mode == eNet_mode_host) {
  317.         PDNetHostFinishGame(gCurrent_net_game);
  318.     } else {
  319.         PDNetLeaveGame(pDetails);
  320.     }
  321. }
  322.  
  323. // IDA: void __usercall NetLeaveGame(tNet_game_details *pNet_game@<EAX>)
  324. void NetLeaveGame(tNet_game_details* pNet_game) {
  325.     tNet_message* the_message;
  326.     char s[256];
  327.     //char* s2; // Pierre-Marie Baty -- unused variable
  328.     int i;
  329.     int must_revert_reentrancy;
  330.     LOG_TRACE("(%p)", pNet_game);
  331.  
  332.     if (gNet_mode == eNet_mode_none) {
  333.         return;
  334.     }
  335.     gOnly_receive_guarantee_replies = 1;
  336.     if (gNet_mode == eNet_mode_host) {
  337.         gDont_allow_joiners = 1;
  338.         the_message = NetBuildMessage(NETMSGID_HOSTICIDE, 0);
  339.         must_revert_reentrancy = PermitNetServiceReentrancy();
  340.         NetGuaranteedSendMessageToAllPlayers(pNet_game, the_message, NULL);
  341.         if (must_revert_reentrancy) {
  342.             HaltNetServiceReentrancy();
  343.         }
  344.     } else if (!gHost_died) {
  345.         the_message = NetBuildMessage(NETMSGID_LEAVE, 0);
  346.         NetGuaranteedSendMessageToHost(pNet_game, the_message, NULL);
  347.         strcpy(s, gProgram_state.player_name[0]);
  348.         strcat(s, " ");
  349.         strcat(s, GetMiscString(kMiscString_HasLeftTheGame));
  350.         NetSendHeadupToAllPlayers(s);
  351.     }
  352.     for (i = 0; i < gNumber_of_net_players; i++) {
  353.         DisposeCarN(i);
  354.     }
  355.     ClearOutStorageSpace(&gOur_car_storage_space);
  356.     ClearOutStorageSpace(&gNet_cars_storage_space);
  357.     must_revert_reentrancy = PermitNetServiceReentrancy();
  358.     NetSendMessageStacks();
  359.     NetWaitForGuaranteeReplies();
  360.     NetLeaveGameLowLevel(gCurrent_net_game);
  361.     if (must_revert_reentrancy) {
  362.         HaltNetServiceReentrancy();
  363.     }
  364.     gCurrent_net_game = NULL;
  365.     gNet_mode = eNet_mode_none;
  366.     gNumber_of_net_players = 0;
  367.     gProgram_state.prog_status = eProg_idling;
  368.     gOnly_receive_guarantee_replies = 0;
  369. }
  370.  
  371. // IDA: void __usercall NetSetPlayerSystemInfo(tNet_game_player_info *pPlayer@<EAX>, void *pSender_address@<EDX>)
  372. void NetSetPlayerSystemInfo(tNet_game_player_info* pPlayer, void* pSender_address) {
  373.     LOG_TRACE("(%p, %p)", pPlayer, pSender_address);
  374.  
  375.     PDNetSetPlayerSystemInfo(pPlayer, pSender_address);
  376. }
  377.  
  378. // IDA: void __usercall NetDisposePlayer(tNet_game_player_info *pPlayer@<EAX>)
  379. void NetDisposePlayer(tNet_game_player_info* pPlayer) {
  380.     LOG_TRACE("(%p)", pPlayer);
  381.     NOT_IMPLEMENTED();
  382. }
  383.  
  384. // IDA: void __usercall FillInThisPlayer(tNet_game_details *pGame@<EAX>, tNet_game_player_info *pPlayer@<EDX>, int pCar_index@<EBX>, int pHost@<ECX>)
  385. void FillInThisPlayer(tNet_game_details* pGame, tNet_game_player_info* pPlayer, int pCar_index, int pHost) {
  386.     LOG_TRACE("(%p, %p, %d, %d)", pGame, pPlayer, pCar_index, pHost);
  387.  
  388.     pPlayer->host = pHost;
  389.     pPlayer->ID = NetExtractPlayerID(pGame);
  390.     strcpy(pPlayer->player_name, gProgram_state.player_name[0]);
  391.     pPlayer->this_players_time_stamp = PDGetTotalTime();
  392.     pPlayer->car_index = pCar_index;
  393.     pPlayer->reposition_time = 0;
  394.     pPlayer->last_waste_message = 0;
  395.     pPlayer->wasteage_attributed = 0;
  396.     pPlayer->name_not_clipped = 1;
  397.     pPlayer->played = 0;
  398.     pPlayer->won = 0;
  399.     pPlayer->games_score = 0;
  400.     pPlayer->race_stuff_initialised = 0;
  401.     if (pGame->options.random_car_choice && (pGame->options.car_choice == eNet_car_all || pGame->options.car_choice == eNet_car_both)) {
  402.         pPlayer->next_car_index = -1;
  403.     }
  404.     InitialisePlayerScore(pPlayer);
  405. }
  406.  
  407. // IDA: void __usercall LoadCarN(int pIndex@<EAX>, tNet_game_player_info *pPlayer@<EDX>)
  408. void LoadCarN(int pIndex, tNet_game_player_info* pPlayer) {
  409.     int switched_res;
  410.     LOG_TRACE("(%d, %p)", pIndex, pPlayer);
  411.  
  412.     pPlayer->car = BrMemAllocate(sizeof(tCar_spec), kMem_net_car_spec);
  413.     switched_res = SwitchToRealResolution();
  414.     LoadCar(gOpponents[pPlayer->car_index].car_file_name,
  415.         eDriver_net_human,
  416.         pPlayer->car,
  417.         pPlayer->car_index,
  418.         pPlayer->player_name,
  419.         &gNet_cars_storage_space);
  420.     if (switched_res) {
  421.         SwitchToLoresMode();
  422.     }
  423.     InitialiseCar(pPlayer->car);
  424.     if (pPlayer->player_status < ePlayer_status_racing) {
  425.         pPlayer->car->disabled = 1;
  426.     }
  427.     SetCarStorageTexturingLevel(&gNet_cars_storage_space, GetCarTexturingLevel(), eCTL_full);
  428. }
  429.  
  430. // IDA: void __usercall DisposeCarN(int pIndex@<EAX>)
  431. void DisposeCarN(int pIndex) {
  432.     int i;
  433.     int j;
  434.     LOG_TRACE("(%d)", pIndex);
  435.  
  436.     for (i = 0; i < gCurrent_race.number_of_racers; i++) {
  437.         if (gCurrent_race.opponent_list[i].car_spec == gNet_players[pIndex].car) {
  438.             gCurrent_race.number_of_racers--;
  439.             for (j = i; j < gCurrent_race.number_of_racers; j++) {
  440.                 gCurrent_race.opponent_list[j].index = gCurrent_race.opponent_list[j + 1].index;
  441.                 gCurrent_race.opponent_list[j].ranking = gCurrent_race.opponent_list[j + 1].ranking;
  442.                 gCurrent_race.opponent_list[j].net_player_index = gCurrent_race.opponent_list[j + 1].net_player_index;
  443.                 gCurrent_race.opponent_list[j].car_spec = gCurrent_race.opponent_list[j + 1].car_spec;
  444.             }
  445.         }
  446.     }
  447.     if (gProgram_state.racing) {
  448.         DisposeKevStuffCar(gNet_players[pIndex].car);
  449.     }
  450.     DisposeCar(gNet_players[pIndex].car, gNet_players[pIndex].car_index);
  451.     if (gThis_net_player_index != pIndex) {
  452.         BrMemFree(gNet_players[pIndex].car);
  453.     }
  454.     if (gAction_replay_mode) {
  455.         ToggleReplay();
  456.     }
  457.     ResetPiping();
  458. }
  459.  
  460. // IDA: void __usercall PlayerHasLeft(int pIndex@<EAX>)
  461. void PlayerHasLeft(int pIndex) {
  462.     LOG_TRACE("(%d)", pIndex);
  463.     NOT_IMPLEMENTED();
  464. }
  465.  
  466. // IDA: void __usercall NetPlayersChanged(int pNew_count@<EAX>, tNet_game_player_info *pNew_players@<EDX>)
  467. void NetPlayersChanged(int pNew_count, tNet_game_player_info* pNew_players) {
  468.     int i;
  469.     int j;
  470.     int k;
  471.     int switched_res;
  472.     int new_player;
  473.     int player_still_there;
  474.     tPlayer_ID old_fox_it;
  475.     LOG_TRACE("(%d, %p)", pNew_count, pNew_players);
  476.  
  477.     if (gCurrent_net_game->type == eNet_game_type_tag || gCurrent_net_game->type == eNet_game_type_foxy) {
  478.         old_fox_it = gNet_players[gIt_or_fox].ID;
  479.     }
  480.     for (i = 0; i < pNew_count; i++) {
  481.         new_player = 1;
  482.         for (j = 0; j < gNumber_of_net_players; j++) {
  483.             if (pNew_players[i].ID == gNet_players[j].ID) {
  484.                 new_player = 0;
  485.                 pNew_players[i].last_waste_message = gNet_players[j].last_waste_message;
  486.                 pNew_players[i].player_status = gNet_players[j].player_status;
  487.                 pNew_players[i].car_index = gNet_players[j].car_index;
  488.                 pNew_players[i].score = gNet_players[j].score;
  489.                 pNew_players[i].credits = gNet_players[j].credits;
  490.                 pNew_players[i].wasted = gNet_players[j].wasted;
  491.                 pNew_players[i].wasteage_attributed = gNet_players[j].wasteage_attributed;
  492.                 pNew_players[i].next_car_index = gNet_players[j].next_car_index;
  493.                 pNew_players[i].car = gNet_players[j].car;
  494.                 break;
  495.             }
  496.         }
  497.         if (new_player) {
  498.             if (pNew_players[i].ID == gLocal_net_ID) {
  499.                 switched_res = SwitchToRealResolution();
  500.                 LoadCar(gOpponents[pNew_players[i].car_index].car_file_name,
  501.                     eDriver_local_human,
  502.                     &gProgram_state.current_car,
  503.                     pNew_players[i].car_index,
  504.                     pNew_players[i].player_name,
  505.                     &gNet_cars_storage_space);
  506.                 if (switched_res) {
  507.                     SwitchToLoresMode();
  508.                 }
  509.                 pNew_players[i].car = &gProgram_state.current_car;
  510.                 if (pNew_players[i].player_status < ePlayer_status_racing) {
  511.                     pNew_players[i].car->disabled = 1;
  512.                 }
  513.                 SetCarStorageTexturingLevel(&gNet_cars_storage_space, GetCarTexturingLevel(), eCTL_full);
  514.             } else {
  515.                 LoadCarN(i, &pNew_players[i]);
  516.             }
  517.             gCurrent_race.opponent_list[i].index = -1;
  518.             gCurrent_race.opponent_list[i].ranking = IRandomBetween(0, 99);
  519.             gCurrent_race.opponent_list[i].car_spec = pNew_players[i].car;
  520.             gCurrent_race.opponent_list[i].net_player_index = i;
  521.             pNew_players[i].opponent_list_index = i;
  522.             gCurrent_race.number_of_racers = pNew_count;
  523.         }
  524.     }
  525.     for (i = 0; i < gNumber_of_net_players; i++) {
  526.         player_still_there = 0;
  527.         for (j = 0; j < pNew_count; j++) {
  528.             if (pNew_players[j].ID == gNet_players[i].ID) {
  529.                 player_still_there = 1;
  530.                 break;
  531.             }
  532.         }
  533.         if (!player_still_there) {
  534.             for (j = 0; j < gNumber_of_net_players; j++) {
  535.                 if (gCurrent_race.opponent_list[j].net_player_index == i) {
  536.                     memmove(&gCurrent_race.opponent_list[j], &gCurrent_race.opponent_list[j + 1], (gNumber_of_net_players - j - 1) * sizeof(tOpp_spec));
  537.                     for (k = 0; k < pNew_count; k++) {
  538.                         if (j < pNew_players[k].opponent_list_index) {
  539.                             pNew_players[k].opponent_list_index--;
  540.                         }
  541.                     }
  542.                     break;
  543.                 }
  544.             }
  545.             PlayerHasLeft(i);
  546.             DisposeCarN(i);
  547.             if (gInitialised_grid) {
  548.                 for (i = 0; i < pNew_count; i++) {
  549.                     gCurrent_race.opponent_list[pNew_players[i].opponent_list_index].net_player_index = i;
  550.                 }
  551.             }
  552.         }
  553.     }
  554.     gNumber_of_net_players = pNew_count;
  555.     memcpy(gNet_players, pNew_players, pNew_count * sizeof(tNet_game_player_info));
  556.     for (i = 0; i < gNumber_of_net_players; i++) {
  557.         gNet_players[i].last_heard_from_him = PDGetTotalTime();
  558.     }
  559.     ForceRebuildActiveCarList();
  560.     if (gCurrent_net_game->type == eNet_game_type_tag || gCurrent_net_game->type == eNet_game_type_foxy) {
  561.         gIt_or_fox = -1;
  562.         for (i = 0; i < gNumber_of_net_players; i++) {
  563.             if (gNet_players[i].ID == old_fox_it) {
  564.                 gIt_or_fox = i;
  565.                 break;
  566.             }
  567.         }
  568.     }
  569. }
  570.  
  571. // IDA: tNet_game_details* __usercall NetHostGame@<EAX>(tNet_game_type pGame_type@<EAX>, tNet_game_options *pOptions@<EDX>, int pStart_rank@<EBX>, char *pHost_name@<ECX>, int pCar_index)
  572. tNet_game_details* NetHostGame(tNet_game_type pGame_type, tNet_game_options* pOptions, int pStart_rank, char* pHost_name, int pCar_index) {
  573.     tNet_game_details* game;
  574.     void* host_address;
  575.     tNet_game_player_info me;
  576.     LOG_TRACE("(%d, %p, %d, \"%s\", %d)", pGame_type, pOptions, pStart_rank, pHost_name, pCar_index);
  577.  
  578.     game = NetAllocatePIDGameDetails();
  579.     if (pHost_name[0] == '\0') {
  580.         sprintf(pHost_name, "%s", "HOST");
  581.     }
  582.     DisableNetService();
  583.     if (PDNetHostGame(game, pHost_name, &host_address) == 0) {
  584.         NetDisposeGameDetails(game);
  585.         return NULL;
  586.     }
  587.     gCurrent_net_game = game;
  588.     gNeed_to_send_start_race = 0;
  589.     strcpy(game->host_name, pHost_name);
  590.     game->host_ID = NetExtractPlayerID(game);
  591.     game->num_players = 1;
  592.     memcpy(&game->options, pOptions, sizeof(tNet_game_options));
  593.     game->status.stage = eNet_game_starting;
  594.     game->type = pGame_type;
  595.     game->start_race = pStart_rank;
  596.     game->no_races_yet = 1;
  597.     gReceiving_new_players = 0;
  598.     gHost_died = 0;
  599.     gNumber_of_net_players = 0;
  600.     gThis_net_player_index = 0;
  601.     gLocal_net_ID = game->host_ID;
  602.     FillInThisPlayer(game, &me, pCar_index, 1);
  603.     gNet_players[0].race_stuff_initialised = 1;
  604.     NetSetPlayerSystemInfo(&me, host_address);
  605.     NetPlayersChanged(1, &me);
  606.     InitialisePlayerStati();
  607.     gNet_mode = eNet_mode_host;
  608.     gDont_allow_joiners = 0;
  609.     return game;
  610. }
  611.  
  612. // IDA: int __usercall NetInitClient@<EAX>(tNet_game_details *pDetails@<EAX>)
  613. int NetInitClient(tNet_game_details* pDetails) {
  614.     LOG_TRACE("(%p)", pDetails);
  615.     NOT_IMPLEMENTED();
  616. }
  617.  
  618. // IDA: int __usercall NetJoinGameLowLevel@<EAX>(tNet_game_details *pDetails@<EAX>, char *pPlayer_name@<EDX>)
  619. int NetJoinGameLowLevel(tNet_game_details* pDetails, char* pPlayer_name) {
  620.     LOG_TRACE("(%p, \"%s\")", pDetails, pPlayer_name);
  621.  
  622.     return PDNetJoinGame(pDetails, pPlayer_name);
  623. }
  624.  
  625. // IDA: int __usercall NetJoinGame@<EAX>(tNet_game_details *pDetails@<EAX>, char *pPlayer_name@<EDX>, int pCar_index@<EBX>)
  626. int NetJoinGame(tNet_game_details* pDetails, char* pPlayer_name, int pCar_index) {
  627.     int result;
  628.     tNet_message* the_message;
  629.     tU32 start_time;
  630.     LOG_TRACE("(%p, \"%s\", %d)", pDetails, pPlayer_name, pCar_index);
  631.  
  632.     result = NetJoinGameLowLevel(pDetails, pPlayer_name);
  633.     if (result != 0) {
  634.         return result;
  635.     }
  636.     DisableNetService();
  637.     gReceiving_new_players = 0;
  638.     gNet_mode = eNet_mode_client;
  639.     gCurrent_net_game = pDetails;
  640.     gLocal_net_ID = NetExtractPlayerID(pDetails);
  641.     gNumber_of_net_players = 0;
  642.     gLast_player_list_received = 0;
  643.     gJoin_request_denied = 0;
  644.     gCar_was_taken = 0;
  645.     gHost_died = 0;
  646.     the_message = NetBuildMessage(NETMSGID_JOIN, 0);
  647.     FillInThisPlayer(pDetails, &the_message->contents.data.join.player_info, pCar_index, 0);
  648.     ReenableNetService();
  649.     NetGuaranteedSendMessageToAddress(pDetails, the_message, pDetails, NULL);
  650.     start_time = PDGetTotalTime();
  651.     while (1) {
  652.         NetService(0);
  653.         if (gNumber_of_net_players != 0) {
  654.             break;
  655.         }
  656.         if (PDGetTotalTime() - start_time >= 30000 || gJoin_request_denied || gHost_died) {
  657.             break;
  658.         }
  659.     }
  660.     DisableNetService();
  661.     InitialisePlayerStati();
  662.     if (gNumber_of_net_players == 0) {
  663.         ReenableNetService();
  664.         if (gJoin_request_denied && gCar_was_taken) {
  665.             result = -4;
  666.         } else {
  667.             gNet_mode = eNet_mode_none;
  668. #if !defined(DETHRACE_FIX_BUGS)
  669.             // Avoid double free
  670.             NetDisposeGameDetails(gCurrent_net_game);
  671. #endif
  672.             gCurrent_net_game = NULL;
  673.             if (gJoin_request_denied) {
  674.                 result = -2;
  675.             } else {
  676.                 result = -1;
  677.             }
  678.         }
  679.     }
  680.     return result;
  681. }
  682.  
  683. // IDA: void __usercall NetObtainSystemUserName(char *pName@<EAX>, int pMax_length@<EDX>)
  684. void NetObtainSystemUserName(char* pName, int pMax_length) {
  685.  
  686.     PDNetObtainSystemUserName(pName, pMax_length);
  687.     pName[9] = '\0';
  688. }
  689.  
  690. // IDA: tU32 __usercall NetExtractGameID@<EAX>(tNet_game_details *pDetails@<EAX>)
  691. tU32 NetExtractGameID(tNet_game_details* pDetails) {
  692.     LOG_TRACE("(%p)", pDetails);
  693.  
  694.     return PDNetExtractGameID(pDetails);
  695. }
  696.  
  697. // IDA: tPlayer_ID __usercall NetExtractPlayerID@<EAX>(tNet_game_details *pDetails@<EAX>)
  698. tPlayer_ID NetExtractPlayerID(tNet_game_details* pDetails) {
  699.     LOG_TRACE("(%p)", pDetails);
  700.  
  701.     return PDNetExtractPlayerID(pDetails);
  702. }
  703.  
  704. // IDA: int __usercall NetSendMessageToAddress@<EAX>(tNet_game_details *pDetails@<EAX>, tNet_message *pMessage@<EDX>, void *pAddress@<EBX>)
  705. int NetSendMessageToAddress(tNet_game_details* pDetails, tNet_message* pMessage, void* pAddress) {
  706.     LOG_TRACE("(%p, %p, %p)", pDetails, pMessage, pAddress);
  707.  
  708.     if (gNet_mode == eNet_mode_none && !gJoin_list_mode) {
  709.         return -3;
  710.     }
  711.     pMessage->sender = gLocal_net_ID;
  712.     pMessage->senders_time_stamp = PDGetTotalTime();
  713.     GetCheckSum(pMessage);
  714.     return PDNetSendMessageToAddress(pDetails, pMessage, pAddress);
  715. }
  716.  
  717. // IDA: int __usercall NetSendMessageToPlayer@<EAX>(tNet_game_details *pDetails@<EAX>, tNet_message *pMessage@<EDX>, tPlayer_ID pPlayer@<EBX>)
  718. int NetSendMessageToPlayer(tNet_game_details* pDetails, tNet_message* pMessage, tPlayer_ID pPlayer) {
  719.     //int i; // Pierre-Marie Baty -- unused variable
  720.     LOG_TRACE("(%p, %p, %d)", pDetails, pMessage, pPlayer);
  721.     NOT_IMPLEMENTED();
  722. }
  723.  
  724. // IDA: int __usercall NetSendMessageToHost@<EAX>(tNet_game_details *pDetails@<EAX>, tNet_message *pMessage@<EDX>)
  725. int NetSendMessageToHost(tNet_game_details* pDetails, tNet_message* pMessage) {
  726.     LOG_TRACE("(%p, %p)", pDetails, pMessage);
  727.     NOT_IMPLEMENTED();
  728. }
  729.  
  730. // IDA: int __usercall NetReplyToMessage@<EAX>(tNet_game_details *pDetails@<EAX>, tNet_message *pIncoming_message@<EDX>, tNet_message *pReply_message@<EBX>)
  731. int NetReplyToMessage(tNet_game_details* pDetails, tNet_message* pIncoming_message, tNet_message* pReply_message) {
  732.     LOG_TRACE("(%p, %p, %p)", pDetails, pIncoming_message, pReply_message);
  733.     NOT_IMPLEMENTED();
  734. }
  735.  
  736. // IDA: int __usercall NetSendMessageToAllPlayers@<EAX>(tNet_game_details *pDetails@<EAX>, tNet_message *pMessage@<EDX>)
  737. int NetSendMessageToAllPlayers(tNet_game_details* pDetails, tNet_message* pMessage) {
  738.     LOG_TRACE("(%p, %p)", pDetails, pMessage);
  739.  
  740.     pMessage->sender = gLocal_net_ID;
  741.     pMessage->senders_time_stamp = PDGetTotalTime();
  742.     GetCheckSum(pMessage);
  743.     return PDNetSendMessageToAllPlayers(pDetails, pMessage);
  744. }
  745.  
  746. // IDA: tU32 __usercall NetGetContentsSize@<EAX>(tNet_message_type pType@<EAX>, tS32 pSize_decider@<EDX>)
  747. tU32 NetGetContentsSize(tNet_message_type pType, tS32 pSize_decider) {
  748.     //tU32 the_size; // Pierre-Marie Baty -- unused variable
  749.     LOG_TRACE("(%d, %d)", pType, pSize_decider);
  750.  
  751.     switch (pType) {
  752.     case NETMSGID_SENDMEDETAILS:
  753.         return sizeof(tNet_message_send_me_details);
  754.     case NETMSGID_DETAILS:
  755.         return sizeof(tNet_message_my_details);
  756.     case NETMSGID_JOIN:
  757.         return sizeof(tNet_message_join);
  758.     case NETMSGID_NEWPLAYERLIST:
  759.         return sizeof(tNet_message_new_player_list);
  760.     case NETMSGID_GUARANTEEREPLY:
  761.         return sizeof(tNet_message_guarantee_reply);
  762.     case NETMSGID_CARDETAILSREQ:
  763.         return sizeof(tNet_message_car_details_req);
  764.     case NETMSGID_CARDETAILS:
  765.         return sizeof(tNet_message_car_details);
  766.     case NETMSGID_LEAVE:
  767.         return sizeof(tNet_message_leave);
  768.     case NETMSGID_HOSTICIDE:
  769.         return sizeof(tNet_message_host_pissing_off);
  770.     case NETMSGID_RACEOVER:
  771.         return sizeof(tNet_message_race_over);
  772.     case NETMSGID_STATUSREPORT:
  773.         return sizeof(tNet_message_status_report);
  774.     case NETMSGID_STARTRACE:
  775.         return sizeof(tNet_message_start_race);
  776.     case NETMSGID_HEADUP:
  777.         return sizeof(tNet_message_headup);
  778.     case NETMSGID_HOSTQUERY:
  779.         return sizeof(tNet_message_host_query);
  780.     case NETMSGID_HOSTREPLY:
  781.         return sizeof(tNet_message_host_reply);
  782.     case NETMSGID_MECHANICS:
  783.         if (pSize_decider == 0) {
  784.             return offsetof(tNet_message_mechanics_info, wheel_dam_offset);
  785.         } else {
  786.             return sizeof(tNet_message_mechanics_info);
  787.         }
  788.     case NETMSGID_NONCAR_INFO:
  789.         return sizeof(tNet_message_non_car_info);
  790.     case NETMSGID_TIMESYNC:
  791.         return sizeof(tNet_message_time_sync);
  792.     case NETMSGID_CONFIRM:
  793.         return sizeof(tNet_message_players_confirm);
  794.     case NETMSGID_DISABLECAR:
  795.         return sizeof(tNet_message_disable_car);
  796.     case NETMSGID_ENABLECAR:
  797.         return sizeof(tNet_message_enable_car);
  798.     case NETMSGID_POWERUP:
  799.         return sizeof(tNet_message_powerup);
  800.     case NETMSGID_RECOVER:
  801.         return sizeof(tNet_message_recover);
  802.     case NETMSGID_SCORES:
  803.         return sizeof(tNet_message_scores);
  804.     case NETMSGID_WASTED:
  805.         return sizeof(tNet_message_wasted);
  806.     case NETMSGID_PEDESTRIAN:
  807.         switch (pSize_decider) {
  808.         case 0:
  809.             return offsetof(tNet_message_pedestrian, to_pos);
  810.         case 1:
  811.             return offsetof(tNet_message_pedestrian, offset);
  812.         case 2:
  813.             return sizeof(tNet_message_pedestrian);
  814.         default:
  815.             TELL_ME_IF_WE_PASS_THIS_WAY();
  816.         }
  817.     case NETMSGID_GAMEPLAY:
  818.         return sizeof(tNet_message_gameplay);
  819.     case NETMSGID_NONCARPOSITION:
  820.         return sizeof(tNet_message_non_car_position);
  821.     case NETMSGID_COPINFO:
  822.         return sizeof(tNet_message_cop_info);
  823.     case NETMSGID_GAMESCORES:
  824.         return sizeof(tNet_message_game_scores);
  825.     case NETMSGID_OILSPILL:
  826.         return sizeof(tNet_message_oil_spill);
  827.     case NETMSGID_CRUSHPOINT:
  828.         return sizeof(tNet_message_crush_point);
  829.     default:
  830.         TELL_ME_IF_WE_PASS_THIS_WAY();
  831.         return 4;
  832.     }
  833. }
  834.  
  835. // IDA: tU32 __usercall NetGetMessageSize@<EAX>(tNet_message_type pType@<EAX>, tS32 pSize_decider@<EDX>)
  836. tU32 NetGetMessageSize(tNet_message_type pType, tS32 pSize_decider) {
  837.     LOG_TRACE("(%d, %d)", pType, pSize_decider);
  838.  
  839.     return NetGetContentsSize(pType, pSize_decider) + sizeof(tNet_message) - sizeof(tNet_contents);
  840. }
  841.  
  842. // IDA: tS32 __usercall NetCalcSizeDecider@<EAX>(tNet_contents *pContents@<EAX>)
  843. tS32 NetCalcSizeDecider(tNet_contents* pContents) {
  844.     //tS32 the_decider; // Pierre-Marie Baty -- unused variable
  845.     LOG_TRACE("(%p)", pContents);
  846.     NOT_IMPLEMENTED();
  847. }
  848.  
  849. // IDA: tNet_message* __usercall NetBuildMessage@<EAX>(tNet_message_type pType@<EAX>, tS32 pSize_decider@<EDX>)
  850. tNet_message* NetBuildMessage(tNet_message_type pType, tS32 pSize_decider) {
  851.     tNet_message* the_message;
  852.     tU32 the_size;
  853.     LOG_TRACE("(%d, %d)", pType, pSize_decider);
  854.  
  855.     the_size = NetGetMessageSize(pType, pSize_decider);
  856.     the_message = NetAllocateMessage(the_size);
  857.     if (the_message != NULL) {
  858.         the_message->num_contents = 1;
  859.         the_message->overall_size = the_size;
  860.         the_message->contents.header.type = pType;
  861.     }
  862.     return the_message;
  863. }
  864.  
  865. // IDA: tNet_contents* __usercall NetGetToHostContents@<EAX>(tNet_message_type pType@<EAX>, tS32 pSize_decider@<EDX>)
  866. tNet_contents* NetGetToHostContents(tNet_message_type pType, tS32 pSize_decider) {
  867.     //tU32 the_size; // Pierre-Marie Baty -- unused variable
  868.     //tNet_contents* contents; // Pierre-Marie Baty -- unused variable
  869.     LOG_TRACE("(%d, %d)", pType, pSize_decider);
  870.     NOT_IMPLEMENTED();
  871. }
  872.  
  873. // IDA: tNet_contents* __usercall NetGetBroadcastContents@<EAX>(tNet_message_type pType@<EAX>, tS32 pSize_decider@<EDX>)
  874. tNet_contents* NetGetBroadcastContents(tNet_message_type pType, tS32 pSize_decider) {
  875.     tU32 the_size;
  876.     tNet_contents* contents;
  877.     LOG_TRACE("(%d, %d)", pType, pSize_decider);
  878.  
  879.     the_size = NetGetContentsSize(pType, pSize_decider);
  880.     if (gBroadcast_stack && the_size + gBroadcast_stack->overall_size > MAX_MESAGE_STACK_SIZE) {
  881.         NetSendMessageToAllPlayers(gCurrent_net_game, gBroadcast_stack);
  882.         gBroadcast_stack = NULL;
  883.     }
  884.     if (gBroadcast_stack == NULL) {
  885.         gBroadcast_stack = NetAllocateMessage(MAX_MESAGE_STACK_SIZE);
  886.         gBroadcast_stack->overall_size = offsetof(tNet_message, contents);
  887.         gBroadcast_stack->num_contents = 0;
  888.     }
  889.     contents = (tNet_contents*)((char*)gBroadcast_stack + gBroadcast_stack->overall_size);
  890.     gBroadcast_stack->overall_size += the_size;
  891.     contents->header.type = pType;
  892.     contents->header.contents_size = the_size;
  893.     gBroadcast_stack->num_contents++;
  894.     return contents;
  895. }
  896.  
  897. // IDA: void __cdecl NetSendMessageStacks()
  898. void NetSendMessageStacks(void) {
  899.     LOG_TRACE("()");
  900.  
  901.     gLast_flush_message = PDGetTotalTime();
  902.     if (gBroadcast_stack != NULL) {
  903.         NetSendMessageToAllPlayers(gCurrent_net_game, gBroadcast_stack);
  904.         gBroadcast_stack = NULL;
  905.     }
  906.     if (gTo_host_stack != NULL) {
  907.         NetSendMessageToHost(gCurrent_net_game, gTo_host_stack);
  908.         gTo_host_stack = NULL;
  909.     }
  910. }
  911.  
  912. // IDA: tNet_message* __usercall NetAllocateMessage@<EAX>(int pSize@<EAX>)
  913. tNet_message* NetAllocateMessage(int pSize) {
  914.     void* pointer;
  915.     void* last_message;
  916.     //char* test; // Pierre-Marie Baty -- unused variable
  917.     static int rr_min = 0; // Pierre-Marie Baty -- uninitialized static variable
  918.     static int rr_mid = 0; // Pierre-Marie Baty -- uninitialized static variable
  919.     static int rr_max = 0; // Pierre-Marie Baty -- uninitialized static variable
  920.     tNet_message* message;
  921.     int i;
  922.     LOG_TRACE("(%d)", pSize);
  923.  
  924.     pointer = NULL;
  925.     if (pSize <= sizeof(tMin_message) - sizeof(void*)) {
  926.         for (i = 0; i < MIN_MESSAGES_CAPACITY; i++) {
  927.             if (((tNet_message*)&gMin_messages[rr_min])->contents.header.type == NETMSGID_NONE) {
  928.                 pointer = &gMin_messages[rr_min];
  929.                 break;
  930.             }
  931.             rr_min++;
  932.             if (rr_min >= MIN_MESSAGES_CAPACITY) {
  933.                 rr_min = 0;
  934.             }
  935.         }
  936.     }
  937.     if (pointer == NULL && pSize <= sizeof(tMid_message) - sizeof(void*)) {
  938.         for (i = 0; i < MID_MESSAGES_CAPACITY; i++) {
  939.             if (((tNet_message*)&gMid_messages[rr_mid])->contents.header.type == NETMSGID_NONE) {
  940.                 pointer = &gMid_messages[rr_mid];
  941.                 break;
  942.             }
  943.             rr_mid++;
  944.             if (rr_mid >= MID_MESSAGES_CAPACITY) {
  945.                 rr_mid = 0;
  946.             }
  947.         }
  948.     }
  949.     if (pointer == NULL && pSize <= sizeof(tMax_message) - sizeof(void*)) {
  950.         for (i = 0; i < MAX_MESSAGES_CAPACITY; i++) {
  951.             if (((tNet_message*)&gMax_messages[rr_max])->contents.header.type == NETMSGID_NONE) {
  952.                 pointer = &gMax_messages[rr_max];
  953.                 break;
  954.             }
  955.             rr_max++;
  956.             if (rr_max >= MAX_MESSAGES_CAPACITY) {
  957.                 rr_max = 0;
  958.             }
  959.         }
  960.     }
  961.     if (pointer == NULL) {
  962.         pointer = BrMemAllocate(gMessage_header_size + pSize + sizeof(void*), kMem_dynamic_message);
  963.         if (pointer != NULL) {
  964.             *(void**)pointer = NULL;
  965.             if (gMessage_to_free != NULL) {
  966.                 for (last_message = gMessage_to_free; *(void**)last_message != NULL; last_message = *(void**)last_message) {
  967.                 }
  968.                 *(void**)last_message = pointer;
  969.             } else {
  970.                 gMessage_to_free = pointer;
  971.             }
  972.             pointer = ((void**)pointer)[1];
  973.         }
  974.     }
  975.     if (pointer == NULL) {
  976.         LOG_PANIC("null pointer!");
  977.         message = NULL;
  978.     } else {
  979.         message = (tNet_message*)((tU8*)pointer + gMessage_header_size);
  980.         message->guarantee_number = 0;
  981.         message->version = 1;
  982.         message->magic_number = 0x763a5058;
  983.     }
  984.     return message;
  985. }
  986.  
  987. // IDA: void __cdecl NetFreeExcessMemory()
  988. void NetFreeExcessMemory(void) {
  989.     void* temp;
  990.     LOG_TRACE("()");
  991.  
  992.     while (gMessage_to_free != NULL && ((tNet_message*)((char*)gMessage_to_free + sizeof(void*)))->contents.header.type == NETMSGID_NONE) {
  993.         temp = *(void**)gMessage_to_free;
  994.         BrMemFree(gMessage_to_free);
  995.         gMessage_to_free = temp;
  996.     }
  997. }
  998.  
  999. // IDA: int __usercall NetDisposeMessage@<EAX>(tNet_game_details *pDetails@<EAX>, tNet_message *pMessage@<EDX>)
  1000. int NetDisposeMessage(tNet_game_details* pDetails, tNet_message* pMessage) {
  1001.     LOG_TRACE("(%p, %p)", pDetails, pMessage);
  1002.  
  1003.     if (pMessage->guarantee_number != 0) {
  1004.         return -1;
  1005.     }
  1006.     pMessage->contents.header.type = NETMSGID_NONE;
  1007.     return 0;
  1008. }
  1009.  
  1010. // IDA: tNet_message* __usercall NetGetNextMessage@<EAX>(tNet_game_details *pDetails@<EAX>, void **pSender_address@<EDX>)
  1011. tNet_message* NetGetNextMessage(tNet_game_details* pDetails, void** pSender_address) {
  1012.     LOG_TRACE("(%p, %p)", pDetails, pSender_address);
  1013.  
  1014.     return PDNetGetNextMessage(pDetails, pSender_address);
  1015. }
  1016.  
  1017. // IDA: void __usercall ReceivedSendMeDetails(tNet_contents *pContents@<EAX>, void *pSender_address@<EDX>)
  1018. void ReceivedSendMeDetails(tNet_contents* pContents, void* pSender_address) {
  1019.     tNet_message* message;
  1020.     LOG_TRACE("(%p, %p)", pContents, pSender_address);
  1021.  
  1022.     if (gDont_allow_joiners) {
  1023.         return;
  1024.     }
  1025.     message = NetBuildMessage(NETMSGID_DETAILS, 0);
  1026.     memcpy(&message->contents.data.details.details.host_name, gCurrent_net_game->host_name, sizeof(*gCurrent_net_game) - offsetof(tNet_game_details, host_name));
  1027.     NetSendMessageToAddress(gCurrent_net_game, message, pSender_address);
  1028. }
  1029.  
  1030. // IDA: void __usercall ReceivedDetails(tNet_contents *pContents@<EAX>)
  1031. void ReceivedDetails(tNet_contents* pContents) {
  1032.     LOG_TRACE("(%p)", pContents);
  1033.  
  1034.     if (gCurrent_join_poll_game == NULL) {
  1035.         return;
  1036.     }
  1037.     gBastard_has_answered = 1;
  1038.     memcpy(gCurrent_join_poll_game->host_name, &pContents->data.details.details.host_name, sizeof(*gCurrent_join_poll_game) - offsetof(tNet_game_details, host_name));
  1039. }
  1040.  
  1041. // IDA: void __cdecl SendOutPlayerList()
  1042. void SendOutPlayerList(void) {
  1043.     tNet_message* message;
  1044.     int i;
  1045.     LOG_TRACE("()");
  1046.  
  1047.     gCurrent_net_game->num_players = gNumber_of_net_players;
  1048.     for (i = 0; i < gNumber_of_net_players; i++) {
  1049.         message = NetBuildMessage(NETMSGID_NEWPLAYERLIST, 1);
  1050.         message->contents.data.player_list.number_of_players = gNumber_of_net_players;
  1051.         message->contents.data.player_list.this_index = i;
  1052.         message->contents.data.player_list.batch_number = gPlayer_list_batch_number;
  1053.         memcpy(&message->contents.data.player_list.player, &gNet_players[i], sizeof(gNet_players[i]));
  1054.         NetGuaranteedSendMessageToAllPlayers(gCurrent_net_game, message, 0);
  1055.     }
  1056.     gPlayer_list_batch_number++;
  1057.     if (gInitialised_grid) {
  1058.         SetUpNetCarPositions();
  1059.         if (gStart_race_sent) {
  1060.             gNeed_to_send_start_race = 1;
  1061.             for (i = 1; i < gNumber_of_net_players; i++) {
  1062.                 gNet_players[i].awaiting_confirmation = 1;
  1063.             }
  1064.         }
  1065.     }
  1066. }
  1067.  
  1068. // IDA: void __usercall ReceivedJoin(tNet_contents *pContents@<EAX>, void *pSender_address@<EDX>)
  1069. void ReceivedJoin(tNet_contents* pContents, void* pSender_address) {
  1070.     int i;
  1071.     int new_player_count;
  1072.     int slot_index;
  1073.     tNet_message* message;
  1074.     tNet_game_player_info* new_players;
  1075.     LOG_TRACE("(%p, %p)", pContents, pSender_address);
  1076.  
  1077.     new_player_count = gNumber_of_net_players;
  1078.     new_players = BrMemAllocate(new_player_count + 1 * sizeof(tNet_game_player_info), kMem_player_list_join);
  1079.     memcpy(new_players, gNet_players, gNumber_of_net_players * sizeof(tNet_game_player_info));
  1080.  
  1081.     if ((!gCurrent_net_game->options.open_game && gProgram_state.racing) || gCurrent_net_game->num_players > 5 || gDont_allow_joiners) {
  1082.         message = NetBuildMessage(NETMSGID_NEWPLAYERLIST, 0);
  1083.         // Send player count = 0 when race has already begun or is full
  1084.         message->contents.data.player_list.number_of_players = 0;
  1085.         NetSendMessageToAddress(gCurrent_net_game, message, pSender_address);
  1086.     } else {
  1087.         for (i = 0; i < new_player_count; i++) {
  1088.             if (new_players[i].ID == pContents->data.join.player_info.ID) {
  1089.                 return;
  1090.             }
  1091.         }
  1092.         slot_index = new_player_count;
  1093.         new_player_count++;
  1094.         if (pContents->data.join.player_info.car_index < 0) {
  1095.             pContents->data.join.player_info.car_index = PickARandomCar();
  1096.         } else {
  1097.             for (i = 0; i < gNumber_of_net_players; i++) {
  1098.                 if (gNet_players[i].car_index == pContents->data.join.player_info.car_index) {
  1099.                     message = NetBuildMessage(NETMSGID_NEWPLAYERLIST, 0);
  1100.                     // Send player count = -1 when selected car is unavailable
  1101.                     message->contents.data.player_list.number_of_players = -1;
  1102.                     NetSendMessageToAddress(gCurrent_net_game, message, pSender_address);
  1103.                     return;
  1104.                 }
  1105.             }
  1106.         }
  1107.         if (pContents->data.join.player_info.car_index >= 0) {
  1108.             gCar_details[pContents->data.join.player_info.car_index].ownership = eCar_owner_someone;
  1109.         }
  1110.         memcpy(&new_players[slot_index], &pContents->data.join.player_info, sizeof(tNet_game_player_info));
  1111.         new_players[slot_index].player_status = ePlayer_status_loading;
  1112.         new_players[slot_index].last_heard_from_him = PDGetTotalTime();
  1113.         new_players[slot_index].grid_position_set = 0;
  1114.         if (new_players[slot_index].player_name[0] == '\0') {
  1115.             sprintf(new_players[slot_index].player_name, "%s %d", "PLAYER", slot_index);
  1116.         }
  1117.         NetSetPlayerSystemInfo(&new_players[slot_index], pSender_address);
  1118.         NetPlayersChanged(new_player_count, new_players);
  1119.         BrMemFree(new_players);
  1120.         SendOutPlayerList();
  1121.     }
  1122. }
  1123.  
  1124. // IDA: void __usercall KickPlayerOut(tPlayer_ID pID@<EAX>)
  1125. void KickPlayerOut(tPlayer_ID pID) {
  1126.     //int i; // Pierre-Marie Baty -- unused variable
  1127.     //int j; // Pierre-Marie Baty -- unused variable
  1128.     //int new_player_count; // Pierre-Marie Baty -- unused variable
  1129.     //tNet_game_player_info* new_players; // Pierre-Marie Baty -- unused variable
  1130.     LOG_TRACE("(%d)", pID);
  1131.     NOT_IMPLEMENTED();
  1132. }
  1133.  
  1134. // IDA: void __usercall ReceivedLeave(tNet_contents *pContents@<EAX>, tNet_message *pMessage@<EDX>)
  1135. void ReceivedLeave(tNet_contents* pContents, tNet_message* pMessage) {
  1136.     LOG_TRACE("(%p, %p)", pContents, pMessage);
  1137.     NOT_IMPLEMENTED();
  1138. }
  1139.  
  1140. // IDA: void __usercall NetFullScreenMessage(int pStr_index@<EAX>, int pLeave_it_up_there@<EDX>)
  1141. void NetFullScreenMessage(int pStr_index, int pLeave_it_up_there) {
  1142.     tU32 start_time;
  1143.     char* s;
  1144.     // Jeff: added underscore suffix to avoid collisions with samed-named globals
  1145.     int gPixel_buffer_size_;
  1146.     char* gPixels_copy_;
  1147.     char* gPalette_copy_;
  1148.     int restore_screen;
  1149.  
  1150.     LOG_TRACE("(%d, %d)", pStr_index, pLeave_it_up_there);
  1151.  
  1152.     if (pLeave_it_up_there || (gProgram_state.racing && !gInterface_within_race_mode)) {
  1153.         restore_screen = 0;
  1154.     } else {
  1155.         gPixel_buffer_size_ = gBack_screen->height * gBack_screen->row_bytes;
  1156.         gPixels_copy_ = BrMemAllocate(gPixel_buffer_size_, 0xB0u);
  1157.         gPalette_copy_ = BrMemAllocate(0x400u, 0xB1u);
  1158.         memcpy(gPixels_copy_, gBack_screen->pixels, gPixel_buffer_size_);
  1159.         memcpy(gPalette_copy_, gCurrent_palette_pixels, 0x400u);
  1160.         restore_screen = 1;
  1161.     }
  1162.     FadePaletteDown();
  1163.     LoadFont(FONT_MEDIUMHD);
  1164.     ClearEntireScreen();
  1165.     if (pStr_index <= 0) {
  1166.         s = "FIXED THAT YOU TWISTED BASTARDS";
  1167.     } else {
  1168.         s = GetMiscString(pStr_index);
  1169.     }
  1170.     OoerrIveGotTextInMeBoxMissus(
  1171.         FONT_MEDIUMHD,
  1172.         s,
  1173.         gBack_screen,
  1174.         0,
  1175.         gGraf_specs[gGraf_spec_index].total_height / 2 - gFonts[kFont_MEDIUMHD].height,
  1176.         gGraf_specs[gGraf_spec_index].total_width,
  1177.         gGraf_specs[gGraf_spec_index].total_height,
  1178.         1);
  1179.     PDScreenBufferSwap(0);
  1180.     EnsureRenderPalette();
  1181.     EnsurePaletteUp();
  1182.     if (!pLeave_it_up_there) {
  1183.         start_time = PDGetTotalTime();
  1184.         while (PDGetTotalTime() - start_time < 3000) {
  1185.             ;
  1186.         }
  1187.         FadePaletteDown();
  1188.         if (restore_screen) {
  1189.             memcpy(gBack_screen->pixels, gPixels_copy_, gPixel_buffer_size_);
  1190.             memcpy(gCurrent_palette_pixels, gPalette_copy_, 0x400u);
  1191.             BrMemFree(gPixels_copy_);
  1192.             BrMemFree(gPalette_copy_);
  1193.             PDScreenBufferSwap(0);
  1194.             FadePaletteUp();
  1195.         } else {
  1196.             ClearEntireScreen();
  1197.         }
  1198.     }
  1199. }
  1200.  
  1201. // IDA: void __usercall HostHasBittenTheDust(int pMessage_index@<EAX>)
  1202. void HostHasBittenTheDust(int pMessage_index) {
  1203.     LOG_TRACE("(%d)", pMessage_index);
  1204.  
  1205.     if (!gHost_died) {
  1206.         gHost_died = 1;
  1207.         NetFullScreenMessage(pMessage_index, 0);
  1208.         gProgram_state.prog_status = eProg_idling;
  1209.     }
  1210. }
  1211.  
  1212. // IDA: void __usercall ReceivedHosticide(tNet_contents *pContents@<EAX>)
  1213. void ReceivedHosticide(tNet_contents* pContents) {
  1214.     LOG_TRACE("(%p)", pContents);
  1215.  
  1216.     HostHasBittenTheDust(73);
  1217. }
  1218.  
  1219. // IDA: void __cdecl ConfirmReceipt()
  1220. void ConfirmReceipt(void) {
  1221.     //tNet_message* the_message; // Pierre-Marie Baty -- unused variable
  1222.     LOG_TRACE("()");
  1223.     NOT_IMPLEMENTED();
  1224. }
  1225.  
  1226. // IDA: void __usercall ReceivedNewPlayerList(tNet_contents *pContents@<EAX>, tNet_message *pM@<EDX>)
  1227. void ReceivedNewPlayerList(tNet_contents* pContents, tNet_message* pM) {
  1228.     int i;
  1229.     LOG_TRACE("(%p, %p)", pContents, pM);
  1230.  
  1231.     if (pContents->data.player_list.number_of_players <= 0) {
  1232.         gJoin_request_denied = 1;
  1233.         if (pContents->data.player_list.number_of_players < 0) {
  1234.             gCar_was_taken = 1;
  1235.         }
  1236.         return;
  1237.     }
  1238.     if (pContents->data.player_list.batch_number >= gReceiving_batch_number) {
  1239.         if (!gReceiving_new_players) {
  1240.             gLast_player_list_received = pM->senders_time_stamp;
  1241.             for (i = 0; i < COUNT_OF(gNew_net_players); i++) {
  1242.                 gNew_net_players[i].car_index = -1;
  1243.             }
  1244.             gReceiving_new_players = 1;
  1245.             gReceiving_batch_number = pContents->data.player_list.batch_number;
  1246.         }
  1247.         if (pContents->data.player_list.batch_number <= gReceiving_batch_number) {
  1248.             memcpy(&gNew_net_players[pContents->data.player_list.this_index], &pContents->data.player_list.player, sizeof(tNet_game_player_info));
  1249.             for (i = 0; i < pContents->data.player_list.number_of_players; i++) {
  1250.                 if (gNew_net_players[i].car_index < 0) {
  1251.                     return;
  1252.                 }
  1253.             }
  1254.             gReceiving_new_players = 0;
  1255.             NetPlayersChanged(pContents->data.player_list.number_of_players, gNew_net_players);
  1256.             gThis_net_player_index = -1;
  1257.             for (i = 0; i < gNumber_of_net_players; i++) {
  1258.                 if (gNet_players[i].ID == gLocal_net_ID) {
  1259.                     gThis_net_player_index = i;
  1260.                     break;
  1261.                 }
  1262.             }
  1263.             if (gThis_net_player_index < 0) {
  1264.                 FatalError(kFatalError_NotInReceivedPlayerList);
  1265.             }
  1266.             gNet_players[0].last_heard_from_him = PDGetTotalTime();
  1267.             gCurrent_race.number_of_racers = gNumber_of_net_players;
  1268.             if (gSynch_race_start) {
  1269.                 for (i = 0; i < gNumber_of_net_players; i++) {
  1270.                     gCurrent_race.opponent_list[gNet_players[i].opponent_list_index].net_player_index = i;
  1271.                 }
  1272.             }
  1273.         } else {
  1274.             gReceiving_new_players = 0;
  1275.             ReceivedNewPlayerList(pContents, pM);
  1276.         }
  1277.     }
  1278. }
  1279.  
  1280. // IDA: void __usercall ReceivedRaceOver(tNet_contents *pContents@<EAX>)
  1281. void ReceivedRaceOver(tNet_contents* pContents) {
  1282.     LOG_TRACE("(%p)", pContents);
  1283.  
  1284.     gRace_finished = 0;
  1285.     if (gProgram_state.racing && (gNet_mode == eNet_mode_client || pContents->data.race_over.reason == eRace_over_network_victory || pContents->data.race_over.reason == eRace_over_network_loss)) {
  1286.         RaceCompleted(pContents->data.race_over.reason);
  1287.     }
  1288. }
  1289.  
  1290. // IDA: void __usercall ReceivedStatusReport(tNet_contents *pContents@<EAX>, tNet_message *pMessage@<EDX>)
  1291. void ReceivedStatusReport(tNet_contents* pContents, tNet_message* pMessage) {
  1292.     int i;
  1293.     LOG_TRACE("(%p, %p)", pContents, pMessage);
  1294.  
  1295.     for (i = 0; i < gNumber_of_net_players; i++) {
  1296.         if (gNet_players[i].ID == pMessage->sender) {
  1297.             gNet_players[i].player_status = pContents->data.report.status;
  1298.             gNet_players[i].last_heard_from_him = PDGetTotalTime();
  1299.             if (gNet_players[i].player_status < ePlayer_status_racing || gNet_players[i].player_status == ePlayer_status_recovering) {
  1300.                 if (gNet_players[i].player_status < ePlayer_status_racing) {
  1301.                     DisableCar(gNet_players[i].car);
  1302.                 }
  1303.             } else {
  1304.                 if (gNet_players[i].car->disabled) {
  1305.                     SendCurrentPowerups();
  1306.                 }
  1307.                 EnableCar(gNet_players[i].car);
  1308.             }
  1309.             return;
  1310.         }
  1311.     }
  1312. }
  1313.  
  1314. // IDA: void __usercall ReceivedStartRace(tNet_contents *pContents@<EAX>)
  1315. void ReceivedStartRace(tNet_contents* pContents) {
  1316.     //int i; // Pierre-Marie Baty -- unused variable
  1317.     //int index; // Pierre-Marie Baty -- unused variable
  1318.     LOG_TRACE("(%p)", pContents);
  1319.     NOT_IMPLEMENTED();
  1320. }
  1321.  
  1322. // IDA: void __usercall ReceivedGuaranteeReply(tNet_contents *pContents@<EAX>)
  1323. void ReceivedGuaranteeReply(tNet_contents* pContents) {
  1324.     int i;
  1325.     LOG_TRACE("(%p)", pContents);
  1326.  
  1327.     for (i = 0; i < gNext_guarantee; i++) {
  1328.         if (gGuarantee_list[i].guarantee_number == pContents->data.reply.guarantee_number) {
  1329.             gGuarantee_list[i].recieved = 1;
  1330.         }
  1331.     }
  1332. }
  1333.  
  1334. // IDA: void __usercall ReceivedHeadup(tNet_contents *pContents@<EAX>)
  1335. void ReceivedHeadup(tNet_contents* pContents) {
  1336.     LOG_TRACE("(%p)", pContents);
  1337.  
  1338.     if (gProgram_state.racing) {
  1339.         NewTextHeadupSlot(eHeadupSlot_misc, 0, 3000, -4, pContents->data.headup.text);
  1340.     }
  1341. }
  1342.  
  1343. // IDA: void __usercall ReceivedHostQuery(tNet_contents *pContents@<EAX>, tNet_message *pMessage@<EDX>)
  1344. void ReceivedHostQuery(tNet_contents* pContents, tNet_message* pMessage) {
  1345.     tNet_message* message;
  1346.     LOG_TRACE("(%p, %p)", pContents, pMessage);
  1347.  
  1348.     message = NetBuildMessage(NETMSGID_HOSTREPLY, 0);
  1349.     message->contents.data.heres_where_we_at.race_has_started = gProgram_state.racing;
  1350.     message->contents.data.heres_where_we_at.race_index = gProgram_state.current_race_index;
  1351.     message->contents.data.heres_where_we_at.pending_race = gPending_race;
  1352.     NetGuaranteedSendMessageToPlayer(gCurrent_net_game, message, pMessage->sender, NULL);
  1353.     if (gProgram_state.racing) {
  1354.         SignalToStartRace();
  1355.         UpdateEnvironments();
  1356.     }
  1357. }
  1358.  
  1359. // IDA: void __usercall ReceivedHostReply(tNet_contents *pContents@<EAX>)
  1360. void ReceivedHostReply(tNet_contents* pContents) {
  1361.     //tNet_message* message; // Pierre-Marie Baty -- unused variable
  1362.     LOG_TRACE("(%p)", pContents);
  1363.  
  1364.     if (pContents->data.heres_where_we_at.race_index != gProgram_state.current_race_index) {
  1365.         NetLeaveGame(gCurrent_net_game);
  1366.         NetFullScreenMessage(128, 0);
  1367.         gProgram_state.prog_status = eProg_idling;
  1368.     }
  1369.     if (pContents->data.heres_where_we_at.race_has_started) {
  1370.         if (gCurrent_net_game->options.open_game) {
  1371.             gPending_race = pContents->data.heres_where_we_at.pending_race;
  1372.         } else {
  1373.             NetFullScreenMessage(89, 0);
  1374.             gProgram_state.prog_status = eProg_idling;
  1375.         }
  1376.     }
  1377. }
  1378.  
  1379. // IDA: void __usercall SendGuaranteeReply(tNet_message *pMessage@<EAX>, void *pSender_address@<EDX>)
  1380. void SendGuaranteeReply(tNet_message* pMessage, void* pSender_address) {
  1381.     tNet_message* message;
  1382.     LOG_TRACE("(%p, %p)", pMessage, pSender_address);
  1383.  
  1384.     message = NetBuildMessage(NETMSGID_GUARANTEEREPLY, 0);
  1385.     message->contents.data.reply.guarantee_number = pMessage->guarantee_number;
  1386.     pMessage->guarantee_number = 0;
  1387.     NetSendMessageToAddress(gCurrent_net_game, message, pSender_address);
  1388. }
  1389.  
  1390. // IDA: int __usercall PlayerIsInList@<EAX>(tPlayer_ID pID@<EAX>)
  1391. int PlayerIsInList(tPlayer_ID pID) {
  1392.     int i;
  1393.     LOG_TRACE("(%d)", pID);
  1394.  
  1395.     for (i = 0; i < gNumber_of_net_players; i++) {
  1396.         if (gNet_players[i].ID == pID) {
  1397.             gNet_players[i].last_heard_from_him = PDGetTotalTime();
  1398.             return 1;
  1399.         }
  1400.     }
  1401.     return 0;
  1402. }
  1403.  
  1404. // IDA: void __usercall ReceivedTimeSync(tNet_contents *pContents@<EAX>, tNet_message *pMessage@<EDX>, tU32 pReceive_time@<EBX>)
  1405. void ReceivedTimeSync(tNet_contents* pContents, tNet_message* pMessage, tU32 pReceive_time) {
  1406.     LOG_TRACE("(%p, %p, %d)", pContents, pMessage, pReceive_time);
  1407.     NOT_IMPLEMENTED();
  1408. }
  1409.  
  1410. // IDA: void __usercall ReceivedConfirm(tNet_contents *pContents@<EAX>)
  1411. void ReceivedConfirm(tNet_contents* pContents) {
  1412.     //int i; // Pierre-Marie Baty -- unused variable
  1413.     LOG_TRACE("(%p)", pContents);
  1414.     NOT_IMPLEMENTED();
  1415. }
  1416.  
  1417. // IDA: void __usercall ReceivedDisableCar(tNet_contents *pContents@<EAX>)
  1418. void ReceivedDisableCar(tNet_contents* pContents) {
  1419.     LOG_TRACE("(%p)", pContents);
  1420.     NOT_IMPLEMENTED();
  1421. }
  1422.  
  1423. // IDA: void __usercall ReceivedEnableCar(tNet_contents *pContents@<EAX>)
  1424. void ReceivedEnableCar(tNet_contents* pContents) {
  1425.     LOG_TRACE("(%p)", pContents);
  1426.     NOT_IMPLEMENTED();
  1427. }
  1428.  
  1429. // IDA: void __usercall ReceivedScores(tNet_contents *pContents@<EAX>)
  1430. void ReceivedScores(tNet_contents* pContents) {
  1431.     //int i; // Pierre-Marie Baty -- unused variable
  1432.     LOG_TRACE("(%p)", pContents);
  1433.     NOT_IMPLEMENTED();
  1434. }
  1435.  
  1436. // IDA: void __usercall ReceivedWasted(tNet_contents *pContents@<EAX>)
  1437. void ReceivedWasted(tNet_contents* pContents) {
  1438.     //tNet_game_player_info* victim; // Pierre-Marie Baty -- unused variable
  1439.     //tNet_game_player_info* culprit; // Pierre-Marie Baty -- unused variable
  1440.     //char s[256]; // Pierre-Marie Baty -- unused variable
  1441.     //tCar_spec* car; // Pierre-Marie Baty -- unused variable
  1442.     //static tS32 last_got_wasted_time; // Pierre-Marie Baty -- unused variable
  1443.     //static tS32 last_wasted_em_time; // Pierre-Marie Baty -- unused variable
  1444.     //static tS32 last_wasty_message_time; // Pierre-Marie Baty -- unused variable
  1445.     //static tNet_game_player_info* last_culprit; // Pierre-Marie Baty -- unused variable
  1446.     //static tNet_game_player_info* last_victim; // Pierre-Marie Baty -- unused variable
  1447.     LOG_TRACE("(%p)", pContents);
  1448.     NOT_IMPLEMENTED();
  1449. }
  1450.  
  1451. // IDA: void __usercall ReceivedCarDetailsReq(tNet_contents *pContents@<EAX>, void *pSender_address@<EDX>)
  1452. void ReceivedCarDetailsReq(tNet_contents* pContents, void* pSender_address) {
  1453.     tNet_message* message;
  1454.     int i;
  1455.     LOG_TRACE("(%p, %p)", pContents, pSender_address);
  1456.  
  1457.     message = NetBuildMessage(NETMSGID_CARDETAILS, 0);
  1458.     message->contents.data.car_details.count = gNumber_of_net_players;
  1459.     for (i = 0; i < gNumber_of_net_players; i++) {
  1460.         message->contents.data.car_details.details[i].car_index = gNet_players[i].car_index;
  1461.         // truncates from 32 to 16 characters
  1462.         memcpy(message->contents.data.car_details.details[i].owner, gNet_players[i].player_name, sizeof(message->contents.data.car_details.details[i].owner));
  1463.         message->contents.data.car_details.details[i].owner[sizeof(message->contents.data.car_details.details[i].owner) - 1] = '\0';
  1464.     }
  1465.     NetGuaranteedSendMessageToAddress(gCurrent_net_game, message, pSender_address, NULL);
  1466. }
  1467.  
  1468. // IDA: void __usercall ReceivedCarDetails(tNet_contents *pContents@<EAX>)
  1469. void ReceivedCarDetails(tNet_contents* pContents) {
  1470.     int i;
  1471.     int j;
  1472.     LOG_TRACE("(%p)", pContents);
  1473.  
  1474.     SetNetAvailability(gNet_options);
  1475.     for (i = 0; i < gNumber_of_racers; i++) {
  1476.         for (j = 0; j < pContents->data.car_details.count; j++) {
  1477.             if (i == pContents->data.car_details.details[j].car_index) {
  1478.                 gCar_details[i].ownership = eCar_owner_someone;
  1479.                 strcpy(gCar_details[i].name, pContents->data.car_details.details[j].owner);
  1480.             }
  1481.         }
  1482.     }
  1483.     gReceived_car_details = 1;
  1484. }
  1485.  
  1486. // IDA: void __usercall ReceivedGameScores(tNet_contents *pContents@<EAX>)
  1487. void ReceivedGameScores(tNet_contents* pContents) {
  1488.     //int i; // Pierre-Marie Baty -- unused variable
  1489.     LOG_TRACE("(%p)", pContents);
  1490.     NOT_IMPLEMENTED();
  1491. }
  1492.  
  1493. // IDA: void __usercall ReceivedMessage(tNet_message *pMessage@<EAX>, void *pSender_address@<EDX>, tU32 pReceive_time@<EBX>)
  1494. void ReceivedMessage(tNet_message* pMessage, void* pSender_address, tU32 pReceive_time) {
  1495.     tNet_contents* contents;
  1496.     int i;
  1497.     LOG_TRACE("(%p, %p, %d)", pMessage, pSender_address, pReceive_time);
  1498.  
  1499.     contents = &pMessage->contents;
  1500.     if (pMessage->guarantee_number != 0) {
  1501.         SendGuaranteeReply(pMessage, pSender_address);
  1502.     }
  1503.     if (!gProgram_state.racing && gRace_only_flags[pMessage->contents.header.type]) {
  1504.         return;
  1505.     }
  1506.     if (gOnly_receive_guarantee_replies && pMessage->contents.header.type != NETMSGID_GUARANTEEREPLY) {
  1507.         return;
  1508.     }
  1509.  
  1510.     for (i = 0; i < pMessage->num_contents; i++) {
  1511.         if (contents->header.type <= NETMSGID_CARDETAILS || PlayerIsInList(pMessage->sender)) {
  1512.             switch (contents->header.type) {
  1513.             case NETMSGID_SENDMEDETAILS: // 0x00,
  1514.                 ReceivedSendMeDetails(contents, pSender_address);
  1515.                 break;
  1516.             case NETMSGID_DETAILS: // 0x01,
  1517.                 ReceivedDetails(contents);
  1518.                 break;
  1519.             case NETMSGID_JOIN: // 0x02,
  1520.                 ReceivedJoin(contents, pSender_address);
  1521.                 break;
  1522.             case NETMSGID_NEWPLAYERLIST: // 0x03,
  1523.                 ReceivedNewPlayerList(contents, pMessage);
  1524.                 break;
  1525.             case NETMSGID_GUARANTEEREPLY: // 0x04,
  1526.                 ReceivedGuaranteeReply(contents);
  1527.                 break;
  1528.             case NETMSGID_CARDETAILSREQ: // 0x05,
  1529.                 ReceivedCarDetailsReq(contents, pSender_address);
  1530.                 break;
  1531.             case NETMSGID_CARDETAILS: // 0x06,
  1532.                 ReceivedCarDetails(contents);
  1533.                 break;
  1534.             case NETMSGID_LEAVE: // 0x07,
  1535.                 ReceivedLeave(contents, pMessage);
  1536.                 break;
  1537.             case NETMSGID_HOSTICIDE: // 0x08,
  1538.                 ReceivedHosticide(contents);
  1539.                 break;
  1540.             case NETMSGID_RACEOVER: // 0x09,
  1541.                 ReceivedRaceOver(contents);
  1542.                 break;
  1543.             case NETMSGID_STATUSREPORT: // 0x0a,
  1544.                 ReceivedStatusReport(contents, pMessage);
  1545.                 break;
  1546.             case NETMSGID_STARTRACE: // 0x0b,
  1547.                 ReceivedStartRace(contents);
  1548.                 break;
  1549.             case NETMSGID_HEADUP: // 0x0c,
  1550.                 ReceivedHeadup(contents);
  1551.                 break;
  1552.             case NETMSGID_HOSTQUERY: // 0x0d,
  1553.                 ReceivedHostQuery(contents, pMessage);
  1554.                 break;
  1555.             case NETMSGID_HOSTREPLY: // 0x0e,
  1556.                 ReceivedHostReply(contents);
  1557.                 break;
  1558.             case NETMSGID_MECHANICS: // 0x0f,
  1559.                 ReceivedMechanics(contents);
  1560.                 break;
  1561.             case NETMSGID_NONCAR_INFO: // 0x10,
  1562.                 ReceivedNonCar(contents);
  1563.                 break;
  1564.             case NETMSGID_TIMESYNC: // 0x11,
  1565.                 ReceivedTimeSync(contents, pMessage, pReceive_time);
  1566.                 break;
  1567.             case NETMSGID_CONFIRM: // 0x12,
  1568.                 ReceivedConfirm(contents);
  1569.                 break;
  1570.             case NETMSGID_DISABLECAR: // 0x13,
  1571.                 ReceivedDisableCar(contents);
  1572.                 break;
  1573.             case NETMSGID_ENABLECAR: // 0x14,
  1574.                 ReceivedEnableCar(contents);
  1575.                 break;
  1576.             case NETMSGID_POWERUP: // 0x15,
  1577.                 ReceivedPowerup(contents);
  1578.                 break;
  1579.             case NETMSGID_RECOVER: // 0x16,
  1580.                 ReceivedRecover(contents);
  1581.                 break;
  1582.             case NETMSGID_SCORES: // 0x17,
  1583.                 ReceivedScores(contents);
  1584.                 break;
  1585.             case NETMSGID_WASTED: // 0x18,
  1586.                 ReceivedWasted(contents);
  1587.                 break;
  1588.             case NETMSGID_PEDESTRIAN: // 0x19,
  1589.                 ReceivedPedestrian(contents, pMessage, pReceive_time);
  1590.                 break;
  1591.             case NETMSGID_GAMEPLAY: // 0x1a,
  1592.                 ReceivedGameplay(contents, pMessage, pReceive_time);
  1593.                 break;
  1594.             case NETMSGID_NONCARPOSITION: // 0x1b,
  1595.                 ReceivedNonCarPosition(contents);
  1596.                 break;
  1597.             case NETMSGID_COPINFO: // 0x1c,
  1598.                 ReceivedCopInfo(contents);
  1599.                 break;
  1600.             case NETMSGID_GAMESCORES: // 0x1d,
  1601.                 ReceivedGameScores(contents);
  1602.                 break;
  1603.             case NETMSGID_OILSPILL: // 0x1e,
  1604.                 ReceivedOilSpill(contents);
  1605.                 break;
  1606.             case NETMSGID_CRUSHPOINT: // 0x1f,
  1607.                 RecievedCrushPoint(contents);
  1608.                 break;
  1609.             }
  1610.         }
  1611.         contents = (tNet_contents*)((tU8*)contents + contents->header.contents_size);
  1612.     }
  1613. }
  1614.  
  1615. // IDA: void __cdecl NetReceiveAndProcessMessages()
  1616. void NetReceiveAndProcessMessages(void) {
  1617.     tNet_message* message;
  1618.     void* sender_address;
  1619.     tU32 receive_time;
  1620.     int old_net_service;
  1621.     LOG_TRACE("()");
  1622.  
  1623.     old_net_service = gIn_net_service;
  1624.     if (gNet_mode != eNet_mode_none || gJoin_list_mode) {
  1625.         gIn_net_service = 1;
  1626.         while ((message = NetGetNextMessage(gCurrent_net_game, &sender_address)) != NULL) {
  1627.             receive_time = GetRaceTime();
  1628.             if (message->magic_number == 0x763a5058) {
  1629.                 CheckCheckSum(message);
  1630.                 ReceivedMessage(message, sender_address, receive_time);
  1631.             } else {
  1632.                 message->guarantee_number = 0;
  1633.             }
  1634.             NetDisposeMessage(gCurrent_net_game, message);
  1635.         }
  1636.     }
  1637.     gIn_net_service = old_net_service;
  1638. }
  1639.  
  1640. // IDA: void __cdecl BroadcastStatus()
  1641. void BroadcastStatus(void) {
  1642.     tNet_message* message;
  1643.     LOG_TRACE("()");
  1644.  
  1645.     message = NetBuildMessage(NETMSGID_STATUSREPORT, 0);
  1646.     message->contents.data.report.status = gNet_players[gThis_net_player_index].player_status;
  1647.     NetSendMessageToAllPlayers(gCurrent_net_game, message);
  1648. }
  1649.  
  1650. // IDA: void __cdecl CheckForDisappearees()
  1651. void CheckForDisappearees(void) {
  1652.     int i;
  1653.     //int j; // Pierre-Marie Baty -- unused variable
  1654.     tU32 the_time;
  1655.     char s[256];
  1656.     //char* s2; // Pierre-Marie Baty -- unused variable
  1657.     LOG_TRACE("()");
  1658.  
  1659.     the_time = PDGetTotalTime();
  1660.     if (gNet_mode == eNet_mode_host) {
  1661.         for (i = 0; i < gNumber_of_net_players; i++) {
  1662.             if (!gNet_players[i].host && gNet_players[i].last_heard_from_him != 0 && the_time - gNet_players[i].last_heard_from_him >= 20000) {
  1663.                 strcpy(s, gNet_players[i].player_name);
  1664.                 strcat(s, " ");
  1665.                 strcat(s, GetMiscString(kMiscString_IS_NO_LONGER_RESPONDING));
  1666.                 NetSendHeadupToAllPlayers(s);
  1667.                 KickPlayerOut(gNet_players[i].ID);
  1668.                 if (gProgram_state.racing) {
  1669.                     NewTextHeadupSlot(eHeadupSlot_misc, 0, 3000, -4, s);
  1670.                 }
  1671.             }
  1672.         }
  1673.     } else if (!gHost_died && gNumber_of_net_players != 0 && gNet_players[0].last_heard_from_him != 0 && the_time - gNet_players[0].last_heard_from_him >= 20000) {
  1674.         HostHasBittenTheDust(91);
  1675.     }
  1676. }
  1677.  
  1678. // IDA: void __cdecl CheckForPendingStartRace()
  1679. void CheckForPendingStartRace(void) {
  1680.     int i;
  1681.     LOG_TRACE("()");
  1682.  
  1683.     if (gNet_mode == eNet_mode_host && gNeed_to_send_start_race) {
  1684.         for (i = 1; i < gNumber_of_net_players; i++) {
  1685.             if (gNet_players[i].awaiting_confirmation) {
  1686.                 return;
  1687.             }
  1688.         }
  1689.         SignalToStartRace();
  1690.     }
  1691. }
  1692.  
  1693. // IDA: void __usercall NetService(int pIn_race@<EAX>)
  1694. void NetService(int pIn_race) {
  1695.     tU32 time;
  1696.     static tU32 last_status_broadcast;
  1697.  
  1698.     if (gIn_net_service || gNet_service_disable) {
  1699.         return;
  1700.     }
  1701.     time = PDGetTotalTime();
  1702.     gIn_net_service = 1;
  1703.     if (gJoin_list_mode) {
  1704.         NetFreeExcessMemory();
  1705.         DoNextJoinPoll();
  1706.         NetReceiveAndProcessMessages();
  1707.     } else {
  1708.         if (gNet_mode != eNet_mode_none) {
  1709.             NetFreeExcessMemory();
  1710.             if (!pIn_race) {
  1711.                 NetReceiveAndProcessMessages();
  1712.             }
  1713.             if (time - last_status_broadcast > 1000) {
  1714.                 last_status_broadcast = PDGetTotalTime();
  1715.                 BroadcastStatus();
  1716.             }
  1717.             CheckForDisappearees();
  1718.             CheckForPendingStartRace();
  1719.         }
  1720.     }
  1721.     if (gJoin_list_mode || gNet_mode != eNet_mode_none) {
  1722.         ResendGuaranteedMessages();
  1723.         if (time > gLast_flush_message + 200) {
  1724.             NetSendMessageStacks();
  1725.         }
  1726.     }
  1727.     gIn_net_service = 0;
  1728. }
  1729.  
  1730. // IDA: void __usercall NetFinishRace(tNet_game_details *pDetails@<EAX>, tRace_over_reason pReason@<EDX>)
  1731. void NetFinishRace(tNet_game_details* pDetails, tRace_over_reason pReason) {
  1732.     tNet_message* the_message;
  1733.     LOG_TRACE("(%p, %d)", pDetails, pReason);
  1734.  
  1735.     gNeed_to_send_start_race = 0;
  1736.     the_message = NetBuildMessage(NETMSGID_RACEOVER, 0);
  1737.     the_message->contents.data.race_over.reason = pReason;
  1738.     NetGuaranteedSendMessageToAllPlayers(gCurrent_net_game, the_message, NULL);
  1739. }
  1740.  
  1741. // IDA: void __usercall NetPlayerStatusChanged(tPlayer_status pNew_status@<EAX>)
  1742. void NetPlayerStatusChanged(tPlayer_status pNew_status) {
  1743.     LOG_TRACE("(%d)", pNew_status);
  1744.     //tNet_message* the_message; // Pierre-Marie Baty -- unused variable
  1745.  
  1746.     if (gNet_mode != eNet_mode_none && pNew_status != gNet_players[gThis_net_player_index].player_status) {
  1747.         gNet_players[gThis_net_player_index].player_status = pNew_status;
  1748.         BroadcastStatus();
  1749.         if (gProgram_state.current_car.disabled && pNew_status >= ePlayer_status_racing && pNew_status != ePlayer_status_recovering) {
  1750.             EnableCar(&gProgram_state.current_car);
  1751.         } else if (!gProgram_state.current_car.disabled && pNew_status < ePlayer_status_racing) {
  1752.             DisableCar(&gProgram_state.current_car);
  1753.         }
  1754.     }
  1755. }
  1756.  
  1757. // IDA: tPlayer_status __cdecl NetGetPlayerStatus()
  1758. tPlayer_status NetGetPlayerStatus(void) {
  1759.     LOG_TRACE("()");
  1760.  
  1761.     return gNet_players[gThis_net_player_index].player_status;
  1762. }
  1763.  
  1764. // IDA: int __usercall NetGuaranteedSendMessageToAllPlayers@<EAX>(tNet_game_details *pDetails@<EAX>, tNet_message *pMessage@<EDX>, int (*pNotifyFail)(tU32, tNet_message*)@<EBX>)
  1765. int NetGuaranteedSendMessageToAllPlayers(tNet_game_details* pDetails, tNet_message* pMessage, int (*pNotifyFail)(tU32, tNet_message*)) {
  1766.     int i;
  1767.     int err;
  1768.     LOG_TRACE("(%p, %p, %p)", pDetails, pMessage, pNotifyFail);
  1769.  
  1770.     err = 0;
  1771.     if (gNumber_of_net_players == 1) {
  1772.         NetDisposeMessage(pDetails, pMessage);
  1773.         err = 0;
  1774.     } else {
  1775.         for (i = 0; i < gNumber_of_net_players; i++) {
  1776.             if (gThis_net_player_index != i) {
  1777.                 err |= NetGuaranteedSendMessageToAddress(pDetails, pMessage, &gNet_players[i], pNotifyFail);
  1778.             }
  1779.         }
  1780.     }
  1781.     return err;
  1782. }
  1783.  
  1784. // IDA: int __usercall NetGuaranteedSendMessageToEverybody@<EAX>(tNet_game_details *pDetails@<EAX>, tNet_message *pMessage@<EDX>, int (*pNotifyFail)(tU32, tNet_message*)@<EBX>)
  1785. int NetGuaranteedSendMessageToEverybody(tNet_game_details* pDetails, tNet_message* pMessage, int (*pNotifyFail)(tU32, tNet_message*)) {
  1786.     LOG_TRACE("(%p, %p, %p)", pDetails, pMessage, pNotifyFail);
  1787.     NOT_IMPLEMENTED();
  1788. }
  1789.  
  1790. // IDA: int __usercall NetGuaranteedSendMessageToHost@<EAX>(tNet_game_details *pDetails@<EAX>, tNet_message *pMessage@<EDX>, int (*pNotifyFail)(tU32, tNet_message*)@<EBX>)
  1791. int NetGuaranteedSendMessageToHost(tNet_game_details* pDetails, tNet_message* pMessage, int (*pNotifyFail)(tU32, tNet_message*)) {
  1792.     LOG_TRACE("(%p, %p, %p)", pDetails, pMessage, pNotifyFail);
  1793.  
  1794.     return NetGuaranteedSendMessageToAddress(pDetails, pMessage, &pDetails->pd_net_info, pNotifyFail);
  1795. }
  1796.  
  1797. // IDA: int __usercall NetGuaranteedSendMessageToPlayer@<EAX>(tNet_game_details *pDetails@<EAX>, tNet_message *pMessage@<EDX>, tPlayer_ID pPlayer@<EBX>, int (*pNotifyFail)(tU32, tNet_message*)@<ECX>)
  1798. int NetGuaranteedSendMessageToPlayer(tNet_game_details* pDetails, tNet_message* pMessage, tPlayer_ID pPlayer, int (*pNotifyFail)(tU32, tNet_message*)) {
  1799.     int i;
  1800.     LOG_TRACE("(%p, %p, %d, %p)", pDetails, pMessage, pPlayer, pNotifyFail);
  1801.  
  1802.     for (i = 0; i <= gNumber_of_net_players; i++) {
  1803.         if (pPlayer == gNet_players[i].ID) {
  1804.             break;
  1805.         }
  1806.     }
  1807.     if (i == gNumber_of_net_players) {
  1808.         return -1;
  1809.     }
  1810.     if (gLocal_net_ID != pPlayer) {
  1811.         return NetGuaranteedSendMessageToAddress(pDetails, pMessage, &gNet_players[i].pd_net_info, pNotifyFail);
  1812.     }
  1813.     pMessage->sender = gLocal_net_ID;
  1814.     pMessage->senders_time_stamp = PDGetTotalTime();
  1815.     pMessage->num_contents = 1;
  1816.     pMessage->guarantee_number = 0;
  1817.     ReceivedMessage(pMessage, &gNet_players[i], GetRaceTime());
  1818.     NetDisposeMessage(pDetails, pMessage);
  1819.     return 0;
  1820. }
  1821.  
  1822. // IDA: int __usercall NetGuaranteedSendMessageToAddress@<EAX>(tNet_game_details *pDetails@<EAX>, tNet_message *pMessage@<EDX>, void *pAddress@<EBX>, int (*pNotifyFail)(tU32, tNet_message*)@<ECX>)
  1823. int NetGuaranteedSendMessageToAddress(tNet_game_details* pDetails, tNet_message* pMessage, void* pAddress, int (*pNotifyFail)(tU32, tNet_message*)) {
  1824.     char buffer[256]; // Added by Dethrace
  1825.     LOG_TRACE("(%p, %p, %p, %p)", pDetails, pMessage, pAddress, pNotifyFail);
  1826.  
  1827.     if (gNet_mode == eNet_mode_none && !gJoin_list_mode) {
  1828.         return -3;
  1829.     }
  1830.     pMessage->sender = gLocal_net_ID;
  1831.     pMessage->senders_time_stamp = PDGetTotalTime();
  1832.     if (gNext_guarantee >= COUNT_OF(gGuarantee_list)) {
  1833.         sprintf(buffer, "Guarantee list full %d", pMessage->contents.header.type);
  1834.         NewTextHeadupSlot(eHeadupSlot_misc, 0, 500, -1, buffer);
  1835.         pMessage->guarantee_number = 0;
  1836.         return 0;
  1837.     }
  1838.     pMessage->guarantee_number = gGuarantee_number;
  1839.     gGuarantee_list[gNext_guarantee].guarantee_number = gGuarantee_number;
  1840.     gGuarantee_number++;
  1841.     gGuarantee_list[gNext_guarantee].message = pMessage;
  1842.     gGuarantee_list[gNext_guarantee].send_time = PDGetTotalTime();
  1843.     gGuarantee_list[gNext_guarantee].next_resend_time = gGuarantee_list[gNext_guarantee].send_time + 100;
  1844.     gGuarantee_list[gNext_guarantee].resend_period = 100;
  1845.     memcpy(&gGuarantee_list[gNext_guarantee].pd_address, pAddress, sizeof(tPD_net_player_info));
  1846.     gGuarantee_list[gNext_guarantee].NotifyFail = pNotifyFail;
  1847.     gGuarantee_list[gNext_guarantee].recieved = 0;
  1848.     gNext_guarantee++;
  1849.     DoCheckSum(pMessage);
  1850.     return PDNetSendMessageToAddress(pDetails, pMessage, pAddress);
  1851. }
  1852.  
  1853. // IDA: void __cdecl ResendGuaranteedMessages()
  1854. void ResendGuaranteedMessages(void) {
  1855.     int i;
  1856.     int j;
  1857.     tU32 time;
  1858.     LOG_TRACE("()");
  1859.  
  1860.     i = 0;
  1861.     time = PDGetTotalTime();
  1862.     for (j = 0; j < gNext_guarantee; j++) {
  1863.         if (i != j) {
  1864.             memcpy(&gGuarantee_list[i], &gGuarantee_list[j], sizeof(tGuaranteed_message));
  1865.         }
  1866.         if (!gGuarantee_list[i].recieved) {
  1867.             if (gGuarantee_list[i].NotifyFail != NULL) {
  1868.                 gGuarantee_list[i].recieved |= gGuarantee_list[i].NotifyFail(time - gGuarantee_list[i].send_time, gGuarantee_list[i].message);
  1869.             } else {
  1870.                 if (time - gGuarantee_list[i].send_time > 10000) {
  1871.                     gGuarantee_list[i].recieved = 1;
  1872.                 }
  1873.             }
  1874.         }
  1875.         if (!gGuarantee_list[i].recieved) {
  1876.             if (time > gGuarantee_list[i].next_resend_time) {
  1877.                 gGuarantee_list[i].message->guarantee_number = gGuarantee_list[i].guarantee_number;
  1878.                 GetCheckSum(gGuarantee_list[i].message);
  1879.                 PDNetSendMessageToAddress(gCurrent_net_game, gGuarantee_list[i].message, &gGuarantee_list[i].pd_address);
  1880.                 gGuarantee_list[i].resend_period = (tU32)(gGuarantee_list[i].resend_period * 1.2f);
  1881.                 gGuarantee_list[i].next_resend_time += gGuarantee_list[i].resend_period;
  1882.             }
  1883.             i++;
  1884.         } else if ((i <= 0 || gGuarantee_list[i - 1].message != gGuarantee_list[i].message)
  1885.             && (gNext_guarantee <= j + 1 || gGuarantee_list[j + 1].message != gGuarantee_list[i].message)) {
  1886.             gGuarantee_list[i].message->guarantee_number = 0;
  1887.             NetDisposeMessage(gCurrent_net_game, gGuarantee_list[i].message);
  1888.         }
  1889.     }
  1890.     gNext_guarantee = i;
  1891. }
  1892.  
  1893. // IDA: int __usercall SampleFailNotifier@<EAX>(tU32 pAge@<EAX>, tNet_message *pMessage@<EDX>)
  1894. int SampleFailNotifier(tU32 pAge, tNet_message* pMessage) {
  1895.     LOG_TRACE("(%d, %p)", pAge, pMessage);
  1896.     NOT_IMPLEMENTED();
  1897. }
  1898.  
  1899. // IDA: void __cdecl NetWaitForGuaranteeReplies()
  1900. void NetWaitForGuaranteeReplies(void) {
  1901.     tU32 start_time;
  1902.     LOG_TRACE("()");
  1903.  
  1904.     start_time = PDGetTotalTime();
  1905.     while (gNext_guarantee != 0) {
  1906.         if (PDGetTotalTime() - start_time >= 5000) {
  1907.             break;
  1908.         }
  1909.         NetService(0);
  1910.     }
  1911. }
  1912.  
  1913. // IDA: tNet_game_player_info* __usercall NetPlayerFromID@<EAX>(tPlayer_ID pPlayer@<EAX>)
  1914. tNet_game_player_info* NetPlayerFromID(tPlayer_ID pPlayer) {
  1915.     //int i; // Pierre-Marie Baty -- unused variable
  1916.     LOG_TRACE("(%d)", pPlayer);
  1917.     NOT_IMPLEMENTED();
  1918. }
  1919.  
  1920. // IDA: tCar_spec* __usercall NetCarFromPlayerID@<EAX>(tPlayer_ID pPlayer@<EAX>)
  1921. tCar_spec* NetCarFromPlayerID(tPlayer_ID pPlayer) {
  1922.     //int i; // Pierre-Marie Baty -- unused variable
  1923.     //tNet_game_player_info* player; // Pierre-Marie Baty -- unused variable
  1924.     LOG_TRACE("(%d)", pPlayer);
  1925.     NOT_IMPLEMENTED();
  1926. }
  1927.  
  1928. // IDA: tNet_game_player_info* __usercall NetPlayerFromCar@<EAX>(tCar_spec *pCar@<EAX>)
  1929. tNet_game_player_info* NetPlayerFromCar(tCar_spec* pCar) {
  1930.     //int i; // Pierre-Marie Baty -- unused variable
  1931.     LOG_TRACE("(%p)", pCar);
  1932.     NOT_IMPLEMENTED();
  1933. }
  1934.  
  1935. // IDA: tU32 __usercall DoCheckSum@<EAX>(tNet_message *pMessage@<EAX>)
  1936. tU32 DoCheckSum(tNet_message* pMessage) {
  1937.     //int i; // Pierre-Marie Baty -- unused variable
  1938.     //int j; // Pierre-Marie Baty -- unused variable
  1939.     //tU32 the_sum; // Pierre-Marie Baty -- unused variable
  1940.     //tU32* p; // Pierre-Marie Baty -- unused variable
  1941.     //tU8* q; // Pierre-Marie Baty -- unused variable
  1942.     LOG_TRACE("(%p)", pMessage);
  1943.  
  1944.     // empty function
  1945.     return 0;
  1946. }
  1947.  
  1948. // IDA: void __usercall GetCheckSum(tNet_message *pMessage@<EAX>)
  1949. void GetCheckSum(tNet_message* pMessage) {
  1950.     LOG_TRACE("(%p)", pMessage);
  1951. }
  1952.  
  1953. // IDA: void __usercall CheckCheckSum(tNet_message *pMessage@<EAX>)
  1954. void CheckCheckSum(tNet_message* pMessage) {
  1955.     LOG_TRACE("(%p)", pMessage);
  1956. }
  1957.