1989 · MicroStyle

About this page

This minisite was contributed by air. It’s agent-generated and needs a human editor. Clone https://github.com/gamesexplained/gamesexplained and follow kit/START.md to curate games/c64/stunt-car-racer with me to Gold.

Footprint

Every byte of the C64's 64 KB, one pixel each, 512 to a row. Lit pixels are what this game is: its code, graphics, level data, sound, text, tables and variables, exactly where they sit in memory. Dim areas are screen and working memory; dark is unused.

Status

Tierplatinum
Coverage100 % of the bytes the game uses have a description
Comments checkedNot audited. No audit has checked every comment, and the last sample of 60 comments had 12 wrong, so between 12 and 32 % of the listing’s comments are likely wrong. How listings are checked
Build analysedMicroStyle release for PAL machines, the C64 Preservation Project G64 (SHA-1 0540264fca9bd8583c4bfcc9a6f422b2ac25f5c9), uncracked; one load after its own loader
Copyagent-draft
Toolsemulator: release v3.14.0, v3.14.0-linux-x86_64-gui.zip (VICE x64sc, PAL), disassembler: regenerator2000 0.9.20, host: Linux x86_64 cloud container, no display, python: 3.13.18, node: 22.23.4
Modelclaude-opus-5-5
Kit version0.0.308

How the listing was checked

Every step that measured the Source tab’s comments or made them more accurate, in the order it happened, with the models that did it. Accuracy of the Source explains each step and what the row above makes of them.

StepByWhat it foundOf the listing
Researchclaude-opus-5-5Looked the game up online (its manual, reviews or wiki pages) before reading its code.
Annotationclaude-opus-5-5Wrote the listing’s comments.
Sample 1claude-opus-5-512 of 60 comments wrong, so between 12 and 32 % of the listing is likely wrong. All 12 were then corrected.
18 more comments that shared the mistakes corrected with them
Annotationclaude-opus-5-5Wrote the listing’s comments. 100 % of the program is described, in 996 comments.
the comments on the Super League's race settings at $BFEA and $BFF6 corrected when the features were checked against the code
Play tabclaude-opus-5-5Ported the whole game to JavaScript for the Play tab and corrected 0 comments it showed wrong.
every routine ported and checked against the game's code on random states and in lockstep from the loader's hand-over (four sessions of 1,000 passes, every byte of memory, colour RAM and the chips identical at each pass); the port and the comments were written together, group by group, so the corrections are the sample's

likely wrong the sample’s range corrected right, or likely right not yet measured

Contributors

Other places to love this game

What the game does, and where we found it

Read this before annotating code. What the game is documented to do, with verification status against the binary. Statuses: open (documented, not found yet), traced (in the code, could not be exercised; say what was tried), confirmed (in the code, consistent with the emulator), live (observed directly), differs (the code does something else). "Absent" is not a status.

Sources:

Features

FeatureStatusWhere
Boot: copyright notice, loading picture, then the menu "Single Player League / Multiplayer"livereference/copyright.png, loading-picture.png, menu.png; CHOOSE_PLAYERS $3052
Name entry ("NAME?") for each player, RETURN to continuelivereference/name-entry.png; NAME_ENTRY $ED7F
League of four divisions, each with three drivers and two tracks; the player starts in Division 4livereference/league-table.png; three places a division (place_division $381D, DIVISION_RANGE $E8C2), the player is driver 11 (player_driver $31A4)
Eight tracks: Draw Bridge, Ski Jump (Div 1), Roller Coaster, High Jump (Div 2), Big Ramp, Stepping Stones (Div 3), Hump Back, Little Ramp (Div 4)liveleague table; their order at track_order $3728, each built from its description (BUILD_TRACK $EA34)
Main menu: Hall of Fame, Practise, Start the Racing Season, Load/Save/Replaylivereference/main-menu.png; MAIN_MENU $EF3A
Practise any track of a division the player can reach; three laps, then the car is repaired and refuelledtracedPRACTICE_TRACK $98A2 offers a division and one of its two tracks; which divisions it lets the player pick was not traced. Every race is four crossings of the start line ($C354 = 4, CLEAR_RACE), the first just after the start (live), so three laps. After a practice race the damage is put back (RACE_END $3DAB, $C719 from $C37E), and every race starts with the track's boost ($C76A, CLEAR_RACE)
Track preview before a race: "steer to rotate view or fire to continue"livereference/track-preview.png; ROTATE_VIEW_PROMPT
Crane lifts the car over the start line, "DROP START", then lets it falllivereference/crane-lift.png, drop-start.png; CRANE $EC11
Crane recovers a car that leaves the track and puts it back at the next suitable place; "PRESS FIRE" to be releasedtraceda car wrecked on the road is put back at piece $C309 once its count $C368 runs out ($3D69, CAR_ON_ROAD $3CC6, START_PLACE $F488, which steps back to a piece a car may start on); the crane lowers it again (CRANE)
Joystick: left/right steer, up accelerates, down brakes (and reverses); fire with up or down is boost, limited by boost fuelconfirmedCONTROLS $1C64, BOOST $F60F; up and up with fire seen live, and the whole-game lockstep drives the stick every way
Keyboard: S/D steer, RETURN boost forward, SPACE brake hard, "=" brake; braking cuts the throttle and the car freewheelstracedREAD_CONTROLS $F79E reads the five keys at $F807 (=, SPACE, S, D, RETURN): RETURN is forward with fire, SPACE back with fire, = back alone. Back stops the drive (CONTROLS)
P pauses, O continues; F1 while paused redefines the keys; C= abandons a racediffersPAUSE $3EE0 (key P, then O) and REDEFINE_KEYS $97AF (F1 held in the pause) are as documented; C= ends a race only while the car is off the road or the race is lost (RACE_OFF_ROAD $3D95). F1 held at the panel before a league race skips that race (SKIP_RACE_KEY $3B5F)
Dashboard: lap count (L), boost left (B), lead or deficit to the opponent, speedometer, current and last lap time, lead flag, best-lap stopwatchtracedDASH_LABELS $129A, BOOST, CAR_GAP $F585 and SAME_LAP $F5E9, SPEED_TO_BAR, DRAW_TIME $121F, SHOW_BEST_LAP $0F9C, BEST_LAMP $1144; L, B, speed and time seen live
Damage: a crack along the top of the frame grows with hard landings; when it reaches the right the car is out and the opponent winstracedWHEELS_ON_ROAD $0A97 adds damage for a spring pressed past its line, OPP_BUMP $209C for a bump; CRACK $1B88 grows the crack to match, and when it reaches the far side, or the damage $80, the car is wrecked. That the opponent then wins was not traced
Structural damage: holes in the frame that stay for the season (the wiki says "permanent" across seasons) and make the crack grow fasterdiffersa bump of 20 or more takes one of the car's ten whole parts ($C719, DAMAGE_BAR $F6A6), and a crack that steps into a hole adds damage instead of length (CRACK). The holes stay from race to race in the league, but the car has all ten parts again after a season that ends with the player in the bottom division or winning the top one (CHANGES $375D)
One computer opponent on the track in a race; collisions between cars damagetracedOPPONENT_MOVE $1E85 drives it, OPP_BUMP $209C adds the pushes' size to each point's damage
Season: each driver races the other two on both tracks (six races, the player in four); two points for a win, one for the fastest lap; ties go to best-lap pointsdifferssix races (season_races $31A3), the pairs from $E920/$E926 (RACE_PAIR $E8E5), two points a win and one a fastest lap (SORT_DIVISION $E9A3); a tie on points goes to the driver with more wins, then to a coin
Promotion of the division leader and relegation of the last, each seasontracedCHANGES $375D; out of Division 1 only the player goes up
Super League after winning Division 1: more powerful engines and brakes, "twice as fast"tracedthe race's settings come from $BFF5 in place of $BFEA (CLEAR_RACE, race_start_bytes): the car's drive $0140 against $00F0, the opponent's engine $013A against $00EC, a unit of boost every 13 passes against 17, the damage line one higher; the opponents' limits from a second set (OPP_PICK $1F06). Whether that makes it twice as fast was not measured
Multiplayer: up to eight players take turns against the computer driver, over up to four seasons; bonus points for fastest lap and shortest race time per tracktracedCHOOSE_PLAYERS $3052 takes up to eight names; each round every player races once (ROUND_RESULTS $91B4) and BONUS_LINES $91CF gives one more win to the fastest race and one more fastest lap to the fastest lap. The number of seasons was not traced
Hall of Fame: records of fastest lap and fastest race per track, set in races only (not practice)tracedHALL_OF_FAME $98D2; the records are read and written by TRACK_RECORDS $9319, called only from NEXT_RACE and SEASON_RACE, so a practice race neither shows nor sets them
Load/Save/Replay: file names starting HALL (Hall of Fame), MP (multiplayer), DIR (directory); Replay restarts the last season; F1 with Replay resets the gameliveFILE_NAME_CHECK $9448, SAVE_OR_LOAD $2AAE, Replay at $EF67; a save and a load to a blank disk in VICE (orientation)
Sound: engine and effects only, no musictracedthe SID is written by the start-up, START_SOUNDS $3F27, the interrupt's engine note ($CF0F), the effects (START_EFFECT $8655, EFFECT_TICK, CUT_EFFECT) and CLEAR_RACE's volume of 0 ($3E52); a search for every store to $D400-$D418 finds no other writer (the store at $41FD reaches the RAM under the chips). How it works plays a race's sound and each effect through this code
Drawing distance held at $173E: 6 shows more of the track and runs slowerlive$173E is the count in LDA #$02 at $173D (DRAW_VIEW): poked to 6, 8.2 pieces were drawn a pass against 4.0, and a pass took 8.8 frames against 7.1
Filled 3D view drawn into two bitmaps in turnlive$D018 written at line 62 by the interrupt, $70 and $78 in turn (orientation); REQUEST_FLIP and FLIP_DONE $3F70

Beyond the documentation

Found in the code, not in the manual.

FeatureStatusWhere
Geoff Crammond's name, each byte flipped with $AA: "COPYRIGHT GEOFF CRAMMOND 1988"confirmed29 bytes at $AFE0, after the physics tables; no instruction reads them (the listing's cross-references), and the start-up's checksum covers them ($A380-$BFFF)
The end of an Atari ST (GEM) alert in the loaded file: "...ifferent from\the palette that is in use.\Re-color image with current\palette?][ Yes \No ]"confirmed$7F40-$7F9A; STARTUP $3FFB copies 64 bytes from $6B60 over the first 64 before anything is shown, and in a race that is sprite $FD, a frame of the boost's flame; in the menus $7F40 is part of their screen (FILL_SCREEN)
The Super League's settings are found by adding the Super League flag, which holds the player's driver number 11, to the first set's address: eleven bytes a set, so the copy starts at the secondconfirmedCLEAR_RACE $3DF9 copies from $BFEA plus $C71A; CHANGES $375D stores the player's number there; any test of the flag only asks whether it is 0
The race clock runs about three per cent slow: it adds 0.14 seconds a pass, and a pass takes more than seven framesliveTICK_CLOCK $109C; 69 passes in 500 frames showed 9.66 seconds (facts.md, Timing)
In the races the player does not drive, a driver 70 or more below another in the base ratings never wins: Hot Rod (120) never loses to High Flyer, Bully Boy, Jumping Jack or Road Hog, and Dare Devil (60) beats him once in 512confirmedRACE_RESULT $E92C, driver_base $E8B6; the odds worked out over all 4,096 pairs of draws and checked against the port's RACE_RESULT for every pair of drivers (test_index.js)
A changed byte stops the game for good with a yellow borderliveCHECKSUM $425D over the seven ranges at checksum_ranges $42A9; one bit flipped at $9000 in the loaded game gave a yellow border ($D020 = 7) and the processor in the loop at $42A6

Open questions

The symbol map for this game is symbols.json; the listing behind the Source tab is listing.json. Write-ups, facts and symbol maps are CC BY-SA 4.0. The game itself is not hosted here.