1985 · Gremlin Graphics

Tycoon Tex

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/c16/tycoon-tex with me to Gold.

Tex runs along his own oil pipeline, jumping the breaks and shooting what comes at him. Where he stands on the screen sets how fast the world goes by, in two layers at two speeds, and he has to run: at the slowest speed no break can be jumped.

Unusually, the authors’ own source survives. What it shows of how Tycoon Tex was made, from a cheat taken out to extra lives made ten times rarer on the way to the tape, is on the Source code tab.

01 · The game

Lay the pipeline before the oil pressure runs out

A cassette for the 16 KB Commodore 16, published by Gremlin Graphics in 1985, programmed by Anthony J. Clarke of Micro Projects with graphics by Matthew Clarke.

The menu: TYCOON TEX across the top over a desert skyline, THE TYCOONS! high-score table on the left, and PLAY THE GAME, WATCH THE DEMO, EASY, NO. OF LIVES:3 and SOUND: OFF on the right. Level 1: Tex, a cowboy, stands on a grey pipeline at the bottom left of a desert, a jet flies over, and two bars, OIL PRESSURE and % COMPLETED, run across the top.

The menu and the start of level 1, in plus4emu. On the right Tex stands on his pipeline at the bottom of the desert, a jet crosses the sky, and the two bars across the top are OIL PRESSURE and % COMPLETED.

Tex is an oil tycoon walking along his pipeline. The pipe runs across the bottom of the screen and comes in from the right as he moves, faster the further right he stands. Some stretches of it are broken, and a break must be jumped: Tex falls into one and loses a life. A jet drops bombs on him, and arrows, bouncing bombs and crash explosives come at him; his sixgun scores points off all but the jet.

The % COMPLETED bar fills as he runs and as he scores, and a full bar ends the level. The OIL PRESSURE bar above it drains all the while, faster on the harder settings, and when it empties the game is over however many lives are left. The scene changes with every level, the desert, the ice and a grey surface pipe in turn, and the enemies grow in number and come back sooner.

02 · Running

Where Tex stands sets the speed

The play screen, running on the game's own code. Move Tex with the arrow keys or the buttons: the further right he stands, the faster the pipe and the skyline go by. Up jumps, and the space bar fires.

The game's five raster interrupts (irq_frame, irq_skyline, irq_field, irq_pipe and irq_scroller), run once a frame in their order on the kit's 6502 over the listing, after start and start_game ($29D3) have built the level. The main loop is left out, so the pressure, the running points, the bouncy bomb and the crash explosive stand still, and no enemy is sent. Tex keeps his lives. Against the game in plus4emu, stopped at irq_pipe in each of 419 frames of level 2 with the joystick moved, jumping and firing, Tex, the scroll registers, his legs, the jump, the bullet and the message were the same in every frame, and again through a fall into a break and back.

Tex stands on columns 1 to 27 and moves one column every third frame. Eight of those columns set a speed when he reaches them: 1, 4, 7, 10, 13, 16, 19 and 22 (set_speed, speed_columns). Between them the speed stays where it was, so Tex walking back from column 22 keeps the top speed until he reaches 19. The speed picks a value from three tables: how many pixels the pipe moves each frame (pipe_speeds), how many the skyline moves (skyline_speeds), and how many frames pass between pictures of his running legs (leg_delays).

The pipe goes up to 7 pixels a frame and the skyline only to 3, so the skyline seems further away. At speed 1 the skyline's single pixel comes every other frame, which scroll_skyline counts in half_rate. Each band has a fine scroll of its own in TED's register $FF07, set by its own interrupt, and when the fine scroll passes a whole character the band's rows move one cell left and a new column comes in at the right (shift_skyline, shift_pipe). The 38-column window hides the column being filled.

Running also pays. While the speed is above 0 the main loop adds a point to the score and 0 to 4 eighths of a cell to % COMPLETED every 24 passes, more at the higher speeds (main_loop, completed_rates). Tex standing at column 1 completes nothing.

03 · Sound

Sound: three effects and no music

SOUND is OFF on the menu as the game loads. Switched on, it plays the sixgun, a hit, and a falling tone while the pressure left at the end of a level is counted into the score.

EffectWhat TED playsFrames
the sixgunvoice 1's square wave at full volume, its pitch falling from about 18,500 Hz to 739 Hz20
a hitvoice 2's noise at full volume, its pitch falling from about 7,900 Hz to 440 Hz19
the pressure countedvoice 2's square wave at volume 3, a step lower for each eighth of pressure counted, from about 2,260 Hz to 435 Hz for a full barabout 246

Each effect is the game's own code from the listing on the kit's 6502: shot_sound or hit_sound once, then tick_sounds once a frame, as irq_scroller calls it; and for the count, level_complete's loop from $3916 with a full bar. Its writes to TED's sound registers play through the site's model of TED. Run so, the sixgun and the hit write what the game wrote in plus4emu, frame by frame, and the count writes the same 208 values. Each of its passes is played 42,290 cycles apart, the average in plus4emu, where they took 39,068 to 47,517 as the interrupts' work changed (test_tex.js).

TED, the chip that also draws the screen, has two voices: two square waves, or a square and noise. The game sets their pitch values and the volume straight into TED's registers, the sixgun when Tex fires (fire_bullet) and the hit when a bullet scores (move_bullet). Every routine returns at once while SOUND is off (sound_on).

tick_shot_sound lowers the sixgun's pitch value by 8 a frame, and when the low byte runs below zero it takes 1 from the high bits it keeps in $DC. It ORs those bits into $FF10, which is voice 2's, where voice 1's are in $FF12. So voice 1 keeps the high bits 3 that shot_sound gave it and the sweep stays in the top quarter of TED's range, values $3F9 down to $369: it starts above what most ears hear and falls to 739 Hz. With the bits in $FF12, as the checkbox plays it, the value would drop to $2F9 in the first frame and sweep from 423 Hz to 273 Hz. That version is a guess at what was meant, not the game's (Discoveries).

04 · One frame, rebuilt from memory

The screen is drawn in five bands

Five raster interrupts a frame each set TED up for one band of the screen, so one picture needs five sets of its registers.

A frame of level 10, drawn from the screen memory (colours at $0800, characters at $0C00) and the character set as the game had them when irq_pipe began, with the registers each band's interrupt writes, by the site's TED renderer. Against plus4emu's own picture of the same frame, 0 of the 64,000 pixels differ. Drawn with one set of registers, as the message band leaves them at the end of the frame, 20,797 differ.

InterruptRaster lineRowsCharactersFine scroll
irq_frame204, below the last row0 to 2, the bars and the score128 at $3C00, 40 columnsnone
irq_skyline233 to 7, the skyline256 at $1000, 38 columns$06
irq_field658 to 21, the play field128 at $3C00, 38 columnsnone
irq_pipe17622 and 23, the pipeline256 at $1000, 38 columns$1B
irq_scroller19224, the message128 at $3C00, 38 columns$1C

The C16 has no sprites, so everything on the screen is a character. The bars, the score, the play field and the message use the game's main character set at $3C00, 128 multicolour characters holding the font, Tex, the bars and the enemies (font to block_char). The skyline and the pipe use a second set of 256 at $1000, room for five skyline pictures and the pipe's pieces (skyline_chars, pipe_chars). Each band sets its own background and two shared colours, which the scene chooses (set_scene_colours, scene_colours), so the sky, the ground and the pipe each have colours of their own.

The first line of the skyline is drawn half set up. irq_skyline changes the character set and the scroll first and the colours after, and the beam draws that line in between: the skyline's characters in the colours of the bars. The rebuilt frame draws it so, as plus4emu does.

05 · Tex

Tex is fifteen characters

Tex is three characters across and five down, drawn into the play field like the letters of the score. His legs are the bottom two rows, redrawn as he runs.

Speed

Drawn from the listing's characters $40-$4E in the desert's colours, at four times their size. The pictures of his legs are put in by the game's animate_legs on the kit's 6502, every leg_delays frames at the speed chosen. Lying down is turn_tex, run once, drawn with tex_lying_layout.

draw_tex puts characters $40 to $4E on the screen at Tex's cell, row by row from tex_layout, and looks at the pipe under him on the way (check_hole). animate_legs copies one of four pictures from leg_frames over characters $49 to $4E, his bottom two rows, in the order 1, 3, 0, 2 (leg_frame_order): every 22 frames at speed 1 and every frame at speed 7.

When Tex dies, tex_death saves his characters at $0400, and turn_tex turns each of them a quarter turn: its eight rows become its eight columns. Both draw_tex and erase_tex are patched to read tex_lying_layout, five columns by three rows, so that he lies on his side. Then sink_tex slides his characters down a pixel every second frame, 23 times, while the pipe slows to a stop. His characters are put back, a life goes, and he starts again at column 1 on a new stretch of pipe.

06 · The pipeline

A break is one more piece of pipe

The pipe comes in at the right edge one column at a time, from pieces chosen at random. A break is a piece too, and the columns that kill are decided by the character under Tex's feet.

The pieces drawn from the listing, in the pipe band's colours for each scene (scene0_pieces, scene1_pieces, common_pieces). The break is made by the game's build_break on the kit's 6502 and laid as feed_pipe lays a piece, and each of its columns is tested with the game's check_hole, as draw_tex calls it with Tex's left column above: red below a column means Tex falls there.

A piece is a run of characters in piece_buffer, two to a column, and feed_pipe puts the next two into column 39 of rows 22 and 23 each time the pipe moves a whole character. The desert and the ice each have three pieces of their own; the surface pipe has only the four every scene shares, the plain pipe and three decorated pieces that come every 9th, 14th and 12th time their roll comes up (next_pipe_piece, rare_limits).

Each time a piece is chosen while the first random byte has its top bit set, break_timer counts down, and the 18th such time makes a break instead: a left edge, one or two middles, each two columns picked at random from three, and a right edge (build_break). From level 4 a break can have three middles (break_parts). A bomb or a crash explosive that lands on the pipe breaks it too, six columns wide (break_pipe).

Tex falls when the character of the pipe's top row under his left column is one of $D9 to $E9 (check_hole). That is every column of a break but its leftmost, and the right edge counts as gap too. Tex does not move across while he jumps: the pipe carries the break under him during the jump's 20 frames, so how far a jump takes him depends on his speed, which the Discoveries tab follows to its end.

07 · Oil pressure

The pressure only ever falls

The inlay says the faster Tex runs, the quicker the pressure builds. Nothing in the code raises it during a level: it falls an eighth of a cell at a steady pace, faster on the harder settings, and when it runs out the game ends.

DifficultyMain loop's wait (loop_paces)Frames a pass, standingPasses an eighth (drain_rates)A full bar lasts

The bar drawn by the game's draw_pressure_bar on the kit's 6502 from the eighths left, and the loss taken by its lose_pressure. The frames a pass were measured in plus4emu: 408, 610 and 1,214 main-loop passes in 1,500 frames with Tex standing still.

The bar is 26 cells of eight eighths: pressure_cells whole cells, then a part cell whose eighths are in pressure_fine, drawn from bar_fill_patterns. A level starts it at 25 cells and 7 eighths, a full bar (next_level). The main loop takes an eighth every 24, 19 or 14 passes on EASY, HARD and IMPOSSIBLE, whether Tex moves or not (main_loop, drain_rate), and each pass waits in delay for 24, 16 or 8 times 256 turns of a loop. A bomb or a crash explosive that reaches the pipe takes 4 eighths, or 2 where the pipe is broken already (break_pipe).

When the part cell holds fewer eighths than the loss, lose_pressure takes the whole cell and refills the part cell to 7, whatever was in it, so the loss is the part cell's eighths and one more. A bomb with 1 eighth in the part cell costs 2, and with 0 it costs 1. When the cells run out main_loop goes to pressure_out, which types BAD NEWS! OIL PRODUCTION HAS CEASED across the field and ends the game, however many lives Tex has left. At the end of a level the pressure left is counted into the score, a point for each eighth and one more (level_complete).

08 · The enemies

Three of the four enemies change with the scene

Every enemy is a few characters drawn into the play field. The arrow, the bouncing bomb and the crash explosive are redrawn for each scene; the jet and its bomb are the same everywhere.

Each enemy's characters as set_scene_graphics copies them in at the start of a level in each scene, run on the kit's 6502, laid out by the game's own tables (arrow_cells, jet_cells, bouncy_cells, explosive_cells) in that scene's colours for the play field.

EnemyHow it movesMoved byPoints
Arrowright to left at Tex's height, a column a frame, from column 36move_arrow_and_jet, in the interrupt25
Jetleft to right across rows 8 and 9, a column every second frame, dropping a bombmove_arrow_and_jetout of reach
Jet's bombfalls 11 rows to the pipe, a row every second framemove_jet_bomb250
Bouncing bombbounces in from the right, starting between rows 12 and 18move_bouncy_bomb, in the main loop50
Crash explosiveflies in and lands on the pipe, breaking it, starting between rows 10 and 17move_explosive, in the main loop200

The jet flies on rows 8 and 9, above the highest row Tex's sixgun reaches, row 14 at the top of a jump, so it cannot be shot (fire_bullet, bullet_stop). Its bomb can, for the most points in the game. The arrow and the jet are moved by the interrupt, once a frame, so they keep the same speed on every setting. The bouncing bomb and the crash explosive are moved by the main loop, a step a pass, so they come faster on HARD and IMPOSSIBLE, where the main loop waits less. Tex dies when any of his cells is drawn over an enemy's character (draw_tex).

09 · Levels

A level chooses its enemies

Each level is a stretch of pipe in its scene. What changes from one to the next is which enemies come, how soon they come back, and how often their timers count.

Each row is the game's next_level ($3A31) run on the kit's 6502 for the first level of the group, through every entry of enemy_pairs or enemy_triples where it chooses at random. Every level is on the Maps / levels tab.

The delay is the least time an enemy stays away after it has gone, in frames for the arrow and the jet and in main-loop passes for the bombs (enemy_delays). It counts down only on frames when a random byte is at least the threshold, so $B0 lets it count about one frame in three and 1 almost always. From level 7 the jet's bombs break the pipe as well as threatening Tex (bit 4 of enemy_mask, end_jet_bomb).

The level is kept as two decimal digits, and next_level takes the delay from two bits of it, bits 5 and 6. That works up to 79. Level 80 is $80 in decimal, those two bits clear, and levels 80 to 99 get the slow enemies of levels 1 to 19 again (Discoveries). After 99 comes 00 (Discoveries). The difficulty on the menu changes only the main loop's wait and the drain (loop_paces, drain_rates).

10 · Controls

A joystick in either port, or five keys

K and J on the menu choose the keyboard or the joystick, and the picture between the two boxes shows which. The game reads both through TED itself, never through the KERNAL.

The control picture as the menu draws it, twelve cells from control_chars, control_colours and the font at $3C00, with menu_keys copying keyboard_icon or joystick_icon into its middle four. The authors' source calls the joystick a "kempston joystick", and beside it holds a drawing of Commodore's own joystick for the C16 and Plus/4, commented out: on the right, drawn into the same cells, it is the one picture here the game never shows (the authors' source).

In playJoystickKeyboard
Left, rightleft, rightZ, X
Jumpup;
FirefireRETURN
Pause, carry onSPACE, C=
End the gameESC

read_controls ($182D), read_keys with key_columns and key_rows, and check_play_keys; all tested in plus4emu.

read_controls reads port 2, and port 1 only when port 2 shows nothing, so a joystick in either port works. Fire is bit 7 of port 2's byte and bit 6 of port 1's, and the routine rewrites one of its own instructions before each read to suit (controls_fire_shift): an LSR for port 2, a NOP for port 1. The inlay names / for down, which the menu and the high-score table read; in play nothing tests down. The pause and the quit keys are in no manual.

11 · Score and lives

A life for every 10,000 points

The score lives on the screen itself, six digits at $0C56-$0C5B, and the lives come from watching one of them.

ForPoints
an arrow25
a bouncing bomb50
a crash explosive200
a jet's bomb250
running, every 24 main-loop passes at speed 1 or more1
the end of a level, for each eighth of pressure left1, and 1 more

move_bullet, main_loop and level_complete; points are added in decimal by add_score.

Each time the score's ten-thousands digit changes, add_score gives Tex a life, up to nine: one at 10,000, 20,000 and so on, and one at 100,000 when the digit goes from 9 to 0. NO. OF LIVES on the menu goes from 1 to 6 and round, 3 as loaded. A death takes a life from the count and from the TYCOONS digit on the screen (tex_death).

The authors’ own source reads the thousands digit there, a life every 1,000 points, and so does the program it built on their disk. The game was made harder after that program was finished (the authors’ source).

THE TYCOONS!, the table on the menu, holds eight scores of six digits with names of seven letters, 5,000 for GREMLIN down to 100 for M.P.LTD as loaded. A score must beat an entry to go in (check_hiscore), and a new entry pushes the ones below it down, losing a digit on the way when the score is big enough (Discoveries).