Subversion Repositories Games.Carmageddon

Rev

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

Rev Author Line No. Line
1 pmbaty 1
#include "network.h"
20 pmbaty 2
#include "brender/brender.h"
1 pmbaty 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
 
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("()");
20 pmbaty 163
    NOT_IMPLEMENTED();
1 pmbaty 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) {
20 pmbaty 179
    //tNet_contents* the_contents; // Pierre-Marie Baty -- unused variable
1 pmbaty 180
    LOG_TRACE("(\"%s\")", pMessage);
20 pmbaty 181
    NOT_IMPLEMENTED();
1 pmbaty 182
}
183
 
184
// IDA: void __usercall NetSendHeadupToPlayer(char *pMessage@<EAX>, tPlayer_ID pPlayer@<EDX>)
185
void NetSendHeadupToPlayer(char* pMessage, tPlayer_ID pPlayer) {
20 pmbaty 186
    //tNet_message* message; // Pierre-Marie Baty -- unused variable
1 pmbaty 187
    LOG_TRACE("(\"%s\", %d)", pMessage, pPlayer);
20 pmbaty 188
    NOT_IMPLEMENTED();
1 pmbaty 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);
20 pmbaty 381
    NOT_IMPLEMENTED();
1 pmbaty 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);
20 pmbaty 463
    NOT_IMPLEMENTED();
1 pmbaty 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) {
20 pmbaty 478
        old_fox_it = gNet_players[gIt_or_fox].ID;
1 pmbaty 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);
20 pmbaty 615
    NOT_IMPLEMENTED();
1 pmbaty 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) {
20 pmbaty 719
    //int i; // Pierre-Marie Baty -- unused variable
1 pmbaty 720
    LOG_TRACE("(%p, %p, %d)", pDetails, pMessage, pPlayer);
20 pmbaty 721
    NOT_IMPLEMENTED();
1 pmbaty 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);
20 pmbaty 727
    NOT_IMPLEMENTED();
1 pmbaty 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);
20 pmbaty 733
    NOT_IMPLEMENTED();
1 pmbaty 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);
20 pmbaty 846
    NOT_IMPLEMENTED();
1 pmbaty 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) {
20 pmbaty 867
    //tU32 the_size; // Pierre-Marie Baty -- unused variable
868
    //tNet_contents* contents; // Pierre-Marie Baty -- unused variable
1 pmbaty 869
    LOG_TRACE("(%d, %d)", pType, pSize_decider);
20 pmbaty 870
    NOT_IMPLEMENTED();
1 pmbaty 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
            }
20 pmbaty 972
            pointer = ((void**)pointer)[1];
1 pmbaty 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;
20 pmbaty 1078
    new_players = BrMemAllocate(new_player_count + 1 * sizeof(tNet_game_player_info), kMem_player_list_join);
1 pmbaty 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) {
20 pmbaty 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
1 pmbaty 1130
    LOG_TRACE("(%d)", pID);
20 pmbaty 1131
    NOT_IMPLEMENTED();
1 pmbaty 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);
20 pmbaty 1137
    NOT_IMPLEMENTED();
1 pmbaty 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,
11 pmbaty 1175
        gGraf_specs[gGraf_spec_index].total_height / 2 - gFonts[kFont_MEDIUMHD].height,
1 pmbaty 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
 
20 pmbaty 1216
    HostHasBittenTheDust(73);
1 pmbaty 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) {
20 pmbaty 1316
    //int i; // Pierre-Marie Baty -- unused variable
1317
    //int index; // Pierre-Marie Baty -- unused variable
1 pmbaty 1318
    LOG_TRACE("(%p)", pContents);
20 pmbaty 1319
    NOT_IMPLEMENTED();
1 pmbaty 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) {
21 pmbaty 1339
        NewTextHeadupSlot(eHeadupSlot_misc, 0, 3000, -4, pContents->data.headup.text);
1 pmbaty 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);
20 pmbaty 1366
        NetFullScreenMessage(128, 0);
1 pmbaty 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 {
20 pmbaty 1373
            NetFullScreenMessage(89, 0);
1 pmbaty 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);
20 pmbaty 1407
    NOT_IMPLEMENTED();
1 pmbaty 1408
}
1409
 
1410
// IDA: void __usercall ReceivedConfirm(tNet_contents *pContents@<EAX>)
1411
void ReceivedConfirm(tNet_contents* pContents) {
20 pmbaty 1412
    //int i; // Pierre-Marie Baty -- unused variable
1 pmbaty 1413
    LOG_TRACE("(%p)", pContents);
20 pmbaty 1414
    NOT_IMPLEMENTED();
1 pmbaty 1415
}
1416
 
1417
// IDA: void __usercall ReceivedDisableCar(tNet_contents *pContents@<EAX>)
1418
void ReceivedDisableCar(tNet_contents* pContents) {
1419
    LOG_TRACE("(%p)", pContents);
20 pmbaty 1420
    NOT_IMPLEMENTED();
1 pmbaty 1421
}
1422
 
1423
// IDA: void __usercall ReceivedEnableCar(tNet_contents *pContents@<EAX>)
1424
void ReceivedEnableCar(tNet_contents* pContents) {
1425
    LOG_TRACE("(%p)", pContents);
20 pmbaty 1426
    NOT_IMPLEMENTED();
1 pmbaty 1427
}
1428
 
1429
// IDA: void __usercall ReceivedScores(tNet_contents *pContents@<EAX>)
1430
void ReceivedScores(tNet_contents* pContents) {
20 pmbaty 1431
    //int i; // Pierre-Marie Baty -- unused variable
1 pmbaty 1432
    LOG_TRACE("(%p)", pContents);
20 pmbaty 1433
    NOT_IMPLEMENTED();
1 pmbaty 1434
}
1435
 
1436
// IDA: void __usercall ReceivedWasted(tNet_contents *pContents@<EAX>)
1437
void ReceivedWasted(tNet_contents* pContents) {
20 pmbaty 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
1 pmbaty 1447
    LOG_TRACE("(%p)", pContents);
20 pmbaty 1448
    NOT_IMPLEMENTED();
1 pmbaty 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) {
20 pmbaty 1488
    //int i; // Pierre-Marie Baty -- unused variable
1 pmbaty 1489
    LOG_TRACE("(%p)", pContents);
20 pmbaty 1490
    NOT_IMPLEMENTED();
1 pmbaty 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) {
21 pmbaty 1669
                    NewTextHeadupSlot(eHeadupSlot_misc, 0, 3000, -4, s);
1 pmbaty 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) {
20 pmbaty 1674
        HostHasBittenTheDust(91);
1 pmbaty 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);
20 pmbaty 1787
    NOT_IMPLEMENTED();
1 pmbaty 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);
21 pmbaty 1834
        NewTextHeadupSlot(eHeadupSlot_misc, 0, 500, -1, buffer);
1 pmbaty 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);
20 pmbaty 1896
    NOT_IMPLEMENTED();
1 pmbaty 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) {
20 pmbaty 1915
    //int i; // Pierre-Marie Baty -- unused variable
1 pmbaty 1916
    LOG_TRACE("(%d)", pPlayer);
20 pmbaty 1917
    NOT_IMPLEMENTED();
1 pmbaty 1918
}
1919
 
1920
// IDA: tCar_spec* __usercall NetCarFromPlayerID@<EAX>(tPlayer_ID pPlayer@<EAX>)
1921
tCar_spec* NetCarFromPlayerID(tPlayer_ID pPlayer) {
20 pmbaty 1922
    //int i; // Pierre-Marie Baty -- unused variable
1923
    //tNet_game_player_info* player; // Pierre-Marie Baty -- unused variable
1 pmbaty 1924
    LOG_TRACE("(%d)", pPlayer);
20 pmbaty 1925
    NOT_IMPLEMENTED();
1 pmbaty 1926
}
1927
 
1928
// IDA: tNet_game_player_info* __usercall NetPlayerFromCar@<EAX>(tCar_spec *pCar@<EAX>)
1929
tNet_game_player_info* NetPlayerFromCar(tCar_spec* pCar) {
20 pmbaty 1930
    //int i; // Pierre-Marie Baty -- unused variable
1 pmbaty 1931
    LOG_TRACE("(%p)", pCar);
20 pmbaty 1932
    NOT_IMPLEMENTED();
1 pmbaty 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
}