Category Archives: Gruepal

Pretty much all the code I had before is now version 4 compliant. All the opcodes that deal with objects and their properties are now fully v1-8 compliant. What I’m mostly doing now is dealing with the screen manipulation that is common to version 4 and higher z-machines. Earlier games were written to pretty much print to the screen in a continuous fashion, whereas 4 and above could split the screen into two windows, print in column/row format, adjust height, font style, etc.

Implementing Multiple Windows

I’ve beefed up the output buffer quite a lot – instead of just being a place to dump text that’s shown on the screen, its now sectioned into multiple areas, such as the status bar for v1-3 games, or windows 0-7 for v4+ games. Each buffer has a raw area the game writes to, and a render area that combines the raw text with CSS code derived from style data from the game to be shown on the browser.

Gruepal can now handle screen differentiation between v1-3 and 4, handle multiple windows on the screen (both splitting and joining), clearing certain windows, and space-based positioning (which a lot of games use). A Mind Forever Voyaging is looking better and better, the next two steps are keeping track of where the screen goes into reverse mode and rendering that via css, then taking care of positioning when position opcodes are used.

Things are moving along, I haven’t found any further bugs when testing out version 3 games (I’m sure they’re there but things are looking fairly stable), so I’m calling Gruepal ready for people to pound away on for v1-3 games. Since my rented server is starting to get a little too big of a load, I found some cheap web hosting with fast processors and setup an account tonight. I will be installing Drupal on there and putting Gruepal builds on it for people to play around with within the next week.

With things looking good for versions 1-3, I wanted to start fleshing out v4-8 support before adding too many extra features – I want to ensure that the core of the engine is done, I may have to make a change that would affect extras and cause a lot of code rewrite.

Versions 4 and Up

I’ve starting working primarily on supporting version 4 stuff, but in the process it will fill in a lot of functionality required for versions 5-8 as well. I’m doing my version 4 work with “A Mind Forever Voyaging” – for two reasons. First, it’s a classic that I’ve heard great things about, and I haven’t had a chance to play it yet, so this will give me an opportunity. Also, it uses a lot of screen manipulation which I need to handle better anyway, so it’s a good game to work with.

Screen Manipulation

There are a lot of decisions I’ve had to make as far as screen manipulation since there isn’t really a screen in the classic sense – the game isn’t directly controlling what the user sees, its rendering to an output buffer which is printed in the user’s browser. Really, through the use of CSS it’s not too bad, I can recreate things – but I gave the user some functionality such as scrolling through the entire history of their game which isn’t part of the z-machine spec, so I need to balance that with things that don’t fit with that, e.g. a clear screen. Does it clear the whole history, or just put a lot of whitespace in so the screen being viewed is cleared, but the user can still scroll up? I’m thinking I’ll probably clear the whole buffer, as there may be times when the game simulates a control panel of some type and it wouldn’t make any sense to have previous renders of what the control panel had been showing in the output buffer.

Anyway, I’ve implemented enough version 4 code that A Mind Forever Voyaging doesn’t crash off the bat – it prints a lot of what it’s supposed to, but it definitely isn’t formatting the text right yet, and some of the text is wrong. My favorite is, instead of saying

“You have entered Communications Mode”

it says

“You have entered dinner.”

Definitely a lookup issue there.

I will post the info here when the testing area is ready to go for the v1-3 code though.

Fixed the Moonmist bug that printed out a strange character when putting your favorite color in. This ended up actually being a biggie with the way I was performing the SREAD opcode, which is the standard opcode that reads in text and does all the parsing/lexical table construction.

There are two buffers you have to fill in that the game expects in a certain format – the text buffer and the parse buffer. The text buffer basically contains a copy of what the user typed, and the parse buffer contains an entry for each word and symbol parsed, entries consisting of what index in the dictionary the word is, how long the word was, and where in the text buffer the word appears.

I had actually made two errors in SREAD which kind of canceled each other out, only not canceling each other out in Moonmist during the favorite color question. One, I had read version 5+ of the SREAD specification by accident, and was off by 1 byte in where I was writing to in the buffer. Everything still worked, because I was also off by one byte in my position calculations within the parse buffer. I fixed both those issues, and everything worked, including the Moonmist issue.

I’ve run into a few more infinite loop bugs in Moonmist, but most of the bugs are ironed out now. After I kill the Moonmist bugs, I’m going to try a few more games, and if things go smoothly, I want to start filling out the code for versions 4-8 of the zmachines, then get Gruepal online for some alpha/beta testing.

Just a quick update for those following along – I had a bug when running The Lurking Horror that would put the game into an endless loop upon pressing one of the buttons on the microwave.

The issue was an honest problem with one of my algorithms. Objects in z-machine games can have properties that tell the game things about them (things like descriptions and exits). Well, I wrote my code to assume that all objects have at least 1 property, when it truth they don’t necessarily, and it bit me in this case. The loop ran past where the object ended (since it was looking for properties where none existed), and general mayhem ensued. Fixed now. I can now cook things in the microwave.

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.

Unfortunately I came down with a nasty cold yesterday, but did manage to finish up the AJAX functionality tonight, including the ability for the page to redirect instead of displaying content (in the case of when the game is restarted/quit – in these cases the browser redirects to another URL which resets the game and sends the user back to the game description screen if they’re quitting).

Also, I implemented the status bar and got that working with both normal page refreshes and via AJAX. Additionally, the current room, score, and moves is now stored in the machine state database entry, which means that its possible to see where everyone online currently is and what the high scores are for all games.

Here’s a quick screenshot of a Zork I screen with status bar. You can see the beginnings of the save/load block as well, though more functionality and cleanup will be going into that.

Just a quick post, I have most the AJAX functionality done. I need to clean up a few little things like making sure the output window is always scrolled to the bottom, and handling when the page needs to redirect (in the case of game restarts/quits), but otherwise it works well.

Things have been a bit hectic lately – with the massive cooking and cleanup of Thanksgiving, and preparing for the TPUG WoC expo (and driving to and from Toronto to get there), I haven’t had a ton of time to do much coding. I did manage to slip in a couple hours last night and finished up the save/restore code.

It was actually pretty easy – what’s nice about DrupalZM is since it’s being driven from the web, it needs to save the state of the z-machine to the DB every page refresh. The save/restore code simply copies the current state of the machine to a save slot. Specifically, the table that stores the state of the zmachine now has a “slot” field associated with each record. Slot 0 indicates the current state, while slots 1-9 are saved games. Anytime a game is saved, DrupalZM simply copies the record in slot 0 to the desired slot, and restoring does vice versa.

I’m implementing a simple block to allow for easy saving/restoring. Classically one would type “save” or “restore” during gameplay, but typing these commands out in DrupalZM instructs the player to use the functionality in the block. The block will make saving/restoring much faster, plus an added bonus is the screen buffer is completely stored during the save process, so when a user restores a game, it shows them all the text on their screen exactly how it was at the time of saving.

To Do

Most of the zmachine is functional for versions 1-3 of zcode, but the following is still left to do (not necessarily in order of how I’ll tackle it):

1. Debug current issues (picking up “all” items seems to fail, zcharacter->ascii translator is still missing small bits of functionality, out of the 3 games I’ve tried, 2 work but 1 gets caught in an endless loop processing upon issuing the first command)
2. Finish all opcodes for versions 4-8 of the zmachine
3. Implement an AJAX interface
4. Finish the save/restore block
5. Implement room location/moves status bar (as well as exporting this with scores to be used elsewhere on site (e.g. location of currently logged in users, high scores per game, etc)
6. Experiment with extra functionality (quasi-multiplayer, automapping, integrating zmachine objects with drupal nodes/fields)

One more quick update – I figured that if Zork I worked so well all the way up to the Troll room, that I could try giving another Zmachine a whirl and see how far it got. I added a node for “The Lurking Horror”, one of my favorite Infocom games of all time. There was one opcode that it used to manually call for a refresh of the status line that I needed to add, but after that…..

You’ve waited until the last minute again. This time it’s the end of the term, so all the TechNet terminals in the dorm are occupied. So, off you go to the old Comp Center. Too bad it’s the worst storm of the winter (Murphy’s Law, right?), and you practically froze to death slogging over here from the dorm. Not to mention jumping at every shadow, what with all the recent disappearances. Time to find a free machine, get to work, and write that twenty page paper.

THE LURKING HORROR
An Interactive Horror
Copyright (c) 1987 by Infocom, Inc. All rights reserved.
THE LURKING HORROR is a trademark of Infocom, Inc.
Release 203 / Serial number 870506

Terminal Room
This is a large room crammed with computer terminals, small computers, and printers. An exit leads south. Banners, posters, and signs festoon the walls. Most of the tables are covered with waste paper, old pizza boxes, and empty Coke cans. There are usually a lot of people here, but tonight it’s almost deserted.

A really whiz-bang pc is right inside the door.

Nearby is one of those ugly molded plastic chairs.

Sitting at a terminal is a hacker whom you recognize.

>s
Second Floor
This is the second floor of the Computer Center. An elevator and call buttons are on the south side of the hallway. A large, noisy room is to the north. Stairs also lead up and down, for the energetic. To the west a corridor leads into a smaller room.

>w
Kitchen
This is a filthy kitchen. The exit is to the east. On the wall near a counter are a refrigerator and a microwave.

Sitting on the kitchen counter is a package of Funny Bones.

>open fridge
Opening the refrigerator reveals a two liter bottle of Classic Coke and a cardboard carton.

After fixing a dumb bitwise math bug and fixing a piece of the insert object logic (after removing an object, it wasn’t setting siblings correctly), things are looking pretty awesome. I would call the following a pretty successful test!

West of House
You are standing in an open field west of a white house, with a boarded front door.
There is a small mailbox here.

>n
North of House
You are facing the north side of a white house. There is no door here, and all the windows are boarded up. To the north a narrow path winds through the trees.

>e
Behind House
You are behind the white house. A path leads into the forest to the east. In one corner of the house there is a small window which is slightly ajar.

>open window
With great effort, you open the window far enough to allow entry.

>go in
Kitchen
You are in the kitchen of the white house. A table seems to have been used recently for the preparation of food. A passage leads to the west and a dark staircase can be seen leading upward. A dark chimney leads down and to the east is a small window which is open.
On the table is an elongated brown sack, smelling of hot peppers.
A bottle is sitting on the table.
The glass bottle contains:
A quantity of water

>take bottle
Taken.

>w
Living Room
You are in the living room. There is a doorway to the east, a wooden door with strange gothic lettering to the west, which appears to be nailed shut, a trophy case, and a large oriental rug in the center of the room.
Above the trophy case hangs an elvish sword of great antiquity.
A battery-powered brass lantern is on the trophy case.

>take lantern
Taken.

>move rug
With a great effort, the rug is moved to one side of the room, revealing the dusty cover of a closed trap door.

>open door
Which door do you mean, the wooden door or the trap door?

>trap
The door reluctantly opens to reveal a rickety staircase descending into darkness.

>i
You are carrying:
A brass lantern
A glass bottle
The glass bottle contains:
A quantity of water

>take sword
Taken.

>d
You have moved into a dark place.
The trap door crashes shut, and you hear someone barring it.

It is pitch black. You are likely to be eaten by a grue.
Your sword is glowing with a faint blue glow.

>turn on lantern
The brass lantern is now on.

Cellar
You are in a dark and damp cellar with a narrow passageway leading north, and a crawlway to the south. On the west is the bottom of a steep metal ramp which is unclimbable.

>n
The Troll Room
This is a small room with passages to the east and south and a forbidding hole leading west. Bloodstains and deep scratches (perhaps made by an axe) mar the walls.
A nasty-looking troll, brandishing a bloody axe, blocks all passages out of the room.
Your sword has begun to glow very brightly.
The troll swings; the blade turns on your armor but crashes broadside into your head.

>kill troll with sword
You are still recovering from that last blow, so your attack is ineffective.
The troll swings his axe, but it misses.

>g
You charge, but the troll jumps nimbly aside.
The axe sweeps past as you jump aside.

>g
The troll is staggered, and drops to his knees.
The troll slowly regains his feet.

>g
The fatal blow strikes the troll square in the heart: He dies.
Almost as soon as the troll breathes his last breath, a cloud of sinister black fog envelops him, and when the fog lifts, the carcass has disappeared.
Your sword is no longer glowing.

>score
Your score is 35 (total of 350 points), in 18 moves.
This gives you the rank of Amateur Adventurer.