1985 · Nintendo

Balloon Fight

This minisite was contributed by air, icyriver2023. It’s agent-generated and needs a human editor. Clone https://github.com/gamesexplained/gamesexplained and follow kit/START.md to curate games/nes/balloon-fight with me to Gold.

The game's program is 16 KB. This page runs its flap, read from the code, and shows the birds' three speeds, the clock behind the storm, and a sound routine that keeps its counters inside Balloon Trip's table of high scores.

01 · The game

A balloonist against the birds

You fly by flapping. The birds fly the same way, and whoever is higher when two meet wins.

The player hangs under two balloons and flaps to rise. Each press of the A button gives one flap, and holding B flaps again and again. Birds sit on the ledges pumping up balloons of their own, then take off and give chase. Coming down on a bird from above pops its balloon, and the bird drops on a parachute. A second hit on the way down sends it into the water, and a bubble rises from the spot for the player to pop. A bird that reaches land instead pumps up a new balloon and comes back in a faster colour. The player's two balloons work the same way: a bird coming down from above takes one, and with none left the player falls. A fish lives in the water. A phase (the game's word for a level) that goes on too long brings a storm: a cloud flashes and throws a spark that bounces around the screen.

Clearing every bird clears the phase. Every three phases there is a bonus round, where balloons rise from chimneys. A third mode, Balloon Trip, scrolls the sky past a lone balloonist, who collects balloons and dodges sparks to earn a place in a table of fifty scores.

The title screen: BALLOON FIGHT and three options Phase 1: the balloonist at the bottom left, three birds on the middle ledge Phase 1 after half a minute: a spark thrown by the cloud

The title screen, phase 1 as play begins, and phase 1 half a minute later with a spark loose. The pictures come from an emulator, a program that behaves like the console.

02 · The music

Music: every tune on the cartridge, played by the game's own sound code

The phases have no music. Eleven short tunes play everywhere else, and one of them loops.

The game's sound driver plays its music and its effects. It is a routine, a piece of the program that other parts call on, and it sits at addresses $F500 to $FBC9. An address is a numbered place in the console's memory, written in hexadecimal (base 16) after a $ sign, and each place holds one byte, a number from 0 to 255. The eleven tunes sit at $FBCA to $FFF6. Both run on this page, on the kit's model of the console's 6502 processor. The page calls the driver once a frame, about 60 times a second, as the game's NMI handler calls $F758. The NMI is the signal the console raises each time it finishes drawing a picture, and the NMI handler is the routine that answers it. Each tune starts from the same request bit the game sets for it: a bit, one on-or-off switch of a byte in memory, that the driver reads as "play this". Every byte the driver writes to the APU, the console's sound chip, goes to the page's model of that chip. The page was checked against the emulator. Started from the same paused game, the page's driver and the console's made the same writes, in the same order, frame for frame, for all eleven tunes and the fourteen effects below. The chip has four channels, four voices that sound at once: two pulse channels, which make a buzzy square wave, a triangle channel, which makes a softer tone, and a noise channel for hiss and drums. The roll shows the pulse channels in blue and orange and the triangle channel in red, with the noise channel along the foot. The triangle's bass goes down to 55 Hz, which a laptop or phone speaker barely plays.

A tune starts with a header of five entries ($FBCA): a tempo, then the address of a list of bytes for each of the four channels. The driver reads each list a byte at a time, and the value of the byte says what it does. A byte from $80 to $BF sets the length of the next note: its low nibble (its last hexadecimal digit) is added to the tempo, and the sum picks a number of frames from a table ($F660). A byte from $C0 to $FE opens a repeat, and $FF jumps back while repeats remain. A 0 ends the channel. Any other byte is a note: an even number that picks an entry in the table of periods at $F600. The period sets the channel's pitch, and note 2 holds a period of 0, which makes it the rest. Once a frame the driver counts each channel's note down, and reads the next byte when the count reaches 0 ($F504). Only the bonus round's tune loops. When its lists run out, the driver sets a flag, a byte it uses as a yes-or-no marker ($07E8), and starts the tune again.

The driver runs on the title screen too, but with the APU switched off. A game that starts switches the APU on ($F1E9), and the demonstration switches it off again. So a game started after a demonstration plays sound, and the demonstration itself is silent.

03 · The sound effects

Sound: fourteen effects, most of them one write of four bytes

The game asks for an effect by setting a request bit, one bit of a byte in memory, and the driver plays the effect on the next frame.

Each effect is started by its request bit ($F0 to $F3) and played by the game's driver on the page, like the tunes above. Most effects are a block of four bytes written to one channel's registers, the chip's settings, and then left to the chip, whose own envelope, sweep and length counter shape the volume, the pitch and the length ($F683). The lightning steps the noise channel's period up every three frames ($F87D); a longer period sounds lower. The spark's bounce and the fish's rise pick random pitches ($F8A6, $F993). The flap is the first block of four bytes, $94 $AB $FD $58: a quiet pulse wave at a fixed volume, whose pitch the sweep slides up from 440 Hz to about 660 Hz before the length counter ends it, 90 ms later. That was measured from the page's model of the chip.

Thunder is the one effect without a sound. The cloud's flash sets bit 3 of the second request byte ($C852). The driver's dispatch, the code that picks which effect to play, shifts that bit out without testing it ($FA59). Bit 4, which the dispatch does answer at that point, is a bird's flap.

04 · The flap

At most one flap every nine frames, and the controller read every third frame

The balloonist's flight comes from four numbers in a table and a short list of states the balloonist moves between. The chart below runs the game's own arithmetic.

Height against time over four seconds, starting in flight at mid-screen. The dots along the foot mark the frames on which a flap was taken. The page runs the game's routines $EA18, $EC49 and $EA58, written again in JavaScript, the language of web pages, in the order the game runs them. They were checked against the game's own code on the 6502 model in the kit, the site's set of tools, over 35,358 frames of random taps and holds, with 1,641 flaps, and never differed in height, velocity, action or frame.

Every actor, the players and the birds, has a vertical velocity: how fast it is moving up or down. The game keeps the velocity in 8.8 fixed point, a whole number of pixels in one byte and 256ths of a pixel in another. Each frame $EA58 adds gravity to the velocity, holds it between a top speed down and a top speed up, and moves the actor by it. A flap takes a fixed amount off the velocity ($EC9B). All four numbers come from tables with one entry for each type of actor ($E601 on). An actor's type is also its colour.

ActorGravity a frameFlapFastest downFastest upFastest sideways

The game does not read the controller every frame. Each actor has a timer that is reloaded with 3 ($E6B8). Only on the frame the timer runs out do the actor's animation, steering and controls run, while the physics runs every frame. So a press of A shorter than three frames can fall between two readings and be missed. After a flap, the actor is set idle with its animation frame, the picture it shows, at 1. A new flap is not accepted until the animation frame has counted round to 0 and the action is back to flapping, which takes three more readings: nine frames ($EC75). Holding B therefore gives a flap every nine frames, which is 14 flaps in two seconds. A gives one flap for each press, and taps faster than the limit are dropped.

05 · One frame, rebuilt

The screen, drawn again from the picture chip's memory

A reconstruction, not a screenshot: the page draws the screen from the picture chip's memory, as a saved moment of the game holds it.

Phase 1 at frame 365, from the snapshot the listing was built from. A snapshot is a saved copy of the whole console at one moment, and the listing is the game's program with notes on every line, on the Source code tab. The page draws the picture from four parts of the memory of the PPU, the console's picture chip. The first is nametable 0, the grid of 960 tiles of 8 by 8 pixels that makes the background. The second is the 64 sprites, the small pictures that move over the background. The game keeps them in a table at $0200, and the NMI copies that table to the chip with DMA, a fast copy the console makes by itself. The third is the palette, 32 colour entries, and the fourth is the two pattern tables, which hold the pixels of every tile. The site's NES renderer draws them. Compared pixel by pixel with the emulator's own picture of the same frame, 0 of 61,440 pixels differ. The collision code decides when two things touch. The boxes are the 16 by 24 pixel rectangles it uses ($EE25): the player's and each bird's.

Everything the game draws goes through one queue. A routine that wants tiles on the screen adds a block to the queue at $0300: the address in the PPU's memory, a count, and the tiles ($C131). While the picture is being drawn, the PPU's memory cannot be written safely. The safe time is the vertical blank, the pause after each picture while a television's beam goes back from the bottom of the screen to the top. In the next vertical blank, the NMI handler sends every block in the queue ($C188) and then sets the scroll back to 0, 0. The status bar is written the same way when it is asked for ($D798), and one star twinkles each frame ($D60D). The sprites are a page of RAM, 256 bytes of the console's working memory, which the handler copies with the sprite DMA. Balloon Trip's scrolling is the one exception. After the handler's work, the game waits for the vertical blank to end. Then it spins in a loop for about 35 scanlines, the lines the beam draws one below the other, and sets the scroll for the rest of the picture ($C0D1). That way the status bar stays still while the sky drifts. The game does not use a timer for this. It also does not use the sprite-zero hit, a flag the picture chip raises when a solid pixel of sprite 0, the first sprite in its table, lands on a solid pixel of the background. The split comes from a delay loop.

06 · The birds

Pink, green and white: the same bird with faster numbers

A bird's colour is its type, and its type indexes every table that makes it move and think.

A bird decides what to do when its timer runs out ($E712). It then reloads the timer with a random number of frames, from a range that depends on its colour: 32 to 63 for pink, 16 to 31 for green, and 8 to 15 for white ($E762). So a white bird decides about four times as often as a pink one. Each decision looks at one player, the two players taking turns. If that player is alive and has not just arrived, the bird flaps when the player is higher than it, and steers toward the player's X, the position across the screen. With no player to chase, the bird only flaps ($E731). Y is the position down the screen, counted from the top, and below Y $A0, near the water, a bird always flaps. The colours' physics are in the table above: a white bird falls faster, flaps harder and flies faster than a pink one.

A bird that loses its balloon drops on a parachute, which sways like a weight on a spring ($E7B1). Each frame, the sway's distance from the middle gains a sixteenth of the sideways speed, and the speed loses a sixteenth of the distance. Nothing in that sum slows the sway, so it never dies away. On the ground, the bird pumps up a new balloon in steps, and the length of a step comes from a table by phase ($F3BA). A bird that had been hit before takes off one colour faster ($ECAE), and a white bird stays white. Hits score as the game's manual says. A bird's balloon is worth 500, 750 or 1,000, by colour. Tearing its parachute in the air is worth 1,000, 1,500 or 2,000, and kicking it while it is on the ground 750, 1,000 or 1,500 ($F06A, $F076).

HitPinkGreenWhiteThe other player
Its balloon popped5007501,0001,000
Its parachute torn in the air1,0001,5002,000
Kicked on the ground7501,0001,5001,000

Who hits whom is decided by height. When two actors' 16 by 24 pixel boxes overlap, the one underneath loses a balloon if the other is more than 4 pixels higher ($EF72). Two birds never hurt each other. After a hit, the victim cannot be hit again for 20 frames ($EF7F).

07 · The phases

Twelve layouts, then phases 4 to 12 for ever

Each phase is built from a record, a fixed list of its clouds, propellers, birds and platforms. The Levels tab draws every one.

Sixteen records are listed at $DB2A. Each record first names the lists of blocks that paint its ledges. Then come its clouds, as positions on the screen's grid; its propellers, with the angle each starts at; its birds, with a position and a colour each; and four tables of platform edges that the collision code reads. Every fourth record is a bonus round's. Its list of birds is empty, and that empty list is what makes the phase a bonus round ($D394). After the sixteenth record, the count goes back to 4 ($F358). So the layouts of phases 4 to 12 and their bonus rounds repeat, while the phase number keeps counting up and the difficulty tables keep climbing.

Phase number ÷ 4Frames a step of pumping takes ($F3BA)Steps before take-off ($F3C3)

In the first two phases the steps are set to 3 instead. The sparks have a schedule of their own. In phase 1 the first lightning comes after 15 counts of 128 frames, which is 32 seconds, and the count falls to 5 by phase 25 ($C761). Each spark thrown is faster than the last ($C89F). The platforms' colours change every four phases ($D45A). A fanfare plays on phase 1 and on the first phase after each bonus round: 4, 7 and 10.

08 · The storm and the fish

A spark every so often, from a random cloud

The storm is a counter that ticks every 128 frames. The fish bites only what is exactly above it.

Once every 128 frames, about two seconds, the storm's counter goes down by one ($C790). At 0, a cloud is chosen at random. The cloud flashes for half a second: the game rewrites the cloud's attributes, the settings that pick which palette colours each patch of the background uses, four times ($C831). Then the cloud throws a spark. The spark sets off in one of four directions, picked at random, at a speed from the spark table plus a random 0 to 31, and the next spark's speed level is one higher. Two sparks can be in the air at once, and while both are, the counter waits at 2. A spark bounces off the top and the sides of the screen and off every platform edge it meets ($CA67). It keeps its speed, and is lost off the bottom. A spark hits a player within 8 pixels sideways and 12 down ($CB1C). Both balloons go at once, and the stunned player tumbles into the water.

The fish swims right under the water, a pixel a frame, and wraps round from X $B1 to $40 ($C64B). Every frame it looks for an actor at exactly its own X whose Y is $B4 or more, which means low on the screen, just above the surface ($C614). Finding one, the fish rises a pixel a frame for 24 frames. It bites if the victim's bottom edge is still at or below it ($C658), and the victim becomes a falling type carried in the fish's mouth. A victim that moves away makes the fish sink back. The fish takes birds as readily as players.

09 · Balloon Trip

Balloon Trip: a fixed opening, then random stretches, and 10,000 points for twenty in a row

The third mode is the same game with the birds taken out and a scrolling sky put in.

The scene moves on odd frames only, one pixel at a time ($C216). Every eight pixels a generator, a routine that makes new things, runs and puts balloons and sparks at the left edge. A step counter that goes up every 32 runs picks each run's generator from a table ($C3BF). For the first two steps, 63 runs, the generator reads the next run's worth of a 122-byte list ($C4AD), so every game opens the same way for about 17 seconds. The list holds only 58 runs, so the last five read on into the code after it ($C527) and turn its bytes into six sparks and a balloon (the Levels tab draws them). Then come five steps of random balloons and sparks, with now and then a bubble at the water line instead. Then there is one step whose generator is a bare RTS, the instruction that ends a routine and goes back to the code that called it, so it makes nothing; a step of sparks alone; and a step of balloons with sparks. A balloon is worth 300 points. Popping twenty without letting one drift off the right edge pays 10,000 points with the perfect-bonus jingle, and raises a balloon's value to 500, then 700 ($C348). A balloon that gets away starts the count of twenty again. Popping a bubble stops the scrolling for two seconds ($ECBA).

The rank in the status bar is the score's place in a table of 50 five-digit scores at $0700. At power-on, the table is filled with 25,000 down to 500, in steps of 500 ($C043). The rank is worked out again after every change to the score ($C539), and at the end the score is written into the table at its rank ($C579). The sound driver uses the table's last entries too, which is a discovery of its own.

10 · The bonus round

Twenty balloons from four chimneys

The bonus round reuses Balloon Trip's balloons, and their value goes up from one bonus round to the next.

Every fourth layout is the bonus round. Twenty balloons rise one at a time from the four chimneys ($CEAE), 40 to 103 frames apart. They sway on the same spring as a parachute, and rise at a speed set by the round ($D112). A balloon within 24 pixels up or down and 16 pixels sideways of a player is popped and counted for that player ($CECE). When the last balloon has gone, the results screen shows each player's count times the round's value, 300, 500 or 700 points, and adds it to the score 100 points at a time ($D213). When the players pop all twenty between them, the screen shows PERFECT!!! and pays a super bonus of 10,000, 15,000, 20,000, 25,000 and then 30,000 points ($D117). A player cannot die here. One who falls bounces back up at Y $C8 with both balloons back ($EB62).