RSS

New Tricks for an Old Z-Machine, Part 3: A Renaissance is Nigh

22 Nov

In 1397, a Byzantine scholar named Manuel Chrysoloras arrived in Florence, Italy. He brought with him knowledge of Greek, along with many ancient manuscripts in Greek and Latin that had been lost to the West in the chaos following the collapse of the Roman Empire. This event is considered by many historians to mark the first stirrings of the Italian Renaissance, and with them the beginning of the epoch of scientific, material, and social Progress which has persisted right up to the present day.

In 1993, an Oxford graduate student named Graham Nelson released a text adventure called Curses that, among other things, functioned as an advertisement for a programming language he called Inform, which targeted Infocom’s old Z-Machine. This event is considered by most of us who have seriously thought about the history of text adventures in the post-Infocom era to mark the first stirrings of the Interactive Fiction Renaissance, and with them the beginning of an interactive-fiction community that remains as artistically vibrant as ever today.

Yes, I can see you rolling your eyes at the foregoing. On one level, it is indeed an unbearably pretentious formulation, this comparing of one of the most earthshaking events in human culture writ large with the activities of a small community of niche enthusiasts. Yet, if we can agree to set aside the differences in scale and importance for the moment, the analogy really is a surprisingly apt one. Like the greater Renaissance in Europe, the Interactive Fiction Renaissance prepared a group of people to begin moving forward again by resurfacing old things that had been presumed lost forever. Taking pride of place among those things, being inextricably bound up with everything that followed, was the Z-Machine, functioning first as a means of running Infocom’s classic games, as we saw in the first article in this series; and then as a means of running new games, as we began to see in the second article and will examine in still more detail today.


As Graham Nelson began to pursue the dream of writing new software to run on Infocom’s old virtual machine, he had no access to the refined tools Infocom had used for that task. Thus he was forced to start from nothing — from what amounted to a bare chunk of (virtual) computing hardware, with no compilers or any other software helpers to aid his efforts. He had to start, in other words, at the bare metal, working in assembly language.

Assembly language is the lowest level at which any computer, whether real or virtual, can be (semi-)practically programmed. Its statements correspond to the individual opcodes of the processor itself, which normally encompass only the most granular of commands: add, subtract, multiply, or divide these numbers together; grab the number from this local register and put it into that memory location; etc. Assembly language is the primordial language which underpins everything, the one which must be utilized first to write the compilers that allow programmers to develop software in less granular, more structured, more human-friendly languages such as C, Pascal, and BASIC.

Already at this level, however, the Z-Machine separates itself from an ordinary computer. Alongside the rudimentary, granular opcodes that are common to any Turing-complete computer, it implements other opcodes that are absurdly baroque. The “read” opcode, for example, does all of the work of accepting a full line of text from the keyboard, then separating out its individual words and “tokenizing” them: i.e., looking them up in a dictionary table stored at a defined location in the virtual machine’s memory and converting them into the codes listed there. Another opcode, “save,” simply orders the interpreter to save the current state of the machine to disk, however it prefers to go about it; ditto the “restore” opcode. These complex and highly specialized opcodes exist because the Z-Machine, while it is indeed a Turing-complete, fully programmable anything machine in the abstract, is nevertheless heavily optimized toward the practical needs of text adventures. Thus an object table meant to represent rooms and things in the world of a game is hard-coded right into its memory map, and there are other single opcodes which encapsulate relatively complex tasks like looking up or changing the properties of an object in the world, or moving one object into another object.

Strictly speaking, none of this is really necessary; the Z-Machine is far more complicated than it needs to be in abstract terms. Infocom could have created a robust virtual machine which implemented only traditional low-level opcodes, building everything else out in the form of software libraries running on said virtual machine. But they had a strong motivation for hard-coding so many of the needs of a text adventure right into the virtual hardware: efficiency. A baroque opcode like “read” meant that all of the many steps and stages which went into accepting the player’s command could take place at the interpreter level, running natively on the host computer. Implementing a virtual machine of any sort was a serious challenge on a 1 MHz 8-bit computer like an Apple II or Commodore 64; Infocom needed every advantage they could get.

By the time of Graham Nelson’s experimentation with the Z-Machine, most of the concerns that had led Infocom to design it in this way had already fallen by the wayside. The average computer of the early 1990s would have been perfectly capable of running text adventures through a simpler and more generic virtual machine where the vagaries of the specific application were implemented in software. Nevertheless, the Z-Machine was the technology Graham had inherited and the one he was determined to utilize. When he began to work on Inform, he tailored it to the assumptions and affordances of the Z-Machine. The result was a high-level programming language with an unusual degree of correspondence to its underlying (virtual) hardware. Most obviously, the earliest versions of Inform couldn’t make games whose total compiled size exceeded 128 K, the limit for the version 3 Z-Machine they targeted. (This figure would be raised to 256 K once Inform began to target the version 4 and 5 Z-Machine.)

Yet this limitation was only the tip of the iceberg. Each function in Inform was limited to a maximum of 15 local variables because that was all that the stack mechanism built into the Z-Machine allowed. Meanwhile only 240 global variables could exist because that was the maximum length of the table of same hard-coded into the Z-Machine’s memory map. Much of Inform came to revolve around the Z-Machine’s similarly hard-coded object table, which was limited to just 255 objects in version 3 of the virtual machine. (This limitation was raised to 65,535 objects in the version 4 and 5 Z-Machine, thereby becoming in practice a non-issue.) Further, each object could have just 32 attributes, or states of being — its weight, its open or closed status, its lit or unlit status, etc. — because that was all that was allowed by the Z-Machine’s standard object table. (Starting with version 4 of the Z-Machine, objects could have up to 48 attributes.) All of the dynamic data in a game — i.e., data that could change during play, as opposed to static data like code and text strings — had to fit into the first 64 K of the story file, an artifact of the Z-Machine’s implementation of virtual memory, which had allowed it to pack 128 K or more of game into computers with far less physical memory than that. This limitation too was inherited by Inform despite the fact that by the early 1990s the virtual-memory system had become superfluous, a mere phantom limb which Inform nevertheless had to accept as part of the bargain with the past which it had struck.

Indeed, having been confronted with so many undeniable disadvantages arising from the use of the Z-Machine, it’s natural for us to ask what actual advantages accrued from the use of a fifteen-year-old virtual machine designed around the restrictions of long-obsolete computers, as opposed to taking the TADS route of designing a brand new virtual machine better suited to the modern world. One obvious answer is portability. By the early 1990s, several different open-source Z-Machine interpreters already existed, which between them had already been ported to virtually every computing platform in the world with any active user base at all. Any Inform game that Graham Nelson or anyone else chose to write would become instantly playable on all of these computers, whose combined numbers far exceeded those to which Mike Roberts, working virtually alone on TADS, had so far managed to port his interpreter. (The only really robust platform for running TADS games at the time was MS-DOS; even the Macintosh interpreters were dogged by bugs and infelicities. And as for Graham’s favored platform, the British-to-the-core Acorn Archimedes… forget about it.)

In reality, though, Inform’s use of the Z-Machine appealed at least as much to the emotions as to technical or practical considerations. The idea of writing new games to run on Infocom’s old virtual machine had a romantic and symbolic allure that many found all but irresistible. What better place to build a Renaissance than on the very foundations left behind by the storied ancients? Many or most of the people who came to use Inform did so because they wanted to feel like the heirs to Infocom’s legacy. Poor TADS never had a chance against that appeal to naked sentimentality.

Even as Inform was first gaining traction, it was widely known that Infocom had had a programming language of their own for the Z-Machine, which they had called ZIL: the “Zork Implementation Language.” Yet no one outside of Infocom had ever seen any actual ZIL code. How closely did Inform, a language that, like ZIL, was designed around the affordances and constraints of the Z-Machine, resemble its older sibling? It wasn’t until some years after Inform had kick-started the Interactive Fiction Renaissance that enough ZIL code was recovered to give a reasonable basis for comparison. The answer, we now know, is that Inform resembles ZIL not at all in terms of syntax. Indeed, the two make for a fascinating case study in how different minds, working on the same problem and equipped with pretty much the same set of tools for doing so, can arrive at radically different solutions.

As I described in an article long ago, ZIL was essentially a subset of the general-purpose programming language MDL, which was used heavily during the 1970s by the Dynamic Modeling Group at MIT, the cradle from which Infocom sprang. (MDL was itself a variant of LISP, for many years the language of choice among artificial-intelligence researchers.) A bare-bones implementation of the famous brass lantern in Zork I looked like this in ZIL:

<OBJECT LANTERN 
           (LOC LIVING-ROOM) 
           (SYNONYM LAMP LANTERN LIGHT) 
           (ADJECTIVE BRASS) 
           (DESC "brass lantern") 
           (FLAGS TAKEBIT LIGHTBIT) 
           (ACTION LANTERN-F) 
           (FDESC "A battery-powered lantern is on the trophy 
             case.") 
           (LDESC "There is a brass lantern (battery-powered) 
             here.") 
           (SIZE 15)>


Inform has a fairly idiosyncratic syntax, but most resembles C, a language which was initially most popular among Unix systems programmers, but which was becoming by the early 1990s the language of choice for serious software of many stripes running under many different operating systems. The same lantern would look something like this in a bare-bones Inform implementation:

Object -> lantern "brass lantern"
  with name 'lamp' 'lantern' 'light' 'brass',
    initial
      "A battery-powered lantern is on the trophy case.",
    description
      "There is a brass lantern (battery-powered) here.",
  after [;
    SwitchOn:
      give self light;
      StartDaemon(self);
    SwitchOff:
      give self ~light;
  ],
  size 15,
  has switchable;


After enough information about ZIL finally emerged to allow comparisons like the above, many Infocom zealots couldn’t help but feel a little disappointed about how poorly Infocom’s language actually fared in contrast to Graham Nelson’s. Having been designed when the gospel of object-oriented programming was still in its infancy, ZIL, while remarkable for embracing object-oriented principles to the extent it does, utilizes them in a slightly sketchy way, via pointers to functions which have to be defined elsewhere in the code. (This is the purpose of the “ACTION LANTERN-F” statement in the ZIL code above — to serve as a pointer to the routine that should run when the player tries to light the lantern.) Inform, on the other hand, allows all of the code and data associated with an object such as the brass lantern to be neatly encapsulated into its description. (The “SwitchOn” and “SwitchOff” statements in the Inform excerpt above explain what should happen when the player tries to light or extinguish the lantern.) A complete implementation of the Zork I lantern in Inform would probably fill a dozen or more lines than what we see above, monitoring the charge of the battery, allowing the player to swap in a new battery, etc. — all neatly organized in one chunk of code. In ZIL, it would be scattered all over the place, wired together via a confusing network of pointers. In terms of readability alone, then, Inform excels in comparison to ZIL.

Most shockingly of all given the Infocom principals’ strong grounding in computer science, they never developed a standard library for ZIL — i.e., a standardized body of code to take care of the details that most text adventures have in common, such as rooms and compass directions, inventory and light sources, as well as the vagaries of parsing the player’s commands and keeping score. Instead the author of each new game began by cannibalizing some of the code to do these things from whatever previous game was deemed to be most like this latest one. From there, the author simply improvised. The Inform standard library, by contrast, was full-featured, rigorous, and exacting by the time the language reached maturity — in many ways a more impressive achievement than the actual programming language which undergirded it.

Because it was coded so much more efficiently than Infocom’s ad-hoc efforts, this standard library allowed an Inform game to pack notably more content into a given number of kilobytes. The early versions of Curses, for example, were already sprawling games by most standards, yet fit inside the 128 K Z-Machine. Later versions did move to, and eventually all but fill, the version 5 Z-Machine with its 256 K memory map. Still, the final Curses offers vastly more content than anything Infocom ever released, with the possible exception only of Zork Zero (a game which was itself designed for a version 6 Z-Machine that took the ceiling to 512 K). Certainly any comparison of A Mind Forever Voyaging and Trinity — both famously big games with a story-file size pegged to the version 4 and 5 limit of 256 K — to the final version of Curses — story-file size: 253 K — must reveal the last to be an even more complex, even more expansive experience.

So, the Inform development system could hold its head up proudly next to ZIL; in fact, it was so well-thought-through that ZIL would thoroughly disappoint by comparison once hobbyists finally learned more about it. But what of Curses itself, the game with which Inform was so indelibly linked during the first few years of its existence? Was it also up to the Infocom standard?



Before delving into that question in earnest, I should perhaps elaborate a bit on Graham Nelson’s own description of Curses from the previous article.

In the game, then, you play the role of a rather hapless scion of a faded aristocratic family. Aristocratic life not being what it once was, you’ve long since been forced to register the familial mansion with the National Trust and open it up to visitors on the weekends in order to pay the bills. As the game proper begins, your family is about to take a jaunt to Paris, and you’ve come up to the attic — a place in as shabby a state as the rest of the house — to look for a tourist map you just know is lying around up here somewhere.

It's become a matter of pride now not to give up. That tourist map of Paris must be up here somewhere in all this clutter, even if it has been five years since your last trip. And it's your own fault. It looks as if your great-grandfather was the last person to tidy up these lofts...

Attic
The attics, full of low beams and awkward angles, begin here in a relatively tidy area which extends north, south and east. The wooden floorboards seem fairly sound, just as well considering how heavy all these teachests are. But the old wiring went years ago, and there's no electric light.


A hinged trapdoor in the floor stands open, and light streams in from below.

In the best tradition of shaggy-dog stories, your search for the map turns into an extended adventure through space and time. You just keep finding more and more secret areas and secret things in the attics and the grounds surrounding the house, including a disconcerting number of portals to other times and places. The whole thing eventually comes to revolve around an ancient familial curse reaching back to the time of Stonehenge. If you manage to get to the end of the game — no small feat, believe me! — you can finally lift the curse. And, yes, you can finally find the bloody Paris tourist map.

It’s hard to know where to start or end any discussion of Curses. It’s one of those works that sends one off on many tangents: its technology, its historical importance, its literary worth as a writing exercise or its ludic worth as an exercise in design. Faced with this confusion, we might as well start with what Curses has meant to me.

For Curses is indeed a game which carries a lot of personal importance for me. I first discovered it about four or five years after its original release, when I was working a painfully dull job as a night-shift system administrator — a job which paid not so much for what I did each night as for my just being there if something should go wrong. I had, in other words, copious amounts of free time on my hands. I used some of it playing a bunch of post-Infocom text adventures which I hadn’t previously realized existed. Because they looked — or could be made to look — like just another scrolling terminal window, they suited my purposes perfectly. Thus my memory of many a 1990s classic is bound up with those nights in a deserted data center — with the strange rhythm of being awake when everyone else is asleep, and vice versa.

Of all the games I played during that time, Curses made one of the greatest impressions on me. I was still young enough then to be profoundly impressionable in general, and I found its casual erudition, its willingness to blend science with poetry, mathematics with history, to be absolutely entrancing. Having been a hopeless Anglophile ever since I first heard a Beatles record at circa six years old, I was well-primed to fall in love with Graham Nelson’s dryly ironic and oh-so-English diction. In fact, as I began to write more seriously and extensively myself in the years that followed, I shamelessly co-opted some of his style as my own. I like to think that I’ve become my own writer in the time since that formative period, but some piece of Graham is undoubtedly still hiding out down there somewhere in the mishmash of little ticks and techniques that constitute my writer’s voice.

For all that Curses entranced me, however, I never came close to completing it. At some point I’d get bogged down by its combinatorial explosion of puzzles and places, by its long chains of dependencies where a single missed or misplaced link would lock me out of victory without my realizing it, and I’d drift away to something else. Eventually, I just stopped coming back altogether.

I was therefore curious and maybe even slightly trepiditious to revisit Curses for this article some two decades after I last attempted to play it. How would it hold up? The answer is, better than I feared but somewhat worse than I might have hoped.

The design certainly shows its age. I have less patience than ever today for walking-dead scenarios that are as easy to stumble into as they are here. I wholeheartedly agree with Graham’s own statement that “Curses is by any reasonable standard too hard.”

So far, so expected. But I was somewhat more surprised by my crotchety middle-aged take on the writing. Mind you, some aspects of it still bring a smile to my face; I still can’t resist saying, “It’s a wrench, but I’ll take it,” every time I pick up a wrench in real life, much to my wife’s disgust. (Luckily, as she’d be the first to point out, I’m not much of a handyman, so I don’t tend to pick up too many of them.) In other places, though, what used to strike me as delightful now seems just a little bit too precious for its own good. I can still recognize the influence it had over me and my own writing, but it does feel at times like an influence I’ve ever so slightly outgrown. Today, things like the game’s quotation of the lovely Dorothy Parker poem “Inventory” — “Four be the things I’d been better without: Love, curiosity, freckles, and doubt.” — when you first type the command of the same name can feel just a little bit facile. Curses is constantly making cultural cross-connections like these, but they’re ultimately more clever than they are profound. It’s a game packed with a lot of cultural stuff, but not one with much to really say about any of it. It instead treats its cultural name-dropping as an end unto itself.

Curses strikes me as a young man’s game, in spite of its showy erudition — or perhaps because of it. It was written by a prodigious young man in that wonderful time of life when the whole world of the intellect — all of it — is fresh and new and exciting, when unexpected pathways of intellectual discovery seem to be opening up everywhere one looks. In this light, Emily Short’s description of it as a game about the sheer joy of cultural discovery rings decidedly true. Graham himself recognizes that he could never hope to write a game like it today; thus his wise decision not to return to the well for a sequel.

But to fairly evaluate Curses, we need to understand its place in the timeline of interactive fiction as well as in the life of the man who created it. It’s often billed — not least by myself, in this very article’s introduction — as the game which kicked off the Interactive Fiction Renaissance, the first of a new breed which didn’t have to settle for being the next best thing to more Infocom games. It was the first hobbyist game which could stand proudly shoulder to shoulder with the best works of Infocom in terms of both technical and literary quality.

On the face of it, this is a fair evaluation — which is, after all, the reason I’ve deployed it. Yet the fact remains that Curses‘s mode of production and overall design aesthetic mark it as a distinctly different beast from the best later works of the Renaissance it heralded. While the games of Infocom certainly were an influence on it, they weren’t the only influence. Indeed, their influence was perhaps less marked in reality than one might imagine from the game’s intimate connection to the Z-Machine, or from its borrowing of some fairly superficial aesthetic elements from Infocom, such as the letterboxed literary quotations which were first employed to such good effect by Trinity. While Curses‘s technology and its prose were unquestionably up to the Infocom standard, in spirit it verged on something else entirely.

In the beginning — the very beginning — text adventures were written on big institutional computers by unabashed eggheads for a very small audience of other eggheads. Games of this type were expected to be hard; questions of fairness rarely even entered the conversation. For these games weren’t just designed for single eggheads to play and conquer — they were rather designed for entire teams of same; adventure gaming in these early days was regarded as a group activity. These games were made publicly available while still works-in-progress; their mode of production bore an ironic resemblance to modern attitudes about “software as a service,” as manifested in modern gaming in things like the Steam Early Access program. In fact, these text-adventures-as-a-service tended not to ever really get finished by their designers; they simply stopped growing one day when their designers left the institution where they lived or simply got bored with them. Graham Nelson was exposed to this tradition early on, via his first encounters with the Crowther and Woods Adventure. (Remember his telling reminiscence: “It seemed like something you were exploring, not something you were trying to win.”) When he came to Cambridge in 1987, he was immersed in a sustained late flowering of this design aesthetic, in the form of the text adventures made for the Phoenix mainframe there.

This attitude cut against the one which Infocom had long since come to embrace by the time Graham arrived at Cambridge: the notion that text adventures should be interactive fictions, soluble by any single player of reasonable intelligence in a reasonable amount of time. As the name “interactive fiction” would imply, Infocom adopted a fundamentally literary mode of production: a game was written, went through lots of internal testing to arrive at some consciously complete state, and then and only then was sent out into the world as the final, definitive work. Infocom might release subsequent versions to fix bugs and incongruities that had slipped through testing, just as the text of a book might receive some additional correcting and polishing between print runs, but Infocom’s games were never dramatically expanded or overhauled after their release. Post-Curses, the hobbyist interactive-fiction community would embrace this Infocom model of production almost exclusively. In fact, a game released “before its time,” still riddled with bugs and sketchily written and implemented, would attract the most scathing of rebukes, and could damage the reputation of its author to the point that she would have a hard time getting anyone to even look at a subsequent game.

Yet Curses was anything but an exemplar of this allegedly enlightened interactive-fiction production function. Graham Nelson’s game grew up in public like the institutional games of yore, being expanded and improved in six major stages, with more than two years elapsing from its first release to its last. Betwixt and between them, Graham shared yet more versions on a more private basis, both among his local peer group and among the burgeoning community of Curses superfans on the Internet. As each new version appeared, these armies of players would jump into it to find the new puzzles and give their feedback on what else might be added to or improved, just as an army of MIT students once did every time the people who would eventually found Infocom put up a new build of the PDP-10 Zork. There are, for example, seven separate ways to solve an early puzzle involving the opening of a stubborn medicine bottle in the final version of Curses, most of them the result of player suggestions.

So, Curses should be understood as an ongoing creative effort — almost, one might say, a collaboration between Graham Nelson and his players — that grew as big as it could and then stopped. A scrupulous commitment to fairness just wasn’t ever in the cards, any more than a rigorously pre-planned plot line. In a telling anecdote, Graham once let slip that he was surprised how many people had finished Curses at all over the years. It was designed, like his beloved Crowther and Woods Adventure, to be a place which you came back to again and again, exploring new nooks and crannies as the fancy took you. If you actually wanted to solve the thing… well, you’d probably need to get yourself a group for that. Even the hint system, grudgingly added in one of the later versions, is oblique; many of the hints come from a devil who tells you the exact opposite of what you ought to be doing. And all of the hints are obscure, and you’re only allowed three of them in any given session.

All of which is to say that, even as it heralded a new era in interactive fiction which would prove every bit as exciting as what had come before, Curses became the last great public world implemented as a single-player text adventure. It’s an archetypal Renaissance work, perched happily on the crossroads between past and future. Its shared debt to the institutional tradition that had stamped so much of interactive fiction’s past and to the Infocom approach that would dictate its future is made most explicit in the name of the language which Graham developed alongside the game. As he told us in the previous article in this series, the first syllable of “Inform” does indeed refer to Infocom, but the second syllable reflects the habit among users of the Cambridge Phoenix mainframe of appending the suffix “-form” to the name of any compiler.

Speaking of Inform: Curses also needs to be understood in light of its most obvious practical purpose at the time of its creation. Most new text-adventure creation systems, reaching all the way back to the time of Scott Adams, have been developed alongside the first game to be written using them. As we’ve seen at some length now in this article and the previous one, Inform was no exception. As Graham would add new features to his language, he would finds ways to utilize them in Curses in order to test them out for himself and demonstrate them to the public. So, just as Inform reflects the Z-Machine’s core capabilities, Curses reflects Inform’s — all of them. And because Inform was designed to be a powerful, complete system capable of producing games equal in technical quality to those of Infocom or anyone else, the puzzles which found their way into Curses became dizzying in their sheer multifariousness. Anything ZIL could do, Graham was not so subtly implying, Inform could do as well or better.

Here, then, the Infocom influence on Curses is much more pronounced. You can almost go through the Infocom catalog game by game, looking at the unique new interactive possibilities each release implemented and then finding a demonstration somewhere in Curses of Inform’s ability to do the same thing. Zork II introduced a robot to which the player’s avatar could issue verbal commands, so Curses does the same thing with a robot mouse; Enchanter had an underground maze whose interconnections the player could alter dynamically, so Curses has a hedge maze which let its player do the same thing; Infidel drew hieroglyphic symbols on the screen using groups of ASCII characters, so Curses has to demonstrate the same capability; etc., etc. (One of the few Infocom affordances that doesn’t show up anywhere in Curses is a detailed spell-casting system, the linchpin of the beloved Enchanter trilogy — but never fear, Graham wrote an entirely separate game just to demonstrate Inform’s capabilities in that area.) If all this doesn’t always do much for the game’s internal coherence, so be it: there were other motivations at work.



Graham Nelson’s own story of the first release of Curses is stamped with the unassuming personality of the man. On May 9, 1993, he uploaded it to an FTP site connected with the Gesellschaft für Mathematik und Datenverarbeitung — a research institute in Bonn, Germany, where a friendly system administrator named Volker Blasius had started an archive for all things interactive fiction. He then wrote up a modest announcement, and posted it to the Usenet newsgroup rec.arts.int-fiction — a group originally set up by stuffy academic hypertext enthusiasts of the Eastgate stripe, which had since been rudely invaded and repurposed by unwashed masses of text-adventure enthusiasts. After doing these things, Graham heard…nothing. Feeling a little disappointed, but realizing that he had after all written a game in a genre whose best days seemed to be behind it, he went about his business — only to discover some days later that his incoming Usenet feed was bollixed. When he got it fixed, he found that his little game had in fact prompted a deluge of excitement. No one had ever seen anything like it. Just where had this mysterious new game that somehow ran on Infocom’s own Z-Machine come from? And where on earth had its equally mysterious author gone to after releasing it?

It really is hard to overstate the impact which Curses, and shortly after it Inform, had on the interactive-fiction community of 1993. Text adventures at that time were largely an exercise in nostalgia; even all of the work that had been done to understand the Z-Machine and make new interpreters for it, which had been such a necessary prerequisite for Graham’s own work, had been done strictly to let people play the old games. While some people were still making new games, none of them could comprehensively stand up next to Infocom at their best. Yes, some of them evinced considerable creativity, even a degree of real literary ambition, but these were held back by the limitations of AGT, the most popular text-adventure development system at the time. Meanwhile Adventions, the makers of the most polished games of this period, who were wise enough to use the technically excellent TADS rather than the more ramshackle AGT, were more competent than inspired in churning out slavish homages to Zork. All of the absolute best text adventures, the ones which combined literary excellence and technical quality, were still those of Infocom, and were all more than half a decade old.

And then along came Curses as a bolt out of the blue. Even if we wish to argue that some aspects of it haven’t aged terribly well, we cannot deny how amazing it was in 1993, with its robust determination to do everything Infocom had done and more, with its distinct and confident literary sensibility, and not least — the appeal this held really cannot be emphasized enough — the fact that it ran on Infocom’s own virtual machine. It dominated all online discussion of text adventures throughout the two years Graham spent continuing to improve and expand it in public. The gravitational pull of Curses was such that when Mike Roberts, the creator of TADS, released an epic of his own later in 1993, it went oddly unremarked — this despite the fact that Perdition’s Flames was progressive in many ways that Curses distinctly wasn’t, making it impossible to lock yourself out of victory, prioritizing fairness above all other considerations. It stands today as the better game in mechanical terms at least, recommendable without the caveats that must accompany Graham’s effort. Yet it never stood a chance in 1993 against the allure of Curses.

And so it was that the quiet, thoughtful Englishman Graham Nelson — hardly the most likely leader of a cultural movement — used Curses and Inform to sculpt a new community of creation in his own image.

Graham’s technological choices became the community’s standards to a well-nigh shocking extent. The version 5 Z-Machine, the last and most advanced of its text-only iterations to come out of Infocom, had only been used by a few late Infocom games, none of them hugely beloved. Thus its implementation had tended to be a somewhat low priority among interpreter writers. But when Curses outgrew the 128 K memory space of the version 3 Z-Machine fairly early in its release cycle, and Graham stepped up to the 256 K version 5 Z-Machine, that decision drove interpreter writers to add support for it; after all, any Z-Machine interpreter worth its salt simply had to be able to play Curses, the sensation of the text-adventure world. Thus the version 5 Z-Machine became the new standard for the hobbyist games that followed, thanks not only to its expanded memory space but also to its more advanced typography and presentation options. (Graham would later define two new versions of the Z-Machine for really big games: an experimental and seldom-used version 7 and a version 8 which did come into common use. Both would allow story files of up to 512 K, just like Infocom’s graphical version 6 Z-Machine.)

Graham was utterly disinterested in making money from his projects. He made Inform entirely free, destroying the shareware model of AGT and TADS. David Malmberg, the longtime steward of AGT, stepped down from that role and released that system as well as freeware in 1994, signalling the end of its active development. Mike Roberts did continue to maintain and improve TADS, but soon bowed to the new world order ushered in by Inform and made it free as well. Not coincidentally, the end of the era of shareware text adventures as well as shareware text-adventure development systems coincided with Graham’s arrival on the scene; from now on, people would almost universally release their games for free. It’s also of more than symbolic significance that, unlike earlier hotbeds of text-adventure fandom which had coalesced around private commercial online services such as CompuServe and GEnie, this latest and most enduring community found its home on the free-and-open Internet.

It’s important to note that Graham’s disinterest in making money in no way implied a lack of seriousness. He approached everything he did in interactive fiction with the attitude that it was worth doing, and worth doing well. In the long run, his careful attention to detail and belief in the medium as something worthy of serious effort and serious study left as pronounced a stamp on the culture of interactive fiction as Inform or Curses themselves.

In 1995, he produced “The Z-Machine Standards Document,” which replaced years of speculation, experimentation, and received hacker wisdom with a codified specification for all extant versions of the Z-Machine. At the same time that he worked on that project, he embarked on The Inform Designer’s Manual, which not only explained the nuts and bolts of coding in the language but also delved deep into questions of design. “The Craft of Adventure,” its included essay on the subject, remains to this day the classic work of its type. Working with what was by now an enthusiastic hobbyist community which tempered its nostalgia for the medium’s commercial past with a belief in its possibilities for the present and future, Graham even saw The Inform Designer’s Manual — all 500-plus pages of it — printed as a physical book, at a time when self-publishing was a much more fraught endeavor than it is today.

But the most amusing tribute to the man’s sheer, well-earned ubiquity may be the way that his personality kept peeking through the cracks of every game made with Inform, unless its author went to truly heroic lengths to prevent it. His wryly ironic standard responses to various commands, as coded into the Inform standard library — “As good-looking as ever” when you examined yourself; “Violence isn’t the answer to this one” when you gave in to frustration and started trying to beat on something; “You are always self-possessed” when you attempted to take yourself — proved damnably difficult to comprehensively stamp out. Thus you’d see such distinctly non-Nelsonian efforts as zombie apocalypses or hardcore erotica suddenly lapsing from time to time into the persona of the bemused Oxford don wandering about behind the scenes, wondering what the heck he’d gotten himself into this time.



Seen with the hindsight of the historian, the necessary prerequisites to an Interactive Fiction Renaissance aren’t hard to identify. The Internet gave text-adventure fans a place to gather and discuss the games of the past, as well as to distribute new ones, all unbeholden to any commercial entity. Free Z-Machine interpreters made it easy to play Infocom’s games, widely recognized as the best of their type ever made, in convenient ways on virtually every computer in existence. Activision’s two Lost Treasures of Infocom collections made the complete Infocom canon easy to acquire, placing all text-adventure fans on an even footing in the course of providing them with their equivalent of The Complete Works of William Shakespeare. And then Graham Nelson came along and gave so much: a superb programming language in Inform, a superb demonstration of where interactive fiction could go in the post-Infocom era in Curses, documentation that exceeded the standard of most professional efforts, and, perhaps most of all, a living example of how interactive fiction was worth taking seriously in all its aspects, worth doing completely and well — and forget worrying about making money out of it. So, my next statement is as cringe-worthy as it is inevitable: Graham Nelson became interactive fiction’s Renaissance Man.

Now, it was just a matter of time before all of these forces forged something rather extraordinary. The year after Graham arrived on the scene in such exciting fashion was actually one of the quietest in the history of text adventures in terms of new releases; AGT was dying, while Inform was just beginning to pick up steam as an entity separate from Curses. But the following year, 1995, would see an embarrassment of worthy releases, large and small, trying all sorts of things, even as the cultural capstone to the new edifice of post-Infocom interactive fiction — an annual Interactive Fiction Competition — arrived to complete the construction process. The events of 1993 had been the harbinger; 1995 would become the true Year One of the Interactive Fiction Renaissance.

(Sources: the book The Inform Designer’s Manual by Graham Nelson; Stephen Granade’s timeline of interactive fiction on Brass Lantern; archives of rec.arts.int-fiction and rec.games.int-fiction, available on the IF Archive. My warmest thanks go once again to Graham Nelson for sharing so much of his story for these articles.

Curses remains available for free. It can of course be played on any Z-Machine interpreter.)

 
42 Comments

Posted by on November 22, 2019 in Digital Antiquaria, Interactive Fiction

 

Tags: , , ,

42 Responses to New Tricks for an Old Z-Machine, Part 3: A Renaissance is Nigh

  1. Jason Scott

    November 22, 2019 at 5:55 pm

    I am delighted that after not even doing me the favor of even responding to an interview for GET LAMP, Graham Nelson finally has put together (with Jimmy’s help) the important backstory of Inform and the part it played in the Z-Machine story.

     
    • Allan Holland

      November 24, 2019 at 9:09 pm

      Between you and Jimmy, I owe a huge debt of gratitude as a lifelong infocom and IF fan. Get Lamp is info nirvana for me. Thank you both times infinity.

       
      • Jason Scott

        November 29, 2019 at 1:20 am

        Jimmy took a fun movie and turned its droppings into a compelling, epic narrative, for which I will always be grateful.

         
  2. Torbjörn Andersson

    November 22, 2019 at 7:16 pm

    “Further, each object could have just 32 properties, or states of being — its weight, its open or closed status, its lit or unlit status, etc. — because that was all that was allowed by the Z-Machine’s standard object table.”

    The open/closed and lit/unlit statuses would probably be attributes (or flags, depending on which specification you’re looking at), rather than properties. For instance “TAKEBIT” AND “LIGHTBIT” in your ZIL example, and “light” and “switchable” in your Inform example.

    The Inform 6 Technical Manual notes that later versions worked around the property limitation by adding “a major data structure not present in the Z-machine architecture: the concept of “individual property”, a mechanism to allow games to have more or less unlimited numbers of properties which don’t need to be declared before use.”

     
    • Jimmy Maher

      November 22, 2019 at 8:00 pm

      Yes, you’re right, of course. Thanks!

      At some point, Inform began to bypass the hard-coded object table entirely — implementing its own data structures in software, as if the Z-Machine was the more bare-bones virtual machine I described it in the article as *not* being. This was possible, of course, because performance was no longer an issue. However, I’m not exactly sure offhand when this happened, other than sometime between the first release of Inform 6 and the first release of Inform 7. I’m not sure if what you’re referring to is the same thing or an interim step.

       
      • Andrew Plotkin

        November 22, 2019 at 8:23 pm

        Individual properties came in with the first release of Inform 6. I6 also added a class inheritance model, giving the language a more explicitly OO slant.

        Those were the last major extension that Inform provided (over Infocom limitations) until the invention of Z-code versions 7 and 8.

         
      • Aula

        November 24, 2019 at 3:39 pm

        “However, I’m not exactly sure offhand when this happened”

        IIRC it was at the same time that Inform started to support Glulx as an alternative target VM. Since Glulx has no opcodes to handle an object tree, Inform needed to be changed so that it wouldn’t try to generate them, which had the side effect of not using them on the Z-Machine either.

         
        • Jimmy Maher

          November 24, 2019 at 4:55 pm

          Ah, yes, that makes a lot of sense…

           
        • Andrew Plotkin

          November 25, 2019 at 4:15 pm

          Whoops, no, that’s not correct.

          When the Glulx back-end went into I6, I deliberately avoided changing the Z-machine generation code. I might have added some minor optimization to the code generator, but that’s all. My concern was to add new functionality as cleanly as possible while not breaking anything that was already there.

          The fact is, I6’s Z-machine code still uses the native Z-code object tables. They are *not* bypassed, and I’m not sure where you’re getting the claim that they are.

          As I said above, I6 adds a new individual property table, and it adds a class hierarchy. (Object classes are represented as special Z-code objects outside the world.) There’s also “strict mode”, which adds *wrappers* around the native Z-code opcodes to check for various errors. But the Z-code opcodes are still there at the bottom.

           
  3. Jason Dyer

    November 22, 2019 at 7:38 pm

    I may be in error on this, but I believe the final version of the medicine bottle had more than 7 methods — 11 I think? I unfortunately no longer have a save file at the end of the game where I could easily check (it’s in the end notes part, I know).

     
    • Jimmy Maher

      November 22, 2019 at 8:17 pm

      Just checked using TXD because I don’t have an end-of-game save handy either. Oddly, the story file seems to list only six — and I believe that one of these, giving it to Aunt Jemima, actually hoses you because she eats the pill inside. But seven is stated in several places online, and that’s Graham’s recollection.

       
  4. Andrew Plotkin

    November 22, 2019 at 8:10 pm

    “Instead the author of each new game began by cannibalizing some of the code to do these things from whatever previous game was deemed to be most like this latest one.”

    When the Infocom source code came out this year (thanks Jason!), it turned out to include a source directory marked “generic”. This was a game with a parser, a couple of blank rooms, and a couple of blank objects — clearly intended as a base for copying.

    The compiled files in that directory are dated 1985 and 1987, so it’s not clear how many Infocom games were started by forking the generic template, as opposed to cloning an earlier full game. But it’s an apparent attempt to standardize the original parser code. (Distinct from the “New Parser” of the final V6 games.)

     
    • Jimmy Maher

      November 22, 2019 at 8:23 pm

      Interesting. In some of the interviews for Get Lamp, Imps described their habit of taking a previous game and stripping it down to only the needful, so this likely was a fairly late practice. The sadly departed Stu Galley, for example, definitely said that The Witness was built on the foundation of Deadline.

       
      • Jason Scott

        November 22, 2019 at 11:32 pm

        I suspect that each of the imps had their own approach to this situation, and in the interviews there’s definitely a “lineage” between them, with a lot eminating from Marc Blank. (For example, Marc Blank to Stu Galley, Marc to Steve Meretzky, and so on.)

        I’m surprised the ZIL community hasn’t tried a “overlapping code” test to see how much of each game’s DNA is like the others from the source code, but when they do, I bet it’ll be informative.

        At various points in the history, like Zarf has hinted, there are attempts to “clean up” the Infocom structure, to various degrees of success. Remember, for example, that both Blank and Berlyn essentially separated from Infocom and worked as remote contractors for various reasons, so their day to day was different. And Bates, I’m sure, caused a lot of cleaning up because he was trying to duplicate the environment and understand it, which meant all the dusty corners got a look.

        I’m just encouraging us to not think of the place as a monolithic “and then they did this” because it’s very obvious that was not the case.

         
      • Quinn Dunki

        November 24, 2019 at 5:06 pm

        Both are probably true. The generic source folder would provide many basics, but it would still have made sense to also start with a similar game to avoid rewriting some of the more subtle things.

        As for Infocom not having a standard library, that makes sense from a technical standpoint. Libraries are a trade off of reduced development time versus code size. If the library is implemented as source, more generic or abstracted services create longer code and larger data structures. If the library is implemented as binary, you have overhead introduced by linkers and potentially code relocation, symbol tables, etc.

        Writing each game from first principles may not be the fastest way, but it likely did result in smallest possible code, the paramount concern. I haven’t seen the “generic” source folder referenced above, but my guess it is provides some very basics- the stuff you CAN share without incurring increased code size from abstraction.

         
        • Jimmy Maher

          November 25, 2019 at 11:35 am

          Although your logic would be completely correct under most scenarios, I’m not certain about this one. A text adventure is a fairly specialized piece of software, and a standard library designed just for that purpose may not suffer so horribly from the inefficiencies you describe, as long as its designers struck the right balance between complexity and commonality. While I’ve by no means extensively analyzed the Infocom source code that was released with such fanfare a while back, my strong impression is that in general it’s not particularly good or efficient code in an abstract sense. There’s a lot of unnecessary elaboration and particularly a lot of local repetition of things that could be better encapsulated into global functions. (This makes a degree of sense, given that a number of the Imps didn’t come to Infocom with a deep background in programming in the abstract, essentially learning ZIL as their first and only language on the fly.)

          And in the end, as they say, the proof is in the pudding: Curses, using the rigorously engineered Inform library, packs a heck of a lot more game into the 256 K Z-Machine than either A Mind Forever Voyaging or Trinity.

           
      • Dave Lebling

        December 7, 2019 at 12:28 am

        …and Suspect was built on Deadline as well. I haven’t polled the other imps on this, but I believe no actual game was based on the “generic” core game.

        Fundamentally it was the space limitations that led us away from having a generic library. With the later, larger size limits, this was potentially something we could have ignored (also ignoring for the moment the limitations of floppy disk capacity), but other issues sucked up a lot of the air that such an effort would have taken.

        Hard as it is to believe, the period in which Zork was written was also early days for the whole object-orientation, inheritance, classes, strong-typing philosophy. In fact, we were right down the hall from Barbara Liskov, who was defining them and promoting them at the same time we were writing Zork. The language she and her team invented (CLU) was in fact originally implemented in Muddle. (It was also very slow in Muddle, so they moved off of it as soon as they could.)

        Jason Scott’s suggestion of DNA testing to determine the parentage of each line or ZIL function is a good one. I suggest someone with a lot of time and energy take it on!

         
  5. matt w

    November 22, 2019 at 8:14 pm

    About the default messages for Curses peeking through in later games–I’m pretty sure I’m not the only Cragne Manor author who went through replacing all the default messages except the one for WAKE (“The dreadful truth is, this is not a dream.”) [FWIW, someone did try to smell the welcome mat, so my effort was not wasted.]

     
    • Jimmy Maher

      November 24, 2019 at 4:58 pm

      That’s actually an amusing example of a message stemming directly from Curses that has remained a part of Inform’s standard library right up until today. It exists in Curses because you enter one of its parallel dimensions by lying down and sleeping. But, as the text says…

       
  6. S. John Ross

    November 22, 2019 at 8:52 pm

    I’m going to get awfully emotional when you get to the parts about I7, when non-programmers like me were invited to play. But it’s certainly also moving reading about these foundations; it really highlights the level of effort Graham put into it all.

     
  7. Keith Palmer

    November 22, 2019 at 9:46 pm

    I recall first encountering Curses as a self-contained Macintosh application in the shareware folder of a monthly “CD-ROM magazine”; unfortunately, I don’t know where those old disks have got to to confirm that memory. However, where some time before (as I commented on “The Last Works Before the Renaissance“) I’d happened on a TADS adventure and merely been amused someone had managed something so nostalgic without really wondering how they’d done it, the “about menu” in Curses described Inform and gave me a sense of potential just over the horizon.

    With that said, though, I didn’t play very far into the game then; having struggled with “The Lost Treasures of Infocom” might have left me intimidated. A while after that I first got connected to the Internet, and one of the first things I went looking for via the just-established Yahoo and its ilk was “text adventure information,” if as much to finally finish A Mind Forever Voyaging and Trinity as anything. The First Interactive Fiction Competition did happen later that year, however, and I did eventually resort to a Curses walkthrough…

     
    • S. John Ross

      November 22, 2019 at 10:42 pm

      If the monthly CD-ROM magazine was Interactive Entertainment, I used to be a department editor there =) You can snag copies of the CDs here: https://archive.org/details/interactive_entertainment

       
      • Keith Palmer

        November 23, 2019 at 2:05 am

        I have the impression the CD-ROM we subscribed to was “Nautilus,” but thanks for the link anyway. One other thing that caught my attention about this piece but which I didn’t put into my first comment was mentioning “adventures meant to be played by a team”; Renga in Blue’s recent ascent of the mountain named “Warp” brought that idea to my mind just before seeing it here.

         
  8. Ross

    November 22, 2019 at 10:55 pm

    I always hoped the number of times I am referenced in footnotes in the Inform Designer’s Manual might someday help me professionally. So far, it has not.

     
  9. Michael

    November 23, 2019 at 12:55 am

    “At the same that that he worked on that project…”
    –>same time?

     
    • Jimmy Maher

      November 23, 2019 at 9:46 am

      Thanks!

       
  10. Eddie

    November 23, 2019 at 6:40 am

    Thank you Jimmy for the wonderful article, and thank you Graham for Inform and Curses.

    It is so amazing to play zcode games on an old Palm IIIx.

    I wish someone would make Frotz for Chromebooks!

     
    • mathew

      November 25, 2019 at 8:02 pm

      DOS Frotz should work in DOSBox for Chromebook.

      Or the Parchment Z-code interpreter should work, in which case you can play Curses right now by going to https://ifdb.tads.org/viewgame?id=plvzam05bmz3enh8 and clicking the Play on-line button.

       
  11. flowmotion

    November 23, 2019 at 6:57 am

    The Inform example here doesn’t appear to be “{C;}-like” at all to my eyes. More like a DSL implemented in Ruby or something from the natural language school like HyperTalk/AppleScript. Or maybe even pascal.

     
    • Ross

      November 23, 2019 at 7:19 am

      Object declarations are the least C-like thing in Inform. The actual procedural code is just exactly straight-up C with like 4 syntactic oddities (The use of colons as separators in the for-loop, square brackets rather than braces for function declarations, the use of the arrow operator for array indexing, and the idiosyncratic escape sequences in strings)

       
  12. Aula

    November 24, 2019 at 3:29 pm

    “given the the Infocom principals’ strong grounding”

    “Graham even saw the The Inform Designer’s Manual”

    both of these have a duplicate “the”

     
    • Jimmy Maher

      November 24, 2019 at 4:55 pm

      Thanks!

       
      • Ken Brubaker

        November 24, 2019 at 8:44 pm

        Actually, the second one is grammatically correct since the first ‘the’ is referring to a title which starts with ‘The’. But it does sound a bit weird.

         
  13. Carl

    November 25, 2019 at 4:47 am

    Not a huge deal of course but assembly language is not the lowest level you can use to program a machine. While you’re right that each mnemonic usually corresponds to an opcode, in assembly language you also have variable declarations, macros, and some assembly languages have subroutines and facilities for memory allocation.
    The lowest level is pure machine code,

     
    • Mike Taylor

      November 25, 2019 at 8:23 am

      True — and inherent in the very name “assembly”, which indicates that the real code is being assembled from some more symbolic representation. Back when I was learning to program on a Commodore Pet 2001, I did write actual 6502 machine language by hand (a little, and very poorly), so I still have some opcodes stuck in my head decades later: hex A9 for Load Direct, AA for Transfer A to X, AD for Load Indirect, 00 for Break, etc. I would poke those numbers directly into their locations.

       
    • Jimmy Maher

      November 25, 2019 at 11:39 am

      I take your point, but I’m going to take refuge in “(semi-)practically.” While I’ve heard a number of stories of people able to write binary code on the fly — I certainly have never had the mind for such a thing, even when I was younger — few would do so unless there just wasn’t any other alternative.

       
  14. Lisa H.

    November 25, 2019 at 5:15 am

    The several references in the comments to Get Lamp make me wonder how many other readers out there have one of the challenge coins. (I had forgotten, or not known, that they were numbered until I looked them up before making this comment and found 1. a cancelled Kickstarter that offered coins made by the same company as a perk, but “they won’t be individually numbered”; and 2. one on eBay for $125 (!!).

     
  15. Peter Olausson

    November 25, 2019 at 6:49 pm

    I must be even more ignorant of modern IF than I thought, since I fail to see how eg “just” 255 objects with “just” 32 attributes each matter to anyone but the most ambitious authors, and indeed are “undeniable disadvantages”.

     
    • Jimmy Maher

      November 25, 2019 at 7:02 pm

      They fill up fast. Every room is an object, as is the player character, every other character or creature, and every, well, *object* in the world (including all the ones you can’t pick up and carry, like tables and carpets and rivers). As are lots of seemingly more abstract things — like every possible direction for movement (that’s twelve objects right there), possible conversation topics, etc. If you can reference it as a direct or indirect object in a command, it’s probably an object in the programmatic sense. Even Infocom struggled mightily with the 255-object limitation, which often bit harder than the 128 K limitation. Today, when players expect a much more richly implemented world as a matter of course, it would be hopeless.

      Attribute inflation is similarly deceptive. Object taxonomy functions via a series of true-false questions, implemented as attribute flags. Am I a room? Am I a door? Am I a compass direction? Am I a living creature? Can I be taken? Can I be opened? AM I currently open? Can I be lit? Can I be turned on and off? AM I turned on? Etc., etc.

       
      • Ross

        November 26, 2019 at 2:33 am

        It has been a heck of a long time, but the most implacable limit you ran up against in the Z-machine was the 64k ram limit. The limits on global properties and attributes mostly impact the design of the library – why some things are lookup tables and others are subroutines, and you can muddle your way around the object limit by recycling objects (There’s a bit of black magic I hammered out years ago – rewriting the object table at runtime in software), but you still ran into the wall that only the first 64k of memory was dynamic and byte-addressable.

         
      • Peter Olausson

        November 27, 2019 at 10:23 am

        Ahh, or should it be ooh — *those* kinds of objects! Then I get it. Completely different.

         
  16. Fuck David Cage

    November 27, 2019 at 8:02 pm

    I think a great game series that shows how much can be programmed, and pushes the limits well
    beyond most games–a series I put on a list of suggestions in the comments for the hall of fame–is Metal Gear Solid. I respect Hideo Kojima for many reasons, such as his complex stories, challenging and fun gameplay and appreciation for the player’s intelligence, and his detailed programming tricks are perfect examples. He managed to program ice melting, enemies who could hear the characters sneeze, commanders who respond to almost everything the player does–even deeply embedded actions, like eating a vulture that has eaten a man and being accused of cannibalism by proxy.

    I wonder how often a programmer got confused by the references to an object as “self,” and forgot whether he was working on an object or the main character? How did the Inform interpreter refer to the main character? This could explain a lot of the bugs on Nathan Simpson and Graham Cree’s lists. *Tangential note: I think fans of those lists would also enjoy David Wonn’s list and Zany Video Game Quotes*

     

Leave a Reply

Your email address will not be published.


This site uses Akismet to reduce spam. Learn how your comment data is processed.