1985 · Epyx

Winter Games

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/winter-games with me to Gold.

What the code does that the manual never says: a judge's sum that wraps round, a crash that costs a tenth of a second, a key that only works with the joystick held down, and a sound effect that writes into the sky.

01 · Figure Skating

Bug: in Figure Skating, falling 19 to 28 times scores a perfect 6.0

A program of nothing but falls, about twenty of them, gets 6.0 from all eight judges. The C64-Wiki gives it as a cheat.

Point at the chart.
The judges' panel showing 6.0 from all eight judges and a total of 6.0
The program in the emulator, played with the joystick alone: stick down with fire 22 times, and nothing else. Every judge gives 6.0.

The base mark for each number of falls, from the game's own base_mark run on the listing's bytes: with no element skated () and with all seven skated cleanly (). test_marks.js checks it against the routine, and against the two programs played in the emulator: 22 falls scored 6.0 and 40 scored 0.0.

Figure Skating adds up the elements skated, takes 0.2 off for each awkward move and 0.7 for each fall, and keeps the result between 0 and 6.0. The mark is one byte, a number from 0 to 255, counted in tenths. After each subtraction the code tests the result with BPL, the "branch if plus" instruction of the 6502, the C64's processor. BPL looks only at the byte's top bit. A result from 128 to 255 counts as below zero and becomes 0. That works while the penalty is small. Once it is larger than the mark by more than 128, the byte wraps round past zero to a number under 128, and the test lets it through.

With no elements the mark starts at 0, and 19 falls take off 133 tenths. The byte wraps round to 123, which the cap then cuts to 60: a 6.0. Every count from 19 to 28 lands between 61 and 123 and is cut to 6.0 the same way. From 29 falls the wrapped number drops under the cap again, 5.3 at 29, and from 37 falls the result is below zero once more and becomes 0. The judges add nothing to a 6.0, as they add nothing to a 0, so all eight show it exactly.

A fall is the easiest move there is: stick down with fire, from skating forward. In the emulator a skater fell about every 1.7 seconds, so the minute holds 19 with time to spare. Free Skating has the same signed test, but there each fall also lowers a ceiling of 6.0 by 0.2, which holds a wrapped penalty down: 26 falls give 0.8.

02 · The menu

Secret: the menu knows nine Summer Games events

After Bobsled, the menu's list of event names runs on into Epyx's two earlier games.

The table of event names (event_names) has sixteen entries. After the seven winter events come Cycling, Pole Vault, Platform Diving, 4 x 400 m Relay, 100 m Dash, Gymnastics, Freestyle Relay, 100 m Freestyle and Skeet Shooting, events of Summer Games and Summer Games II. A switch at $087F would make the menu list all sixteen, from A) to P), and show "YES)" at the end of option 6's line (opt_more_events). Nothing in the game sets the switch, and the disks have no files for those events.

03 · Free Skating

Bug: every Free Skating mark below 6.0 is a tenth short

Free Skating subtracts one tenth more than its rules say, from every program, falls or no falls.

ProgramBy the rulesThe game

"The game" is the base mark from free_mark, run on the listing's bytes for each program. "By the rules" adds up the values the manual gives each element, takes 0.5 off for a fall and keeps the result under the ceiling, as the code means to. A program worth more than its ceiling is cut down to it, and loses nothing.

The 6502, the C64's processor, subtracts with SBC, which uses the carry flag, a single bit the processor keeps for carrying and borrowing. When the flag is clear, SBC takes one more off, so a subtraction normally starts with SEC, which sets the flag. Free Skating works out its fall penalty, five times the falls, with an ADC, an addition, which leaves the flag clear. The SBC that follows has no SEC before it. So the mark loses a tenth even when there are no falls at all. Figure Skating's version of the same code has its SEC.

04 · Bobsled

Bug: a bobsled crash near the end costs only a tenth of a second

A crash is meant to score 99.99. But the wreck keeps sliding down the course, and a crash late enough slides over the line and scores the clock's time.

The wrecked sled past the finish, the clock showing 22.20

Played with the joystick alone: steered down the middle to stretch 164, then held left into the wall. The sled crashed at stretch 168 and the wreck slid over the line: 22.20. The same run steered clean all the way finished in 22.10.

Ten frames in a row against a wall is a crash (check_walls). After it the stick does nothing, but the course keeps moving while the wreck has speed, and the speed drops only one step in every three frames (crash_step). From full speed that is about two seconds, and a dozen stretches of sliding. Only when the speed reaches zero does the run end with 99.99. If the wreck reaches the finish first, the finish records the time on the clock, as for any run.

The last seven stretches are the finish straight, where the sled steers itself to the middle and cannot crash. The stretches just before it are a straight, where holding the stick against a wall is enough. In the emulator a crash at stretch 168 slid over the line, and one at 164 came to a halt before it and scored 99.99.

05 · The S key

Secret: S stops the music, but only with joystick 2 held down

Five events check the S key once a frame to switch the sound off. Pressed on its own, it does nothing.

EventThe switchAs the file holds it
Hot Dog Aerials$6332$77
Biathlon$7884$FE
Figure and Free Skating$4E6A$01
Ski Jump$6C36$00
Bobsled$9E30, at $C130 once copied$01

A press of S, seen while the switch is not 0, sets it to 0 and stops every sound; a press seen while it is 0 sets it to 1 and does nothing else. In Ski Jump, whose file holds 0, the first press does nothing and the second stops the sound. Tested in the emulator in Hot Dog.

The C64's keyboard is a grid of eight columns and eight rows wired to CIA 1, the chip that also reads the joysticks. The chip has two ports, A and B, each eight wires the program can read or set. A program finds a key by driving one column's wire low on port A and reading which rows are low on port B. The sound engine's sound_step does this for S every frame: it writes $FD to port A and looks for S's row on port B ($63AD). But every event's start-up has set port A to input, by writing 0 to its direction register at $DC02. A port set to input drives nothing, so the engine's write never selects the column, and S never shows.

Joystick 2 is wired to port A too. Pushing it down pulls the very line the engine meant to drive, the second one, low. With the stick held down, the column is selected after all, and S works. The engine stops every sound playing, the event's music with it; sounds the event starts later play as usual. Speed Skating's older engine has no S key.

06 · The clocks

Bug: every clock in the game runs a fifth slow on a PAL machine

Times on a European C64 are shorter than the time it takes to skate them.

Every event counts its clock in frames: six frames to a tenth of a second, sixty to a second (Biathlon's clock_tick, Skating's clock_tick, Bobsled's clock_tick, Speed Skating's irq_top). That is right for an American machine, whose screen is drawn sixty times a second. A European machine, a PAL one, draws fifty, so each second on the clock takes 1.2 real seconds. A 22.10 bobsled run takes 26.5 seconds, and Figure Skating's minute lasted about 72 seconds in the emulator. The skating music is timed in frames too, so it still fits the program: Figure Skating's tune lasts 3,633 frames and Free Skating's 7,203.

The tunes and effects are tuned for the same machine. Every event's table of notes puts the C two octaves above middle C at $430F, which is 1,046.5 Hz on an American C64, where the sound chip runs at 1.02 MHz. A European C64 runs it at 0.985 MHz, and every note sounds two-thirds of a semitone flat.

07 · Bobsled

Bug: the bobsled's rumble writes into the sky

The runners' sound picks a random note every frame, and also stores a random number in the picture of the sky, where it shows as a short black dash.

Far piece 24, as in the frame recorded in the left-hand bend from stretch 21, drawn by the game's own draw_far from the listing's bytes with $878A set to the number chosen, and on the right the cells around it, larger, the byte's four dots outlined. The colours are the ones every cell of the far view has in the frame recorded in the emulator: light blue sky and white, with black where a dot's two bits are clear.

The rumble is a sound script that calls a few bytes of machine code each frame (rumble_step_src, run at $C80F). The code picks a random note, then a random length, and stores the length three bytes into the sound's slot, through a pointer: two bytes in zero page, the first 256 bytes of memory, that hold an address. It uses the pointer at $F0. The engine keeps its slot pointer at $80. So the length never reaches the slot, whose count stays at 1, and the note changes every frame, which is what makes it rumble.

The byte goes wherever $F0-$F1 points. Those two bytes belong to the KERNAL, the machine's own operating system, which keeps a table of the screen's lines there. The event never sets them, and they hold $87, $87, so the store lands at $878A. That is one byte of the far view's panorama of sky and hills (far_panorama): the top line of one cell, four dots across, in the 72nd of its 95 columns. The far view shows nineteen columns at a time and draws them again only when the course turns, so the cell is on screen in far pieces 21 to 25, with whatever the byte held when the piece was drawn. The panorama has $69 there, white and light blue. In the emulator $878A took values from 1 to 8 during a run, and each of them turns two or three of the four dots black: a dash in the sky that stays until the view turns again. The frame on the How it works tab has one, drawn while the byte held 2.

08 · Bobsled

Bug: the crash has a whistle no one can hear

A crash starts a sound on the sound chip's third voice, and the same sound switches that voice off.

The crash plays sound 28 (snd_crash_whistle_src): a triangle wave on the third voice, whistling upward for 106 frames. Its script also sets the filter mode, and the mode it writes to $D418 has bit 7 set. On the SID, that bit takes the third voice out of the output unless the filter takes it in, and the script routes the voice past the filter. So the whistle plays to nobody. The bit stays set until every sound is stopped at the end of the run, and in the emulator the engine's copy of $D418 held $8F from the crash on.