Shaft room

In the middle this room a small shaft descends into darkness below. Above the shaft is a metal framework to which a heavy iron chain is attached. There are exits to the west and north. A foul odor can be detected from the latter direction.
From the chain is suspended a basket.

> put the torch and the screwdriver in the basket

torch: Done.
screwdriver: Done.

> turn on the lamp

The brass lantern is now on.

> go north


Another minor bug; the text should be “middle of this room”.

Code for this episode can be found in https://github.com/ericlippert/flathead/tree/blog16.

Last time we said that we were going to implement load, store, pull, inc, dec, inc_chk and dec_chk. We have all the parts we need to do so.

The easiest is load, which takes a single operand, decodes it as a variable, reads the variable value in-place, and then stores it:

let handle_load variable interpreter =
  let variable = Instruction.decode_variable variable in
  read_variable_in_place interpreter variable

Of course our helper method does the store; here we just produce the value. This is side-effect free.

The corresponding write instruction is store:

let handle_store variable value interpreter =
  let variable = Instruction.decode_variable variable in
  write_variable_in_place interpreter variable value

And the corresponding stack-handling instruction is pull. In all versions but 6 it takes a value off the stack, actually popping it, and then stores the value in the given variable in-place. In version 6 there are two forms of the operator; the simple one simply pops and stores. The more complex one I have not yet implemented; we might come back to it later.

I note that this instruction is useful both for its value, in v6, and its side effect in all versions, so I have this one return both the interpreter and the value.

let handle_pull1 x interpreter =
  if (Story.version interpreter.story) = V6 then
    failwith "TODO: user stack pull not yet implemented"
  else
    let variable = Instruction.decode_variable x in
    let value = peek_stack interpreter in
    let popped_interpreter = pop_stack interpreter in
    let store_interpreter = write_variable_in_place popped_interpreter variable value in
    (0, store_interpreter)

let handle_pull0 interpreter =
  (* In version 6 if the operand is omitted then we simply pop the stack
  and store the result normally. *)
  let result = peek_stack interpreter in
  let popped_interpreter = pop_stack interpreter in
  (result, popped_interpreter)

There are two increment and two decrement instructions. The simple ones increment or decrement a variable in-place:

let handle_inc variable interpreter =
  let variable = Instruction.decode_variable variable in
  let original = read_variable_in_place interpreter variable in
  let incremented = original + 1 in
  write_variable_in_place interpreter variable incremented

I sha’n’t bother to show the decrement version; it’s pretty obvious.

There is a more complex version of the increment instruction which takes another operand. This is one of those instructions that is useful both for its side effect and its value: it increments the variable, then compares the new value to a given value. If the new value is now greater than the given value, then the result is 1; otherwise it is 0. This is a branch instruction. You can see how this would be useful; it is basically a one-instruction “for” loop:

let handle_inc_chk variable value interpreter =
  let variable = Instruction.decode_variable variable in
  let value = signed_word value in
  let original = read_variable_in_place interpreter variable in
  let original = signed_word original in
  let incremented = signed_word (original + 1) in
  let write_interpreter = write_variable_in_place interpreter variable incremented in
  let result = if incremented > value then 1 else 0 in
  (result, write_interpreter)

Again, I’ll skip the decrement.

If we run our interpreter now we get through four more instructions before crashing on insert_obj.

37f7: store g00 2e
37fa: store g7a a7
37fd: store g26 01
3800: store g73 1e
3803: insert_obj g73 g00

If you go back several episodes to where we decoded the object table, you’ll see that we are putting the object code for “West of house” into g00 which will be the current location when the game starts.

The code for “small mailbox” is put into g7a. I believe this is where the game stores the current meaning of “it”. If you say “open it” right after the game says “there is a small mailbox here”, it resolves “it” to the mailbox.

I’m not sure what’s up with g26; I think it has something to do with tracking whether the current location is lit. “West of house” is outdoors, and so is lit.

g73 gets 1e, which is the object code for the player, and then we insert the player, whose code is stored in g73, into room “West of house”, whose code is stored in g00. Plainly we are setting up the initial game state here.

Next time on FAIC: we’ll talk about the object manipulation instructions.

2 thoughts on “Shaft room

  1. There seems to be a missing line or so:
    let handle_pull0 interpreter =
    and store the result normally. *)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s