Commodore 64 · 1985 · Novagen Software

Mercenary

This minisite was contributed by air. It’s currently claimed by air who is editing it to reach a Gold tier standard.

Paul Woakes's city of Targ has buildings on 233 of its 256 squares, and the game only ever draws the one you are standing in.

01 · The city in lines

The city of Targ, one building at a time

The game keeps one building in memory, the one in the square you are in, and draws the rest of the city as its roads.

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

Go to

Fly

160 × 136 multicolour pixels, drawn by the page with the game's view code ported routine by routine ($A544, $94E0, $A320, $AFD5, $9054, $96D8, $96E7, $A75C, $99DD) in its two-byte logarithmic floats (tables $5800 to $5BFF), from the models named at $2600 and $2700 and the roads at $2C00 to $2FFF, all read from the listing. Checked against the same routines run in a 6502 simulator: 15,000 random views identical byte for byte. The pictures the game displayed in two snapshots match too, apart from the objects, which this view leaves out. Every building draws the models of all squares but 00-00 at once, which the game never does. The map shows the roads listed for the view (bright), the window of squares they come from, and the square whose building is loaded.

At 08-08, near its north edge, facing north: an empty horizon

08-08, facing north, 3072 units from the edge. Bosher Stadium stands in the next square, dead ahead. Nothing is drawn.

Three thousand units further on, in 08-07: the stadium on the horizon

6144 units further on, in 08-07. The same stadium, now drawn, far off on the horizon.

The square's model is loaded by $9575 only when the high byte of your X or Y changes ($94FE-$952F), from the table at $2600/$2700, and drawn only while your height is under 65536. From higher up you see the roads instead: they are drawn from height 2048 up, as lines between the centres of the squares they join, and from height $200000 a fixed picture of 13 roads replaces them ($902A). So a building is never in view from outside its square, and roads are never in view from the ground. The flying view above has a switch to draw every building at once; the game does 1/256 of that work.

02 · Bug

Bug: stand on one patch of grass at the start and E takes you into the Colony Craft

You crash-land at 08-08, and the Colony Craft hangs straight above you at ALT 64997. There is no lift on the ground here. But one invisible patch of grass, 1,024 units a side and about 14 seconds' walk from where you land, answers the E key as if it were the lift on the Colony Craft's deck. The ride goes down into the Colony Craft's hangar, and E again brings you up on its deck. The published solutions all fly there.

Click anywhere to stand there and press E.

Square 08-08 from above, north up, drawn from the game's bytes: the square's model at $CEF6 (runway marks and the spinning pyramid), the Dart's position (object 1, $2481/$2501), the E key's test at $B40C and the Colony Craft's pad test at $A13D. One grid step is 256 units, 1/256 of the square. The landing point is where the opening leaves you, measured in the emulator.

PlaceX, Y within 08-08Where from
Where you land, facing south$88:00, $88:00live, after the opening
The patch where E works$70:00-$73:FF on both$B40C, $B414
The lift on the deck, where the ride up arrives$71:00, $71:00$A24A
The deck's pad, 64997 up$68:00-$77:FF on both$A13D
The Dominion Dart$96:E4, $8B:77object 1

The Colony Craft sits over 08-08, so its deck and the grass underneath share one X and one Y. Only the height tells them apart. Its lift is entry 8 in the table of lift squares at $B4B6/$B4BE, and the E key's test checks the square and the middle bytes of X and Y. It never reads the height. So the patch under the deck's lift works exactly like the lift.


      
TestOn the deckOn the ground

The E key's test, one instruction group at a time, with the values it reads on the Colony Craft's deck and on the grass under it.

The ride down ends in room 8, the Colony Craft's hangar, whichever end you started from. The ride up from room 8 adds $40FF00 to your height, which puts you on the deck. The game does not know how you got in.

Room 8, the Colony Craft's hangar, reached by pressing E on the grass at 08-08

E on the grass: down into room 8, the Colony Craft's hangar.

Standing on the Colony Craft's deck after the ride up, ALT reading 64997

E again: up on the deck, ALT 64997.

Tumbling down towards the city after walking off the deck

Walk off the pad: you tumble all the way down.

It does not break the game open. Hangar 8's three doors are all keyed to object 23 (room 8's record at $30A6), and you start without it, so the hangar and the deck are as far as you get. Take the lift back down, or walk off the deck: leaving its pad starts the tumbling fall ($A1DA), which never kills you, and you land back on the grass at 08-08. With the key, the patch would take you into the Colony Craft without a craft that can climb to 64997, which the Dart you start next to cannot do until it carries the Poweramp. That follows from the code; it was not played through.

Try it yourself

You need your own copy of the game and a C64 emulator. This was checked in VICE with the original Novagen disk.

  1. Let the opening play to the end. Touch nothing until you stand at LOC 08-08 and Benson has finished "CRASH LANDED ON TARG". You face south.
  2. Turn right three-eighths of a turn, to face north-west. The COMP dial turns red as you pass west; north-west is the middle of the red quarter.
  3. Walk forward for about 14 seconds, about 100 steps, and stop.
  4. Press E. If nothing happens you are off the patch, which is about 2.5 seconds of walking across. An emulator snapshot taken at step 1 makes retrying cheap.
On the patch, facing north-west: an empty field and a red COMP dial
On the patch, facing north-west. Nothing on the screen marks it.

The exact way is to put yourself there. X and Y are three bytes each, and the middle bytes are $73 and $79. In VICE's monitor, > 73 72 and > 79 72, then x to carry on, leave you in the middle of the patch at 08-08. Then press E.

03 · Secret

Secret: shoot a building from the next square and nobody notices

A building shot from outside its square is destroyed, but the game never counts it, never names it, and nobody comes after you for it.

Where the player is while the building falls:
The view at this pass

Pass$F4$B7 = $F5?What runs

The hit and the sixteen passes after it ($871B, $879B), for a missile that reaches 13-04's Commodore sign. The table follows the code's tests pass by pass; the pictures are the emulator's, from the two live runs: the shot from inside the square, and the shot from next door.

When a missile gets within 4096 units of a square's centre below height 2048, $871B marks the square destroyed in $2B00 at once and starts a countdown of 16 passes in $F4 for square $F5. Everything else waits for the countdown: sinking the building, adding it to the count of Palyar or Mechanoid sites, and starting its script, which names it and sends the owner's ship after you. The routine that does all that returns straight away unless you are standing in that square ($87A4). The countdown runs out anyway, and a later hit finds the square already destroyed and does nothing ($87C1). In the emulator, a missile fired east from 12-04, 1024 units up, destroyed 13-04's sign: $2B4D went from $51 to $D1, the Mechanoid count stayed 0, and Benson said nothing, then or later.

Firing from the ground does not work: level flight still points the nose down by a sine of −0.003, so a missile launched 63 units up hits the ground within five passes, before it reaches the next square's centre. From a little higher it does.

04 · Joke

Shooting the Commodore sign makes you a TRAITOR

Ten squares of the city hold billboards: five with the Commodore logo, five with Atari's. Destroying either kind gets a verdict.

The Commodore sign at 13-04

13-04: model $C82E, the Commodore logo on two posts. Also at 03-13, 09-13, 04-15 and 09-15.

The Atari sign at 14-05

14-05: model $C7B2, the Atari logo. Also at 14-08, 12-11, 06-15 and 11-15.

The sign sinkingThe sign flat on the ground
TRAITOR!

Shot from inside its square in the Dart: the Commodore sign sinks into the ground and Benson prints TRAITOR! (live). Its square's byte in $2B00 says Mechanoid, script 17 + 32 = 49; the Atari squares run script 50, GOOD SHOW!

Each square's byte in the table at $2B00 holds its owner (bit 6 Mechanoid, bit 5 nobody's, neither Palyar) and, in its low five bits, a script number n. When the square is destroyed, script 32 + n runs once. Scripts 36 to 48 name the landmarks ("YOU HAVE JUST DESTROYED", then BOSHER STADIUM, say), and all but Novabill's then set off an attack by the square's owner; scripts 49 and 50 print their one word and leave you alone.

05 · The screen

One frame, rebuilt from memory

The view is a bitmap of 160 by 136 wide pixels, and there are two of them: the game draws into one while you look at the other.

One frame of the opening descent, high over the city, drawn by the site's C64 renderer from the memory and video-chip writes recorded in the emulator: all 104,448 pixels match the emulator's own picture of that frame. The button points the view at the other bitmap, which is half drawn.

Above the panel the screen is in multicolour bitmap mode: each byte holds four pixels of two bits, and each pixel is twice as wide as it is tall. Two bitmaps sit in the video chip's second bank, at $4000 and $6000. On every pass the main loop swaps them ($AF84): the counter $24 picks which one the game draws into ($25), and $C7 holds the value the view's raster interrupt writes into $D018 to show the other. At line 186 a second interrupt switches the screen to text for the panel ($BA1E).

The bitmap at $6000 after each of 14 frames, read from the emulator one frame at a time during the same descent. Sky and ground go in first, then nothing changes for six frames while the vertices are transformed, then the lines. At frame 13 the buffers swap and this one is shown.

Seen from above the whole city, a view takes 13 frames to draw, so the picture changes about four times a second. On the ground, with one building to draw, the main loop runs five passes a second.

06 · Flying

The flight model, pass by pass

Every craft but the interstellar ship runs the same flying step once a pass, with its handling read from a 16-byte record: take-off needs speed, the climb fades above the craft's ceiling, and a touchdown crashes only on a steep drop or a steep nose.

crash

Stick

Throttle keys

Run

    The flying step ($9F17-$A13C), the ground routine ($9EFD) and the throttle keys ($B47E, $B499), ported from the listing with the game's two-byte floats and its sine table, and the readouts drawn with the panel's own glyphs from $7800 ($B53D). Checked against the Dart recorded in the emulator (all 253 passes match in speed, throttle, pitch, height, X, Y and the motion record) and against the original code in a 6502 simulator (1.2 million random passes identical). Keys work when the plate has focus: arrows for the stick, digits, SHIFT + digit, SPACE, + and -.

    The throttle keys set a target, and the speed chases it: each pass the speed becomes (speed + throttle × thrust) × kept. On the ground a craft slower than 128 has its nose held level. Faster, it takes the level pitch's sine, -0.003, sinks below height 64 and lands again, every pass, until the stick lifts the nose. In the air the height changes by speed × sine of the pitch × the record's climb factor; climbing above the ceiling byte, that factor's power of two is replaced by the ceiling minus the height's top byte. A touchdown crashes when that pass's height step is 256 or more, or the nose is more than 45 degrees down.

    Two things follow from the arithmetic. Every craft has a hard ceiling: above its ceiling byte the climb shrinks until the truncated step is zero. Flat out with the nose straight up, the Dart stops at ALT 24000, well short of the Colony Craft's 64997; with the Poweramp, as in the jet or the CHEESE, the top is ALT 105000, which the panel prints **000. And the sine table is sampled half a step off, so the level pitch's sine is −0.003, not 0. Level flight sinks slowly, a fast craft on the ground lands again every pass, and in reverse a craft climbs: SHIFT + 0 lifts the Dart off the ground with its nose level, 9 units a pass. The emulator shows the same heights, 67, 74, 82 and on.

    07 · The craft

    Eleven motion records

    Each craft's handling is sixteen bytes at $9DAD, copied to $BEA0 when you board and after every airborne pass.

    RecordCraftRoutineTurn keptTurn stepPitch stepBankClimbSpeed keptCeilingThrust
    The table is read from the game's bytes in listing.json, which the built site serves.

    Decoded from the bytes at $9DAD by the loader $9D99: each float is a mantissa byte m and an exponent byte, worth (1 + m/256) × 2^e, e being the exponent byte's top six bits (signed) and bit 0 the sign. Byte 12 ($10 in records 0-7) is read by nothing. The Dart and CHEESE are named by the game's own messages and the new ship by the script that runs when it is shot; the car, jet, Palyar diamond and land Dart are matched to Zzap!64 13's table by where the objects start and by their top speeds.

    08 · Top speeds

    Top speeds: Zzap!64's table, to the digit

    With key 0 and then + held until the game refuses it, the port's top speeds are the figures Zzap!64 printed in May 1986.

    CraftStarts atAir, the portZzap!64Ground, the portZzap!64
    The speeds are computed by the port, which reads the game's bytes from listing.json, served by the built site.

    SPEED as the panel prints it ($B5A8): the speed's whole part, high byte as two digits and low byte × 25/64 as two more. Zzap!64's figures are green where the port gives the same. Holding + multiplies the throttle by 1.03 a pass and stops after 23 passes at 32512, where the next step would reach 2^15 ($B4A7). On the ground every craft lands each pass and takes record 8's speed kept, 0.25. Zzap!64 13 (May 1986), pages 61-62.

    09 · The underground

    The underground: 174 rooms, each a box with doors drawn on its walls

    Below the city every room is a record of a few bytes: three sizes, two colours and four bytes for each door, drawn as a wire box with the doors' outlines on its walls.

    This viewer reads the game from listing.json, so it needs the built site.

    Room 8, the Colony Craft's hangar, where the lift from 08-08 arrives, looking east at two of its three doors, drawn from the room's record at $30A6 and the door outlines at $928A by a port of the game's projection ($A979) and line drawing ($99DD). The buttons or the arrow keys walk and turn; walking into a doorway, clicking a door or its button goes through it. The port reproduces the game's own drawing byte for byte in 2,942 views of all 174 rooms, run in a 6502 simulator, and room 8's picture in the saved game pixel for pixel.

    A room's record starts with its X size, its height and its Y size, in units of 256 (a city square is 65,536 across). Then come two colours: the view is filled with the first and the lines are drawn in the second. Each door is four bytes: its kind, which wall it is in and which door of the next room you come out of, then the room it leads to and its position on the wall. The list ends with a 0, or with $80 for a dark room.

    10 · Benson's message window

    Benson's message window

    Benson, the craft's computer, speaks through a strip of 23 cells at the bottom of the panel, one character a frame.

    The window and its frame are rows 21-23 of the screen matrix at $5C00, drawn with the character set at $7800 in the colours the code sets: ink from $BBC2, paper from $BA3D. The player is a port of the printer $8DC3. A test runs the game's own code in a 6502 simulator beside it and gets the same window, tick and state on every frame of all 219 messages; the finished "DO YOU WANT TO BUY?" matches the play snapshot byte for byte and the reference screenshot pixel for pixel.

    Each character moves the window one cell left and enters at the right. After 25 characters the printer stops for 99 frames, so a line lasts 124 frames, about 2.5 seconds, and the next line pushes it out. The window is 23 cells wide, so the first two characters of every line scroll off before the pause: the author pads each line with blanks to centre it.

    11 · How a message is stored

    How a message is stored

    A message is a list of one-byte tokens, most of them numbers of words in a dictionary.

      All 64 canned messages (pointers $20A0/$20E0, tokens $151F-$16D2) and the 155 messages inside the scripts, decoded as the printer reads them ($8E1E), with words from the dictionary at $1249-$151B through $2120/$2210. The lines under the table are the printer port's output, which matches the game's code frame by frame.

      A token of 8 or more is a word with a blank before it; 1 to 7 are endings such as S and ED, glued to the word before. $EF is a blank, $F8-$FE print a counter in decimal, $FF starts literal text that runs to the byte with bit 7 set, and 0 ends the message. Words 230 to 238 are nothing but spaces, nine down to one. They centre a line, and word 230 at the end of a message pushes it into a second, empty line that clears the window.

      12 · The event scripts

      The event scripts

      What Benson says, and when, comes from 51 scripts in a small byte code, run one operation per pass of the main loop.

        Every operation reachable from the 51 entries of the table at $0800 and from the opening's script at $7001, 527 in all, decoded as the interpreter $8AB2 reads them, plus two pieces nothing reaches. Triggers come from the room records, the object flags $29C0, the square table $2B00 and the code that starts a script ($8A8C). Headings are the labels of the Source tab.

        An operation byte holds the operation in its low six bits; bit 7 turns a test round. A test is followed by its operands and a two-byte target, where the script goes if the test holds. The interpreter waits while a message is printing, so every script moves at the pace of Benson's window.

        13 · Money in BCD

        Money in BCD, and a purchase without subtraction

        The credits are eight decimal digits in four bytes, and the scripts have no way to subtract: a purchase adds the price's ten's complement.

        Canned message 21 with those credits, as the window shows it:

        What the rooms pay

        The addition is a port of operation 14 ($8C73): four decimal-mode additions from the least significant byte up, the carry out of the top byte dropped. It gives the same bytes as the game's code in a 6502 simulator on 10,000 random purchases and on the live test, 9000 + 99995000 = 4000. The prices are read from the sale rooms' scripts; a price in the table adds to the credits as operation 21 does at $1041.

        Credits start at 9000 ($710C). The Dart's script adds 99995000 ($0A29), which is 5000 short of 100000000; the carry out of the top digit is thrown away, leaving 4000. The Hertz ship costs 999,999 (99000001 at $0E90), but the check before it ($0E6F) only asks whether the top byte is above zero, so it wants 1,000,000.

        14 · Numbers

        Two-byte numbers, multiplied by adding logarithms

        The 3D view works in two-byte floats, a mantissa and a power of two, and multiplies two of them by adding their logarithms from a 256-byte table.

        A and B as the game stores them, and the working of $82FA (multiply), $8334 (divide) and $838B (add), with the logarithms at $5800 and the antilogarithms at $5900 read from the game. Typed numbers are cut to nine significant bits, as $8510 does with the game's positions. Checked: the ports give the same bytes as the game's own routines, run in a 6502 simulator, for 2,000,000 random pairs each and every mantissa pair at 56 exponent pairs.

        Error of the product, every pair of mantissas

        B's mantissa $00 → $FF A's mantissa $00 → $FF
        −0.44 %+0.44 %

        Point at the map to read a pair; click to load it above.

        Each dot is one pair of mantissas: red where the game's result is too big, blue where it is too small, against the exact product (or quotient) of the two stored values. Away from the ends of the range the exponents do not change the error. Computed with the ported routines from the tables in the game.

        15 · Lines

        Drawing a line: eight routines, one per octant

        Each edge in the view is drawn by one of eight short routines that step along the longer axis, add a slope byte to an 8-bit counter (or subtract it), and step sideways whenever the counter wraps.

        The octants as the view shows them (click one)

        Close up

        The counter $08 at each pixel of the last line

        
            

        The view's 160 × 136 pixels, each twice as wide as it is tall, over a sky and ground in the surface's colours from $B27D. Drag to draw; the end may leave the view. Each end is a whole pixel whose offset from the centre becomes a float; from there the port does what $9A94–$9D95 do (the slope by logarithms, the octant through $BBD0, the routine through $BC38/$BC40, the corner from $BBD8/$BBE0 for an end off the view) and runs the routine. Checked: every byte of the bitmap, and the slope, octant and end, match the game's code run in a 6502 simulator for 3,000 random drags and every row and column of the view, in both forms, and 6,000 direct calls of the eight routines.

        16 · Controls

        The keys, as the game reads them

        The game scans the keyboard itself and turns each key into a number, row × 8 + column, with 64 added for SHIFT and 128 for CTRL. The joystick goes in port 2.

        KeyNumberDoesWhere
        Stickwalk or fly; on foot, up and down step 80 units, left and right turn 1/64 of a turn a pass$B2FE, $A165
        Firea missile, from a craft on the surface$886A
        1 to 9, 0throttle 2n+4; 0 is 214, the fastest$B47E, $BC50
        SHIFT + digitthe same, in reverse$B47E
        + and −$28, $2Bthrottle × 1.03 or × 0.98 every pass while held$B499
        SPACE, ←$3C, $39throttle 2−31: stop$BC50
        T$16take an object within 256 units$970A
        B$1Cboard a craft within 512 units$970E
        D$12drop the last object taken$98FE
        L$2Aleave the craft, when landed$98C8
        E$0Ethe lift$B3FD
        Y$19yes, when Benson asksscript op 11
        CTRL + RETURN$81pause, until the next key$B335
        CTRL + Q$BEscatter what you carry over the city and start again in the Dart at 08-08$80E8
        CTRL + S, CTRL + L$8D, $AAsave or load position 0-9 on disk$B382, $819E

        The dispatch is at $B2FE-$B47E. Stick input skips the keyboard for that pass, and any input at all sets bit 7 of $BEC0, which is how Benson knows you have not been doing anything.

        17 · The opening

        The opening: a countdown, then a crash

        The game opens in space, runs its own event script through a failing Novadrive, and drops you in the middle of the city with 9000 credits.

        The countdown in space

        The countdown, over a starfield of 21 stars.

        Targ approaching: maximum reverse thrust

        MAXIMUM REVERSE THRUST, with Targ growing.

        The descent over the city

        The descent: the city's roads from above.

        Crash imminent

        CRASH IMMINENT! Then manual control.

        From the emulator, about 75 seconds from the start of the game to standing at 08-08. The opening's messages were logged from the message window as they played.

        The opening is written in the same byte code as the rest of the game's events, at $7001, and it lives in memory that the second bitmap overwrites once play begins: after the opening it is gone. Its starfield speeds up (−32 a frame, then × 4.05 once, then × 1.012 a frame) and slows down again, and the planet grows as a disc of radius 1024 over the distance, from 1023 to 0 ($74CA). The descent starts at height $7F0088, looking straight down. Script 0 then takes over: CRASH IMMINENT!, one of four landing remarks picked at random ("WHERE AM I", "YOU CRASHED", "GOOD LANDING!", "OUCH!"), the status report ("CRASH LANDED ON TARG", "STATE OF WAR BETWEEN PALYARS AND MECHANOIDS") and the offer of the Dominion Dart for 5000.

        The first message on the original disk is NOVADRIVE COUNTDOWN. The copy this page was made from reads ABC UNLIMITED in its place, the cracking group's name, typed over the same bytes at $7009: it is the only change to the game's text.

        18 · Protection

        The reset button hangs the original

        Novagen's disk makes the game look like a cartridge, so that pressing reset runs one of the game's own loops instead of handing the machine back.

        $8000  $2170           ; cold start
        $8004  C3 C2 CD 38 30  ; CBM80 (crack: 0s)
        
        $2170  SEI
        $2171  LDX #$00
        $2173  STA $2180,X
        $2176  DEX
        $2177  BNE $2171       ; back to LDX
        $2179  INC $2175       ; never reached
        $217C  JMP $2170
        The original after a reset: garbage on screen

        Original: stuck in $2171-$2177.

        The crack after a reset: BASIC's READY prompt

        Crack: BASIC's READY.

        Both were reset in the emulator during play. The original is the contributor's own disk, booted to the same point as the crack.

        On reset the KERNAL checks $8004 for the letters CBM80, and if they are there it jumps through $8000 as if a cartridge were plugged in. The original holds them, so reset runs $2170, inside the dictionary's pointer table. The code after the loop would wipe memory a page at a time: it steps the page byte of its own STA and goes round again. But the loop's branch goes back one instruction too far, to LDX #$00, so X is 0 at every store: the machine writes to $2180 for ever and never gets to the wipe. Either way, after a reset nothing runs but the loop. The cracked copy clears the signature and changes the branch to land on the $00 of LDX #$00, which is a BRK.

        19 · Odds and ends

        Things a pilot would not know

        Small things found in the code and checked in the emulator.

        The bytes at $BCB8-$BCFF, drawn with the game's own panel font (the Atari's space, $00, left blank): a piece of Atari DOS 2's menu, in 40-column lines with the Atari's two-column left margin. Nothing reads them.