Reverse Engineering Sierra's Adventure Game Interpreter - Part 4

13th June 2020 | Programming

One of the most derided and cringe-worthy lines squawked by Cedric the Owl in King's Quest 5 was "Graham, watch out! A poisonous snake!" However, this was not the first time that a King's Quest game misused the term "poisonous" to describe a "venomous" snake. In King's Quest 2, a "poisonous viper" is obstructing King Graham from obtaining one of the golden keys. I thought it would be fun to hack the game and actually make the snake "poisonous".

Using AGI Studio, I opened up the 56th LOGIC file, which is the source code for the screen on the plateau with the snake. I first started by making a small change to the initial message to mirror Cedric's warning:

if (!isset(f108) &&
  !isset(f109) &&
  !isset(f110)) {
  print("Watch out! A poisonous snake!");
}

A poisonous snake would only be lethal if consumed, especially if it secreted a toxic substance which would be deadly to intrepid adventurers. Instead of letting the snake get a taste Graham, let's let Graham get in his own "licks". Since the Sierra games of the 80s were parser-driven, there is a dictionary of words that the game understands. In King's Quest 2, there are up to 255 word groups. Each word group can contain multiple terms which are similar in meaning. A person might type "get rock" or "take stone", and the game would (or should) understand that both phrases mean the same thing.

Once again, using AGI Studio, I opened up the WORDS.TOK file (where all of the tokenized words reside), and searched for the word "eat". It initially found the phrase "leather bridle", which does contain the string "eat", but not quite what I was originally looking for. Continuing the search brought up the "consuming" word group which contained the words "consume", "eat", and "taste". I then added the extra word "lick" to this group and saved the changes to WORD.TOK. Now the game will understand the word "lick".

The final piece of this playful hack is to add the code to allow Graham to lick the "poisonous" snake. At line 10, add the lines:

load.view(92);
load.view(91);

This code pre-loads the two views #92 and #91, which are Graham's choking animation and his death sprite, respectively. Next, at line 85 in the file logic.056 I added the following code.



if (said("consume","snake")) {
  if (isset(f31)) {
    print("You bend over and lick the poisonous snake.");
    set(f147);
    get.posn(o0,v67,v68);
    if (v68 < 45) {
      v67 = 0;
      v68 = 5;
      reposition(o0,v67,v68);
    }
    program.control();
    set(f92);
    set.view(o0,92);
    v94 = 3;
    cycle.time(o0,v94);
    end.of.loop(o0,f93);
  }
}

if (isset(f93)) {
  set.priority(o0,15);
  set.view(o0,91);
  set(f50);
}

There are two parts to this chunk of code. The first part checks to see if the player typed in some variant of "consume snake" such as "lick snake", "eat viper", "taste snake", etc. When this happens, the game then loads in view #92 to display Graham choking after licking the poisonous snake. Once the animation completes, flag f93 is set. After the game interpreter loops again through the script, it will come across the second part of this code snippet since the f93 flag has been set. Graham's character is then swapped from the choking animation to the death sprite (View #91). Finally flag f50 is set, which triggers the death sequence.

Happy hacking and watch out for those "poisonous" snakes!

References