1986 · U.S. Gold

Gauntlet

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

What the code does that the manual never said: poison that can leave a hero with hours of health, armour that does nothing, a timer that reads the wrong number, and a developers' tool left on the disk.

01 · Poison

Bug: poison can make you nearly immortal

Poison takes 100 health, and a potion if there is one, from a hero with no special powers to lose. It does the subtraction in the wrong number system, and with under 100 health left the result wraps round to over 16,000.

The game's arithmetic, ported. The panel digits are drawn with the game's own panel font ($6000), glyph $10 plus each digit. test_poison.js holds the port against the game's code in the kit's 6502 simulator: poison_health ($9F62) for all 256 values of the hundreds byte, and one tick of health_tick ($B933) from all 65,536 health values, every result and every death the same.

Health is kept as four decimal digits in two bytes ($B931 and $B92F for player one): 2000 is $20 $00. The clock takes one off with the processor in decimal mode (health_tick, $B944). Poison, when the hero has no power to lose, takes a potion if it carries one, then one off the high byte with decimal mode off (poison_health, $9F62). From 2000 the high byte becomes $1F, which is not a decimal number: the panel shows a glyph from the word SCORE in the hundreds place, and the decimal countdown treats F as fifteen hundreds, so the hero has 600 more health than it should.

Below 100 there is nothing to borrow from. $00 less one is $FF, the routine never tests for it, and the clock counts down from $FF50 in decimal: 16,550 ticks, nearly six hours of play. In the emulator, a Warrior poisoned with 50 health had $FF $47 after the message, two stray glyphs on the panel, and $FF $07 forty ticks later, still in the game. Poison jugs appear on their own from level 8.

02 · Armour and fight power

Bug: the heroes' armour does nothing

The manual gives each hero an armour rating and sells a potion of extra armour. The game keeps the numbers, then never reads them.

What hitsHealth takenWhere
Grunt, demon, lobber or sorcerer's blow, by level 1 / 2 / 35 / 8 / 10monster_damage $C3F5
Ghost, by level10 / 20 / 30ghost_damage $C3FB
Demon's fireball10shot_hits_player $AC3E
Lobber's rock3shot_hits_player
Death's touch4, fifty timesdeath_drain $BC9B

The same for every hero. In the emulator a level-three grunt was put beside a standing player: in 187 attacks the game read monster_damage 93 times, on alternate attacks, and the six armour values not once. Health fell by 961: 93 blows of 10 and 31 ticks of the clock.

At the start of a game each player gets six damage values from its hero's table, and the armour potion replaces them with lower ones (power_apply, $9D10; damage_taken $9E49). No instruction in the program reads them. A Warrior with 20 % armour and a Wizard with none lose health at exactly the same rate.

Hand-to-hand is the same story. A blow takes $40 off a monster for any hero (fight_damage, $ACCA); the fight-power potion writes a stronger value one place along, at $ACCC, which nothing reads. The potion's other half, more power against generators (fight_power, $ACC8), does work.

03 · Idle timer

Bug: player two's blows keep the doors shut

Stop shooting and the game helps you out: after 30 seconds the doors open, and 150 seconds later every wall becomes an exit. A hand-to-hand blow puts the timer back too, but how far back depends on who struck it, not on how far the timer had got.

After a shot, shot_fire looks up the count to put back by the stage the timer has reached: 30 before the doors open, 150 after, and 255 once the walls are exits, when nothing counts any more ($A75E). After a blow that does not kill, fight_back loads the stage the same way and then looks the count up by the player's number instead ($C54E). Player one's blows always put back 30, and player two's always 150. A second player who fights rather than shoots keeps the doors shut five times as long, and once the doors are open, player one's blows bring the exits sooner than a shot would. In the emulator, the two routines left exactly those counts for each player at each stage.

04 · Left on the disk

Secret: a cable link from the developers' desk

Among the files the game loads is a small program that sends and receives memory through the user port, and nothing in the game calls it.

PINN232 loads at $1388, 5000 in decimal. SYS 5000 receives a block, SYS 5003 several, SYS 5006 sends one, a bit at a time on the user port with a handshake, the border changing colour with each byte (pinn_send_byte, $142A).

Loaded every game, never run. load_files ($9964) loads it with the music and graphics; no instruction in the game program jumps into it.

Its entry points take their numbers from a BASIC statement, so it was driven by hand from the BASIC prompt. It looks like the tool the programmers used to move code between machines while they worked, left in the load list when the game shipped. Beside it, the program carries the prompt "INSERT SIDE 2 OF DISK / THEN PRESS SPACE BAR / TO CONTINUE GAME" with code to wait for it ($A693), which nothing reaches either: every level is on side 1.