First off, I’m renaming the DrupalZM module to the “Gruepal” module (ala Grue from Zork mixed with Drupal), thanks to Seth Cohn for the idea. Subsequent posts with be prefixed with Gruepal.
Also, a few bugs squashed, two of these took a while to track down, a lot of sloshing through zcode assembly –
Planetfall Endless Loop
While Planetfall would start fine, whenever I tried to do anything (move, look, wait, anything), the game would go into an endless loop. Upon tracing through an execution dump, I noticed that it kept comparing variables that were initialized from the random number opcode. For the loop to end, it needed to NOT match a range of numbers, but it was always matching, so the loop continued forever.
It turned out that the RANDOM z-machine opcode is inclusive in its range. I misread this originally, I thought if you specified an upper bound of, let’s say, 8, it would generate a random number from 1 to 7 (e.g. up to 8), which is the C programmer in me, everything is 0 based in an exclusive range (e.g. 8 would be 0-7). I did the see the part about it starting at 1, but not about including the upper bound of the range. In the Planetfall case, it was passing in an upper bound of 7, but I only generated 1-6, and the code was looking for a 7 to exit out of the loop, so it never did. I increased the range to be inclusive, and life was good. Which is good, because Planetfall rules, and I found myself playing quite a bit when I was supposed to be debugging. ๐
Take All Endless Loop
Another issue I noticed was in any game, when I typed “take all”, it would go into an endless loop. This was a REAL tricky one, because the loop wasn’t a tight one, it covered about 100 operations before looping. I nailed it down that the loop wasn’t exiting out when comparing the return value from a function that reported back the index number of the item number in the room to take (e.g. if there were 5 items, it would loop through 1 through 5, taking each item. But in my case, it would just get stuck on keep trying to take 2 over and over again because the iteration counter wasn’t increasing).
The reason is, there’s a little gotcha in the standard CALL opcode which, again, I did know about, but only implemented half of (by mistake). Normally a call statement is for calling a new subroutine – it saves all the information of the current call onto the stack, then (in my implementation’s case), creates a “call record” which has the return address once the subroutine exits and some other info.
Well, normally CALL has the address of the subroutine to set the PC to. However, there’s a gotcha that if its called with 0, it simply returns FALSE and doesn’t actually perform a call. This is to make certain operations in the game easier I imagine, when you need to dynamically call subroutines, and 0 indicates end of list – the false would stop the loop from going. Well, while I did return false, I unfortunately still overwrote part of the call record (which would happen if it was a normal call). But it overwrote the current call record instead of a new one, which could have caused any amount of havoc – in this case it just caused a loop. But I fixed that, and loop is gone.
Kill Me Bug
This one was easy. When I typed “kill me”, it would say “What do you want to kill the me?” instead of the correct “What do you want to kill the me with?” – e.g. it left the “with” out. Leaving words off I’m sure came up in other places, this was just how I found it. The issue is – there are a few opcodes that print to the screen, maybe 5 or so. 1 of them was passing the array with the output buffer by value instead of reference, so even though it was adding the word “with” to the output buffer, when the function exited that would be lost. Just a typo of one character, after adding a & for pass by reference, life was good. This was the bug I thought was having to do with zscii conversion, but it wasn’t!
New Found Bugs
A few more bugs to squash:
1. In lurking horror, using the buttons on the microwave puts the game into an endless loop. I have no idea what’s causing this yet without looking through an execution trace.
2. In Moonmist, when asking the user for their favorite color, it puts a weird symbol before the color repeated back to the user. I’m guessing this is a zscii/zchar issue.
Fun fun!