1986 · Epyx

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

Each of the eight events is a program of its own, written apart from the others and loaded over the last one. They share a music driver, copied nine times, and little else: each keeps its own clock, and bull riding's eight seconds last twenty-four.

01 · The game

Eight sports from eight countries

Up to eight players each pick a country and compete in eight events, from weightlifting in the Soviet Union to sumo in Japan, for medals and the world records saved on the disk.

The title screen: the Epyx logo above WORLD GAMES in chrome letters around a globe, and the graphic artists' names below
The title
A blue menu screen with seven choices, from COMPETE IN ALL THE EVENTS to INCLUDE TRAVELOGUE: (YES)
The menu
The world records screen: a holder and a record for each of the eight events, weightlifting to sumo wrestling
The world records, one for each event
The travelogue for weightlifting: a globe, an airliner and a framed text about lifting in the Soviet Union
The travelogue before weightlifting

The players take part in turns, each with three attempts in most events. Log rolling and sumo put two players on the screen at once, each on their own joystick, and the computer takes the other side when there is nobody to play it. After each event the medals go to the first three, with the winner's anthem, and after all eight the medals are added up for the champion: 5 points for gold, 3 for silver and 1 for bronze.

Before each event an optional travelogue shows the country on a turning globe and explains the sport. The disk has two sides. Side 1 holds the title, the menu, the travelogue, the world records and the first four events. Side 2 holds the menu and the travelogue again, with the last four.

02 · The music

Music: one driver, nine copies

The title and each of the eight events carry their own copy of the same music driver, each with its own tunes. Choose a part, then a tune.

The game's own driver, running on the page over the part's bytes in its listing and called as the part calls it: once at the start, to build the note table and silence the chip, then with the tune's number in the A register to start it, then once a frame from the part's raster interrupt, the routine the video chip calls as it reaches a given line of the screen. The page starts each tune at volume 15, as the part's other tunes leave it, since a few never set the volume themselves. test_music.js holds every button to the game's code over the part's whole listing, every write to the sound chip in order, for a minute of each tune or until it ends.

A tune gives each of the three voices a track, and a track is a list of notes and commands: a byte below $C0 is a note, $60 a rest, the byte after it the note's length, $C0 to $E0 commands that change the sound, and $FF the end (play_music, $18B7 in the title). The same driver plays the title's music, a skater's crash and the wind on the cliff. In the events most tunes are sound effects, a few frames long.

Each copy builds its note table when its part starts, and every copy builds the same one. Its top C, $861E, sounds at 2,093 Hz on an American NTSC machine, whose clock runs at 1,022,727 Hz. A European PAL machine runs at 985,248 Hz, so it plays every note about 65 cents flat, two thirds of a semitone. The player above plays it as a PAL machine does.

Some tunes in the list are never started, and they are here too. A few entries play no note at all: they stop or quiet another sound, or give no voice anything to play.

03 · The anthems

Music: an anthem for each country, and one for Epyx

The menu has a player of its own for the anthems the medal ceremonies play. Epyx is one of the eighteen countries, with a flag and an anthem of its own.

The menu's own player, running on the page over the menu's listing: init_sound ($1E34), then start_tune ($1E71) with the country's number in Y, then anthem_step ($1EA2) twice a frame, as the menu's interrupts call it. test_music.js holds every button to the menu's code, write for write, to each tune's end.

This player is far simpler than the driver in the events. A tune is a list of rows of four bytes: a note for each voice and a length (tune_list, $32C0). Each voice plays a note from a table of semitones (note_freq_lo, $1DC4), with the same attack, decay, sustain and release for every note, set once by init_sound. Every voice lets go of its note five steps before the row's end, so the notes are separated by a short gap.

A country's tune comes from country_tunes ($1E8A), which holds two times the tune's number for each country in the order of the flags. Tunes 18 and 19 play under the final standings and the world records. On the screen where a player picks a country, the S key plays the anthem of the flag under the frame without choosing it.

04 · One frame

The caber toss, rebuilt from memory

One frame of the caber toss, drawn by the page from the memory and the video chip's registers, its settings, as they were, and from every write to them during the frame.

Recorded in VICE as the thrower runs up with the caber, and drawn by the site's C64 library line by line, with each register as it was when the beam reached it. 0 of the 104,448 pixels differ from VICE's own picture of the same frame.

The picture is made of characters, the C64's 8 by 8 tiles, in multicolour mode, where each tile has four colours. Three of them are the same for every tile on the screen, and the interrupt at line 98, a routine the video chip sets off as it reaches that line, changes all three, from sky to field: light blue, light grey and grey above, green, dark grey and light grey below. The scenery is a map 128 columns wide ($8170), and the event draws the 40 columns in view into the screen not shown, then swaps the two (ct_draw_scenery, $197A; ct_swap_screens, $19DB).

The thrower and the caber are sprites, the chip's eight movable pictures. The caber is too tall for one, so it is a column of them, with the thrower beside it. The same eight sprites are used again below the picture, where the interrupt at line 251 moves them for the text row of names.

05 · Memory

Twelve programs, one at a time

The game is a small resident program, the shell, and eleven others it loads in turn: the title, the menu, the travelogue and the eight events. Choose one to see how it fills the C64's 64 KB.

$0000$4000$8000$C000$FFFF

From each program's listing: the ranges its bytes fill and what they are. The shell's bytes stay in memory under every other program.

The shell sits in the low memory, from $0800 to $0FFF: the eight players' records, a jump table, the loader and its prompt to turn the disk, and the world records, 20 bytes for each event. Every other program is one file, packed to save space on the disk. The shell's unpacker copies itself to $D000, where nothing else is kept, and unpacks the file in place from $1000 upwards ($0F00). Slalom alone needs a second file, which the shell copies to $E000: the skier's falls, the course's edges and the code that times the run, checks the gates and plays the music.

The programs share nothing but the shell. Each event has its own interrupts, its own variables at the same addresses in the first 256 bytes of memory and its own copy of the music driver. An event leaves its result as text and as a number in the player's record ($0810 and on), and the menu reads the numbers to hand out the medals.

06 · Weightlifting

The heavier the weight, the later the push

A lift is a script of poses, with windows where a push on the joystick counts. Only the last part of each window is good, and it shrinks as the weight goes up. Choose a lift and a weight, press Start, and push when the bar reaches the green. The last window of each lift is the exception: hold the weight up until it runs out, and pull down only once the judges' lamps are lit.

A weightlifter in a blue singlet stands behind a barbell with red plates on a platform in a grey hall, the judges’ lamps in the panel below
Weightlifting, Soviet Union

The arena, the lifter's poses and the plates are drawn by the page from the event's bitmap ($6000), its sprites (wl_shapes, $9000) and the plates' routine (wl_draw_plates, $1A14). The lift runs the game's scripts (wl_script_data, $2010) 50 times a second, as a PAL machine does, and the judges vote as wl_judges ($14ED) does, with the page's random numbers in place of the 256 the game reads from the sound chip's noise. test_widgets.js holds the page's lift, judges and plates to the game's routines, frame by frame. The bar above the buttons is the page's own: the game shows no timer. Below it, every window of both lifts at the weight, each bar as long as its window; the good part's size is the window's length times the weight's factor, over 256, at least one frame (wl_multiply, $1DCB). The last window of each lift is striped: the script gives it a good part, but a push there still has the stick down in the frame the judges first look at it.

The weight is chosen with left and right, 75 kg to 225 kg in steps of 5 (wl_choose_weight, $13B7). Once fire confirms it, the weight's factor comes from wl_timing ($1493), 31 bytes from $FF at 75 kg down to 1 at 225 kg. A push in the good part counts, and one before it sends the script to its failed lift.

The table ends at 225 kg, but the weight does not. After a round with a good lift, the next round starts 5 kg above it, so a good lift at 225 kg is followed by 230 kg, and the game reads the 32nd factor from the next routine's code (Discoveries). At 865 kg the plates stop the machine (Discoveries).

Held overhead, the lift goes to three judges. Each votes white while the hold is under 48 frames and red after, and two white lamps make a good lift (wl_vote, $1577). The first votes at once and each of the others up to 31 frames after the one before, so a lifter who holds still gets at least two white lamps. Down on the stick puts the weight down, and any judge who has not voted votes red.

The judges first look at the stick in the frame the lift ends ($1502). The last window of both lifts asks for down, and a good push there ends the lift at once, with the stick still down: the weight goes straight down before anyone votes, and all three lamps are red. Left to run out, that window ends the lift just the same, and the judges vote. Checked in VICE on 31 October 2026 in a snatch at 75 kg, both ways.

07 · Barrel jumping

Friction grows with speed

The skater gains speed by pushing in rhythm with the stride, and loses some every frame to friction, more the faster the skater goes. Choose a speed.

A skater on a frozen river with a row of barrels ahead and a village behind
Barrel jumping, Germany

Friction for each of the 16 levels of speed, in 256ths of a pixel a frame (bj_friction, $1B66), against what a push adds.

The speed's level is the speed in halves of a pixel a frame (bj_stride, $1A9D). A counter gains $30 a frame, and each time it passes 256, about every fifth frame, the stride moves on by one of its eight states, chosen by the joystick: right, left or neither. Four of the states push, and from the sixth frame of a push the speed gains 48 a frame, 40 from level 8. Friction takes its level's amount every frame, pushing or not.

Up to level 7 friction is 5 or 6, so the skater gathers speed easily. From level 8 it climbs fast, and at level 12 a push gains 40 while friction takes 45. Level 13's friction, 35, is lower than level 12's, out of line with the rest.

08 · Cliff diving

The body position sets the fall

In the air, up on the stick tucks the diver and down straightens them. The position, from 0 tucked to 7 straight, chooses the drag, the fastest fall and the drift away from the cliff. Choose a position.

A diver stands at the top of a tall brown cliff above the sea
Cliff diving, Mexico
The levels

From the event's tables: cd_drag ($1F35), cd_fall_limit ($1F45), cd_drift ($1F55) and cd_level_score ($2879), the last in binary-coded decimal, two decimal digits to a byte. Speeds are in pixels a frame.

A dive starts with the most it can score for its level, 106 from the top down to 56 from the lowest, and loses points (cd_level_score, $2879). Each new push up or down costs 5 points; held, the position steps on every 6 frames at no further cost (cd_body, $20C6). The diver must reach the water straight: any other pose is a bad entry and a fault (cd_entry, $16E1).

Under the water the diver must turn up with left at the right depth. Each frame of left too early, or of no left once the diver is deep, costs a point, and touching the bottom is a fault (cd_water, $1F65). The whole cliff, from the top level to the sea, is on the Maps tab.

09 · Slalom

A course of twenty sections from seven

The course is 176 rows of 65 columns, cut into seven sections of 25 rows. A run is twenty sections in a fixed order. Choose one of the twenty.

A skier on a white slope between blue and red flags, with trees at the sides
Slalom, France

Drawn by the page from the course (sl_course, $1000), its colours ($9000) and the character set ($4000), in the order at sl_sections ($C543). The flags are left out here: the game writes them into the map as each section comes. The whole run, flags and all, is on the Maps tab.

The course's 65 columns wrap round, and the view shows 40 of them (sl_draw_view, $8795). The run starts at section 0 and ends at section 150, the finish, with the five in between used again in a set order: 25, 75, 100, 125, 75, 50, 25 and so on. There are 39 gates, placed by a row counter of one byte, which goes round at 256, so the first 256 rows of the run hold 20 gates and the rest 19.

Left and right turn the skier a step at a time, and how long the stick must be held for a step depends on the stance and the speed (sl_turn_frames, $8714). With the stick up, at the slowest speed, a step takes 36 half frames; with fire held at the fastest, 3. A gate is missed when the skier passes both its flags on the same side (sl_gate_check, $F2E5): 5 seconds are added. A flag hit head-on is a fall only some of the time (Discoveries).

10 · Log rolling

Points for a log that turns faster than you lean

Every 16 frames each lumberjack's points move by how much faster the log turns than they lean. In the first 30 seconds they go up; after that they come down. Set the log's speed and the lean.

Two lumberjacks stand on a log in a river, with a crowd and pine trees behind
Log rolling, Canada
The lean, as the game shows it
The two lumberjacks on the log; under the river the left meter shows only its middle mark
Lean 1: no cell filled.
The same scene, the left meter with four cells filled to the right of its mark
Lean 13: four cells.
The same scene, the left meter with seven cells filled to the right
Lean 23: seven cells, one step from a fall.
The left lumberjack with arms thrown up, falling, the meter full to the right
Lean 24: the fall begins.

The lean is how far the lumberjack's feet have got ahead of the log or behind it. Each lumberjack has a meter under the river, the player's on the left: from the middle out it fills a cell for every 3 of lean, towards the side of the lean (lr_meters, $1CB2). Seen in VICE on 31 October 2026, in a bout played with the stick, the lean read from $0F70.

The difference d chooses an entry of lr_points_gain ($3490) before 0:30 on the clock and of lr_points_loss ($34B0) after (lr_points, $33D0). test_widgets.js holds the page's sum to the game's routine for every speed and lean, either side of 0:30.

Each change of the stick between left, right and both is a step, which speeds up the lumberjack's feet the way they run (lr_step, $2183). The stick held still pushes the log, and fire turns the lumberjack round. The lean is the feet's speed less the log's, and a lean of 24 either way is a fall (lr_lean, $2297).

The gain table climbs from 0 to 9 as the difference grows. The loss table runs the other way, 9 down to 0, so after 30 seconds a lumberjack who keeps the log turning fast loses least. The clock itself runs slow: it counts a second every 65 or 66 frames, 1.3 seconds on a PAL machine (lr_clock, $3323). At a fall the loser's points are quartered and kept below the winner's (lr_fall_points, $34D0).

11 · Bull riding

Five bulls, five sets of odds

The five bulls look alike, but each chooses its next move with a random number against five thresholds of its own. The table shows each bull's chances after each kind of move. Choose a bull.

A rider on a bucking bull coming out of the chute into a rodeo arena with full stands; the text row reads BULL: EARTHQUAKE and 0:30
Bull riding, United States
The five bulls in the chute
The rider on a brown bull in the chute; BULL: FERDINAND
Ferdinand
The same rider and bull; BULL: ELMER
Elmer
The same rider and bull; BULL: BOB
Bob
The same rider and bull; BULL: TORNADO
Tornado
The same rider and bull; BULL: EARTHQUAKE
Earthquake

All five bulls look the same: only the name under the picture changes. The bull is drawn from one set of poses and shapes (br_draw_bull, $1E16), and the bull's number, $24, is read only for its name ($1951) and its odds ($2235, $2241). Seen in VICE on 31 October 2026: each bull chosen in practice and caught at the same frame in the chute, the pictures the same pixel for pixel above the text row.

The thresholds are the bull's five bytes in br_bull_odds ($2332), against a random number from 0 to 255 (br_choose_move, $222C). test_widgets.js holds the page's rule to the game's routine for every bull, every move and every pair of random numbers.

A move is a buck, a run or a spin. To stay on, the rider must hold the stick the right way at one frame of each move: towards the head during a run, towards the tail during a buck, and down during a spin (br_stick_left, $17A1; br_stick_right, $17C8). The wrong way, or nothing, throws the rider off, and the ride scores nothing.

A move's points depend on the move before it, so the score depends on the bull: Ferdinand mostly runs, and Earthquake bucks. The ride ends at 8 on the clock, which takes 24 seconds (Discoveries). The bull's moves come from the frame counter and a generator called only by the bull and the pennants, so nothing the rider does changes them (br_random, $2351).

12 · Caber toss

Feet by the pixel, inches by the bus

The toss is measured on the screen, from the thrower's legs to the foot of the caber where it lands: a foot for every 8 pixels between the two sprites, plus 10 feet, and the pixels left over for the inches. Move the gap.

A man in a kilt holds a long caber upright on a green field with tents and a stand behind
Caber toss, Scotland
The thrower stands at the left of the field and the caber leans on the ground in front of him, its foot to the right. A white box marks sprite 3 over the thrower's legs and a yellow box sprite 7 over the caber's foot; an arrow joins the left edges of the two boxes. The text row reads 12 feet 5 inches.
The measure: from the left edge of sprite 3, the thrower's legs (white), to the left edge of sprite 7, the foot of the caber (yellow). Here the gap is 18 pixels: 2 feet over the 10, and 2 pixels over, 5 inches. A throw in VICE on 31 October 2026, its landing set to a good one by hand (the caber's pose, $3C, made $10 as it touched the ground), then measured by the game; the sprites' places read from the video chip as ct_show_result ran.

The gap between sprites 7 and 3, and the inches from ct_inches ($2297), indexed by twice the pixels left over plus one bit read from colour RAM (ct_show_result, $2170).

The thrower runs with left and right in time with the stride, and fire held plants the caber. While fire is held a count grows by the run's speed each frame, and each time it passes a threshold the caber leans a step further: $38, $68, $90, $B4 and $D4 ($1CC2, read at $1AB5). A lean of 5 fells it. Letting go throws it, and the caber must turn over and land on its far end (ct_landing, $22AC).

The inches take one bit from a read of colour RAM, the memory that holds each character's colour, which holds only four bits a byte. The other four read as whatever was last on the data bus, the lines every chip shares with the processor, so the bit changes from one throw to the next, and below 4 pixels over it decides between two inches. The release has a quirk of its own (Discoveries).

13 · Sumo

A score that drops every five seconds

A sumo score is the force of the bout, the speeds of the two wrestlers added up each frame they touch, divided by the bout's length. The length is counted in steps of 256 frames, so the score drops each time a bout passes another 5.12 seconds. Set the push.

Two sumo wrestlers face each other in a ring, a referee between them
Sumo, Japan

The winner's score for a bout of steady pushing, for each length from 1 to 60 seconds: the total doubled, its upper 16 bits divided by the length in units of 256 frames plus one, and the loser's halved (su_final_scores, $26DF). test_widgets.js holds the page's sum to the game's routine on thousands of totals and lengths.

The wrestlers push by moving the stick, and each push costs strength, so pushing tires a wrestler (su_push, $2495). Each frame they touch, the force between them is added to both totals and again to the one winning the push; during a throw it counts double (su_score_frame, $2615). A wrestler who goes down, or puts a foot out of the ring, loses (su_ring, $1F1F).

Dividing by whole steps of 256 frames makes a sawtooth. A bout of 5.1 seconds divides by 1 and one of 5.2 seconds by 2, so the same steady push scores about half as much in the longer bout.

14 · Random numbers

Random numbers from five places

The events were written apart, and each found its random numbers in its own way.

WhereHow
Weightlifting256 readings of the sound chip's third voice, left running as noise by the shell, kept at $0400 (wl_random, $197D)
The menua generator in the last three bytes of the eighth player's record (random, $1AD9), from which sumo takes its seed and log rolling its frame counter
Bull riding, cliff diving, log rolling, sumothe frame counter added to a state that is shifted with feedback, each in its own copy ($2351, $2B20, $2ED8, $2B96)
The music driversvoice 3's oscillator, for a command that plays a random note
Caber tossone bit of the data bus, read through colour RAM's missing upper half ($2170)

The shell starts the third voice as noise at the frequency $FFFF (sid_start, $0D18), so the top eight bits of its output change too fast to follow. Weightlifting reads them 256 times at its start and keeps the readings, and later takes one at a time, such as the one that chooses between the two endings of a lift held too long ($1546).