Subversion Repositories Games.Carmageddon

Rev

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

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