Subversion Repositories Games.Carmageddon

Rev

Rev 18 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
#include "mainloop.h"
2
#include "brender/brender.h"
3
#include "car.h"
4
#include "controls.h"
5
#include "crush.h"
6
#include "depth.h"
7
#include "displays.h"
8
#include "drmem.h"
9
#include "flicplay.h"
10
#include "globvars.h"
11
#include "globvrkm.h"
12
#include "globvrpb.h"
13
#include "graphics.h"
14
#include "harness/config.h"
15
#include "harness/hooks.h"
16
#include "harness/trace.h"
17
#include "input.h"
18
#include "main.h"
19
#include "mainmenu.h"
20
#include "netgame.h"
21
#include "network.h"
22
#include "oil.h"
23
#include "opponent.h"
24
#include "pd/sys.h"
25
#include "pedestrn.h"
26
#include "piping.h"
27
#include "powerup.h"
28
#include "pratcam.h"
29
#include "replay.h"
30
#include "s3/s3.h"
31
#include "skidmark.h"
32
#include "sound.h"
33
#include "spark.h"
34
#include "structur.h"
35
#include "trig.h"
36
#include "utility.h"
37
#include "world.h"
38
#include <stdlib.h>
39
 
40
int gNasty_kludgey_cockpit_variable;
41
tInfo_mode gInfo_mode;
42
tU32 gLast_tick_count;
43
tU32 gActual_last_tick_count;
44
tU32 gAverage_frame_period;
45
tU32 gOld_camera_time;
46
tU32 gLast_wasted_massage_start;
47
float gMr_odo;
48
tU32 gWasted_last_flash;
49
tTime_bonus_state gTime_bonus_state;
50
int gQueued_wasted_massages_count;
51
int gTime_bonus;
52
int gRace_bonus_headup;
53
int gWasted_flash_state;
54
int gLast_time_headup;
55
int gTime_bonus_headup;
56
int gQueued_wasted_massages[5];
57
tU32 gTime_bonus_start;
58
int gLast_credit_headup__mainloop; // suffix added to avoid duplicate symbol
59
 
60
// IDA: void __cdecl ToggleInfo()
61
void ToggleInfo(void) {
62
    LOG_TRACE("()");
63
 
64
    if (gProgram_state.game_completed) {
65
        if (KeyIsDown(KEYMAP_CONTROL_ANY)) {
66
            gAR_fudge_headups = !gAR_fudge_headups;
67
        } else {
68
            gInfo_on = !gInfo_on;
69
            if (gInfo_on) {
70
                gInfo_mode = PDKeyDown(KEY_SHIFT_ANY);
71
            }
72
        }
73
    }
74
}
75
 
76
// IDA: void __cdecl CalculateFrameRate()
77
void CalculateFrameRate(void) {
78
    static tU32 last_time;
79
    tU32 new_time;
80
    static int last_rates[30];
81
    int new_rate;
82
    int i;
83
    LOG_TRACE("()");
84
 
85
    new_time = PDGetTotalTime();
86
    if (new_time != last_time) {
87
        new_rate = 10000u / (new_time - last_time);
88
        gFrame_rate = new_rate;
89
        for (i = 0; i < COUNT_OF(last_rates); ++i) {
90
            gFrame_rate += last_rates[i];
91
        }
92
        gFrame_rate /= COUNT_OF(last_rates) + 1;
93
        for (i = 0; i < COUNT_OF(last_rates) - 1; i++) {
94
            last_rates[i] = last_rates[i + 1];
95
        }
96
        last_rates[29] = new_rate;
97
        last_time = new_time;
98
    }
99
}
100
 
101
// IDA: void __cdecl LoseOldestWastedMassage()
102
void LoseOldestWastedMassage(void) {
103
    int i;
104
    LOG_TRACE("()");
105
 
106
    for (i = 1; i < gQueued_wasted_massages_count; i++) {
107
        gQueued_wasted_massages[i - 1] = gQueued_wasted_massages[i];
108
    }
109
    gQueued_wasted_massages_count--;
110
    gLast_wasted_massage_start = GetTotalTime();
111
}
112
 
113
// IDA: void __usercall QueueWastedMassage(int pIndex@<EAX>)
114
void QueueWastedMassage(int pIndex) {
115
    LOG_TRACE("(%d)", pIndex);
116
 
117
    if (gQueued_wasted_massages_count == COUNT_OF(gQueued_wasted_massages)) {
118
        LoseOldestWastedMassage();
119
    }
120
    if (gQueued_wasted_massages_count == 0) {
121
        gLast_wasted_massage_start = GetTotalTime();
122
    }
123
    gQueued_wasted_massages[gQueued_wasted_massages_count] = pIndex;
124
    gQueued_wasted_massages_count++;
125
}
126
 
127
// IDA: void __cdecl MungeHeadups()
128
void MungeHeadups(void) {
129
    char the_text[256];
130
    //int flash_rate; // Pierre-Marie Baty -- unused variable
131
    int new_countdown;
132
    int net_credits;
133
    int previous_gtimer;
134
    //int previous_time_bonus; // Pierre-Marie Baty -- unused variable
135
    int effective_timer;
136
    int bonus;
137
    int oppo_count;
138
    tU32 the_time;
139
    float bearing;
140
    //br_material* nearby; // Pierre-Marie Baty -- unused variable
141
    //tPixelmap_user_data* user; // Pierre-Marie Baty -- unused variable
142
    static tU32 last_rattle_time;
143
    LOG_TRACE("()");
144
 
145
    ClearHeadupSlot(3);
146
    gMr_odo = (double)gFrame_period * gProgram_state.current_car.speedo_speed * WORLD_SCALE / 1600.0 + gMr_odo;
147
    if (gInfo_on) {
148
        bearing = 360.0 - FastScalarArcTan2(gCamera_to_world.m[0][2], gCamera_to_world.m[2][2]);
149
        if (gInfo_mode) {
150
            sprintf(
151
                the_text,
152
                "P'cam: curr=%d, ambi=%d, pend=%d Car: c=%+.3f, a=%+.3f, b=%+.3f",
153
                PratcamGetCurrent(),
154
                PratcamGetAmbient(),
155
                PratcamGetPending(),
156
                gCar_to_view->curvature,
157
                gCar_to_view->acc_force,
158
                gCar_to_view->brake_force);
159
        } else {
160
            sprintf(
161
                the_text,
162
                "%d.%d (%.3f, %.3f, %.3f) %.0f, %.0f, MILES=%.2f",
163
                gFrame_rate / 10,
164
                gFrame_rate % 10,
165
                gSelf->t.t.translate.t.v[0],
166
                gSelf->t.t.translate.t.v[1],
167
                gSelf->t.t.translate.t.v[2],
168
                gCamera_to_horiz_angle,
169
                bearing,
170
                gMr_odo);
171
        }
172
        ChangeHeadupText(gProgram_state.frame_rate_headup, the_text);
173
    } else {
174
        ChangeHeadupText(gProgram_state.frame_rate_headup, "");
175
    }
176
    net_credits = gProgram_state.credits_earned - gProgram_state.credits_lost;
177
    if (fabs((double)(gProgram_state.credits_earned - gProgram_state.credits_lost) - (double)gLast_credit_headup__mainloop) / (double)gFrame_period > 1.2) {
178
        if (net_credits - gLast_credit_headup__mainloop <= 0) {
179
            net_credits = (double)gLast_credit_headup__mainloop
180
                - ((double)(gLast_credit_headup__mainloop - net_credits) + 1000.0)
181
                    * (double)gFrame_period
182
                    * 1.2
183
                    / 1000.0;
184
        } else {
185
            net_credits = (net_credits - gLast_credit_headup__mainloop) + 1000.0 * (double)gFrame_period * 1.2 / 1000.0
186
                + (double)gLast_credit_headup__mainloop;
187
        }
188
    }
189
    gLast_credit_headup__mainloop = net_credits;
190
    if (gCountdown) {
191
        new_countdown = 7.5 - (double)GetRaceTime() / 1000.0;
192
        if (new_countdown < 0) {
193
            new_countdown = 0;
194
        }
195
        if (gCountdown != new_countdown && new_countdown <= 5) {
196
            gCountdown = new_countdown;
197
            NewImageHeadupSlot(5, 0, 800, new_countdown + 4);
198
            DRS3StartSound(gPedestrians_outlet, gCountdown + 8000);
199
            if (!new_countdown) {
200
                MakeFlagWavingBastardWaveHisFlagWhichIsTheProbablyTheLastThingHeWillEverDo();
201
            }
202
        }
203
    }
204
    if (fabs((double)gTimer - (double)gLast_time_headup) / (double)gFrame_period <= 10.0) {
205
        effective_timer = gTimer;
206
    } else if (gTimer - gLast_time_headup <= 0) {
207
        effective_timer = gTimer;
208
    } else {
209
        effective_timer = gFrame_period * 10.0 + gLast_time_headup;
210
    }
211
    gLast_time_headup = effective_timer;
212
    if (gNet_mode != eNet_mode_none) {
213
        DoNetworkHeadups(net_credits);
214
    } else {
215
        if (net_credits < 0) {
216
            sprintf(the_text, "\xF8%d\xFA %s", -net_credits, GetMiscString(kMiscString_LOSS));
217
        } else {
218
            sprintf(the_text, "\xF8%d\xFA %s", net_credits, GetMiscString(net_credits < 100000 ? kMiscString_PROFIT : kMiscString_PRFT));
219
        }
220
        ChangeHeadupText(gCredits_won_headup, the_text);
221
        if (gPedestrians_on) {
222
            sprintf(the_text, "\xF8%d\xFA/%d %s", gProgram_state.peds_killed, gTotal_peds, GetMiscString(kMiscString_KILLS));
223
            ChangeHeadupText(gPed_kill_count_headup, the_text);
224
        } else {
225
            ChangeHeadupText(gPed_kill_count_headup, "");
226
        }
227
        if (gQueued_wasted_massages_count && GetTotalTime() > gLast_wasted_massage_start + 5000) {
228
            LoseOldestWastedMassage();
229
        }
230
        if (gQueued_wasted_massages_count) {
231
            if (Flash(150, &gWasted_last_flash, &gWasted_flash_state)) {
232
                sprintf(the_text, "\xF9%s %s", gOpponents[gQueued_wasted_massages[0]].abbrev_name, GetMiscString(kMiscString_WASTED_46));
233
            } else {
234
                sprintf(the_text, " ");
235
            }
236
        } else {
237
            oppo_count = GetCarCount(eVehicle_opponent);
238
            sprintf(the_text, "%s \xF8%d\xFA/%d", GetMiscString(kMiscString_WASTED_19), oppo_count - NumberOfOpponentsLeft(), oppo_count);
239
        }
240
        ChangeHeadupText(gCar_kill_count_headup, the_text);
241
        if (effective_timer > 1199000) {
242
            effective_timer = 1199000;
243
        }
244
        TimerString(effective_timer, the_text, 1, 0);
245
        ChangeHeadupText(gTimer_headup, the_text);
246
        sprintf(the_text, "%s \xF8%d\xFA/%d %s \xF8%d\xFA/%d", GetMiscString(kMiscString_CP), gCheckpoint, gCheckpoint_count, GetMiscString(kMiscString_LAP), gLap, gTotal_laps);
247
        ChangeHeadupText(gLaps_headup, the_text);
248
        the_time = GetTotalTime() - gTime_bonus_start;
249
        switch (gTime_bonus_state) {
250
        case eTime_bonus_initial_pause:
251
            if (the_time >= 500) {
252
                bonus = gCurrent_race.bonus_score[gRace_over_reason][gProgram_state.skill_level];
253
                sprintf(the_text, "%s %d", GetMiscString(kMiscString_TimeBonus), bonus);
254
                DRS3StartSound(gPedestrians_outlet, 8015);
255
                ChangeHeadupText(gRace_bonus_headup, the_text);
256
                gProgram_state.credits_earned += bonus;
257
                gTime_bonus_state = eTime_bonus_race_bonus;
258
                gTime_bonus_start = GetTotalTime();
259
            }
260
            gRace_finished = 10000;
261
            break;
262
        case eTime_bonus_race_bonus:
263
            if (the_time >= 2000) {
264
                gTime_bonus_state = eTime_bonus_tb_up;
265
                gTime_bonus_start = GetTotalTime();
266
                last_rattle_time = 0;
267
            }
268
            gRace_finished = 10000;
269
            break;
270
        case eTime_bonus_tb_up:
271
            if (gTimer) {
272
                if (the_time - last_rattle_time > 15) {
273
                    previous_gtimer = gTimer;
274
                    gTimer -= 1000 * ((the_time - last_rattle_time) / 15);
275
                    if (gTimer < 0) {
276
                        gTimer = 0;
277
                    }
278
                    gTime_bonus += (previous_gtimer - gTimer) / 1000 * gPoints_per_second[gProgram_state.skill_level];
279
                    last_rattle_time += 15 * ((the_time - last_rattle_time) / 15);
280
                }
281
                sprintf(the_text, "%s %d", GetMiscString(kMiscString_TimeBonus), gTime_bonus);
282
                ChangeHeadupText(gTime_bonus_headup, the_text);
283
            } else {
284
                gTime_bonus_state = eTime_bonus_tb_pause;
285
                gTime_bonus_start = GetTotalTime();
286
                last_rattle_time = 0;
287
            }
288
            gRace_finished = 10000;
289
            break;
290
        case eTime_bonus_tb_pause:
291
            if (the_time >= 1000) {
292
                gTime_bonus_state = eTime_bonus_tb_down;
293
                gTime_bonus_start = GetTotalTime();
294
                last_rattle_time = 0;
295
            }
296
            gRace_finished = 10000;
297
            break;
298
        case eTime_bonus_tb_down:
299
            if (gTime_bonus) {
300
                if (the_time - last_rattle_time > 15) {
301
                    bonus = gTime_bonus;
302
                    gTime_bonus -= (the_time - last_rattle_time) * gPoints_per_second[gProgram_state.skill_level] / 15;
303
                    if (gTime_bonus < 0) {
304
                        gTime_bonus = 0;
305
                    }
306
                    gProgram_state.credits_earned += bonus - gTime_bonus;
307
                    last_rattle_time += 15 * ((the_time - last_rattle_time) / 15);
308
                }
309
                sprintf(the_text, "%s %d", GetMiscString(kMiscString_TimeBonus), gTime_bonus);
310
                ChangeHeadupText(gTime_bonus_headup, the_text);
311
            } else {
312
                gTime_bonus_state = eTime_bonus_end_pause;
313
                gTime_bonus_start = GetTotalTime();
314
            }
315
            gRace_finished = 10000;
316
            break;
317
        case eTime_bonus_end_pause:
318
            if (the_time >= 2000 && gRace_finished > 1) {
319
                gRace_finished = 1;
320
            }
321
            break;
322
        default:
323
            return;
324
        }
325
    }
326
}
327
 
328
// IDA: void __usercall UpdateFramePeriod(tU32 *pCamera_period@<EAX>)
329
void UpdateFramePeriod(tU32* pCamera_period) {
330
    tU32 new_tick_count;
331
    tU32 new_camera_tick_count;
332
    int error;
333
    static int last_AR_mode;
334
    LOG_TRACE("(%p)", pCamera_period);
335
 
336
    if (gAction_replay_mode != last_AR_mode) {
337
        if (gAction_replay_mode) {
338
            gLast_replay_frame_time = GetTotalTime();
339
        } else {
340
            gLast_tick_count = GetTotalTime();
341
        }
342
        last_AR_mode = gAction_replay_mode;
343
    }
344
    if (gAction_replay_mode) {
345
        gFrame_period = abs((int)(gLast_replay_frame_time - gLast_tick_count));
346
        gLast_tick_count = gLast_replay_frame_time;
347
        new_camera_tick_count = PDGetTotalTime();
348
        new_tick_count = GetTotalTime();
349
        if (gOld_camera_time) {
350
            *pCamera_period = new_camera_tick_count - gOld_camera_time;
351
        } else {
352
            *pCamera_period = 0;
353
        }
354
        gOld_camera_time = new_camera_tick_count;
355
        if (gFrame_period) {
356
            *pCamera_period = gFrame_period;
357
        }
358
    } else {
359
        new_tick_count = GetTotalTime();
360
        gLast_tick_count += gFrame_period;
361
        error = new_tick_count - gLast_tick_count;
362
        gFrame_period = new_tick_count - gActual_last_tick_count;
363
        if ((new_tick_count - gActual_last_tick_count) > 500 && new_tick_count - gRace_start > 2000) {
364
            gFrame_period = gAverage_frame_period / 10;
365
            gLast_tick_count = new_tick_count;
366
            if (gNet_mode) {
367
                if (gNet_mode == eNet_mode_client) {
368
                    gProgram_state.current_car.last_car_car_collision = 0;
369
                }
370
            }
371
        }
372
        gAverage_frame_period = 9 * gAverage_frame_period / 10 + gFrame_period;
373
        if ((new_tick_count - gRace_start) > 2000) {
374
            gFrame_period = gAverage_frame_period / 10;
375
        }
376
        if ((int)(error + gFrame_period) > 0) {
377
            gFrame_period += error;
378
        } else {
379
            gLast_tick_count = new_tick_count;
380
        }
381
        *pCamera_period = gFrame_period;
382
        gActual_last_tick_count = new_tick_count;
383
    }
384
    if (gFrame_period >= 10) {
385
        if (gFrame_period > 1000) {
386
            gFrame_period = 1000;
387
            gLast_tick_count = new_tick_count;
388
        }
389
    } else {
390
        // The following makes the timer go too fast when the real frame rate is high (=low frame period)
391
#ifndef DETHRACE_FIX_BUGS
392
        gFrame_period = 10;
393
#endif
394
        gLast_tick_count = new_tick_count;
395
    }
396
    if (*pCamera_period >= 10) {
397
        if (*pCamera_period > 1000) {
398
            *pCamera_period = 1000;
399
        }
400
    } else {
401
        *pCamera_period = 10;
402
    }
403
}
404
 
405
// IDA: tU32 __cdecl GetLastTickCount()
406
tU32 GetLastTickCount(void) {
407
    LOG_TRACE("()");
408
 
409
    return gLast_tick_count;
410
}
411
 
412
// IDA: void __cdecl CheckTimer()
413
void CheckTimer(void) {
414
    tS32 time_in_seconds;
415
    tS32 time_left;
416
    static tU32 last_time_in_seconds = 0;
417
    static tU32 last_demo_time_in_seconds = 0;
418
    LOG_TRACE("()");
419
 
420
    if (harness_game_config.freeze_timer) {
421
        return;
422
    }
423
 
424
    if (!gFreeze_timer && !gCountdown && !gRace_finished) {
425
        if (gFrame_period < (tU32) gTimer) { // Pierre-Marie Baty -- added type cast
426
            if (gNet_mode == eNet_mode_none) {
427
                gTimer -= gFrame_period;
428
            }
429
            time_left = gTimer + 500;
430
            time_in_seconds = (time_left) / 1000;
431
            if (time_in_seconds != last_time_in_seconds && time_in_seconds <= 10) {
432
                DRS3StartSound(gPedestrians_outlet, 1001);
433
            }
434
            last_time_in_seconds = time_in_seconds;
435
        } else {
436
            gTimer = 0;
437
            RaceCompleted(eRace_over_out_of_time);
438
        }
439
 
440
        if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo || harness_game_info.mode == eGame_splatpack_xmas_demo) {
441
            if (harness_game_config.demo_timeout != 0) {
442
                time_left = harness_game_config.demo_timeout - GetRaceTime();
443
                time_in_seconds = (time_left + 500) / 1000;
444
                if (time_in_seconds != last_demo_time_in_seconds && time_in_seconds <= 10)
445
                    DRS3StartSound(gPedestrians_outlet, 1001);
446
                last_demo_time_in_seconds = time_in_seconds;
447
                if (time_left <= 0) {
448
                    gTimer = 0;
449
                    RaceCompleted(eRace_over_demo);
450
                }
451
            }
452
        }
453
    }
454
}
455
 
456
// IDA: int __cdecl MungeRaceFinished()
457
int MungeRaceFinished(void) {
458
    LOG_TRACE("()");
459
 
460
    if (!gRace_finished || gAction_replay_mode || (gNet_mode != eNet_mode_none && gRace_over_reason == eRace_not_over_yet)) {
461
        return 0;
462
    }
463
    if (gRace_finished > gFrame_period) {
464
        gRace_finished -= gFrame_period;
465
    } else {
466
        if (!gTimer || gNet_mode != eNet_mode_none) {
467
            gRace_finished = 0;
468
            return 1;
469
        }
470
        gRace_finished = 15 * gTimer + 4500;
471
        gRace_bonus_headup = NewTextHeadupSlot(9, 0, 0, -4, "");
472
        gTime_bonus_headup = NewTextHeadupSlot(10, 0, 0, -4, "");
473
        gTime_bonus = 0;
474
        gTime_bonus_start = GetTotalTime();
475
        gTime_bonus_state = eTime_bonus_initial_pause;
476
    }
477
    return PDKeyDown(KEY_RETURN) || PDKeyDown(KEY_KP_ENTER);
478
}
479
 
480
// IDA: tRace_result __cdecl MainGameLoop()
481
tRace_result MainGameLoop(void) {
482
    tU32 camera_period;
483
    tU32 start_menu_time;
484
    tU32 frame_start_time;
485
    tRace_result result;
486
    int tried_to_allocate_AR;
487
    int i;
488
    int bonus;
489
    LOG_TRACE("()");
490
 
491
    tried_to_allocate_AR = 0;
492
    gCar_to_view = &gProgram_state.current_car;
493
    gOld_camera_time = 0;
494
    ClearEntireScreen();
495
    ResetPalette();
496
    gLast_credit_headup__mainloop = 0;
497
    gLast_time_headup = gTimer;
498
    gRace_bonus_headup = -1;
499
    gTime_bonus_headup = -1;
500
    gTime_bonus_start = 0;
501
    gTime_bonus_state = eTime_bonus_none;
502
    gLast_replay_frame_time = PDGetTotalTime();
503
    gLast_tick_count = GetTotalTime();
504
    gActual_last_tick_count = gLast_tick_count;
505
    gQueued_wasted_massages_count = 0;
506
    gWasted_flash_state = 0;
507
    gWasted_last_flash = 0;
508
    RevertPalette();
509
    gHost_abandon_game = 0;
510
    gNo_races_yet = 0;
511
    gRace_over_reason = eRace_not_over_yet;
512
    gMr_odo = 0.0;
513
    gReceived_game_scores = 0;
514
    ShowSpecialVolumesIfRequ();
515
    gProgram_state.racing = 1;
516
    if (gNet_mode == eNet_mode_host) {
517
        gCurrent_net_game->status.stage = eNet_game_playing;
518
    }
519
    NetPlayerStatusChanged(ePlayer_status_racing);
520
    GetAverageGridPosition(&gCurrent_race);
521
    ForceRebuildActiveCarList();
522
    PrintMemoryDump(0, "ABOUT TO ENTER MAINLOOP");
523
 
524
    do {
525
        frame_start_time = GetTotalTime();
526
        CyclePollKeys();
527
        CheckSystemKeys(1);
528
        NetReceiveAndProcessMessages();
529
        if (gHost_abandon_game || gProgram_state.prog_status == eProg_idling) {
530
            break;
531
        }
532
        if (gNet_mode && gMap_mode
533
            && ((gCurrent_net_game->type == eNet_game_type_foxy && gThis_net_player_index == gIt_or_fox)
534
                || (gCurrent_net_game->type == eNet_game_type_tag && gThis_net_player_index != gIt_or_fox))) {
535
            ToggleMap();
536
        }
537
        ResetGrooveFlags();
538
        MungeEngineNoise();
539
        ServiceGameInRace();
540
        EnterUserMessage();
541
        UpdateFramePeriod(&camera_period);
542
        if (!gAction_replay_mode) {
543
            DoPowerupPeriodics(gFrame_period);
544
        }
545
        ResetLollipopQueue();
546
        if (!gAction_replay_mode) {
547
            MungeOpponents(gFrame_period);
548
            PollCarControls(gFrame_period);
549
        }
550
        PollCameraControls(camera_period);
551
        if (gAction_replay_mode) {
552
            DoActionReplay(gFrame_period);
553
        } else {
554
            ControlOurCar(gFrame_period);
555
            ApplyPhysicsToCars(gLast_tick_count - gRace_start, gFrame_period);
556
            PipeCarPositions();
557
            NetSendMessageStacks();
558
            CheckRecoveryOfCars(gFrame_period + gLast_tick_count - gRace_start);
559
        }
560
        if (!gNasty_kludgey_cockpit_variable) {
561
            gNasty_kludgey_cockpit_variable = 1;
562
            ToggleCockpit();
563
        }
564
        gOur_pos = &gSelf->t.t.translate.t;
565
        PositionExternalCamera(&gProgram_state.current_car, camera_period);
566
        BrActorToActorMatrix34(&gCamera_to_world, gCamera, gUniverse_actor);
567
        BrActorToActorMatrix34(&gRearview_camera_to_world, gRearview_camera, gUniverse_actor);
568
        gCamera_to_horiz_angle = FastScalarArcTan2(gCamera_to_world.m[2][1], gCamera_to_world.m[1][1]);
569
        gYon_squared = ((br_camera*)gCamera->type_data)->yon_z * ((br_camera*)gCamera->type_data)->yon_z
570
            * gYon_multiplier
571
            * gYon_multiplier;
572
        if (!gAction_replay_mode) {
573
            CheckCheckpoints();
574
        }
575
        ChangingView();
576
        MungeCarGraphics(gFrame_period);
577
        FunkThoseTronics();
578
        GrooveThoseDelics();
579
        DoWheelDamage(gFrame_period);
580
        CalculateFrameRate();
581
        MungePedestrians(gFrame_period);
582
        CameraBugFix(&gProgram_state.current_car, camera_period);
583
        if (!gAction_replay_mode) {
584
            MungeHeadups();
585
            ProcessOilSpills(gFrame_period);
586
        }
587
        MungeShrapnel(gFrame_period);
588
        ChangeDepthEffect();
589
        ServiceGameInRace();
590
        EnterUserMessage();
591
        SkidsPerFrame();
592
        if (!gWait_for_it) {
593
            RenderAFrame(1);
594
        }
595
        CheckReplayTurnOn();
596
        if (!gRecover_car
597
            && gProgram_state.prog_status == eProg_game_ongoing
598
            && !gPalette_fade_time
599
            && (gNet_mode == eNet_mode_none
600
                || !gAction_replay_mode
601
                || gProgram_state.current_car.car_master_actor->t.t.mat.m[3][0] < 500.0)) {
602
 
603
            EnsureRenderPalette();
604
            EnsurePaletteUp();
605
        }
606
        DoNetGameManagement();
607
        if (KeyIsDown(KEYMAP_ESCAPE) && !gEntering_message) {
608
            WaitForNoKeys();
609
            if (gAction_replay_mode) {
610
                ToggleReplay();
611
            } else {
612
                start_menu_time = PDGetTotalTime();
613
                FadePaletteDown();
614
                ClearEntireScreen();
615
                GoingToInterfaceFromRace();
616
                DoMainMenuScreen(0, 0, 1);
617
                GoingBackToRaceFromInterface();
618
                AddLostTime(PDGetTotalTime() - start_menu_time);
619
            }
620
        }
621
        if (gAction_replay_mode) {
622
            PollActionReplayControls(gFrame_period);
623
        } else {
624
            CheckTimer();
625
        }
626
        if (!gAction_replay_mode && gKnobbled_frame_period) {
627
            while (GetTotalTime() - frame_start_time < (tU32) gKnobbled_frame_period) { // Pierre-Marie Baty -- added type cast
628
                ;
629
            }
630
        }
631
        if (!tried_to_allocate_AR) {
632
            tried_to_allocate_AR = 1;
633
            PrintMemoryDump(0, "JUST RENDERED 1ST STUFF");
634
            InitialisePiping();
635
            PrintMemoryDump(0, "JUST ALLOCATED ACTION REPLAY BUFFER");
636
        }
637
        if (gNet_mode == eNet_mode_client && gAbandon_game) {
638
            gProgram_state.prog_status = eProg_idling;
639
            gAbandon_game = 0;
640
        }
641
 
642
    } while (gProgram_state.prog_status == eProg_game_ongoing
643
        && !MungeRaceFinished()
644
        && !gAbandon_game
645
        && !gHost_abandon_game);
646
    PrintMemoryDump(0, "JUST EXITED MAINLOOP");
647
    FadePaletteDown();
648
    ClearEntireScreen();
649
    SuspendPendingFlic();
650
    RevertPalette();
651
    if (gMap_mode) {
652
        ToggleMap();
653
    }
654
    EnsureSpecialVolumesHidden();
655
    FadePaletteDown();
656
    NetPlayerStatusChanged(ePlayer_status_loading);
657
    if (gProgram_state.prog_status == eProg_game_ongoing) {
658
        ResetCarScreens();
659
    }
660
    if (gAbandon_game && gNet_mode == eNet_mode_host && gRace_over_reason < eRace_over_network_victory) {
661
        NetFinishRace(gCurrent_net_game, eRace_over_abandoned);
662
    }
663
    if (gAction_replay_mode) {
664
        ToggleReplay();
665
    }
666
    // From splatpack x-mas demo
667
    if (gArrow_mode) {
668
        ToggleArrow();
669
    }
670
 
671
    if (gHost_abandon_game) {
672
        result = eRace_game_abandonned;
673
    } else if (gProgram_state.prog_status == eProg_game_ongoing) {
674
        if (gAbandon_game) {
675
            result = eRace_aborted;
676
        } else if (gRace_over_reason == eRace_over_out_of_time || gRace_over_reason == eRace_over_demo) {
677
            result = eRace_timed_out;
678
        } else {
679
            result = eRace_completed;
680
        }
681
    } else {
682
        result = eRace_game_abandonned;
683
    }
684
    if (result >= eRace_completed) {
685
        gProgram_state.redo_race_index = -1;
686
    } else {
687
        gProgram_state.redo_race_index = gProgram_state.current_race_index;
688
    }
689
    gAbandon_game = 0;
690
    gSynch_race_start = 0;
691
    gInitialised_grid = 0;
692
    gHost_abandon_game = 0;
693
    S3StopAllOutletSounds();
694
    if (gTime_bonus_state > eTime_bonus_none) {
695
        gTime_bonus += gTimer / 1000 * gPoints_per_second[gProgram_state.skill_level];
696
        gProgram_state.credits_earned += gTime_bonus;
697
    }
698
    if (gTime_bonus_state < eTime_bonus_race_bonus) {
699
        // FIXME: gRace_over_reason can be -1 eRace_not_over_yet (=-1) when aborting a race
700
        bonus = gCurrent_race.bonus_score[gRace_over_reason][gProgram_state.skill_level];
701
        gProgram_state.credits_earned += bonus;
702
    }
703
    if (gNet_mode != eNet_mode_none) {
704
        for (i = 0; i < gNumber_of_net_players; i++) {
705
            StopCarBeingIt(gNet_players[i].car);
706
        }
707
    }
708
    gProgram_state.racing = 0;
709
    if (gNet_mode == eNet_mode_host) {
710
        gCurrent_net_game->status.stage = eNet_game_starting;
711
    }
712
    WaitForNoKeys();
713
    if (gNet_mode && gAbandon_game) {
714
        gProgram_state.prog_status = eProg_idling;
715
    }
716
    return result;
717
}
718
 
719
// IDA: tRace_result __cdecl DoRace()
720
tRace_result DoRace(void) {
721
    tRace_result result;
722
    LOG_TRACE("()");
723
 
724
    gRace_start = GetTotalTime();
725
    result = MainGameLoop();
726
    return result;
727
}