1986 · MicroProse

Gunship

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

An Apache helicopter simulator in which BASIC, the programming language built into the C64, runs everything but the flight. Six of the eight programs on the disk are written in BASIC. For the flight they hand over to a 3D engine written in machine code, the processor's own instructions, which builds its whole world from wireframe shapes of a few dozen bytes each.

01 · The game

An attack helicopter in five theatres

You fly an AH-64 Apache for the US Army. You start in training in the USA, then move on to Southeast Asia, Central America, the Middle East and Western Europe.

The briefing for a mission in Western Europe
The briefing: a primary and a secondary target, and the enemy's strength.
The cockpit on the ground in Western Europe
The cockpit. Above is the 3D view, below are the instruments and the CRT in the middle.

Each mission has two targets, a primary and a secondary. Before take-off you arm the helicopter with Sidewinder missiles, FFAR rockets, Hellfire missiles, cannon rounds, chaff and flares. You start the two engines, engage the rotor and raise the collective, the lever that sets how hard the rotor lifts. You find the targets on the map, destroy what you can and fly home to land at a friendly base. After landing, a debriefing scores the mission and may award a medal or a promotion. Your pilot is saved to disk between missions in a roster of up to eight.

Damage comes in fourteen kinds, each with a lamp along the top of the canopy. A hit can stop an engine, blind the gunsight or leak fuel. A wrecked helicopter or a dead pilot ends the career.

02 · Fly over the theatres

Fly over the theatres in the game's own 3D view

The view below is drawn by the game's own 3D routine, from wherever you put the helicopter. The game draws only nine squares of its map, the helicopter's own and eight ahead, so a hill or a base appears from nothing when its square joins the nine.

Click the view, then ← → turn, ↑ ↓ nose down and up, W S forward and back, R F climb and descend, Q E roll.

Go to

Fly

-

The flight's view routine, view_frame at $8F01, run on the site's copy of the C64's processor. Its memory is the flight's, with the theatre's terrain file, map and units as they were in memory on a mission there. The eye is set the way the game's main loop sets it from the helicopter: its place, its height plus 24, and its heading, pitch and roll turned round. The site's model of the video chip shows the bitmap the routine drew inside a frame of the cockpit recorded in the emulator, the program that plays the part of a C64. The Hind and the missiles are left out. The map beside it is drawn by the game's draw_map, as on the Maps page, with every unit shown: the yellow squares are the nine the view drew, and the red mark is the helicopter with a line for its heading. The page moves the helicopter without the game's flight model, so it can stop in mid-air and fly backwards.

The map has 16 by 16 squares, and each view draws nine of them. The routine view_squares ($832B) takes the eighth of the compass the view faces and reads a list of nine steps from the helicopter's square ($82D9), one list for each eighth. Facing north, the nine are the helicopter's square, the squares either side of it and the six beyond. Facing north-east, the helicopter's square is the south-west corner of a block of three by three. Nothing outside the nine is drawn. A hill one square behind the helicopter is gone, and a base three squares ahead appears only when the helicopter crosses into the next square. Turn on the spot and the yellow block on the map swings round with the view.

The sky is never drawn as a shape. The routine draws each square's fixed object first, a hill where the terrain has one, and then fill_sky ($A82C) goes down each of the window's 32 columns from the top, filling it with sky until it meets a drawn pixel. The outline of a hill is enough to make it stand solid against the sky. The switchable objects, the units among them, are drawn after the fill, over the sky.

03 · The world in wireframe

The 3D world is made of wireframe shapes

The tanks, missile launchers, bunkers, bases and hills in the 3D view are all wireframes. Each is one record of a few dozen bytes in the theatre's terrain file.

-

Drawn from the bytes of Western Europe's terrain file, as they sit in memory during a flight. A number written with a $ is in hexadecimal, base 16, and most such numbers on this page are addresses in the C64's 64 KB of memory. Each point is a combination of one x value, one y value and one height, picked by the tables at $1C37, $1CA8 and $1D19, or it is a fraction of another point. Every edge the shape lists is drawn here. The game leaves out an edge when both of the faces it joins turn away from the eye. Drag the picture to turn it.

A shape's record starts with how many points it has and their numbers ($1E9F on). Then come its faces, five bytes each, a colour number and its edges. An edge names two faces and two points, or a single point drawn as a dot. A flat shape has no faces, so all its edges are always drawn. The hills are the only shapes whose faces matter for more than drawing. The routine project ($894A) sets a flag when a hill's face turns towards the eye from inside the hill, which means the helicopter has flown into it. The main loop then ends the flight as a crash ($31F8).

Most things in the world have two shapes, a near view and a far one. A hill seen from far away is only its ridge lines, and a base is only its outline. Each of the 33 kinds of terrain lists a fixed object (a hill, or nothing) and up to eight switchable ones. A table at $E200 holds a byte for each square of the map, and each of its bits switches one of those objects on. A shape stored from $24E3 on can be locked as a target, and the byte after the shape names it. That byte plus 11 is the number of the message the CRT prints, so the shape at $27BE prints "T-72".

04 · The title

The title: the helicopter rises into view

Before the menu, the title lifts an Apache up from below the screen to the sound of its rotor, writes GUNSHIP under it a letter at a time and plays the Ride of the Valkyries. Every picture is put together from two copies of the screen.

The title's main loop and its raster interrupt, written again in JavaScript routine by routine and run on the title's own bytes. The site's model of the video chip draws each frame as the beam would, and its model of the SID plays the sound. It starts where the title turns the screen on. Before that the screen is blank while the title clears both copies of it.

The title keeps two copies of the screen, two multicolour bitmaps: one at $4000 in the video chip's bank 1 and one at $C000 in bank 3, with their screen colours at $6000 and $E000. The main loop draws the next picture into the copy the chip is not showing, sets frame_ready ($8F62) and waits. The raster interrupt (irq, $8940) takes the new picture at the top of the next frame. A new picture comes every other frame, 25 a second. The screen is split as well. Down to the line under the rotor's blades, the chip shows the copy with the newest rotor in it. From that line down (irq_band, $8A6B), it shows the copy with the newest helicopter. So the rotor can turn at every picture while the helicopter's body is only copied when it has to move.

The helicopter climbs with the video chip's fine scroll, the three low bits of $D011, which move the whole picture down by 0 to 7 lines. At each picture the title takes one line off (fine_scroll, $8FBC), so the helicopter rises a line without a byte of its bitmap moving. Meanwhile the title builds the helicopter a character row higher in the hidden copy, a few rows at each step: four of its character rows at a time, then its screen colours. When the scroll runs out and starts again at 7, the chip is switched to that copy, and the colour RAM, which both copies share, moves up a row (title_rise_rows, $82A7). Near the top the helicopter slows down: pictures without a step come in between, more and more of them, until it settles at character row 4.

The blades are drawn again at every picture (rotor_frame, $8532): one of four frames, two character rows tall, copied out of the GUNSHIP picture that comes with the title by eight copies of 80 bytes. The routine writes their addresses into its own instructions first. It clears the row under the blades, so they leave no trail as they climb. Three sprites make the mast and the rotor head, and the interrupt moves them with the blades at every frame. The interrupt also plays the rotor's sound, which fades in over about two and a half seconds before the helicopter appears and rises in pitch every fourth picture as it climbs.

Once the helicopter is up, the gun under its nose turns, one view every six pictures. Then GUNSHIP is written under it a letter at a time (draw_letter, $8743), each letter with a note and a glint, a sprite that sparkles on it. Each letter is drawn twice, into each copy of the screen, ten pictures apart. After a short pause the tune plays, below. A key pressed during the title ends it, and BASIC carries on from where it called the title.

05 · Music: the title

Music: the Ride of the Valkyries

The title plays the opening of Wagner's Ride of the Valkyries once the helicopter has risen and GUNSHIP is written under it. It is the only music in the game.

The game's own player, tune_play ($8E89), run on the title's bytes by the site's copy of the 6502, the C64's processor. The title calls it once a frame from a raster interrupt, code that the video chip starts when it reaches a chosen line of the screen. A frame is one picture on the television, 50 a second in Europe. The notes go through the site's model of the SID, the C64's sound chip. Its three streams are set back to where they start when the file is loaded: $9117, $91C7 and $95D1. A test beside the page runs the same calls on the title's whole memory and compares every write.

Each voice's stream is a note number and a length, two bytes a note. $80 is a rest and $81 the end. The length is multiplied by the tempo: 2 frames a unit on a PAL machine, the European C64 with 50 frames a second, and 3 on an NTSC machine, the American one with 60 (tempo_by_tv, $8530). A unit therefore lasts a twenty-fifth of a second on PAL and a twentieth on NTSC, so the tune plays a little slower in America. Each note number picks the note's frequency for the SID from two tables, one for the low byte and one for the high ($9006, $9082). The tables have 16 entries to an octave: 12 notes, then 4 zeros. The table's values are those of an NTSC machine, so on a PAL machine every note sounds a little flat.

The first voice plays a pulse wave and the other two a sawtooth (tune_waves, $9003). The player ends the tune when any voice reads $81. A key pressed during the tune skips it.

06 · Sound: the effects

Sound: ten effects from one small table

Every sound in a flight but the rotor and the engines is one of ten effects. Each is a list of values to write into the SID's registers, the sound chip's settings, and the frame on which to write each one.

The game's own effect player, sound_step ($9A39), run once a frame on the flight's bytes by the site's copy of the 6502, as the flight's raster interrupt calls it, after sound_start ($9AAC) as the game starts each effect. It plays through the site's model of the SID. The test beside the page compares every write with the same calls on the flight's whole memory.

All ten effects sit in one page of 256 bytes, so each one's address is a single byte (sound_effects, $EC00). An effect's entries are three bytes: the frame it is due on, a SID register and the value to write. A frame with bit 7 set starts a slide instead: from then on, each frame adds a step to a register. The slide's register is the low three bits of its start value, so a slide can only reach voice 1 and the first byte of voice 2. Effect 0 is never asked for by any of the flight's calls.

Effect 9, an engine's starter, is effect 0 with its slides going the other way. Its first entry names register $50, where effect 0's names register 1. The SID repeats its registers every 32 bytes, so the write lands on register 16, the low byte of voice 3's pulse width.

Under the effects, the main loop keeps two voices going all through the flight ($3BBD). Voice 2's pitch is the rotor's speed, and its pulse width follows the height. Voice 3 is the engines' whine.

07 · The cockpit

Two pictures, one screen

The cockpit is two pictures, each a bitmap that sets every pixel, in two different 16 KB banks of memory. The video chip can see only one bank at a time, and a raster interrupt switches it from one bank to the other a third of the way down the screen.

One whole frame of the game in flight, recorded in the emulator, the program that plays the part of a C64 (every write to the video chip with the line it came on, and the memory the chip reads), and drawn here by the site's model of the video chip. 104,447 of its 104,448 pixels match the emulator's own picture of the same frame. The one that differs is in the border.

The window at the top is rows 0-12 of a bitmap at $4000 or $6000, in the video chip's bank 1, with its colours at $7C00. The panel below is rows 13-24 of a bitmap at $C000 or $E000, in bank 3, with its colours at $EC00. The interrupt at line $9A, line 154 (irq_split, $94B8), moves the chip to bank 3 for the panel. The one at line $FB, line 251 (irq_bottom, $9206), comes below the picture. It moves the chip back and shows whichever window was finished last.

Both halves are double-buffered: each has two copies, one on screen and one being drawn. The engine draws the next view into the window bitmap the chip is not showing (draw_view, $8451), then swaps the two. The swap is a write to the chip's register $D018, which says where in the bank the picture is, and $910C holds its four settings. The rows of each 8 KB bitmap that never reach the screen hold other things: sprites, the records of the 128 units (the tanks, launchers and bases on the ground, and the moving things in the air) at $5100, the messages, the map's font and much of the engine's code.

On a Commodore 128, whose processor can run at twice the speed, the engine switches the processor to 2 MHz below the picture and back to 1 MHz at its top (engine_on, $9110; irq_c128, $948F). The fast part is the time the video chip is not reading the screen.

08 · The map

The theatre on one screen

Pressing Z shows the big map: the theatre's terrain in characters, the units you have seen, and the waypoint.

One frame of the big map in Western Europe, recorded in the emulator and drawn by the site's model of the video chip. 25 of its 104,448 pixels differ from the emulator's picture, all on the sprites, the small movable pictures the chip draws over the screen. The Maps / levels tab draws all five theatres.

A theatre is 16 by 16 squares, one byte each, and each byte is the number of one of 33 terrains (theatre_map, $1A86). The big map shows the middle 12 by 12 (draw_map, $9685). The map is drawn in characters, as text is, from a font at $C800 whose characters are small pictures of terrain. Each square is three characters wide and two high. A terrain's six characters follow each other in the font, from character 58 on. Their colours come from a table by character code ($E33C).

A unit appears on the map only once the helicopter has seen it. Seeing it sets bit 4 of the unit's type byte ($5300). Its character is drawn in its square: friendly units in white, targets in one colour and other enemies in another.

09 · Flying it

Controls

The joystick is the cyclic, the stick that tilts the rotor to fly the helicopter forward, back or sideways. The keyboard does everything else.

KeyWhat it does
Joystick, port 2The cyclic: forward, back and the two sides (joystick, $E40C)
FireThe chosen weapon, with the CRT on the target view ($3D60)
F1, F3, F5, F7The collective up 4, up 1, down 1 or down 4, from 0 to 42 ($3383)
1, 2Start or stop engine 1 or engine 2 ($3406)
3Engage or free the rotor's clutch
4, 5, 6, 7Choose the Sidewinders, the FFARs, the Hellfires or the cannon ($348D)
9, minusChaff, a flare ($34FC)
RETURNStop turning
SPACEStep the CRT on to its next display (crt_next, $9CCD)
Right SHIFTAsk for the next target
HOME, £, DELLook ahead, left, right
ZThe big map; ← on it switches fast motion on and off
C=, left SHIFTThe stores and the damage pictures, loaded from the disk
RUN/STOPPause
RUN/STOP and RESTOREAbort the flight

From the key handling in the main loop, $332E to $3500. The interrupt reads the keyboard once a frame (keyboard, $A8D8) and puts a newly pressed key in the keyboard buffer, where the main loop finds it.

The joystick routine keeps what it reads only if two timers are still running the way the code on side 1 of the disk left them. The timers are in CIA 2, one of the C64's two input and output chips. The routine compares the high bytes of timers A and B, and unless they are $7D to $80 apart, it throws away what it read ($E423). The Discoveries tab has the test.

10 · Weapons and hits

Each ground unit falls to one kind of missile

A missile of the wrong kind that hits a ground unit does nothing at all. The flight engine names one missile kind for each of the sixteen kinds of unit, and only the Hind falls to any missile.

Unit kindDestroyed byIts own weaponRadar

Read from the flight's listing: the table at $B5A4 (1 the FFAR, 2 the Hellfire, 0 the Sidewinder) and each kind's attributes at $53A8 (bits 0-2 its weapon: 0 to 2 a gun whose reach is that number plus 1, times $800, half a map square; 3 and up a missile of that kind; bit 6 radar). A unit's kind is a number from 0 to 15 in bits 0-3 of its type byte. The names the CRT shows for units come from their shapes, not their kinds, so this table can only number the kinds.

The cannon works another way. Each shot takes a random fraction of the cannon's range and hits when that is beyond the target's distance. The range shrinks with a worse aim, a harder style of mission and a damaged gun ($3D60). The colour of the target box tells the pilot how good the shot is: the aim and the distance give a class from 0 to 3, which picks one of four colours ($3CB6, $53A4).

When an enemy shoots at the helicopter, hit_helicopter ($5AE5) decides whether it hits. First a random number from 0 to 15 is checked against the attacker's chance ($5ADD: 4 in 16, 8 in 16 or always, by the attacker). Then the pass counter, which goes up by one each time round the main loop, is checked: its lowest two bits, a number from 0 to 3, must be below zpa_4C. That variable is 0 in training, and on a mission it is the style of missions plus 1. So in training nothing ever hits. Of the shots that pass the first test, a quarter hit on regular missions, a half on volunteer missions and three quarters on volunteer hazardous duty. A hit sets one of the fourteen damage bits at random. More than 7 hits, less zpa_4C, stop both engines. The Discoveries tab lets you try the test.

11 · Eight programs

BASIC around a machine-code engine

The title, the front end, the debriefing and the base are BASIC programs. They call routines in a machine-code library through a table of jumps at $7500, one jump for each routine. Only the flight itself is machine code.

ProgramWhat it doesSource
GUNSHIPThe title, the tune and the credits, then the library and the roster checktitle, library
BEGINThe identity check, the roster, the duty and the briefing, the checklist and the armingfront
6Side 2's loader: the flight's files, moved where the engine wants themloader, helpers
G2 and MThe flight: the BASIC that sets it up and the engineflight
BThe mission result summarydebrief
EThe base: scores, medals, promotions, repairs, and the roster savedbase

One program hands over to the next by printing a LOAD command on the screen, putting a RETURN in the keyboard buffer and ending with NEW, so BASIC loads it as if it had been typed.

The front end passes the mission to the flight in the cassette buffer at $033C, memory the C64 keeps for tape loading and Gunship borrows. G2 copies the mission into the engine's variables. They wait at $3F00 until the engine swaps them into zero page, the first 256 bytes of memory, which the processor reaches fastest (swap_zp, $919B). The last file G2 loads, AWH, is a few bytes that land on the processor's stack, where it keeps the address to return to after a routine. So when the load is over, it returns into the engine at $3100 instead of into BASIC (flight_start). When the flight ends, the engine drops that return and goes back to G2, and the debriefing reads the flight's results from $3F00.