#include "mainloop.h"
#include "brender.h"
#include "car.h"
#include "controls.h"
#include "crush.h"
#include "depth.h"
#include "displays.h"
#include "drmem.h"
#include "flicplay.h"
#include "globvars.h"
#include "globvrkm.h"
#include "globvrpb.h"
#include "graphics.h"
#include "harness/config.h"
#include "harness/hooks.h"
#include "harness/trace.h"
#include "input.h"
#include "main.h"
#include "mainmenu.h"
#include "netgame.h"
#include "network.h"
#include "oil.h"
#include "opponent.h"
#include "pd/sys.h"
#include "pedestrn.h"
#include "piping.h"
#include "powerup.h"
#include "pratcam.h"
#include "replay.h"
#include "s3/s3.h"
#include "skidmark.h"
#include "sound.h"
#include "spark.h"
#include "structur.h"
#include "trig.h"
#include "utility.h"
#include "world.h"
#include <stdlib.h>
int gNasty_kludgey_cockpit_variable;
tInfo_mode gInfo_mode;
tU32 gLast_tick_count;
tU32 gActual_last_tick_count;
tU32 gAverage_frame_period;
tU32 gOld_camera_time;
tU32 gLast_wasted_massage_start;
float gMr_odo;
tU32 gWasted_last_flash;
tTime_bonus_state gTime_bonus_state;
int gQueued_wasted_massages_count;
int gTime_bonus;
int gRace_bonus_headup;
int gWasted_flash_state;
int gLast_time_headup;
int gTime_bonus_headup;
int gQueued_wasted_massages[5];
tU32 gTime_bonus_start;
int gLast_credit_headup__mainloop; // suffix added to avoid duplicate symbol
// IDA: void __cdecl ToggleInfo()
void ToggleInfo(void) {
LOG_TRACE("()");
if (gProgram_state.game_completed) {
if (KeyIsDown(KEYMAP_CONTROL_ANY)) {
gAR_fudge_headups = !gAR_fudge_headups;
} else {
gInfo_on = !gInfo_on;
if (gInfo_on) {
gInfo_mode = PDKeyDown(KEY_SHIFT_ANY);
}
}
}
}
// IDA: void __cdecl CalculateFrameRate()
void CalculateFrameRate(void) {
static tU32 last_time;
tU32 new_time;
static int last_rates[30];
int new_rate;
int i;
LOG_TRACE("()");
new_time = PDGetTotalTime();
if (new_time != last_time) {
new_rate = 10000u / (new_time - last_time);
gFrame_rate = new_rate;
for (i = 0; i < COUNT_OF(last_rates); ++i) {
gFrame_rate += last_rates[i];
}
gFrame_rate /= COUNT_OF(last_rates) + 1;
for (i = 0; i < COUNT_OF(last_rates) - 1; i++) {
last_rates[i] = last_rates[i + 1];
}
last_rates[29] = new_rate;
last_time = new_time;
}
}
// IDA: void __cdecl LoseOldestWastedMassage()
void LoseOldestWastedMassage(void) {
int i;
LOG_TRACE("()");
for (i = 1; i < gQueued_wasted_massages_count; i++) {
gQueued_wasted_massages[i - 1] = gQueued_wasted_massages[i];
}
gQueued_wasted_massages_count--;
gLast_wasted_massage_start = GetTotalTime();
}
// IDA: void __usercall QueueWastedMassage(int pIndex@<EAX>)
void QueueWastedMassage(int pIndex) {
LOG_TRACE("(%d)", pIndex);
if (gQueued_wasted_massages_count == COUNT_OF(gQueued_wasted_massages)) {
LoseOldestWastedMassage();
}
if (gQueued_wasted_massages_count == 0) {
gLast_wasted_massage_start = GetTotalTime();
}
gQueued_wasted_massages[gQueued_wasted_massages_count] = pIndex;
gQueued_wasted_massages_count++;
}
// IDA: void __cdecl MungeHeadups()
void MungeHeadups(void) {
char the_text[256];
//int flash_rate; // Pierre-Marie Baty -- unused variable
int new_countdown;
int net_credits;
int previous_gtimer;
//int previous_time_bonus; // Pierre-Marie Baty -- unused variable
int effective_timer;
int bonus;
int oppo_count;
tU32 the_time;
float bearing;
//br_material* nearby; // Pierre-Marie Baty -- unused variable
//tPixelmap_user_data* user; // Pierre-Marie Baty -- unused variable
static tU32 last_rattle_time;
LOG_TRACE("()");
ClearHeadupSlot(3);
gMr_odo = (double)gFrame_period * gProgram_state.current_car.speedo_speed * WORLD_SCALE / 1600.0 + gMr_odo;
if (gInfo_on) {
bearing = 360.0 - FastScalarArcTan2(gCamera_to_world.m[0][2], gCamera_to_world.m[2][2]);
if (gInfo_mode) {
the_text,
"P'cam: curr=%d, ambi=%d, pend=%d Car: c=%+.3f, a=%+.3f, b=%+.3f",
PratcamGetCurrent(),
PratcamGetAmbient(),
PratcamGetPending(),
gCar_to_view->curvature,
gCar_to_view->acc_force,
gCar_to_view->brake_force);
} else {
the_text,
"%d.%d (%.3f, %.3f, %.3f) %.0f, %.0f, MILES=%.2f",
gFrame_rate / 10,
gFrame_rate % 10,
gSelf->t.t.translate.t.v[0],
gSelf->t.t.translate.t.v[1],
gSelf->t.t.translate.t.v[2],
gCamera_to_horiz_angle,
bearing,
gMr_odo);
}
ChangeHeadupText(gProgram_state.frame_rate_headup, the_text);
} else {
ChangeHeadupText(gProgram_state.frame_rate_headup, "");
}
net_credits = gProgram_state.credits_earned - gProgram_state.credits_lost;
if (fabs((double)(gProgram_state.
credits_earned - gProgram_state.
credits_lost) - (double)gLast_credit_headup__mainloop
) / (double)gFrame_period
> 1.2) {
if (net_credits - gLast_credit_headup__mainloop <= 0) {
net_credits = (double)gLast_credit_headup__mainloop
- ((double)(gLast_credit_headup__mainloop - net_credits) + 1000.0)
* (double)gFrame_period
* 1.2
/ 1000.0;
} else {
net_credits = (net_credits - gLast_credit_headup__mainloop) + 1000.0 * (double)gFrame_period * 1.2 / 1000.0
+ (double)gLast_credit_headup__mainloop;
}
}
gLast_credit_headup__mainloop = net_credits;
if (gCountdown) {
new_countdown = 7.5 - (double)GetRaceTime() / 1000.0;
if (new_countdown < 0) {
new_countdown = 0;
}
if (gCountdown != new_countdown && new_countdown <= 5) {
gCountdown = new_countdown;
NewImageHeadupSlot(5, 0, 800, new_countdown + 4);
DRS3StartSound(gPedestrians_outlet, gCountdown + 8000);
if (!new_countdown) {
MakeFlagWavingBastardWaveHisFlagWhichIsTheProbablyTheLastThingHeWillEverDo();
}
}
}
if (fabs((double)gTimer
- (double)gLast_time_headup
) / (double)gFrame_period
<= 10.0) {
effective_timer = gTimer;
} else if (gTimer - gLast_time_headup <= 0) {
effective_timer = gTimer;
} else {
effective_timer = gFrame_period * 10.0 + gLast_time_headup;
}
gLast_time_headup = effective_timer;
if (gNet_mode != eNet_mode_none) {
DoNetworkHeadups(net_credits);
} else {
if (net_credits < 0) {
sprintf(the_text
, "\xF8%d\xFA %s", -net_credits
, GetMiscString
(kMiscString_LOSS
));
} else {
sprintf(the_text
, "\xF8%d\xFA %s", net_credits
, GetMiscString
(net_credits
< 100000 ? kMiscString_PROFIT
: kMiscString_PRFT
));
}
ChangeHeadupText(gCredits_won_headup, the_text);
if (gPedestrians_on) {
sprintf(the_text
, "\xF8%d\xFA/%d %s", gProgram_state.
peds_killed, gTotal_peds
, GetMiscString
(kMiscString_KILLS
));
ChangeHeadupText(gPed_kill_count_headup, the_text);
} else {
ChangeHeadupText(gPed_kill_count_headup, "");
}
if (gQueued_wasted_massages_count && GetTotalTime() > gLast_wasted_massage_start + 5000) {
LoseOldestWastedMassage();
}
if (gQueued_wasted_massages_count) {
if (Flash(150, &gWasted_last_flash, &gWasted_flash_state)) {
sprintf(the_text
, "\xF9%s %s", gOpponents
[gQueued_wasted_massages
[0]].
abbrev_name, GetMiscString
(kMiscString_WASTED_46
));
} else {
}
} else {
oppo_count = GetCarCount(eVehicle_opponent);
sprintf(the_text
, "%s \xF8%d\xFA/%d", GetMiscString
(kMiscString_WASTED_19
), oppo_count
- NumberOfOpponentsLeft
(), oppo_count
);
}
ChangeHeadupText(gCar_kill_count_headup, the_text);
if (effective_timer > 1199000) {
effective_timer = 1199000;
}
TimerString(effective_timer, the_text, 1, 0);
ChangeHeadupText(gTimer_headup, the_text);
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
);
ChangeHeadupText(gLaps_headup, the_text);
the_time = GetTotalTime() - gTime_bonus_start;
switch (gTime_bonus_state) {
case eTime_bonus_initial_pause:
if (the_time >= 500) {
bonus = gCurrent_race.bonus_score[gRace_over_reason][gProgram_state.skill_level];
sprintf(the_text
, "%s %d", GetMiscString
(kMiscString_TimeBonus
), bonus
);
DRS3StartSound(gPedestrians_outlet, 8015);
ChangeHeadupText(gRace_bonus_headup, the_text);
gProgram_state.credits_earned += bonus;
gTime_bonus_state = eTime_bonus_race_bonus;
gTime_bonus_start = GetTotalTime();
}
gRace_finished = 10000;
break;
case eTime_bonus_race_bonus:
if (the_time >= 2000) {
gTime_bonus_state = eTime_bonus_tb_up;
gTime_bonus_start = GetTotalTime();
last_rattle_time = 0;
}
gRace_finished = 10000;
break;
case eTime_bonus_tb_up:
if (gTimer) {
if (the_time - last_rattle_time > 15) {
previous_gtimer = gTimer;
gTimer -= 1000 * ((the_time - last_rattle_time) / 15);
if (gTimer < 0) {
gTimer = 0;
}
gTime_bonus += (previous_gtimer - gTimer) / 1000 * gPoints_per_second[gProgram_state.skill_level];
last_rattle_time += 15 * ((the_time - last_rattle_time) / 15);
}
sprintf(the_text
, "%s %d", GetMiscString
(kMiscString_TimeBonus
), gTime_bonus
);
ChangeHeadupText(gTime_bonus_headup, the_text);
} else {
gTime_bonus_state = eTime_bonus_tb_pause;
gTime_bonus_start = GetTotalTime();
last_rattle_time = 0;
}
gRace_finished = 10000;
break;
case eTime_bonus_tb_pause:
if (the_time >= 1000) {
gTime_bonus_state = eTime_bonus_tb_down;
gTime_bonus_start = GetTotalTime();
last_rattle_time = 0;
}
gRace_finished = 10000;
break;
case eTime_bonus_tb_down:
if (gTime_bonus) {
if (the_time - last_rattle_time > 15) {
bonus = gTime_bonus;
gTime_bonus -= (the_time - last_rattle_time) * gPoints_per_second[gProgram_state.skill_level] / 15;
if (gTime_bonus < 0) {
gTime_bonus = 0;
}
gProgram_state.credits_earned += bonus - gTime_bonus;
last_rattle_time += 15 * ((the_time - last_rattle_time) / 15);
}
sprintf(the_text
, "%s %d", GetMiscString
(kMiscString_TimeBonus
), gTime_bonus
);
ChangeHeadupText(gTime_bonus_headup, the_text);
} else {
gTime_bonus_state = eTime_bonus_end_pause;
gTime_bonus_start = GetTotalTime();
}
gRace_finished = 10000;
break;
case eTime_bonus_end_pause:
if (the_time >= 2000 && gRace_finished > 1) {
gRace_finished = 1;
}
break;
default:
return;
}
}
}
// IDA: void __usercall UpdateFramePeriod(tU32 *pCamera_period@<EAX>)
void UpdateFramePeriod(tU32* pCamera_period) {
tU32 new_tick_count;
tU32 new_camera_tick_count;
int error;
static int last_AR_mode;
LOG_TRACE("(%p)", pCamera_period);
if (gAction_replay_mode != last_AR_mode) {
if (gAction_replay_mode) {
gLast_replay_frame_time = GetTotalTime();
} else {
gLast_tick_count = GetTotalTime();
}
last_AR_mode = gAction_replay_mode;
}
if (gAction_replay_mode) {
gFrame_period
= abs((int)(gLast_replay_frame_time
- gLast_tick_count
));
gLast_tick_count = gLast_replay_frame_time;
new_camera_tick_count = PDGetTotalTime();
new_tick_count = GetTotalTime();
if (gOld_camera_time) {
*pCamera_period = new_camera_tick_count - gOld_camera_time;
} else {
*pCamera_period = 0;
}
gOld_camera_time = new_camera_tick_count;
if (gFrame_period) {
*pCamera_period = gFrame_period;
}
} else {
new_tick_count = GetTotalTime();
gLast_tick_count += gFrame_period;
error = new_tick_count - gLast_tick_count;
gFrame_period = new_tick_count - gActual_last_tick_count;
if ((new_tick_count - gActual_last_tick_count) > 500 && new_tick_count - gRace_start > 2000) {
gFrame_period = gAverage_frame_period / 10;
gLast_tick_count = new_tick_count;
if (gNet_mode) {
if (gNet_mode == eNet_mode_client) {
gProgram_state.current_car.last_car_car_collision = 0;
}
}
}
gAverage_frame_period = 9 * gAverage_frame_period / 10 + gFrame_period;
if ((new_tick_count - gRace_start) > 2000) {
gFrame_period = gAverage_frame_period / 10;
}
if ((int)(error + gFrame_period) > 0) {
gFrame_period += error;
} else {
gLast_tick_count = new_tick_count;
}
*pCamera_period = gFrame_period;
gActual_last_tick_count = new_tick_count;
}
if (gFrame_period >= 10) {
if (gFrame_period > 1000) {
gFrame_period = 1000;
gLast_tick_count = new_tick_count;
}
} else {
// The following makes the timer go too fast when the real frame rate is high (=low frame period)
#ifndef DETHRACE_FIX_BUGS
gFrame_period = 10;
#endif
gLast_tick_count = new_tick_count;
}
if (*pCamera_period >= 10) {
if (*pCamera_period > 1000) {
*pCamera_period = 1000;
}
} else {
*pCamera_period = 10;
}
}
// IDA: tU32 __cdecl GetLastTickCount()
tU32 GetLastTickCount(void) {
LOG_TRACE("()");
return gLast_tick_count;
}
// IDA: void __cdecl CheckTimer()
void CheckTimer(void) {
tS32 time_in_seconds;
tS32 time_left;
static tU32 last_time_in_seconds = 0;
static tU32 last_demo_time_in_seconds = 0;
LOG_TRACE("()");
if (harness_game_config.freeze_timer) {
return;
}
if (!gFreeze_timer && !gCountdown && !gRace_finished) {
if (gFrame_period < (tU32) gTimer) { // Pierre-Marie Baty -- added type cast
if (gNet_mode == eNet_mode_none) {
gTimer -= gFrame_period;
}
time_left = gTimer + 500;
time_in_seconds = (time_left) / 1000;
if (time_in_seconds != last_time_in_seconds && time_in_seconds <= 10) {
DRS3StartSound(gPedestrians_outlet, 1001);
}
last_time_in_seconds = time_in_seconds;
} else {
gTimer = 0;
RaceCompleted(eRace_over_out_of_time);
}
if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo || harness_game_info.mode == eGame_splatpack_xmas_demo) {
if (harness_game_config.demo_timeout != 0) {
time_left = harness_game_config.demo_timeout - GetRaceTime();
time_in_seconds = (time_left + 500) / 1000;
if (time_in_seconds != last_demo_time_in_seconds && time_in_seconds <= 10)
DRS3StartSound(gPedestrians_outlet, 1001);
last_demo_time_in_seconds = time_in_seconds;
if (time_left <= 0) {
gTimer = 0;
RaceCompleted(eRace_over_demo);
}
}
}
}
}
// IDA: int __cdecl MungeRaceFinished()
int MungeRaceFinished(void) {
LOG_TRACE("()");
if (!gRace_finished || gAction_replay_mode || (gNet_mode != eNet_mode_none && gRace_over_reason == eRace_not_over_yet)) {
return 0;
}
if (gRace_finished > gFrame_period) {
gRace_finished -= gFrame_period;
} else {
if (!gTimer || gNet_mode != eNet_mode_none) {
gRace_finished = 0;
return 1;
}
gRace_finished = 15 * gTimer + 4500;
gRace_bonus_headup = NewTextHeadupSlot(9, 0, 0, -4, "");
gTime_bonus_headup = NewTextHeadupSlot(10, 0, 0, -4, "");
gTime_bonus = 0;
gTime_bonus_start = GetTotalTime();
gTime_bonus_state = eTime_bonus_initial_pause;
}
return PDKeyDown(KEY_RETURN) || PDKeyDown(KEY_KP_ENTER);
}
// IDA: tRace_result __cdecl MainGameLoop()
tRace_result MainGameLoop(void) {
tU32 camera_period;
tU32 start_menu_time;
tU32 frame_start_time;
tRace_result result;
int tried_to_allocate_AR;
int i;
int bonus;
LOG_TRACE("()");
tried_to_allocate_AR = 0;
gCar_to_view = &gProgram_state.current_car;
gOld_camera_time = 0;
ClearEntireScreen();
ResetPalette();
gLast_credit_headup__mainloop = 0;
gLast_time_headup = gTimer;
gRace_bonus_headup = -1;
gTime_bonus_headup = -1;
gTime_bonus_start = 0;
gTime_bonus_state = eTime_bonus_none;
gLast_replay_frame_time = PDGetTotalTime();
gLast_tick_count = GetTotalTime();
gActual_last_tick_count = gLast_tick_count;
gQueued_wasted_massages_count = 0;
gWasted_flash_state = 0;
gWasted_last_flash = 0;
RevertPalette();
gHost_abandon_game = 0;
gNo_races_yet = 0;
gRace_over_reason = eRace_not_over_yet;
gMr_odo = 0.0;
gReceived_game_scores = 0;
ShowSpecialVolumesIfRequ();
gProgram_state.racing = 1;
if (gNet_mode == eNet_mode_host) {
gCurrent_net_game->status.stage = eNet_game_playing;
}
NetPlayerStatusChanged(ePlayer_status_racing);
GetAverageGridPosition(&gCurrent_race);
ForceRebuildActiveCarList();
PrintMemoryDump(0, "ABOUT TO ENTER MAINLOOP");
do {
frame_start_time = GetTotalTime();
CyclePollKeys();
CheckSystemKeys(1);
NetReceiveAndProcessMessages();
if (gHost_abandon_game || gProgram_state.prog_status == eProg_idling) {
break;
}
if (gNet_mode && gMap_mode
&& ((gCurrent_net_game->type == eNet_game_type_foxy && gThis_net_player_index == gIt_or_fox)
|| (gCurrent_net_game->type == eNet_game_type_tag && gThis_net_player_index != gIt_or_fox))) {
ToggleMap();
}
ResetGrooveFlags();
MungeEngineNoise();
ServiceGameInRace();
EnterUserMessage();
UpdateFramePeriod(&camera_period);
if (!gAction_replay_mode) {
DoPowerupPeriodics(gFrame_period);
}
ResetLollipopQueue();
if (!gAction_replay_mode) {
MungeOpponents(gFrame_period);
PollCarControls(gFrame_period);
}
PollCameraControls(camera_period);
if (gAction_replay_mode) {
DoActionReplay(gFrame_period);
} else {
ControlOurCar(gFrame_period);
ApplyPhysicsToCars(gLast_tick_count - gRace_start, gFrame_period);
PipeCarPositions();
NetSendMessageStacks();
CheckRecoveryOfCars(gFrame_period + gLast_tick_count - gRace_start);
}
if (!gNasty_kludgey_cockpit_variable) {
gNasty_kludgey_cockpit_variable = 1;
ToggleCockpit();
}
gOur_pos = &gSelf->t.t.translate.t;
PositionExternalCamera(&gProgram_state.current_car, camera_period);
BrActorToActorMatrix34(&gCamera_to_world, gCamera, gUniverse_actor);
BrActorToActorMatrix34(&gRearview_camera_to_world, gRearview_camera, gUniverse_actor);
gCamera_to_horiz_angle = FastScalarArcTan2(gCamera_to_world.m[2][1], gCamera_to_world.m[1][1]);
gYon_squared = ((br_camera*)gCamera->type_data)->yon_z * ((br_camera*)gCamera->type_data)->yon_z
* gYon_multiplier
* gYon_multiplier;
if (!gAction_replay_mode) {
CheckCheckpoints();
}
ChangingView();
MungeCarGraphics(gFrame_period);
FunkThoseTronics();
GrooveThoseDelics();
DoWheelDamage(gFrame_period);
CalculateFrameRate();
MungePedestrians(gFrame_period);
CameraBugFix(&gProgram_state.current_car, camera_period);
if (!gAction_replay_mode) {
MungeHeadups();
ProcessOilSpills(gFrame_period);
}
MungeShrapnel(gFrame_period);
ChangeDepthEffect();
ServiceGameInRace();
EnterUserMessage();
SkidsPerFrame();
if (!gWait_for_it) {
RenderAFrame(1);
}
CheckReplayTurnOn();
if (!gRecover_car
&& gProgram_state.prog_status == eProg_game_ongoing
&& !gPalette_fade_time
&& (gNet_mode == eNet_mode_none
|| !gAction_replay_mode
|| gProgram_state.current_car.car_master_actor->t.t.mat.m[3][0] < 500.0)) {
EnsureRenderPalette();
EnsurePaletteUp();
}
DoNetGameManagement();
if (KeyIsDown(KEYMAP_ESCAPE) && !gEntering_message) {
WaitForNoKeys();
if (gAction_replay_mode) {
ToggleReplay();
} else {
start_menu_time = PDGetTotalTime();
FadePaletteDown();
ClearEntireScreen();
GoingToInterfaceFromRace();
DoMainMenuScreen(0, 0, 1);
GoingBackToRaceFromInterface();
AddLostTime(PDGetTotalTime() - start_menu_time);
}
}
if (gAction_replay_mode) {
PollActionReplayControls(gFrame_period);
} else {
CheckTimer();
}
if (!gAction_replay_mode && gKnobbled_frame_period) {
while (GetTotalTime() - frame_start_time < (tU32) gKnobbled_frame_period) { // Pierre-Marie Baty -- added type cast
;
}
}
if (!tried_to_allocate_AR) {
tried_to_allocate_AR = 1;
PrintMemoryDump(0, "JUST RENDERED 1ST STUFF");
InitialisePiping();
PrintMemoryDump(0, "JUST ALLOCATED ACTION REPLAY BUFFER");
}
if (gNet_mode == eNet_mode_client && gAbandon_game) {
gProgram_state.prog_status = eProg_idling;
gAbandon_game = 0;
}
} while (gProgram_state.prog_status == eProg_game_ongoing
&& !MungeRaceFinished()
&& !gAbandon_game
&& !gHost_abandon_game);
PrintMemoryDump(0, "JUST EXITED MAINLOOP");
FadePaletteDown();
ClearEntireScreen();
SuspendPendingFlic();
RevertPalette();
if (gMap_mode) {
ToggleMap();
}
EnsureSpecialVolumesHidden();
FadePaletteDown();
NetPlayerStatusChanged(ePlayer_status_loading);
if (gProgram_state.prog_status == eProg_game_ongoing) {
ResetCarScreens();
}
if (gAbandon_game && gNet_mode == eNet_mode_host && gRace_over_reason < eRace_over_network_victory) {
NetFinishRace(gCurrent_net_game, eRace_over_abandoned);
}
if (gAction_replay_mode) {
ToggleReplay();
}
// From splatpack x-mas demo
if (gArrow_mode) {
ToggleArrow();
}
if (gHost_abandon_game) {
result = eRace_game_abandonned;
} else if (gProgram_state.prog_status == eProg_game_ongoing) {
if (gAbandon_game) {
result = eRace_aborted;
} else if (gRace_over_reason == eRace_over_out_of_time || gRace_over_reason == eRace_over_demo) {
result = eRace_timed_out;
} else {
result = eRace_completed;
}
} else {
result = eRace_game_abandonned;
}
if (result >= eRace_completed) {
gProgram_state.redo_race_index = -1;
} else {
gProgram_state.redo_race_index = gProgram_state.current_race_index;
}
gAbandon_game = 0;
gSynch_race_start = 0;
gInitialised_grid = 0;
gHost_abandon_game = 0;
S3StopAllOutletSounds();
if (gTime_bonus_state > eTime_bonus_none) {
gTime_bonus += gTimer / 1000 * gPoints_per_second[gProgram_state.skill_level];
gProgram_state.credits_earned += gTime_bonus;
}
if (gTime_bonus_state < eTime_bonus_race_bonus) {
// FIXME: gRace_over_reason can be -1 eRace_not_over_yet (=-1) when aborting a race
bonus = gCurrent_race.bonus_score[gRace_over_reason][gProgram_state.skill_level];
gProgram_state.credits_earned += bonus;
}
if (gNet_mode != eNet_mode_none) {
for (i = 0; i < gNumber_of_net_players; i++) {
StopCarBeingIt(gNet_players[i].car);
}
}
gProgram_state.racing = 0;
if (gNet_mode == eNet_mode_host) {
gCurrent_net_game->status.stage = eNet_game_starting;
}
WaitForNoKeys();
if (gNet_mode && gAbandon_game) {
gProgram_state.prog_status = eProg_idling;
}
return result;
}
// IDA: tRace_result __cdecl DoRace()
tRace_result DoRace(void) {
tRace_result result;
LOG_TRACE("()");
gRace_start = GetTotalTime();
result = MainGameLoop();
return result;
}