#include "network.h"
#include "brender/brender.h"
#include "car.h"
#include "controls.h"
#include "displays.h"
#include "errors.h"
#include "globvars.h"
#include "globvrpb.h"
#include "graphics.h"
#include "harness/hooks.h"
#include "harness/trace.h"
#include "loading.h"
#include "netgame.h"
#include "newgame.h"
#include "oil.h"
#include "opponent.h"
#include "pd/net.h"
#include "pd/sys.h"
#include "pedestrn.h"
#include "piping.h"
#include "powerup.h"
#include "replay.h"
#include "spark.h"
#include "structur.h"
#include "utility.h"
#include "world.h"
#include <stdlib.h>
tU32 gMess_max_flags;
tU32 gMess_mid_flags;
tU32 gMess_min_flags;
tU32 gGuarantee_number;
int gNet_service_disable = 0;
int gIn_net_service = 0;
int gPlayer_list_batch_number = 0;
int gOnly_receive_guarantee_replies = 0;
void* gMessage_to_free;
tNet_message* gBroadcast_stack;
tNet_message* gTo_host_stack;
tU32 gLast_flush_message = 0;
int gRace_only_flags[33] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1,
0
};
int gJoin_list_mode;
tNet_game_player_info gNew_net_players[6];
tGuaranteed_message gGuarantee_list[100]; // DOS debug symbols has this as [150]
tMid_message* gMid_messages;
tU32 gLast_player_list_received;
tMin_message* gMin_messages;
void (*gAdd_proc)(tNet_game_details*);
int gReceiving_batch_number;
int gReceiving_new_players;
tMax_message* gMax_messages;
int gNext_guarantee;
tU32 gAsk_time;
int gNet_initialised;
int gDont_allow_joiners;
tNet_game_details* gCurrent_join_poll_game;
int gMessage_header_size;
int gJoin_poll_index;
int gJoin_request_denied;
int gHost_died;
int gCar_was_taken;
int gBastard_has_answered;
int gTime_for_next_one;
int gReceived_game_scores;
#define MIN_MESSAGES_CAPACITY 20
#define MID_MESSAGES_CAPACITY 10
#define MAX_MESSAGES_CAPACITY 20
#define MAX_MESAGE_STACK_SIZE 512
// IDA: int __cdecl NetInitialise()
int NetInitialise(void) {
int i;
LOG_TRACE("()");
SwitchToRealResolution();
InitAbuseomatic();
gNet_service_disable = 0;
gIn_net_service = 0;
gMessage_header_size = PDNetGetHeaderSize();
gOnly_receive_guarantee_replies = 0;
gMin_messages = BrMemAllocate(MIN_MESSAGES_CAPACITY * (gMessage_header_size + sizeof(tMin_message)), kMem_net_min_messages);
gMid_messages = BrMemAllocate(MID_MESSAGES_CAPACITY * (gMessage_header_size + sizeof(tMid_message)), kMem_net_mid_messages);
gMax_messages = BrMemAllocate(MAX_MESSAGES_CAPACITY * (gMessage_header_size + sizeof(tMax_message)), kMem_net_max_messages);
for (i = 0; i < MIN_MESSAGES_CAPACITY; i++) {
((tNet_message*)&gMin_messages[i])->contents.header.type = NETMSGID_NONE;
}
for (i = 0; i < MID_MESSAGES_CAPACITY; i++) {
((tNet_message*)&gMid_messages[i])->contents.header.type = NETMSGID_NONE;
}
for (i = 0; i < MAX_MESSAGES_CAPACITY; i++) {
((tNet_message*)&gMax_messages[i])->contents.header.type = NETMSGID_NONE;
}
gNet_initialised = PDNetInitialise() == 0;
if (gNet_initialised) {
InitNetHeadups();
}
GenerateItFoxShadeTable();
gDont_allow_joiners = 0;
SwitchToLoresMode();
return !gNet_initialised;
}
// IDA: int __cdecl NetShutdown()
int NetShutdown(void) {
int err;
//int i; // Pierre-Marie Baty -- unused variable
LOG_TRACE("()");
err = PDNetShutdown();
DisposeAbuseomatic();
BrMemFree(gMin_messages);
BrMemFree(gMid_messages);
BrMemFree(gMax_messages);
DisposeNetHeadups();
return err;
}
// IDA: void __cdecl ShutdownNetIfRequired()
void ShutdownNetIfRequired(void) {
LOG_TRACE("()");
if (gNet_initialised) {
NetShutdown();
gNet_initialised = 0;
}
}
// IDA: void __cdecl DisableNetService()
void DisableNetService(void) {
LOG_TRACE("()");
gNet_service_disable = 1;
}
// IDA: void __cdecl ReenableNetService()
void ReenableNetService(void) {
LOG_TRACE("()");
gNet_service_disable = 0;
}
// IDA: int __cdecl PermitNetServiceReentrancy()
int PermitNetServiceReentrancy(void) {
int prev;
LOG_TRACE("()");
prev = !!gIn_net_service;
if (prev) {
gIn_net_service = 0;
}
return prev;
}
// IDA: void __cdecl HaltNetServiceReentrancy()
void HaltNetServiceReentrancy(void) {
LOG_TRACE("()");
NOT_IMPLEMENTED();
}
// IDA: void __usercall NetSendHeadupToAllPlayers(char *pMessage@<EAX>)
void NetSendHeadupToAllPlayers(char* pMessage) {
tNet_contents* the_contents;
LOG_TRACE("(\"%s\")", pMessage);
if (gNet_mode) {
the_contents = NetGetBroadcastContents(NETMSGID_HEADUP, 0);
strcpy(the_contents
->data.
headup.
text, pMessage
);
}
}
// IDA: void __usercall NetSendHeadupToEverybody(char *pMessage@<EAX>)
void NetSendHeadupToEverybody(char* pMessage) {
//tNet_contents* the_contents; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(\"%s\")", pMessage);
NOT_IMPLEMENTED();
}
// IDA: void __usercall NetSendHeadupToPlayer(char *pMessage@<EAX>, tPlayer_ID pPlayer@<EDX>)
void NetSendHeadupToPlayer(char* pMessage, tPlayer_ID pPlayer) {
//tNet_message* message; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(\"%s\", %d)", pMessage, pPlayer);
NOT_IMPLEMENTED();
}
// IDA: void __cdecl InitialisePlayerStati()
void InitialisePlayerStati(void) {
int i;
LOG_TRACE("()");
for (i = 0; i < COUNT_OF(gNet_players); i++) {
gNet_players[i].last_heard_from_him = PDGetTotalTime();
gNet_players[i].player_status = ePlayer_status_loading;
}
}
// IDA: void __cdecl LeaveTempGame()
void LeaveTempGame(void) {
LOG_TRACE("()");
if (gCurrent_join_poll_game != NULL) {
NetLeaveGameLowLevel(gCurrent_join_poll_game);
}
gTime_for_next_one = 1;
gCurrent_join_poll_game = NULL;
}
// IDA: void __cdecl DisposeCurrentJoinPollGame()
void DisposeCurrentJoinPollGame(void) {
LOG_TRACE("()");
if (gCurrent_join_poll_game != NULL) {
NetDisposeGameDetails(gCurrent_join_poll_game);
gCurrent_join_poll_game = NULL;
}
}
// IDA: void __cdecl DoNextJoinPoll()
void DoNextJoinPoll(void) {
tNet_message* the_message;
LOG_TRACE("()");
if (gTime_for_next_one) {
gCurrent_join_poll_game = NetAllocatePIDGameDetails();
if (gCurrent_join_poll_game != NULL) {
if (PDNetGetNextJoinGame(gCurrent_join_poll_game, gJoin_poll_index)) {
if (NetJoinGameLowLevel(gCurrent_join_poll_game, "!TEMP!")) {
DisposeCurrentJoinPollGame();
} else {
gTime_for_next_one = 0;
the_message = NetBuildMessage(NETMSGID_SENDMEDETAILS, 0);
NetSendMessageToAddress(gCurrent_join_poll_game, the_message, gCurrent_join_poll_game);
gBastard_has_answered = 0;
gAsk_time = PDGetTotalTime();
}
gJoin_poll_index++;
} else {
gJoin_poll_index = 0;
if (gCurrent_join_poll_game != NULL) {
DisposeCurrentJoinPollGame();
}
}
}
} else {
if (gBastard_has_answered) {
gAdd_proc(gCurrent_join_poll_game);
LeaveTempGame();
} else {
if (PDGetTotalTime() - gAsk_time > 10000) {
LeaveTempGame();
DisposeCurrentJoinPollGame();
}
}
}
}
// IDA: void __usercall NetStartProducingJoinList(void (*pAdd_proc)(tNet_game_details*)@<EAX>)
void NetStartProducingJoinList(void (*pAdd_proc)(tNet_game_details*)) {
LOG_TRACE("(%p)", pAdd_proc);
gAdd_proc = pAdd_proc;
gJoin_list_mode = 1;
gBastard_has_answered = 0;
gTime_for_next_one = 1;
gJoin_poll_index = 0;
gCurrent_join_poll_game = NULL;
PDNetStartProducingJoinList();
}
// IDA: void __cdecl NetEndJoinList()
void NetEndJoinList(void) {
LOG_TRACE("()");
gJoin_list_mode = 0;
DisposeCurrentJoinPollGame();
LeaveTempGame();
PDNetEndJoinList();
}
// IDA: void __usercall NetDisposePIDGameInfo(tNet_game_details *pDetails@<EAX>)
void NetDisposePIDGameInfo(tNet_game_details* pDetails) {
LOG_TRACE("(%p)", pDetails);
if (pDetails != NULL) {
BrMemFree(pDetails);
}
}
// IDA: void __usercall NetDisposeGameDetails(tNet_game_details *pDetails@<EAX>)
void NetDisposeGameDetails(tNet_game_details* pDetails) {
LOG_TRACE("(%p)", pDetails);
// LOG_WARN("NetDisposeGameDetails(%p)", pDetails);
if (pDetails != NULL) {
NetDisposePIDGameInfo(pDetails);
}
}
// IDA: tNet_game_details* __cdecl NetAllocatePIDGameDetails()
tNet_game_details* NetAllocatePIDGameDetails(void) {
//tNet_game_details* game; // Pierre-Marie Baty -- unused variable
LOG_TRACE("()");
return BrMemAllocate(sizeof(tNet_game_details), kMem_net_pid_details);
}
// IDA: void __usercall NetLeaveGameLowLevel(tNet_game_details *pDetails@<EAX>)
void NetLeaveGameLowLevel(tNet_game_details* pDetails) {
LOG_TRACE("(%p)", pDetails);
if (gNet_mode == eNet_mode_host) {
PDNetHostFinishGame(gCurrent_net_game);
} else {
PDNetLeaveGame(pDetails);
}
}
// IDA: void __usercall NetLeaveGame(tNet_game_details *pNet_game@<EAX>)
void NetLeaveGame(tNet_game_details* pNet_game) {
tNet_message* the_message;
char s[256];
//char* s2; // Pierre-Marie Baty -- unused variable
int i;
int must_revert_reentrancy;
LOG_TRACE("(%p)", pNet_game);
if (gNet_mode == eNet_mode_none) {
return;
}
gOnly_receive_guarantee_replies = 1;
if (gNet_mode == eNet_mode_host) {
gDont_allow_joiners = 1;
the_message = NetBuildMessage(NETMSGID_HOSTICIDE, 0);
must_revert_reentrancy = PermitNetServiceReentrancy();
NetGuaranteedSendMessageToAllPlayers(pNet_game, the_message, NULL);
if (must_revert_reentrancy) {
HaltNetServiceReentrancy();
}
} else if (!gHost_died) {
the_message = NetBuildMessage(NETMSGID_LEAVE, 0);
NetGuaranteedSendMessageToHost(pNet_game, the_message, NULL);
strcpy(s
, gProgram_state.
player_name[0]);
strcat(s
, GetMiscString
(kMiscString_HasLeftTheGame
));
NetSendHeadupToAllPlayers(s);
}
for (i = 0; i < gNumber_of_net_players; i++) {
DisposeCarN(i);
}
ClearOutStorageSpace(&gOur_car_storage_space);
ClearOutStorageSpace(&gNet_cars_storage_space);
must_revert_reentrancy = PermitNetServiceReentrancy();
NetSendMessageStacks();
NetWaitForGuaranteeReplies();
NetLeaveGameLowLevel(gCurrent_net_game);
if (must_revert_reentrancy) {
HaltNetServiceReentrancy();
}
gCurrent_net_game = NULL;
gNet_mode = eNet_mode_none;
gNumber_of_net_players = 0;
gProgram_state.prog_status = eProg_idling;
gOnly_receive_guarantee_replies = 0;
}
// IDA: void __usercall NetSetPlayerSystemInfo(tNet_game_player_info *pPlayer@<EAX>, void *pSender_address@<EDX>)
void NetSetPlayerSystemInfo(tNet_game_player_info* pPlayer, void* pSender_address) {
LOG_TRACE("(%p, %p)", pPlayer, pSender_address);
PDNetSetPlayerSystemInfo(pPlayer, pSender_address);
}
// IDA: void __usercall NetDisposePlayer(tNet_game_player_info *pPlayer@<EAX>)
void NetDisposePlayer(tNet_game_player_info* pPlayer) {
LOG_TRACE("(%p)", pPlayer);
NOT_IMPLEMENTED();
}
// IDA: void __usercall FillInThisPlayer(tNet_game_details *pGame@<EAX>, tNet_game_player_info *pPlayer@<EDX>, int pCar_index@<EBX>, int pHost@<ECX>)
void FillInThisPlayer(tNet_game_details* pGame, tNet_game_player_info* pPlayer, int pCar_index, int pHost) {
LOG_TRACE("(%p, %p, %d, %d)", pGame, pPlayer, pCar_index, pHost);
pPlayer->host = pHost;
pPlayer->ID = NetExtractPlayerID(pGame);
strcpy(pPlayer
->player_name
, gProgram_state.
player_name[0]);
pPlayer->this_players_time_stamp = PDGetTotalTime();
pPlayer->car_index = pCar_index;
pPlayer->reposition_time = 0;
pPlayer->last_waste_message = 0;
pPlayer->wasteage_attributed = 0;
pPlayer->name_not_clipped = 1;
pPlayer->played = 0;
pPlayer->won = 0;
pPlayer->games_score = 0;
pPlayer->race_stuff_initialised = 0;
if (pGame->options.random_car_choice && (pGame->options.car_choice == eNet_car_all || pGame->options.car_choice == eNet_car_both)) {
pPlayer->next_car_index = -1;
}
InitialisePlayerScore(pPlayer);
}
// IDA: void __usercall LoadCarN(int pIndex@<EAX>, tNet_game_player_info *pPlayer@<EDX>)
void LoadCarN(int pIndex, tNet_game_player_info* pPlayer) {
int switched_res;
LOG_TRACE("(%d, %p)", pIndex, pPlayer);
pPlayer->car = BrMemAllocate(sizeof(tCar_spec), kMem_net_car_spec);
switched_res = SwitchToRealResolution();
LoadCar(gOpponents[pPlayer->car_index].car_file_name,
eDriver_net_human,
pPlayer->car,
pPlayer->car_index,
pPlayer->player_name,
&gNet_cars_storage_space);
if (switched_res) {
SwitchToLoresMode();
}
InitialiseCar(pPlayer->car);
if (pPlayer->player_status < ePlayer_status_racing) {
pPlayer->car->disabled = 1;
}
SetCarStorageTexturingLevel(&gNet_cars_storage_space, GetCarTexturingLevel(), eCTL_full);
}
// IDA: void __usercall DisposeCarN(int pIndex@<EAX>)
void DisposeCarN(int pIndex) {
int i;
int j;
LOG_TRACE("(%d)", pIndex);
for (i = 0; i < gCurrent_race.number_of_racers; i++) {
if (gCurrent_race.opponent_list[i].car_spec == gNet_players[pIndex].car) {
gCurrent_race.number_of_racers--;
for (j = i; j < gCurrent_race.number_of_racers; j++) {
gCurrent_race.opponent_list[j].index = gCurrent_race.opponent_list[j + 1].index;
gCurrent_race.opponent_list[j].ranking = gCurrent_race.opponent_list[j + 1].ranking;
gCurrent_race.opponent_list[j].net_player_index = gCurrent_race.opponent_list[j + 1].net_player_index;
gCurrent_race.opponent_list[j].car_spec = gCurrent_race.opponent_list[j + 1].car_spec;
}
}
}
if (gProgram_state.racing) {
DisposeKevStuffCar(gNet_players[pIndex].car);
}
DisposeCar(gNet_players[pIndex].car, gNet_players[pIndex].car_index);
if (gThis_net_player_index != pIndex) {
BrMemFree(gNet_players[pIndex].car);
}
if (gAction_replay_mode) {
ToggleReplay();
}
ResetPiping();
}
// IDA: void __usercall PlayerHasLeft(int pIndex@<EAX>)
void PlayerHasLeft(int pIndex) {
LOG_TRACE("(%d)", pIndex);
NOT_IMPLEMENTED();
}
// IDA: void __usercall NetPlayersChanged(int pNew_count@<EAX>, tNet_game_player_info *pNew_players@<EDX>)
void NetPlayersChanged(int pNew_count, tNet_game_player_info* pNew_players) {
int i;
int j;
int k;
int switched_res;
int new_player;
int player_still_there;
tPlayer_ID old_fox_it;
LOG_TRACE("(%d, %p)", pNew_count, pNew_players);
if (gCurrent_net_game->type == eNet_game_type_tag || gCurrent_net_game->type == eNet_game_type_foxy) {
old_fox_it = gNet_players[gIt_or_fox].ID;
}
for (i = 0; i < pNew_count; i++) {
new_player = 1;
for (j = 0; j < gNumber_of_net_players; j++) {
if (pNew_players[i].ID == gNet_players[j].ID) {
new_player = 0;
pNew_players[i].last_waste_message = gNet_players[j].last_waste_message;
pNew_players[i].player_status = gNet_players[j].player_status;
pNew_players[i].car_index = gNet_players[j].car_index;
pNew_players[i].score = gNet_players[j].score;
pNew_players[i].credits = gNet_players[j].credits;
pNew_players[i].wasted = gNet_players[j].wasted;
pNew_players[i].wasteage_attributed = gNet_players[j].wasteage_attributed;
pNew_players[i].next_car_index = gNet_players[j].next_car_index;
pNew_players[i].car = gNet_players[j].car;
break;
}
}
if (new_player) {
if (pNew_players[i].ID == gLocal_net_ID) {
switched_res = SwitchToRealResolution();
LoadCar(gOpponents[pNew_players[i].car_index].car_file_name,
eDriver_local_human,
&gProgram_state.current_car,
pNew_players[i].car_index,
pNew_players[i].player_name,
&gNet_cars_storage_space);
if (switched_res) {
SwitchToLoresMode();
}
pNew_players[i].car = &gProgram_state.current_car;
if (pNew_players[i].player_status < ePlayer_status_racing) {
pNew_players[i].car->disabled = 1;
}
SetCarStorageTexturingLevel(&gNet_cars_storage_space, GetCarTexturingLevel(), eCTL_full);
} else {
LoadCarN(i, &pNew_players[i]);
}
gCurrent_race.opponent_list[i].index = -1;
gCurrent_race.opponent_list[i].ranking = IRandomBetween(0, 99);
gCurrent_race.opponent_list[i].car_spec = pNew_players[i].car;
gCurrent_race.opponent_list[i].net_player_index = i;
pNew_players[i].opponent_list_index = i;
gCurrent_race.number_of_racers = pNew_count;
}
}
for (i = 0; i < gNumber_of_net_players; i++) {
player_still_there = 0;
for (j = 0; j < pNew_count; j++) {
if (pNew_players[j].ID == gNet_players[i].ID) {
player_still_there = 1;
break;
}
}
if (!player_still_there) {
for (j = 0; j < gNumber_of_net_players; j++) {
if (gCurrent_race.opponent_list[j].net_player_index == i) {
memmove(&gCurrent_race.
opponent_list[j
], &gCurrent_race.
opponent_list[j
+ 1], (gNumber_of_net_players
- j
- 1) * sizeof(tOpp_spec
));
for (k = 0; k < pNew_count; k++) {
if (j < pNew_players[k].opponent_list_index) {
pNew_players[k].opponent_list_index--;
}
}
break;
}
}
PlayerHasLeft(i);
DisposeCarN(i);
if (gInitialised_grid) {
for (i = 0; i < pNew_count; i++) {
gCurrent_race.opponent_list[pNew_players[i].opponent_list_index].net_player_index = i;
}
}
}
}
gNumber_of_net_players = pNew_count;
memcpy(gNet_players
, pNew_players
, pNew_count
* sizeof(tNet_game_player_info
));
for (i = 0; i < gNumber_of_net_players; i++) {
gNet_players[i].last_heard_from_him = PDGetTotalTime();
}
ForceRebuildActiveCarList();
if (gCurrent_net_game->type == eNet_game_type_tag || gCurrent_net_game->type == eNet_game_type_foxy) {
gIt_or_fox = -1;
for (i = 0; i < gNumber_of_net_players; i++) {
if (gNet_players[i].ID == old_fox_it) {
gIt_or_fox = i;
break;
}
}
}
}
// 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)
tNet_game_details* NetHostGame(tNet_game_type pGame_type, tNet_game_options* pOptions, int pStart_rank, char* pHost_name, int pCar_index) {
tNet_game_details* game;
void* host_address;
tNet_game_player_info me;
LOG_TRACE("(%d, %p, %d, \"%s\", %d)", pGame_type, pOptions, pStart_rank, pHost_name, pCar_index);
game = NetAllocatePIDGameDetails();
if (pHost_name[0] == '\0') {
}
DisableNetService();
if (PDNetHostGame(game, pHost_name, &host_address) == 0) {
NetDisposeGameDetails(game);
return NULL;
}
gCurrent_net_game = game;
gNeed_to_send_start_race = 0;
strcpy(game
->host_name
, pHost_name
);
game->host_ID = NetExtractPlayerID(game);
game->num_players = 1;
memcpy(&game
->options
, pOptions
, sizeof(tNet_game_options
));
game->status.stage = eNet_game_starting;
game->type = pGame_type;
game->start_race = pStart_rank;
game->no_races_yet = 1;
gReceiving_new_players = 0;
gHost_died = 0;
gNumber_of_net_players = 0;
gThis_net_player_index = 0;
gLocal_net_ID = game->host_ID;
FillInThisPlayer(game, &me, pCar_index, 1);
gNet_players[0].race_stuff_initialised = 1;
NetSetPlayerSystemInfo(&me, host_address);
NetPlayersChanged(1, &me);
InitialisePlayerStati();
gNet_mode = eNet_mode_host;
gDont_allow_joiners = 0;
return game;
}
// IDA: int __usercall NetInitClient@<EAX>(tNet_game_details *pDetails@<EAX>)
int NetInitClient(tNet_game_details* pDetails) {
LOG_TRACE("(%p)", pDetails);
NOT_IMPLEMENTED();
}
// IDA: int __usercall NetJoinGameLowLevel@<EAX>(tNet_game_details *pDetails@<EAX>, char *pPlayer_name@<EDX>)
int NetJoinGameLowLevel(tNet_game_details* pDetails, char* pPlayer_name) {
LOG_TRACE("(%p, \"%s\")", pDetails, pPlayer_name);
return PDNetJoinGame(pDetails, pPlayer_name);
}
// IDA: int __usercall NetJoinGame@<EAX>(tNet_game_details *pDetails@<EAX>, char *pPlayer_name@<EDX>, int pCar_index@<EBX>)
int NetJoinGame(tNet_game_details* pDetails, char* pPlayer_name, int pCar_index) {
int result;
tNet_message* the_message;
tU32 start_time;
LOG_TRACE("(%p, \"%s\", %d)", pDetails, pPlayer_name, pCar_index);
result = NetJoinGameLowLevel(pDetails, pPlayer_name);
if (result != 0) {
return result;
}
DisableNetService();
gReceiving_new_players = 0;
gNet_mode = eNet_mode_client;
gCurrent_net_game = pDetails;
gLocal_net_ID = NetExtractPlayerID(pDetails);
gNumber_of_net_players = 0;
gLast_player_list_received = 0;
gJoin_request_denied = 0;
gCar_was_taken = 0;
gHost_died = 0;
the_message = NetBuildMessage(NETMSGID_JOIN, 0);
FillInThisPlayer(pDetails, &the_message->contents.data.join.player_info, pCar_index, 0);
ReenableNetService();
NetGuaranteedSendMessageToAddress(pDetails, the_message, pDetails, NULL);
start_time = PDGetTotalTime();
while (1) {
NetService(0);
if (gNumber_of_net_players != 0) {
break;
}
if (PDGetTotalTime() - start_time >= 30000 || gJoin_request_denied || gHost_died) {
break;
}
}
DisableNetService();
InitialisePlayerStati();
if (gNumber_of_net_players == 0) {
ReenableNetService();
if (gJoin_request_denied && gCar_was_taken) {
result = -4;
} else {
gNet_mode = eNet_mode_none;
#if !defined(DETHRACE_FIX_BUGS)
// Avoid double free
NetDisposeGameDetails(gCurrent_net_game);
#endif
gCurrent_net_game = NULL;
if (gJoin_request_denied) {
result = -2;
} else {
result = -1;
}
}
}
return result;
}
// IDA: void __usercall NetObtainSystemUserName(char *pName@<EAX>, int pMax_length@<EDX>)
void NetObtainSystemUserName(char* pName, int pMax_length) {
PDNetObtainSystemUserName(pName, pMax_length);
pName[9] = '\0';
}
// IDA: tU32 __usercall NetExtractGameID@<EAX>(tNet_game_details *pDetails@<EAX>)
tU32 NetExtractGameID(tNet_game_details* pDetails) {
LOG_TRACE("(%p)", pDetails);
return PDNetExtractGameID(pDetails);
}
// IDA: tPlayer_ID __usercall NetExtractPlayerID@<EAX>(tNet_game_details *pDetails@<EAX>)
tPlayer_ID NetExtractPlayerID(tNet_game_details* pDetails) {
LOG_TRACE("(%p)", pDetails);
return PDNetExtractPlayerID(pDetails);
}
// IDA: int __usercall NetSendMessageToAddress@<EAX>(tNet_game_details *pDetails@<EAX>, tNet_message *pMessage@<EDX>, void *pAddress@<EBX>)
int NetSendMessageToAddress(tNet_game_details* pDetails, tNet_message* pMessage, void* pAddress) {
LOG_TRACE("(%p, %p, %p)", pDetails, pMessage, pAddress);
if (gNet_mode == eNet_mode_none && !gJoin_list_mode) {
return -3;
}
pMessage->sender = gLocal_net_ID;
pMessage->senders_time_stamp = PDGetTotalTime();
GetCheckSum(pMessage);
return PDNetSendMessageToAddress(pDetails, pMessage, pAddress);
}
// IDA: int __usercall NetSendMessageToPlayer@<EAX>(tNet_game_details *pDetails@<EAX>, tNet_message *pMessage@<EDX>, tPlayer_ID pPlayer@<EBX>)
int NetSendMessageToPlayer(tNet_game_details* pDetails, tNet_message* pMessage, tPlayer_ID pPlayer) {
//int i; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(%p, %p, %d)", pDetails, pMessage, pPlayer);
NOT_IMPLEMENTED();
}
// IDA: int __usercall NetSendMessageToHost@<EAX>(tNet_game_details *pDetails@<EAX>, tNet_message *pMessage@<EDX>)
int NetSendMessageToHost(tNet_game_details* pDetails, tNet_message* pMessage) {
LOG_TRACE("(%p, %p)", pDetails, pMessage);
NOT_IMPLEMENTED();
}
// IDA: int __usercall NetReplyToMessage@<EAX>(tNet_game_details *pDetails@<EAX>, tNet_message *pIncoming_message@<EDX>, tNet_message *pReply_message@<EBX>)
int NetReplyToMessage(tNet_game_details* pDetails, tNet_message* pIncoming_message, tNet_message* pReply_message) {
LOG_TRACE("(%p, %p, %p)", pDetails, pIncoming_message, pReply_message);
NOT_IMPLEMENTED();
}
// IDA: int __usercall NetSendMessageToAllPlayers@<EAX>(tNet_game_details *pDetails@<EAX>, tNet_message *pMessage@<EDX>)
int NetSendMessageToAllPlayers(tNet_game_details* pDetails, tNet_message* pMessage) {
LOG_TRACE("(%p, %p)", pDetails, pMessage);
pMessage->sender = gLocal_net_ID;
pMessage->senders_time_stamp = PDGetTotalTime();
GetCheckSum(pMessage);
return PDNetSendMessageToAllPlayers(pDetails, pMessage);
}
// IDA: tU32 __usercall NetGetContentsSize@<EAX>(tNet_message_type pType@<EAX>, tS32 pSize_decider@<EDX>)
tU32 NetGetContentsSize(tNet_message_type pType, tS32 pSize_decider) {
//tU32 the_size; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(%d, %d)", pType, pSize_decider);
switch (pType) {
case NETMSGID_SENDMEDETAILS:
return sizeof(tNet_message_send_me_details);
case NETMSGID_DETAILS:
return sizeof(tNet_message_my_details);
case NETMSGID_JOIN:
return sizeof(tNet_message_join);
case NETMSGID_NEWPLAYERLIST:
return sizeof(tNet_message_new_player_list);
case NETMSGID_GUARANTEEREPLY:
return sizeof(tNet_message_guarantee_reply);
case NETMSGID_CARDETAILSREQ:
return sizeof(tNet_message_car_details_req);
case NETMSGID_CARDETAILS:
return sizeof(tNet_message_car_details);
case NETMSGID_LEAVE:
return sizeof(tNet_message_leave);
case NETMSGID_HOSTICIDE:
return sizeof(tNet_message_host_pissing_off);
case NETMSGID_RACEOVER:
return sizeof(tNet_message_race_over);
case NETMSGID_STATUSREPORT:
return sizeof(tNet_message_status_report);
case NETMSGID_STARTRACE:
return sizeof(tNet_message_start_race);
case NETMSGID_HEADUP:
return sizeof(tNet_message_headup);
case NETMSGID_HOSTQUERY:
return sizeof(tNet_message_host_query);
case NETMSGID_HOSTREPLY:
return sizeof(tNet_message_host_reply);
case NETMSGID_MECHANICS:
if (pSize_decider == 0) {
return offsetof(tNet_message_mechanics_info
, wheel_dam_offset
);
} else {
return sizeof(tNet_message_mechanics_info);
}
case NETMSGID_NONCAR_INFO:
return sizeof(tNet_message_non_car_info);
case NETMSGID_TIMESYNC:
return sizeof(tNet_message_time_sync);
case NETMSGID_CONFIRM:
return sizeof(tNet_message_players_confirm);
case NETMSGID_DISABLECAR:
return sizeof(tNet_message_disable_car);
case NETMSGID_ENABLECAR:
return sizeof(tNet_message_enable_car);
case NETMSGID_POWERUP:
return sizeof(tNet_message_powerup);
case NETMSGID_RECOVER:
return sizeof(tNet_message_recover);
case NETMSGID_SCORES:
return sizeof(tNet_message_scores);
case NETMSGID_WASTED:
return sizeof(tNet_message_wasted);
case NETMSGID_PEDESTRIAN:
switch (pSize_decider) {
case 0:
return offsetof(tNet_message_pedestrian
, to_pos
);
case 1:
return offsetof(tNet_message_pedestrian
, offset
);
case 2:
return sizeof(tNet_message_pedestrian);
default:
TELL_ME_IF_WE_PASS_THIS_WAY();
}
case NETMSGID_GAMEPLAY:
return sizeof(tNet_message_gameplay);
case NETMSGID_NONCARPOSITION:
return sizeof(tNet_message_non_car_position);
case NETMSGID_COPINFO:
return sizeof(tNet_message_cop_info);
case NETMSGID_GAMESCORES:
return sizeof(tNet_message_game_scores);
case NETMSGID_OILSPILL:
return sizeof(tNet_message_oil_spill);
case NETMSGID_CRUSHPOINT:
return sizeof(tNet_message_crush_point);
default:
TELL_ME_IF_WE_PASS_THIS_WAY();
return 4;
}
}
// IDA: tU32 __usercall NetGetMessageSize@<EAX>(tNet_message_type pType@<EAX>, tS32 pSize_decider@<EDX>)
tU32 NetGetMessageSize(tNet_message_type pType, tS32 pSize_decider) {
LOG_TRACE("(%d, %d)", pType, pSize_decider);
return NetGetContentsSize(pType, pSize_decider) + sizeof(tNet_message) - sizeof(tNet_contents);
}
// IDA: tS32 __usercall NetCalcSizeDecider@<EAX>(tNet_contents *pContents@<EAX>)
tS32 NetCalcSizeDecider(tNet_contents* pContents) {
//tS32 the_decider; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(%p)", pContents);
NOT_IMPLEMENTED();
}
// IDA: tNet_message* __usercall NetBuildMessage@<EAX>(tNet_message_type pType@<EAX>, tS32 pSize_decider@<EDX>)
tNet_message* NetBuildMessage(tNet_message_type pType, tS32 pSize_decider) {
tNet_message* the_message;
tU32 the_size;
LOG_TRACE("(%d, %d)", pType, pSize_decider);
the_size = NetGetMessageSize(pType, pSize_decider);
the_message = NetAllocateMessage(the_size);
if (the_message != NULL) {
the_message->num_contents = 1;
the_message->overall_size = the_size;
the_message->contents.header.type = pType;
}
return the_message;
}
// IDA: tNet_contents* __usercall NetGetToHostContents@<EAX>(tNet_message_type pType@<EAX>, tS32 pSize_decider@<EDX>)
tNet_contents* NetGetToHostContents(tNet_message_type pType, tS32 pSize_decider) {
//tU32 the_size; // Pierre-Marie Baty -- unused variable
//tNet_contents* contents; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(%d, %d)", pType, pSize_decider);
NOT_IMPLEMENTED();
}
// IDA: tNet_contents* __usercall NetGetBroadcastContents@<EAX>(tNet_message_type pType@<EAX>, tS32 pSize_decider@<EDX>)
tNet_contents* NetGetBroadcastContents(tNet_message_type pType, tS32 pSize_decider) {
tU32 the_size;
tNet_contents* contents;
LOG_TRACE("(%d, %d)", pType, pSize_decider);
the_size = NetGetContentsSize(pType, pSize_decider);
if (gBroadcast_stack && the_size + gBroadcast_stack->overall_size > MAX_MESAGE_STACK_SIZE) {
NetSendMessageToAllPlayers(gCurrent_net_game, gBroadcast_stack);
gBroadcast_stack = NULL;
}
if (gBroadcast_stack == NULL) {
gBroadcast_stack = NetAllocateMessage(MAX_MESAGE_STACK_SIZE);
gBroadcast_stack
->overall_size
= offsetof(tNet_message
, contents
);
gBroadcast_stack->num_contents = 0;
}
contents = (tNet_contents*)((char*)gBroadcast_stack + gBroadcast_stack->overall_size);
gBroadcast_stack->overall_size += the_size;
contents->header.type = pType;
contents->header.contents_size = the_size;
gBroadcast_stack->num_contents++;
return contents;
}
// IDA: void __cdecl NetSendMessageStacks()
void NetSendMessageStacks(void) {
LOG_TRACE("()");
gLast_flush_message = PDGetTotalTime();
if (gBroadcast_stack != NULL) {
NetSendMessageToAllPlayers(gCurrent_net_game, gBroadcast_stack);
gBroadcast_stack = NULL;
}
if (gTo_host_stack != NULL) {
NetSendMessageToHost(gCurrent_net_game, gTo_host_stack);
gTo_host_stack = NULL;
}
}
// IDA: tNet_message* __usercall NetAllocateMessage@<EAX>(int pSize@<EAX>)
tNet_message* NetAllocateMessage(int pSize) {
void* pointer;
void* last_message;
//char* test; // Pierre-Marie Baty -- unused variable
static int rr_min = 0; // Pierre-Marie Baty -- uninitialized static variable
static int rr_mid = 0; // Pierre-Marie Baty -- uninitialized static variable
static int rr_max = 0; // Pierre-Marie Baty -- uninitialized static variable
tNet_message* message;
int i;
LOG_TRACE("(%d)", pSize);
pointer = NULL;
if (pSize <= sizeof(tMin_message) - sizeof(void*)) {
for (i = 0; i < MIN_MESSAGES_CAPACITY; i++) {
if (((tNet_message*)&gMin_messages[rr_min])->contents.header.type == NETMSGID_NONE) {
pointer = &gMin_messages[rr_min];
break;
}
rr_min++;
if (rr_min >= MIN_MESSAGES_CAPACITY) {
rr_min = 0;
}
}
}
if (pointer == NULL && pSize <= sizeof(tMid_message) - sizeof(void*)) {
for (i = 0; i < MID_MESSAGES_CAPACITY; i++) {
if (((tNet_message*)&gMid_messages[rr_mid])->contents.header.type == NETMSGID_NONE) {
pointer = &gMid_messages[rr_mid];
break;
}
rr_mid++;
if (rr_mid >= MID_MESSAGES_CAPACITY) {
rr_mid = 0;
}
}
}
if (pointer == NULL && pSize <= sizeof(tMax_message) - sizeof(void*)) {
for (i = 0; i < MAX_MESSAGES_CAPACITY; i++) {
if (((tNet_message*)&gMax_messages[rr_max])->contents.header.type == NETMSGID_NONE) {
pointer = &gMax_messages[rr_max];
break;
}
rr_max++;
if (rr_max >= MAX_MESSAGES_CAPACITY) {
rr_max = 0;
}
}
}
if (pointer == NULL) {
pointer = BrMemAllocate(gMessage_header_size + pSize + sizeof(void*), kMem_dynamic_message);
if (pointer != NULL) {
*(void**)pointer = NULL;
if (gMessage_to_free != NULL) {
for (last_message = gMessage_to_free; *(void**)last_message != NULL; last_message = *(void**)last_message) {
}
*(void**)last_message = pointer;
} else {
gMessage_to_free = pointer;
}
pointer = ((void**)pointer)[1];
}
}
if (pointer == NULL) {
LOG_PANIC("null pointer!");
message = NULL;
} else {
message = (tNet_message*)((tU8*)pointer + gMessage_header_size);
message->guarantee_number = 0;
message->version = 1;
message->magic_number = 0x763a5058;
}
return message;
}
// IDA: void __cdecl NetFreeExcessMemory()
void NetFreeExcessMemory(void) {
void* temp;
LOG_TRACE("()");
while (gMessage_to_free != NULL && ((tNet_message*)((char*)gMessage_to_free + sizeof(void*)))->contents.header.type == NETMSGID_NONE) {
temp = *(void**)gMessage_to_free;
BrMemFree(gMessage_to_free);
gMessage_to_free = temp;
}
}
// IDA: int __usercall NetDisposeMessage@<EAX>(tNet_game_details *pDetails@<EAX>, tNet_message *pMessage@<EDX>)
int NetDisposeMessage(tNet_game_details* pDetails, tNet_message* pMessage) {
LOG_TRACE("(%p, %p)", pDetails, pMessage);
if (pMessage->guarantee_number != 0) {
return -1;
}
pMessage->contents.header.type = NETMSGID_NONE;
return 0;
}
// IDA: tNet_message* __usercall NetGetNextMessage@<EAX>(tNet_game_details *pDetails@<EAX>, void **pSender_address@<EDX>)
tNet_message* NetGetNextMessage(tNet_game_details* pDetails, void** pSender_address) {
LOG_TRACE("(%p, %p)", pDetails, pSender_address);
return PDNetGetNextMessage(pDetails, pSender_address);
}
// IDA: void __usercall ReceivedSendMeDetails(tNet_contents *pContents@<EAX>, void *pSender_address@<EDX>)
void ReceivedSendMeDetails(tNet_contents* pContents, void* pSender_address) {
tNet_message* message;
LOG_TRACE("(%p, %p)", pContents, pSender_address);
if (gDont_allow_joiners) {
return;
}
message = NetBuildMessage(NETMSGID_DETAILS, 0);
memcpy(&message
->contents.
data.
details.
details.
host_name, gCurrent_net_game
->host_name
, sizeof(*gCurrent_net_game
) - offsetof(tNet_game_details
, host_name
));
NetSendMessageToAddress(gCurrent_net_game, message, pSender_address);
}
// IDA: void __usercall ReceivedDetails(tNet_contents *pContents@<EAX>)
void ReceivedDetails(tNet_contents* pContents) {
LOG_TRACE("(%p)", pContents);
if (gCurrent_join_poll_game == NULL) {
return;
}
gBastard_has_answered = 1;
memcpy(gCurrent_join_poll_game
->host_name
, &pContents
->data.
details.
details.
host_name, sizeof(*gCurrent_join_poll_game
) - offsetof(tNet_game_details
, host_name
));
}
// IDA: void __cdecl SendOutPlayerList()
void SendOutPlayerList(void) {
tNet_message* message;
int i;
LOG_TRACE("()");
gCurrent_net_game->num_players = gNumber_of_net_players;
for (i = 0; i < gNumber_of_net_players; i++) {
message = NetBuildMessage(NETMSGID_NEWPLAYERLIST, 1);
message->contents.data.player_list.number_of_players = gNumber_of_net_players;
message->contents.data.player_list.this_index = i;
message->contents.data.player_list.batch_number = gPlayer_list_batch_number;
memcpy(&message
->contents.
data.
player_list.
player, &gNet_players
[i
], sizeof(gNet_players
[i
]));
NetGuaranteedSendMessageToAllPlayers(gCurrent_net_game, message, 0);
}
gPlayer_list_batch_number++;
if (gInitialised_grid) {
SetUpNetCarPositions();
if (gStart_race_sent) {
gNeed_to_send_start_race = 1;
for (i = 1; i < gNumber_of_net_players; i++) {
gNet_players[i].awaiting_confirmation = 1;
}
}
}
}
// IDA: void __usercall ReceivedJoin(tNet_contents *pContents@<EAX>, void *pSender_address@<EDX>)
void ReceivedJoin(tNet_contents* pContents, void* pSender_address) {
int i;
int new_player_count;
int slot_index;
tNet_message* message;
tNet_game_player_info* new_players;
LOG_TRACE("(%p, %p)", pContents, pSender_address);
new_player_count = gNumber_of_net_players;
new_players = BrMemAllocate(new_player_count + 1 * sizeof(tNet_game_player_info), kMem_player_list_join);
memcpy(new_players
, gNet_players
, gNumber_of_net_players
* sizeof(tNet_game_player_info
));
if ((!gCurrent_net_game->options.open_game && gProgram_state.racing) || gCurrent_net_game->num_players > 5 || gDont_allow_joiners) {
message = NetBuildMessage(NETMSGID_NEWPLAYERLIST, 0);
// Send player count = 0 when race has already begun or is full
message->contents.data.player_list.number_of_players = 0;
NetSendMessageToAddress(gCurrent_net_game, message, pSender_address);
} else {
for (i = 0; i < new_player_count; i++) {
if (new_players[i].ID == pContents->data.join.player_info.ID) {
return;
}
}
slot_index = new_player_count;
new_player_count++;
if (pContents->data.join.player_info.car_index < 0) {
pContents->data.join.player_info.car_index = PickARandomCar();
} else {
for (i = 0; i < gNumber_of_net_players; i++) {
if (gNet_players[i].car_index == pContents->data.join.player_info.car_index) {
message = NetBuildMessage(NETMSGID_NEWPLAYERLIST, 0);
// Send player count = -1 when selected car is unavailable
message->contents.data.player_list.number_of_players = -1;
NetSendMessageToAddress(gCurrent_net_game, message, pSender_address);
return;
}
}
}
if (pContents->data.join.player_info.car_index >= 0) {
gCar_details[pContents->data.join.player_info.car_index].ownership = eCar_owner_someone;
}
memcpy(&new_players
[slot_index
], &pContents
->data.
join.
player_info, sizeof(tNet_game_player_info
));
new_players[slot_index].player_status = ePlayer_status_loading;
new_players[slot_index].last_heard_from_him = PDGetTotalTime();
new_players[slot_index].grid_position_set = 0;
if (new_players[slot_index].player_name[0] == '\0') {
sprintf(new_players
[slot_index
].
player_name, "%s %d", "PLAYER", slot_index
);
}
NetSetPlayerSystemInfo(&new_players[slot_index], pSender_address);
NetPlayersChanged(new_player_count, new_players);
BrMemFree(new_players);
SendOutPlayerList();
}
}
// IDA: void __usercall KickPlayerOut(tPlayer_ID pID@<EAX>)
void KickPlayerOut(tPlayer_ID pID) {
//int i; // Pierre-Marie Baty -- unused variable
//int j; // Pierre-Marie Baty -- unused variable
//int new_player_count; // Pierre-Marie Baty -- unused variable
//tNet_game_player_info* new_players; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(%d)", pID);
NOT_IMPLEMENTED();
}
// IDA: void __usercall ReceivedLeave(tNet_contents *pContents@<EAX>, tNet_message *pMessage@<EDX>)
void ReceivedLeave(tNet_contents* pContents, tNet_message* pMessage) {
LOG_TRACE("(%p, %p)", pContents, pMessage);
NOT_IMPLEMENTED();
}
// IDA: void __usercall NetFullScreenMessage(int pStr_index@<EAX>, int pLeave_it_up_there@<EDX>)
void NetFullScreenMessage(int pStr_index, int pLeave_it_up_there) {
tU32 start_time;
char* s;
// Jeff: added underscore suffix to avoid collisions with samed-named globals
int gPixel_buffer_size_;
char* gPixels_copy_;
char* gPalette_copy_;
int restore_screen;
LOG_TRACE("(%d, %d)", pStr_index, pLeave_it_up_there);
if (pLeave_it_up_there || (gProgram_state.racing && !gInterface_within_race_mode)) {
restore_screen = 0;
} else {
gPixel_buffer_size_ = gBack_screen->height * gBack_screen->row_bytes;
gPixels_copy_ = BrMemAllocate(gPixel_buffer_size_, 0xB0u);
gPalette_copy_ = BrMemAllocate(0x400u, 0xB1u);
memcpy(gPixels_copy_
, gBack_screen
->pixels
, gPixel_buffer_size_
);
memcpy(gPalette_copy_
, gCurrent_palette_pixels
, 0x400u
);
restore_screen = 1;
}
FadePaletteDown();
LoadFont(FONT_MEDIUMHD);
ClearEntireScreen();
if (pStr_index <= 0) {
s = "FIXED THAT YOU TWISTED BASTARDS";
} else {
s = GetMiscString(pStr_index);
}
OoerrIveGotTextInMeBoxMissus(
FONT_MEDIUMHD,
s,
gBack_screen,
0,
gGraf_specs[gGraf_spec_index].total_height / 2 - gFonts[kFont_MEDIUMHD].height,
gGraf_specs[gGraf_spec_index].total_width,
gGraf_specs[gGraf_spec_index].total_height,
1);
PDScreenBufferSwap(0);
EnsureRenderPalette();
EnsurePaletteUp();
if (!pLeave_it_up_there) {
start_time = PDGetTotalTime();
while (PDGetTotalTime() - start_time < 3000) {
;
}
FadePaletteDown();
if (restore_screen) {
memcpy(gBack_screen
->pixels
, gPixels_copy_
, gPixel_buffer_size_
);
memcpy(gCurrent_palette_pixels
, gPalette_copy_
, 0x400u
);
BrMemFree(gPixels_copy_);
BrMemFree(gPalette_copy_);
PDScreenBufferSwap(0);
FadePaletteUp();
} else {
ClearEntireScreen();
}
}
}
// IDA: void __usercall HostHasBittenTheDust(int pMessage_index@<EAX>)
void HostHasBittenTheDust(int pMessage_index) {
LOG_TRACE("(%d)", pMessage_index);
if (!gHost_died) {
gHost_died = 1;
NetFullScreenMessage(pMessage_index, 0);
gProgram_state.prog_status = eProg_idling;
}
}
// IDA: void __usercall ReceivedHosticide(tNet_contents *pContents@<EAX>)
void ReceivedHosticide(tNet_contents* pContents) {
LOG_TRACE("(%p)", pContents);
HostHasBittenTheDust(73);
}
// IDA: void __cdecl ConfirmReceipt()
void ConfirmReceipt(void) {
//tNet_message* the_message; // Pierre-Marie Baty -- unused variable
LOG_TRACE("()");
NOT_IMPLEMENTED();
}
// IDA: void __usercall ReceivedNewPlayerList(tNet_contents *pContents@<EAX>, tNet_message *pM@<EDX>)
void ReceivedNewPlayerList(tNet_contents* pContents, tNet_message* pM) {
int i;
LOG_TRACE("(%p, %p)", pContents, pM);
if (pContents->data.player_list.number_of_players <= 0) {
gJoin_request_denied = 1;
if (pContents->data.player_list.number_of_players < 0) {
gCar_was_taken = 1;
}
return;
}
if (pContents->data.player_list.batch_number >= gReceiving_batch_number) {
if (!gReceiving_new_players) {
gLast_player_list_received = pM->senders_time_stamp;
for (i = 0; i < COUNT_OF(gNew_net_players); i++) {
gNew_net_players[i].car_index = -1;
}
gReceiving_new_players = 1;
gReceiving_batch_number = pContents->data.player_list.batch_number;
}
if (pContents->data.player_list.batch_number <= gReceiving_batch_number) {
memcpy(&gNew_net_players
[pContents
->data.
player_list.
this_index], &pContents
->data.
player_list.
player, sizeof(tNet_game_player_info
));
for (i = 0; i < pContents->data.player_list.number_of_players; i++) {
if (gNew_net_players[i].car_index < 0) {
return;
}
}
gReceiving_new_players = 0;
NetPlayersChanged(pContents->data.player_list.number_of_players, gNew_net_players);
gThis_net_player_index = -1;
for (i = 0; i < gNumber_of_net_players; i++) {
if (gNet_players[i].ID == gLocal_net_ID) {
gThis_net_player_index = i;
break;
}
}
if (gThis_net_player_index < 0) {
FatalError(kFatalError_NotInReceivedPlayerList);
}
gNet_players[0].last_heard_from_him = PDGetTotalTime();
gCurrent_race.number_of_racers = gNumber_of_net_players;
if (gSynch_race_start) {
for (i = 0; i < gNumber_of_net_players; i++) {
gCurrent_race.opponent_list[gNet_players[i].opponent_list_index].net_player_index = i;
}
}
} else {
gReceiving_new_players = 0;
ReceivedNewPlayerList(pContents, pM);
}
}
}
// IDA: void __usercall ReceivedRaceOver(tNet_contents *pContents@<EAX>)
void ReceivedRaceOver(tNet_contents* pContents) {
LOG_TRACE("(%p)", pContents);
gRace_finished = 0;
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)) {
RaceCompleted(pContents->data.race_over.reason);
}
}
// IDA: void __usercall ReceivedStatusReport(tNet_contents *pContents@<EAX>, tNet_message *pMessage@<EDX>)
void ReceivedStatusReport(tNet_contents* pContents, tNet_message* pMessage) {
int i;
LOG_TRACE("(%p, %p)", pContents, pMessage);
for (i = 0; i < gNumber_of_net_players; i++) {
if (gNet_players[i].ID == pMessage->sender) {
gNet_players[i].player_status = pContents->data.report.status;
gNet_players[i].last_heard_from_him = PDGetTotalTime();
if (gNet_players[i].player_status < ePlayer_status_racing || gNet_players[i].player_status == ePlayer_status_recovering) {
if (gNet_players[i].player_status < ePlayer_status_racing) {
DisableCar(gNet_players[i].car);
}
} else {
if (gNet_players[i].car->disabled) {
SendCurrentPowerups();
}
EnableCar(gNet_players[i].car);
}
return;
}
}
}
// IDA: void __usercall ReceivedStartRace(tNet_contents *pContents@<EAX>)
void ReceivedStartRace(tNet_contents* pContents) {
//int i; // Pierre-Marie Baty -- unused variable
//int index; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(%p)", pContents);
NOT_IMPLEMENTED();
}
// IDA: void __usercall ReceivedGuaranteeReply(tNet_contents *pContents@<EAX>)
void ReceivedGuaranteeReply(tNet_contents* pContents) {
int i;
LOG_TRACE("(%p)", pContents);
for (i = 0; i < gNext_guarantee; i++) {
if (gGuarantee_list[i].guarantee_number == pContents->data.reply.guarantee_number) {
gGuarantee_list[i].recieved = 1;
}
}
}
// IDA: void __usercall ReceivedHeadup(tNet_contents *pContents@<EAX>)
void ReceivedHeadup(tNet_contents* pContents) {
LOG_TRACE("(%p)", pContents);
if (gProgram_state.racing) {
NewTextHeadupSlot(4, 0, 3000, -4, pContents->data.headup.text);
}
}
// IDA: void __usercall ReceivedHostQuery(tNet_contents *pContents@<EAX>, tNet_message *pMessage@<EDX>)
void ReceivedHostQuery(tNet_contents* pContents, tNet_message* pMessage) {
tNet_message* message;
LOG_TRACE("(%p, %p)", pContents, pMessage);
message = NetBuildMessage(NETMSGID_HOSTREPLY, 0);
message->contents.data.heres_where_we_at.race_has_started = gProgram_state.racing;
message->contents.data.heres_where_we_at.race_index = gProgram_state.current_race_index;
message->contents.data.heres_where_we_at.pending_race = gPending_race;
NetGuaranteedSendMessageToPlayer(gCurrent_net_game, message, pMessage->sender, NULL);
if (gProgram_state.racing) {
SignalToStartRace();
UpdateEnvironments();
}
}
// IDA: void __usercall ReceivedHostReply(tNet_contents *pContents@<EAX>)
void ReceivedHostReply(tNet_contents* pContents) {
//tNet_message* message; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(%p)", pContents);
if (pContents->data.heres_where_we_at.race_index != gProgram_state.current_race_index) {
NetLeaveGame(gCurrent_net_game);
NetFullScreenMessage(128, 0);
gProgram_state.prog_status = eProg_idling;
}
if (pContents->data.heres_where_we_at.race_has_started) {
if (gCurrent_net_game->options.open_game) {
gPending_race = pContents->data.heres_where_we_at.pending_race;
} else {
NetFullScreenMessage(89, 0);
gProgram_state.prog_status = eProg_idling;
}
}
}
// IDA: void __usercall SendGuaranteeReply(tNet_message *pMessage@<EAX>, void *pSender_address@<EDX>)
void SendGuaranteeReply(tNet_message* pMessage, void* pSender_address) {
tNet_message* message;
LOG_TRACE("(%p, %p)", pMessage, pSender_address);
message = NetBuildMessage(NETMSGID_GUARANTEEREPLY, 0);
message->contents.data.reply.guarantee_number = pMessage->guarantee_number;
pMessage->guarantee_number = 0;
NetSendMessageToAddress(gCurrent_net_game, message, pSender_address);
}
// IDA: int __usercall PlayerIsInList@<EAX>(tPlayer_ID pID@<EAX>)
int PlayerIsInList(tPlayer_ID pID) {
int i;
LOG_TRACE("(%d)", pID);
for (i = 0; i < gNumber_of_net_players; i++) {
if (gNet_players[i].ID == pID) {
gNet_players[i].last_heard_from_him = PDGetTotalTime();
return 1;
}
}
return 0;
}
// IDA: void __usercall ReceivedTimeSync(tNet_contents *pContents@<EAX>, tNet_message *pMessage@<EDX>, tU32 pReceive_time@<EBX>)
void ReceivedTimeSync(tNet_contents* pContents, tNet_message* pMessage, tU32 pReceive_time) {
LOG_TRACE("(%p, %p, %d)", pContents, pMessage, pReceive_time);
NOT_IMPLEMENTED();
}
// IDA: void __usercall ReceivedConfirm(tNet_contents *pContents@<EAX>)
void ReceivedConfirm(tNet_contents* pContents) {
//int i; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(%p)", pContents);
NOT_IMPLEMENTED();
}
// IDA: void __usercall ReceivedDisableCar(tNet_contents *pContents@<EAX>)
void ReceivedDisableCar(tNet_contents* pContents) {
LOG_TRACE("(%p)", pContents);
NOT_IMPLEMENTED();
}
// IDA: void __usercall ReceivedEnableCar(tNet_contents *pContents@<EAX>)
void ReceivedEnableCar(tNet_contents* pContents) {
LOG_TRACE("(%p)", pContents);
NOT_IMPLEMENTED();
}
// IDA: void __usercall ReceivedScores(tNet_contents *pContents@<EAX>)
void ReceivedScores(tNet_contents* pContents) {
//int i; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(%p)", pContents);
NOT_IMPLEMENTED();
}
// IDA: void __usercall ReceivedWasted(tNet_contents *pContents@<EAX>)
void ReceivedWasted(tNet_contents* pContents) {
//tNet_game_player_info* victim; // Pierre-Marie Baty -- unused variable
//tNet_game_player_info* culprit; // Pierre-Marie Baty -- unused variable
//char s[256]; // Pierre-Marie Baty -- unused variable
//tCar_spec* car; // Pierre-Marie Baty -- unused variable
//static tS32 last_got_wasted_time; // Pierre-Marie Baty -- unused variable
//static tS32 last_wasted_em_time; // Pierre-Marie Baty -- unused variable
//static tS32 last_wasty_message_time; // Pierre-Marie Baty -- unused variable
//static tNet_game_player_info* last_culprit; // Pierre-Marie Baty -- unused variable
//static tNet_game_player_info* last_victim; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(%p)", pContents);
NOT_IMPLEMENTED();
}
// IDA: void __usercall ReceivedCarDetailsReq(tNet_contents *pContents@<EAX>, void *pSender_address@<EDX>)
void ReceivedCarDetailsReq(tNet_contents* pContents, void* pSender_address) {
tNet_message* message;
int i;
LOG_TRACE("(%p, %p)", pContents, pSender_address);
message = NetBuildMessage(NETMSGID_CARDETAILS, 0);
message->contents.data.car_details.count = gNumber_of_net_players;
for (i = 0; i < gNumber_of_net_players; i++) {
message->contents.data.car_details.details[i].car_index = gNet_players[i].car_index;
// truncates from 32 to 16 characters
memcpy(message
->contents.
data.
car_details.
details[i
].
owner, gNet_players
[i
].
player_name, sizeof(message
->contents.
data.
car_details.
details[i
].
owner));
message->contents.data.car_details.details[i].owner[sizeof(message->contents.data.car_details.details[i].owner) - 1] = '\0';
}
NetGuaranteedSendMessageToAddress(gCurrent_net_game, message, pSender_address, NULL);
}
// IDA: void __usercall ReceivedCarDetails(tNet_contents *pContents@<EAX>)
void ReceivedCarDetails(tNet_contents* pContents) {
int i;
int j;
LOG_TRACE("(%p)", pContents);
SetNetAvailability(gNet_options);
for (i = 0; i < gNumber_of_racers; i++) {
for (j = 0; j < pContents->data.car_details.count; j++) {
if (i == pContents->data.car_details.details[j].car_index) {
gCar_details[i].ownership = eCar_owner_someone;
strcpy(gCar_details
[i
].
name, pContents
->data.
car_details.
details[j
].
owner);
}
}
}
gReceived_car_details = 1;
}
// IDA: void __usercall ReceivedGameScores(tNet_contents *pContents@<EAX>)
void ReceivedGameScores(tNet_contents* pContents) {
//int i; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(%p)", pContents);
NOT_IMPLEMENTED();
}
// IDA: void __usercall ReceivedMessage(tNet_message *pMessage@<EAX>, void *pSender_address@<EDX>, tU32 pReceive_time@<EBX>)
void ReceivedMessage(tNet_message* pMessage, void* pSender_address, tU32 pReceive_time) {
tNet_contents* contents;
int i;
LOG_TRACE("(%p, %p, %d)", pMessage, pSender_address, pReceive_time);
contents = &pMessage->contents;
if (pMessage->guarantee_number != 0) {
SendGuaranteeReply(pMessage, pSender_address);
}
if (!gProgram_state.racing && gRace_only_flags[pMessage->contents.header.type]) {
return;
}
if (gOnly_receive_guarantee_replies && pMessage->contents.header.type != NETMSGID_GUARANTEEREPLY) {
return;
}
for (i = 0; i < pMessage->num_contents; i++) {
if (contents->header.type <= NETMSGID_CARDETAILS || PlayerIsInList(pMessage->sender)) {
switch (contents->header.type) {
case NETMSGID_SENDMEDETAILS: // 0x00,
ReceivedSendMeDetails(contents, pSender_address);
break;
case NETMSGID_DETAILS: // 0x01,
ReceivedDetails(contents);
break;
case NETMSGID_JOIN: // 0x02,
ReceivedJoin(contents, pSender_address);
break;
case NETMSGID_NEWPLAYERLIST: // 0x03,
ReceivedNewPlayerList(contents, pMessage);
break;
case NETMSGID_GUARANTEEREPLY: // 0x04,
ReceivedGuaranteeReply(contents);
break;
case NETMSGID_CARDETAILSREQ: // 0x05,
ReceivedCarDetailsReq(contents, pSender_address);
break;
case NETMSGID_CARDETAILS: // 0x06,
ReceivedCarDetails(contents);
break;
case NETMSGID_LEAVE: // 0x07,
ReceivedLeave(contents, pMessage);
break;
case NETMSGID_HOSTICIDE: // 0x08,
ReceivedHosticide(contents);
break;
case NETMSGID_RACEOVER: // 0x09,
ReceivedRaceOver(contents);
break;
case NETMSGID_STATUSREPORT: // 0x0a,
ReceivedStatusReport(contents, pMessage);
break;
case NETMSGID_STARTRACE: // 0x0b,
ReceivedStartRace(contents);
break;
case NETMSGID_HEADUP: // 0x0c,
ReceivedHeadup(contents);
break;
case NETMSGID_HOSTQUERY: // 0x0d,
ReceivedHostQuery(contents, pMessage);
break;
case NETMSGID_HOSTREPLY: // 0x0e,
ReceivedHostReply(contents);
break;
case NETMSGID_MECHANICS: // 0x0f,
ReceivedMechanics(contents);
break;
case NETMSGID_NONCAR_INFO: // 0x10,
ReceivedNonCar(contents);
break;
case NETMSGID_TIMESYNC: // 0x11,
ReceivedTimeSync(contents, pMessage, pReceive_time);
break;
case NETMSGID_CONFIRM: // 0x12,
ReceivedConfirm(contents);
break;
case NETMSGID_DISABLECAR: // 0x13,
ReceivedDisableCar(contents);
break;
case NETMSGID_ENABLECAR: // 0x14,
ReceivedEnableCar(contents);
break;
case NETMSGID_POWERUP: // 0x15,
ReceivedPowerup(contents);
break;
case NETMSGID_RECOVER: // 0x16,
ReceivedRecover(contents);
break;
case NETMSGID_SCORES: // 0x17,
ReceivedScores(contents);
break;
case NETMSGID_WASTED: // 0x18,
ReceivedWasted(contents);
break;
case NETMSGID_PEDESTRIAN: // 0x19,
ReceivedPedestrian(contents, pMessage, pReceive_time);
break;
case NETMSGID_GAMEPLAY: // 0x1a,
ReceivedGameplay(contents, pMessage, pReceive_time);
break;
case NETMSGID_NONCARPOSITION: // 0x1b,
ReceivedNonCarPosition(contents);
break;
case NETMSGID_COPINFO: // 0x1c,
ReceivedCopInfo(contents);
break;
case NETMSGID_GAMESCORES: // 0x1d,
ReceivedGameScores(contents);
break;
case NETMSGID_OILSPILL: // 0x1e,
ReceivedOilSpill(contents);
break;
case NETMSGID_CRUSHPOINT: // 0x1f,
RecievedCrushPoint(contents);
break;
}
}
contents = (tNet_contents*)((tU8*)contents + contents->header.contents_size);
}
}
// IDA: void __cdecl NetReceiveAndProcessMessages()
void NetReceiveAndProcessMessages(void) {
tNet_message* message;
void* sender_address;
tU32 receive_time;
int old_net_service;
LOG_TRACE("()");
old_net_service = gIn_net_service;
if (gNet_mode != eNet_mode_none || gJoin_list_mode) {
gIn_net_service = 1;
while ((message = NetGetNextMessage(gCurrent_net_game, &sender_address)) != NULL) {
receive_time = GetRaceTime();
if (message->magic_number == 0x763a5058) {
CheckCheckSum(message);
ReceivedMessage(message, sender_address, receive_time);
} else {
message->guarantee_number = 0;
}
NetDisposeMessage(gCurrent_net_game, message);
}
}
gIn_net_service = old_net_service;
}
// IDA: void __cdecl BroadcastStatus()
void BroadcastStatus(void) {
tNet_message* message;
LOG_TRACE("()");
message = NetBuildMessage(NETMSGID_STATUSREPORT, 0);
message->contents.data.report.status = gNet_players[gThis_net_player_index].player_status;
NetSendMessageToAllPlayers(gCurrent_net_game, message);
}
// IDA: void __cdecl CheckForDisappearees()
void CheckForDisappearees(void) {
int i;
//int j; // Pierre-Marie Baty -- unused variable
tU32 the_time;
char s[256];
//char* s2; // Pierre-Marie Baty -- unused variable
LOG_TRACE("()");
the_time = PDGetTotalTime();
if (gNet_mode == eNet_mode_host) {
for (i = 0; i < gNumber_of_net_players; i++) {
if (!gNet_players[i].host && gNet_players[i].last_heard_from_him != 0 && the_time - gNet_players[i].last_heard_from_him >= 20000) {
strcpy(s
, gNet_players
[i
].
player_name);
strcat(s
, GetMiscString
(kMiscString_IS_NO_LONGER_RESPONDING
));
NetSendHeadupToAllPlayers(s);
KickPlayerOut(gNet_players[i].ID);
if (gProgram_state.racing) {
NewTextHeadupSlot(4, 0, 3000, -4, s);
}
}
}
} 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) {
HostHasBittenTheDust(91);
}
}
// IDA: void __cdecl CheckForPendingStartRace()
void CheckForPendingStartRace(void) {
int i;
LOG_TRACE("()");
if (gNet_mode == eNet_mode_host && gNeed_to_send_start_race) {
for (i = 1; i < gNumber_of_net_players; i++) {
if (gNet_players[i].awaiting_confirmation) {
return;
}
}
SignalToStartRace();
}
}
// IDA: void __usercall NetService(int pIn_race@<EAX>)
void NetService(int pIn_race) {
static tU32 last_status_broadcast;
if (gIn_net_service || gNet_service_disable) {
return;
}
gIn_net_service = 1;
if (gJoin_list_mode) {
NetFreeExcessMemory();
DoNextJoinPoll();
NetReceiveAndProcessMessages();
} else {
if (gNet_mode != eNet_mode_none) {
NetFreeExcessMemory();
if (!pIn_race) {
NetReceiveAndProcessMessages();
}
if (time - last_status_broadcast
> 1000) {
last_status_broadcast = PDGetTotalTime();
BroadcastStatus();
}
CheckForDisappearees();
CheckForPendingStartRace();
}
}
if (gJoin_list_mode || gNet_mode != eNet_mode_none) {
ResendGuaranteedMessages();
if (time > gLast_flush_message
+ 200) {
NetSendMessageStacks();
}
}
gIn_net_service = 0;
}
// IDA: void __usercall NetFinishRace(tNet_game_details *pDetails@<EAX>, tRace_over_reason pReason@<EDX>)
void NetFinishRace(tNet_game_details* pDetails, tRace_over_reason pReason) {
tNet_message* the_message;
LOG_TRACE("(%p, %d)", pDetails, pReason);
gNeed_to_send_start_race = 0;
the_message = NetBuildMessage(NETMSGID_RACEOVER, 0);
the_message->contents.data.race_over.reason = pReason;
NetGuaranteedSendMessageToAllPlayers(gCurrent_net_game, the_message, NULL);
}
// IDA: void __usercall NetPlayerStatusChanged(tPlayer_status pNew_status@<EAX>)
void NetPlayerStatusChanged(tPlayer_status pNew_status) {
LOG_TRACE("(%d)", pNew_status);
//tNet_message* the_message; // Pierre-Marie Baty -- unused variable
if (gNet_mode != eNet_mode_none && pNew_status != gNet_players[gThis_net_player_index].player_status) {
gNet_players[gThis_net_player_index].player_status = pNew_status;
BroadcastStatus();
if (gProgram_state.current_car.disabled && pNew_status >= ePlayer_status_racing && pNew_status != ePlayer_status_recovering) {
EnableCar(&gProgram_state.current_car);
} else if (!gProgram_state.current_car.disabled && pNew_status < ePlayer_status_racing) {
DisableCar(&gProgram_state.current_car);
}
}
}
// IDA: tPlayer_status __cdecl NetGetPlayerStatus()
tPlayer_status NetGetPlayerStatus(void) {
LOG_TRACE("()");
return gNet_players[gThis_net_player_index].player_status;
}
// IDA: int __usercall NetGuaranteedSendMessageToAllPlayers@<EAX>(tNet_game_details *pDetails@<EAX>, tNet_message *pMessage@<EDX>, int (*pNotifyFail)(tU32, tNet_message*)@<EBX>)
int NetGuaranteedSendMessageToAllPlayers(tNet_game_details* pDetails, tNet_message* pMessage, int (*pNotifyFail)(tU32, tNet_message*)) {
int i;
int err;
LOG_TRACE("(%p, %p, %p)", pDetails, pMessage, pNotifyFail);
err = 0;
if (gNumber_of_net_players == 1) {
NetDisposeMessage(pDetails, pMessage);
err = 0;
} else {
for (i = 0; i < gNumber_of_net_players; i++) {
if (gThis_net_player_index != i) {
err |= NetGuaranteedSendMessageToAddress(pDetails, pMessage, &gNet_players[i], pNotifyFail);
}
}
}
return err;
}
// IDA: int __usercall NetGuaranteedSendMessageToEverybody@<EAX>(tNet_game_details *pDetails@<EAX>, tNet_message *pMessage@<EDX>, int (*pNotifyFail)(tU32, tNet_message*)@<EBX>)
int NetGuaranteedSendMessageToEverybody(tNet_game_details* pDetails, tNet_message* pMessage, int (*pNotifyFail)(tU32, tNet_message*)) {
LOG_TRACE("(%p, %p, %p)", pDetails, pMessage, pNotifyFail);
NOT_IMPLEMENTED();
}
// IDA: int __usercall NetGuaranteedSendMessageToHost@<EAX>(tNet_game_details *pDetails@<EAX>, tNet_message *pMessage@<EDX>, int (*pNotifyFail)(tU32, tNet_message*)@<EBX>)
int NetGuaranteedSendMessageToHost(tNet_game_details* pDetails, tNet_message* pMessage, int (*pNotifyFail)(tU32, tNet_message*)) {
LOG_TRACE("(%p, %p, %p)", pDetails, pMessage, pNotifyFail);
return NetGuaranteedSendMessageToAddress(pDetails, pMessage, &pDetails->pd_net_info, pNotifyFail);
}
// IDA: int __usercall NetGuaranteedSendMessageToPlayer@<EAX>(tNet_game_details *pDetails@<EAX>, tNet_message *pMessage@<EDX>, tPlayer_ID pPlayer@<EBX>, int (*pNotifyFail)(tU32, tNet_message*)@<ECX>)
int NetGuaranteedSendMessageToPlayer(tNet_game_details* pDetails, tNet_message* pMessage, tPlayer_ID pPlayer, int (*pNotifyFail)(tU32, tNet_message*)) {
int i;
LOG_TRACE("(%p, %p, %d, %p)", pDetails, pMessage, pPlayer, pNotifyFail);
for (i = 0; i <= gNumber_of_net_players; i++) {
if (pPlayer == gNet_players[i].ID) {
break;
}
}
if (i == gNumber_of_net_players) {
return -1;
}
if (gLocal_net_ID != pPlayer) {
return NetGuaranteedSendMessageToAddress(pDetails, pMessage, &gNet_players[i].pd_net_info, pNotifyFail);
}
pMessage->sender = gLocal_net_ID;
pMessage->senders_time_stamp = PDGetTotalTime();
pMessage->num_contents = 1;
pMessage->guarantee_number = 0;
ReceivedMessage(pMessage, &gNet_players[i], GetRaceTime());
NetDisposeMessage(pDetails, pMessage);
return 0;
}
// IDA: int __usercall NetGuaranteedSendMessageToAddress@<EAX>(tNet_game_details *pDetails@<EAX>, tNet_message *pMessage@<EDX>, void *pAddress@<EBX>, int (*pNotifyFail)(tU32, tNet_message*)@<ECX>)
int NetGuaranteedSendMessageToAddress(tNet_game_details* pDetails, tNet_message* pMessage, void* pAddress, int (*pNotifyFail)(tU32, tNet_message*)) {
char buffer[256]; // Added by Dethrace
LOG_TRACE("(%p, %p, %p, %p)", pDetails, pMessage, pAddress, pNotifyFail);
if (gNet_mode == eNet_mode_none && !gJoin_list_mode) {
return -3;
}
pMessage->sender = gLocal_net_ID;
pMessage->senders_time_stamp = PDGetTotalTime();
if (gNext_guarantee >= COUNT_OF(gGuarantee_list)) {
sprintf(buffer
, "Guarantee list full %d", pMessage
->contents.
header.
type);
NewTextHeadupSlot(4, 0, 500, -1, buffer);
pMessage->guarantee_number = 0;
return 0;
}
pMessage->guarantee_number = gGuarantee_number;
gGuarantee_list[gNext_guarantee].guarantee_number = gGuarantee_number;
gGuarantee_number++;
gGuarantee_list[gNext_guarantee].message = pMessage;
gGuarantee_list[gNext_guarantee].send_time = PDGetTotalTime();
gGuarantee_list[gNext_guarantee].next_resend_time = gGuarantee_list[gNext_guarantee].send_time + 100;
gGuarantee_list[gNext_guarantee].resend_period = 100;
memcpy(&gGuarantee_list
[gNext_guarantee
].
pd_address, pAddress
, sizeof(tPD_net_player_info
));
gGuarantee_list[gNext_guarantee].NotifyFail = pNotifyFail;
gGuarantee_list[gNext_guarantee].recieved = 0;
gNext_guarantee++;
DoCheckSum(pMessage);
return PDNetSendMessageToAddress(pDetails, pMessage, pAddress);
}
// IDA: void __cdecl ResendGuaranteedMessages()
void ResendGuaranteedMessages(void) {
int i;
int j;
LOG_TRACE("()");
i = 0;
for (j = 0; j < gNext_guarantee; j++) {
if (i != j) {
memcpy(&gGuarantee_list
[i
], &gGuarantee_list
[j
], sizeof(tGuaranteed_message
));
}
if (!gGuarantee_list[i].recieved) {
if (gGuarantee_list[i].NotifyFail != NULL) {
gGuarantee_list
[i
].
recieved |= gGuarantee_list
[i
].
NotifyFail(time - gGuarantee_list
[i
].
send_time, gGuarantee_list
[i
].
message);
} else {
if (time - gGuarantee_list
[i
].
send_time > 10000) {
gGuarantee_list[i].recieved = 1;
}
}
}
if (!gGuarantee_list[i].recieved) {
if (time > gGuarantee_list
[i
].
next_resend_time) {
gGuarantee_list[i].message->guarantee_number = gGuarantee_list[i].guarantee_number;
GetCheckSum(gGuarantee_list[i].message);
PDNetSendMessageToAddress(gCurrent_net_game, gGuarantee_list[i].message, &gGuarantee_list[i].pd_address);
gGuarantee_list[i].resend_period = (tU32)(gGuarantee_list[i].resend_period * 1.2f);
gGuarantee_list[i].next_resend_time += gGuarantee_list[i].resend_period;
}
i++;
} else if ((i <= 0 || gGuarantee_list[i - 1].message != gGuarantee_list[i].message)
&& (gNext_guarantee <= j + 1 || gGuarantee_list[j + 1].message != gGuarantee_list[i].message)) {
gGuarantee_list[i].message->guarantee_number = 0;
NetDisposeMessage(gCurrent_net_game, gGuarantee_list[i].message);
}
}
gNext_guarantee = i;
}
// IDA: int __usercall SampleFailNotifier@<EAX>(tU32 pAge@<EAX>, tNet_message *pMessage@<EDX>)
int SampleFailNotifier(tU32 pAge, tNet_message* pMessage) {
LOG_TRACE("(%d, %p)", pAge, pMessage);
NOT_IMPLEMENTED();
}
// IDA: void __cdecl NetWaitForGuaranteeReplies()
void NetWaitForGuaranteeReplies(void) {
tU32 start_time;
LOG_TRACE("()");
start_time = PDGetTotalTime();
while (gNext_guarantee != 0) {
if (PDGetTotalTime() - start_time >= 5000) {
break;
}
NetService(0);
}
}
// IDA: tNet_game_player_info* __usercall NetPlayerFromID@<EAX>(tPlayer_ID pPlayer@<EAX>)
tNet_game_player_info* NetPlayerFromID(tPlayer_ID pPlayer) {
//int i; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(%d)", pPlayer);
NOT_IMPLEMENTED();
}
// IDA: tCar_spec* __usercall NetCarFromPlayerID@<EAX>(tPlayer_ID pPlayer@<EAX>)
tCar_spec* NetCarFromPlayerID(tPlayer_ID pPlayer) {
//int i; // Pierre-Marie Baty -- unused variable
//tNet_game_player_info* player; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(%d)", pPlayer);
NOT_IMPLEMENTED();
}
// IDA: tNet_game_player_info* __usercall NetPlayerFromCar@<EAX>(tCar_spec *pCar@<EAX>)
tNet_game_player_info* NetPlayerFromCar(tCar_spec* pCar) {
//int i; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(%p)", pCar);
NOT_IMPLEMENTED();
}
// IDA: tU32 __usercall DoCheckSum@<EAX>(tNet_message *pMessage@<EAX>)
tU32 DoCheckSum(tNet_message* pMessage) {
//int i; // Pierre-Marie Baty -- unused variable
//int j; // Pierre-Marie Baty -- unused variable
//tU32 the_sum; // Pierre-Marie Baty -- unused variable
//tU32* p; // Pierre-Marie Baty -- unused variable
//tU8* q; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(%p)", pMessage);
// empty function
return 0;
}
// IDA: void __usercall GetCheckSum(tNet_message *pMessage@<EAX>)
void GetCheckSum(tNet_message* pMessage) {
LOG_TRACE("(%p)", pMessage);
}
// IDA: void __usercall CheckCheckSum(tNet_message *pMessage@<EAX>)
void CheckCheckSum(tNet_message* pMessage) {
LOG_TRACE("(%p)", pMessage);
}