The sequence of events in the main game loop
Here is a high-level look at the main program flow, from the first menu to the end of a race. For more information on the loading process that precedes the first menu, see the deep dive on the jigsaw puzzle binary.
Each section is broken down into parts that mirror the structure of the source code, so it should be easy enough to find the relevant parts mentioned below.
Main game loop
--------------
The main game loop starts when we begin a new game, and restarts when we press SHIFT and right arrow.
1/6: Main game loop (Part 1 of 6)
- Initialise the grid positions, race positions and points for all 20 non-player drivers
- Set up the optimum steering for each section for the Novice class, storing the results in sectionSteering
- Print the "practice/competition" menu
- If practice is chosen, reset the lap times and jump to the HeadToTrack routine to get the wing settings and go to the track
2/6: Main game loop (Part 2 of 6)
- If we get here then we chose "competition" in part 1
- Print the "class of race" menu and process the choice
- Print the "duration of qualifying laps" menu and process the choice
3/6: Main game loop (Part 3 of 6)
- Reset the best lap times for each driver
- If we are starting a new competition, ask for the player's name
- Call the HeadToTrack routine to get the wing settings and go to the track for the qualifying lap, returning here when done
- Ask whether there are any other players, and if so, get their names and run their qualifying laps too
4/6: Main game loop (Part 4 of 6)
- Check the slowest qualifying lap times against the trackLapTimeMin and trackLapTimeSec values from the track data file
- If the player times are too slow for the chosen class, make the game easier by changing the race class
5/6: Main game loop (Part 5 of 6)
- Set up the optimum steering for each section for the current race class (which may have been amended in the previous step), storing the results in sectionSteering
- Print the current race class and wait for SPACE to be pressed
- Print the driver table and wait for SPACE to be pressed
- Print the "number of laps" menu and process the choice
- Print the player's name and wait for SPACE to be pressed
- Call the HeadToTrack routine to get the wing settings and run the race, returning here when done
6/6: Main game loop (Part 6 of 6)
- Sort the drivers by total race time
- Call the AwardRacePoints routine to award race points
- Sort the driver table by calling the SortDrivers routine
- Print the driver table, ordered by best lap times, and wait for SPACE to be pressed
- Print the driver table, ordered by accumulated points, and wait for SPACE or RETURN to be pressed (re-showing the driver tables for the latter)
- If there are other players, jump back to part 5 to print the next driver's name and run their race
- This race is run, so jump back to part 2 to print the "duration of qualifying laps" menu, ready for the next race in the championship
Main driving loop
-----------------
The main driving loop takes over when we go to the track to do a practice lap or join a race.
It is joined from the main game loop by calling the HeadToTrack routine, which asks for the wing settings and calls the main driving loop at MainDrivingLoop. It also deals with the exit from the main driving loop, whether we choose to return to the pits (in which case it shows the wing settings menu again), or when the race has ended (in which case it returns to the main game loop).
1/5: Main driving loop (Part 1 of 5)
- Switch from mode 7 to the custom screen mode
- Copy the dash data from the main game code to screen memory
- Copy the data from the dash data blocks to the screen to draw the track view
- Zero the timer (we jump back here when restarting practice laps)
- Reset the driving variables by calling the ResetVariables routine (we jump back here when restarting qualifying laps)
- Build the 3D objects for the player's car (we jump back here when restarting a Novice race)
- Call ScaleWingSettings to scale the wing settings
2/5: Main driving loop (Part 2 of 5)
- This is the main driving loop, which consists of a long sequence of subroutine calls that implement the vast majority of the game functionality
- Call ProcessTime to increment the timers and the main loop counter, and recalculate the driver speeds for the non-player drivers (every 32 iterations only)
- Call ShowStartingLights to show the starting lights on the right of the screen, if this is the start of a race
- Call ProcessDrivingKeys to check for and process the main driving keys
- Call ApplyDrivingModel to apply the driving model to the player's car
- Call GetTrackAndMarkers to calculate the coordinates for the track verges and corner markers
- Call MovePlayerOnTrack to update the position of the player's car within the current track segment
- Call MovePlayerSegment to move the player's car into the correct segment
- Call UpdateLapTimers to update the lap timers and display timer-related messages at the top of the screen
- Call MakeDrivingSounds to make the relevant sounds for the engine and tyres (for the first time)
- Call ResetTrackLines to reset the track lines below the horizon in the track view
- Call DrawTrack to draw the track into the screen buffer
- Call MakeDrivingSounds to make the relevant sounds for the engine and tyres (for the second time)
- Call SetBackground to set the background colour for any track lines in the track view that do not currently have a background set
- Call BuildRoadSign to build the road sign, if one is visible
- Call DrawCarOrSign to draw the road sign we just built
- Call DrawCornerMarkers to draw any visible corner markers
- Call MoveAndDrawCars to move the cars around the track and draw any that are visible, up to a maximum of five
- Call CopyTyreDashEdges to copy the pixels from the edges of the left tyre and right dashboard so they can be used when drawing the track view around the tyres and dashboard, and fill the blocks to the right of the edges with the appropriate content
- Call UpdateMirrors to update the view in the wing mirrors
- Call MakeDrivingSounds to make the relevant sounds for the engine and tyres (for the third time)
- Call MoveHorizon to move the position of the horizon palette switch up or down, depending on the current track pitch angle
- Call ProcessContact to process any car-on-car contact, if there has been any
- Call CheckForCrash to check to see if we have crashed into the fence, and if so, display the fence, make the crash sound and set the height of the car above the track to 127 (so if this is a Novice race, we get dropped back onto the track by the crane in part 3)
- Call DrawTrackView to copy the data from the dash data blocks to the screen to draw the track view, fitting it around the tyres and dashboard
3/5: Main driving loop (Part 3 of 5)
- If we crashed into the fence in part 2 and this is a Novice race, we are practising or we are driving a qualifying lap, then rejoin the race by jumping back to the relevant point in part 1
- If we didn't crash, jump to part 5 to keep driving
4/5: Main driving loop (Part 4 of 5)
- If we get here then we have either quit the race (via SHIFT-f4), or we crashed during an Amateur or a Professional race, or the track timer ran down
- In all cases, we are done racing and need to leave the track
- But first, we print a "please wait" message and call the FinishRace routine to finish racing all the non-player drivers around the track
- And then we jump to the end of part 5 to return to the menus
5/5: Main driving loop (Part 5 of 5)
- Process all shifted keys by calling ProcessShiftedKeys
- If we have pressed a key that makes us leave the track, jump to part 4 to process it
- Call MakeDrivingSounds to make the relevant sounds for the engine and tyres (for the fourth time)
- Call UpdateDashboard to update the rev counter on the dashboard
- Loop back to part 2 to keep driving
- If we get here then we need to leave the track and return to the game menu
- Copy the dash data from screen memory back to the main game code
- Disable the custom screen mode and switch to mode 7
- Return from the main driving loop, which returns us to the HeadToTrack routine