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
> 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
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
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
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.
There seems to be a missing line or so:
let handle_pull0 interpreter =
and store the result normally. *)
The top half of that comment got deleted somehow. Fixed. Thanks!