When is a bug not a bug?
Feb. 11th, 2026 03:05 amIn my last post, I asserted that it was not a bug that the cyclops did not fight. (Not according to the combat rules that govern the troll and the thief, anyway.) There was some Patreon and Discord discussion about that; I'm pulling it out into a new post.
(Is my blog going to just be a stream of Infocom trivia for the next two years? Maybe! I'm winging it here.)
Why doesn't the cyclops fight? Well, it's these lines of code:
<SET CNT 0>
<REPEAT ()
<SET CNT <+ .CNT 1>>
<COND (<EQUAL? .CNT .LEN>
<SET RES T>
<RETURN T>)>
<SET OO <GET ,VILLAINS .CNT>>
Translating to more familiar pseudocode:
CNT = 0
repeat {
CNT++
if (CNT == LEN) return
OO = VILLAINS[CNT]
// this monster attacks
}
The VILLAINS table is an LTABLE, meaning it starts with a length field (3). Then entry 1 is the troll, entry 2 is the thief, entry 3 is the cyclops. The loop exits as soon as CNT is 3, so the cyclops never attacks. Simple.
The interesting comparison is Mini-Zork. This was a cut-down Zork, meant either as a demo, a more approachable game, or a version that would run on a cassette-based C64 -- I'm not sure of the precise story.
(Mini-Zork was the first ZIL code to circulate publicly, earlier than the big Infocom source release of 2019. So it got a lot of scrutiny.)
The point is, Mini-Zork has essentially the same logic, except the cyclops has been removed from the VILLAINS table. (His combat responses have been removed as well.) So the table LEN is 2, and the thief never attacks. That is clearly a bug. And the buggy line is <EQUAL? .CNT .LEN>.
(<==? .CNT .LEN>, because this version of ZIL let you abbreviate the operator. Means the same thing though.)
So am I really saying that the same line of code is a bug in Mini-Zork but not a bug in Zork? Sure! A bug is when the code doesn't do what you want. Infocom manifestly wanted the thief to fight but not the cyclops.
What's happened here is that a developer (probably Lebling or Blank, but who knows) made what should have been a simple change: removing one entry from a table. The table length wasn't hard-wired; everything that relies on VILLAINS checks its length. So the change should have been safe, but whoops, it wasn't. It resulted in a bug in Mini-Zork.
That wasn't a bug in the original game. It's what we call "an accident waiting to happen", or a "booby-trap", or a rake or a footgun, or, you know, bad code. Different situation entirely.
(Not a criticism. All IF games are made of bad code. It's just the nature of the beast.)
Let's compare a different bug (non-bug?) which also popped up in Discord discussion.
The strange machine in the depths of the coal mine is defined this way:
<OBJECT MACHINE
(IN MACHINE-ROOM)
(SYNONYM MACHINE PDP10 DRYER LID)
(DESC "machine")
(FLAGS CONTBIT NDESCBIT TRYTAKEBIT)
(ACTION MACHINE-F)
(CAPACITY 50)>
You can refer to it as a MACHINE, or a DRYER (the description says it's "reminiscent of a clothes dryer"), or a LID (so that OPEN LID is a synonym for OPEN MACHINE). Or you can call it a PDP10. A PDP-10 doesn't look anything like a dryer (fridge, sure) but any Zork insider would be familiar with the thing. Both MIT Zork and Infocom's version were developed on PDP-10 hardware.
So, great in-joke. Except it doesn't work:
>examine dryer You can't see any dryer here!
>examine pdp10 I don't know the word "pdp10".
(Infocom's parser reports unknown words whether you've found the item in question or not. So you don't have to journey to the Machine Room to test this.)
Here's a how-de-do! What happened?
To answer this, we must dig into the ZIL dictionary format. These words (MACHINE, DRYER, etc) aren't stored in plain ASCII. They're compressed using the Z-machine's text compression scheme.
In short: a Z-machine character is five bits. A dict entry is exactly four bytes -- two 16-bit words -- with three characters packed into each 16-bit word. So that's a maximum of six characters. The last word has a "stop bit" (the sixteenth bit) indicating that it's the end of the string.
(Then there's three flag bytes at the end of the entry, but those aren't relevant here.)
The six-character limit is well-known. You can type EXAMIN LANTER and the game will accept it. What's not so obvious is that some symbols are more expensive. Five bits isn't enough to distinguish every typable character, after all. So digits and punctuation are actually multi-character sequences: a "shift" code followed by a shifted value.
So the word PDP10 gets encoded as the sequence P D P shift 1 shift 0, or:
10101 01001 10101 00101 01001 00101
P D P shift 1 shift
The final 0 gets cut off, because it's the seventh Z-character.
Like I said, lots of game words get truncated. What's different about this one? It's truncated in the middle of a multi-character sequence. Apparently Infocom's ZIL compiler gets confused by this and omits the stop bit! (Remember the stop bit?) And that confuses the parser, so the word can never be matched.
I looked through the game dictionary and found another example of a missing stop bit. (I wasn't the first to do this.)
<OBJECT DAM
(IN DAM-ROOM)
(SYNONYM DAM GATE GATES FCD\#3)
(DESC "dam")
(FLAGS NDESCBIT TRYTAKEBIT)
(ACTION DAM-FUNCTION)>
The backslash is just a source-code escape. This synonym word is supposed to be FCD#3 (Flood Control Dam #3), but again, the word is not recognized.
So the inevitable question: is this a bug? If so, where?
It could be an interpreter bug. After all, the text encoding spec I mentioned isn't an Infocom document. It came out of the IF community of the mid-90s, a time when we didn't have any Infocom documentation. Maybe the game is correct and my interpreter is wrong!
Well, we can check that. Fire up Zork 1 on the Apple 2!
Scratch that idea. My interpreter is behaving correctly, or "the same as Infocom's interpreter", anyhow.
At this point, I'd be happy to call this a bug -- an inferred bug in Infocom's compiler! But in fact we can observe a bit more evidence. Take a look at this object definition:
<OBJECT TREE
(IN LOCAL-GLOBALS)
(SYNONYM TREE BRANCH)
(ADJECTIVE LARGE STORM ;"-TOSSED")
(DESC "tree")
(FLAGS NDESCBIT CLIMBBIT)>
This is a scenery object found all over the outdoors. A couple of locations say "Storm-tossed trees block your way", so they threw in STORM as a synonym. But the -TOSSED part is commented out.
Why? We don't have source code from earlier Zork 1 releases. But we do have compiled game files, and several of them have the word STORM -- with a missing stop bit.
Clearly, this was compiled from the word STORM-TOSSED, and ran into the same compiler bug. But this time, the developers noticed. They figured out what was wrong, and commented out part of the word to avoid the problem. But they missed the parallel situations of PDP10 and FCD#3.
We can also compare Zork 1 release 119, a late development version (never released). This has all the stop bits where they should be. All the funny words work. So by 1988, Infocom had fixed the compiler bug.
Whew. I've either completely narcotized you or opened your eyes to the many dimensions of Infocom game file analysis. Tune in next time when I count every individual one of the 69105 leaves!
(This entry is cross-posted to the Patreon site.)













