Style | StandardCards

Planet Interactive Fiction

Friday, 23. January 2026

Interactive Fiction – The Digital Antiquarian

Omikron: The Nomad Soul

The idea of being in the body of a guy and making love to his wife — when she believes you’re her husband, even though you’re not — was a very strange position to be in. That’s exactly the kind of thing I try to explore in all my games today. — David Cage, speaking […]

The idea of being in the body of a guy and making love to his wife — when she believes you’re her husband, even though you’re not — was a very strange position to be in. That’s exactly the kind of thing I try to explore in all my games today.

— David Cage, speaking from the Department of WTF

The French videogame auteur David Cage has been polarizing critics and gamers for more than a quarter-century with his oddly retro-futurist vision of the medium. He believes that games need to cease prioritizing “action” at the expense of “emotion,” a task which they can best accomplish, according to him, by embracing the aesthetics, techniques, and thematic concerns of cinema. You could lift a sentence or a paragraph from many a post-millennial David Cage interview, drop it into an article from the “interactive movie” boom of the mid-1990s, and no one would notice the difference. The interactive movie is as debatable a proposition today as it was back then; still more debatable in many cases has been Cage’s execution of it. Still, he must be doing something right: he’s been able to keep his studio Quantic Dream alive all these years, making big-budget story-focused single-player games in an industry which hasn’t always been terribly friendly toward such things.

Cage’s very first and least-played game was known as simply The Nomad Soul in Europe, as Omikron: The Nomad Soul in North America; I’ll go with the latter name here, because that’s the one under which you can still find it on digital storefronts today. Released in 1999, it’s both typical and atypical of his later oeuvre. We see the same emphasis on story, the same cinematic sensibility, the same determination to eliminate conventional failure states, even the same granular obsessions with noirish law enforcement, the transmigration of souls, and, well, Blade Runner. But it’s uniquely ambitious in its gameplay, despite having been made for far less money than any other David Cage production. It’s a combination of Beneath a Steel Sky with Tomb Raider with Mortal Kombat with Quake, with a soundtrack provided by David Bowie. If you’re a rambunctious thirteen-year-old, like our old friends Ian and Nigel, you might be thinking that that sounds awesome. If you’re older and wiser, the alarm bells are probably already ringing in your head. Such cynicism is sadly warranted; no jack of all trades has ever mastered fewer of them than Omikron.



David Cage was born in 1969 as David de Gruttola, in the Alsatian border town of Mulhouse, a hop and a skip away from both Germany and Switzerland. He discovered that he had a talent for music at an early age. By the time he was fifteen, he could play piano, guitar, bass, and drums, and had started doing session gigs for studios as far away as Paris. He moved to the City of Light as soon as he finished school. By saving his earnings as a session musician, he was eventually able to buy an existing music studio there that went under the name of Totem. A competent composer as well as instrumentalist, he provided jingles for television commercials and the like. These kinds of ultra-commoditized music productions were rapidly computerizing by the end of the 1980s; it was much cheaper and faster to knock out a simple tune with a bank of keyboards and a MIDI controller than it was to hire a whole band to come in or to overdub the parts one by one on “real” instruments. Thus Totem became David de Gruttola’s entrée into the world of digital technology.

Totem also brought Gruttola into the orbit of the French games industry for the first time. He provided music and/or sound for five games between 1994 and 1996: Super DanyTimecopCheese Cat-astropheVersailles 1685, and Hardline. Roll call of mediocrity though this list may be, it awakened a passion in him. By now in the second half of his twenties, he was still very young by most standards, but old enough to realize that he would never be more than a competent musician or composer. Games, though… games might be another story. Never one to shrink unduly from the grandiose view of himself and his art, he would describe his feelings in this way a decade later:

I remember how many possibilities suddenly opened up because of this new technology. I saw it as a new means of expression, where the world could be pushed to its limits. It was my way of exploring new horizons. I felt like a pioneer filmmaker at the start of the twentieth century: grappling with basic technology, but also being aware that there is everything left to invent — in particular, a new language that is both narrative and visual.

Thus inspired, Gruttola wrote a script of 200 to 250 pages, about a gamer who gets sucked through the monitor into an alternative universe, winding up in a futuristic dystopian city known as Omikron. The script was “naïve but sincere,” he says. “I was dreaming of a game with an open-world city where I could go wherever I wanted, meet anybody, use vehicles, fight, and transfer my soul into another body.” (Ian and Nigel would surely have approved…)

Being neither a programmer nor a visual artist himself, he convinced a handful of friends to help him out. They first tried to implement Omikron on a Sony PlayStation, only to think better of it and turn it into a Windows game instead. Late in 1996, more excited than ever, Gruttola offered his friends a contract: he would pay them to work on the game exclusively for the next six months, using the money he had made from his music business. At the end of that time, they ought to have a decent demo to shop around to publishers. If they could land one, they would be off to the races. If they couldn’t, they would put their ludic dreams away and go back to their old lives. Five of the friends agreed.

So, they made a 3D engine from scratch, then made a first pass at their Blade Runner-like city. “The demo presented an open world,” recalls Oliver Demangel, who left a position at Ubisoft to take a chance with Gruttola. “You could basically walk around in a city and have some limited interaction with the environment around you.” With the demo in hand and his six-month deadline about to expire, Gruttola started calling every publisher in Europe. Or rather “David Cage” did: realizing that his surname didn’t exactly roll off the tongue, he created the nom-de-plume by appropriating the last name of Johnny Cage, his favorite fighter from Mortal Kombat.

The British publisher Eidos, soaring at the time on the wings of Tomb Raider, invited the freshly rechristened game designer to come out to London. Cage flew back to Paris two days later with a signed development contract in hand. On May 2, 1997, Totem morphed into Quantic Dream, a games rather than a music studio. Over the following month, Cage hired another 35 people to join the five friends he had started out with and help them make Omikron: The Nomad Soul.

Games were entering a new era of mass-market cultural relevance during this period. On the other side of the English Channel, Lara Croft, the heroine of Tomb Raider, had become as much an icon of Cool Britannia as the Spice Girls, giving interviews with journalists and lending her bodacious body to glossy magazine covers, undaunted by her ultimate lack of a corporeal form. Thus when David Cage suggested looking for an established pop act to perhaps lend some music to his game, Eidos was immediately receptive to the idea. The list of possibilities that Cage and his mates provided included such contemporary hipster favorites as Björk, Massive Attack, and Archive. And it also included one name from an earlier generation: David Bowie. Bowie proved the only one to return Eidos’s call. He agreed to come to a meeting in London to hear the pitch.

David Bowie bridges the generations with Trent Reznor of Nine Inch Nails.

More than a decade removed from the peak of his commercial success, and still further removed from the unimpeachable, genre-bending run of 1970s albums that will always be the beating heart of his musical legacy, the 1990s version of David Bowie had settled, seemingly comfortably enough, into the role of Britpop’s cool uncle. He went on tour with the likes of Nine Inch Nails and Morrissey and released new albums every other year or so that cautiously incorporated the latest sounds. If the catchy hooks and spark of spontaneity — not to mention the radio play and record sales — weren’t quite there anymore, he did deserve credit for refusing to become a nostalgia act in the way of so many of his peers.

But almost more relevant than Bowie’s current music when it came to Omikron was his deep-seated fascination with the new digital society he saw springing into being around him. He had started to use a computer himself only a few years before: in 1993, when his 22-year-old son Duncan gave him an Apple Macintosh. At first, he used it mostly for playing around with graphics, but he soon found his way onto the Internet for the first time. This digital frontier struck him as a revelation. He became so addicted to surfing the Web that he had to join a support group. He seemed to understand what was coming in a way that few other technologists — never mind rock stars — could match. He became the first prominent musician to make his own website and to use it to engage directly with his fans, the first to debut a new song and its accompanying video on the Internet, the first to co-write a song with a lucky fan whom he would never meet in person. Displaying a head for business that had always been one of his more underrated qualities, he started charging fans a subscription fee for content at a time when few people other than porn purveyors were bothering to even try to make money online. By the time he took the meeting with Eidos and Quantic Dream, he was in the process of setting up BowieNet, his own Internet service provider. (Yes, really!) He had also just floated his “Bowie Bonds,” by which means his fans could help him to raise the $55 million he needed to buy his back catalog, remaster it, and re-release it as a set of deluxe CDs. From social networking to crowd-sourcing, Bowie was clearly well ahead of the curve. “I don’t even think we’ve seen the tip of the iceberg,” he would say in 2000 in a much-quoted television interview. “I think the potential of what the Internet is going to do, both good and bad, is unimaginable. I think we’re on the cusp of something exhilarating and terrifying.” Subsequent history has resoundingly vindicated him, although perhaps not always in the ways that his inner digital utopianist might have preferred.

One thing David Bowie was not, however, was a gamer. He took the meeting about Omikron largely at the behest of his son Duncan, who was. He arrived at Eidos’s headquarters accompanied by said son; by his wife, a former supermodel who went by the name of simply Iman; and by his principal musical collaborator of the past decade, the guitarist Reeves Gabrels. They all sat politely but noncommittally while a very nervous group of game developers told them all about Omikron. “Okay, then, what do you need from me?” asked Bowie when the presentation was over. An unusually abashed David Cage said that, at a minimum, they were hoping to license a song or two for the game — maybe the Cold War-era anthem “‘Heroes'” or, failing that, the more recent “Strangers When We Meet.” But in the end, Bowie could be as involved as he wanted to be.

It turned out that he wanted to be quite involved indeed. Over the next couple of hours, Quantic Dream got all they could have dreamed of and then some. Carried away on a wave of enthusiasm, Bowie and Gabrels promised to write and record a whole new album to serve as the soundtrack to the game. And Bowie said he was willing to appear in it personally in motion-captured form. Maybe he and Gabrels could even perform a virtual concert inside the virtual world. Heads were spinning when Bowie and his entourage finally left the building that day.

Iman and David Bowie both appear in Omikron in motion-captured form.

As promised, Bowie, Iman, and Gabrels came to Paris for a couple of weeks, where they participated in motion-capture and voice-acting sessions and saw and heard more about the world and story of Omikron. Then they went away again; Quantic Dream heard nothing whatsoever from them for months, which made everyone there extremely nervous. But then they popped up again to deliver the finished music — no fewer than ten original songs — right on time, one year almost to the day after they had agreed to the project.

The same tracks were released on September 21, 1999, as hours…, David Bowie’s 23rd studio album. Critics greeted it with some warmth, calling it a welcome return to more conventional songcraft after several albums that had been more electronica than rock. The connection of the album to the not-yet-released game was curiously elided; few reviewers of the album even seemed to realize that it was supposed to be a soundtrack, the first of its type. That same autumn, the veteran progressive-rock group Yes would debut a single original song written for the North American game Homeworld, but Bowie’s contribution to Omikron was on another order of magnitude entirely.

The 1999 David Bowie album hours… was, technically speaking, the soundtrack to Omikron: The Nomad Soul, but you’d have a hard time divining that from looking at it.

Omikron itself appeared about six weeks later. Absolutely no game critic missed the David Bowie connection, which became the lede of every review, thus indicating that the cultural dynamic between games and pop music had perhaps not quite reached a state of equilibrium just yet. But despite the presence of Bowie, reviews of the game were mixed in Europe, downright harsh in North America. Computer Gaming World got off the best zinger against the game it dubbed Omikrud: “We could be coasters, just for one day.” The magazine went on to explain that “the concept of wrapping an adventure game around a David Bowie album is a cool one. The problem here is with the execution. And your own execution will look more and more desirable, the longer you attempt to play this game.” Rude these words may be, but in my experience they’re the truth.


But what if I don’t want to say yes?

Omikron boasts a striking and memorable opening. When you click the “New Game” button, a fellow dressed in a uniform that looks like a cross between Star Trek and T.J. Hooker pops onto the screen and starts talking directly to you, shattering the fourth wall like so much wet plaster. “My name is Kay’l,” he tells you. (His full name will prove to be Kay’l 669, because of course it is.) “I come from a universe parallel to yours. My world needs your help! You’re the only one who can save us!”

Kay’l wants you to transfer your soul into his body and journey with him back to his home dimension. “You must concentrate!” he hisses. To demonstrate how it’s done, Kay’l holds up his hands and doubles over like a constipated man on a toilet. “You’ve done it!” he then declares with some relief. “Now your soul occupies my body.” (If my soul occupies his body, why am I still sitting in front of my monitor watching him talk at me?) “This is the last time we’ll be able to speak together. Once you’ve crossed the breach, you’ll be on your own. I will take over my body when you leave the game and hold your place until you return.” Thus we learn that Omikron intends to go all-in all the time on diegesis. Lord help us.

You-as-Kay’l emerge in an urban alleyway, only to be set upon by a giant demon that seems as out of place here as you do. This infernal creature is about to make short work of you, thereby revealing a flaw in Kay’l’s master plan. Luckily, a police robot shows up at this juncture and scares away the demon, who apparently isn’t all that after all. “You have been the victim of a violent attack,” RoboCop helpfully informs you, seemingly not noticing that you’re dressed in the uniform of a police officer yourself. “Go home and re-hydrate yourself.”

Trying to take his advice, you fumble about for a while with the idiosyncratic and kind of idiotic controls and interface, and finally manage to locate Kay’l’s apartment. There you discover that he’s married, to a fetching woman whose closet is filled only with hot pants and halter tops. (In time, you will learn that this is true of almost all of the women who live in Omikron.) Seeming unconcerned by the fact that her husband has evidently suffered some sort of psychotic break, disappearing for three days and returning with his memory wiped clean, she lies down on the bed to await your ministrations. You lie down beside her; coitus ensues. Oh, my. Less than half an hour into the game, and you’ve already bonked your poor host’s wife. One wonders whether the fellow is inside his body with you watching the action, so to speak, and, if so, whether he’s beginning to regret fetching you out of the inter-dimensional ether.

Kay’l’s wife will later turn out to be a demon in disguise. I guess that makes it okay to have sex with her under false pretenses. And anyway, these people can do the nasty without having to take their clothes off, just like the characters in a Chris Roberts movie.

I do try to be fair, so let me say now that some things about this game are genuinely impressive. The urban environs qualify at first, especially when you consider that they run in a custom-coded 3D engine. It takes some time for the realization to set in that the city of Omikron is more a carefully curated collection of façades — like a Hollywood soundstage — than a believable community. But once it does, it becomes all too obvious that the people and cars you see aren’t actually going anywhere, even as the overuse of the same models and textures becomes difficult to ignore. There’s exactly one type of car to be seen, for example — and, paying tribute to Henry Ford, it seems to be available in exactly one color. Such infelicities notwithstanding, however, it’s still no mean feat that Quantic Dream pulled off here, a couple of years before Grand Theft Auto III. That you can suspend your disbelief even for a while is an achievement in itself in the context of the times.

Yet this is not a space teeming with interesting interactions and hidden nooks and crannies. With one notable exception, which I’ll get to later, very little that isn’t necessary to the linear main plot is implemented beyond a cursory level. The overarching design is that of a traditional adventure game, not a virtual open world at your beck and call. You learn from Kay’l’s wife — assuming you didn’t figure it out from his uniform — that he is a policeman in this world, on the hunt for a serial killer. (Someone is always a policeman on the hunt for a serial killer in David Cage games.) You have to run down a breadcrumb trail of clues, interviewing suspects and witnesses, collecting evidence, and solving puzzles. The sheer scale of the world is more of a hindrance than a benefit to this type of design, because of the sheer quantity of irrelevancies it throws in your face. By the time you get into the middle stages of the game, it’s becoming really, really hard to figure out where it wants you to go next amidst this generic urban sprawl. And by the same point, your little law-enforcement exercise has become a hunt for demons who are on the verge of destroying the entire multiverse, as you crash headlong into a bout of plot inflation that would shock a denizen of the Weimar Republic. The insane twists and turns the plot leads you through do nothing to help you figure out what the hell the game wants from you.

But I was trying to be kind, wasn’t I? In that spirit, let me note that there are forward-thinking aspects to the design. One of David Cage’s overriding concerns throughout his career has been the elimination of game-over failure states. If you get yourself killed here, the game will always find some excuse to bring you back to life. Unfortunately, the plot engine is littered with soft locks, whereby you can make forward progress impossible by doing or not doing something at the right or wrong moment. I assume that these were inadvertent, but that doesn’t make them any more excusable. This is one of several places where the game breaks an implicit contract it has made with its player. It strongly implies at the outset that you can wing it, that you’re expected to truly inhabit the role of a random Joe Earthling whose (nomad) soul has been sucked into this alternative dimension. But in actuality you have to meta-game like crazy to have a chance.

A save point.

The save system is a horror, a demonstration of all the ways that the diegetic approach can go wrong. You have to find save points in the world, then use one of a limited supply of “magic rings” you find lying around to access them. In addition to being an affront to busy adults who might not be able to play for an extra half-hour looking for the next save point — precisely the folks whom David Cage says games need to become better at attracting — this system is another great way to soft-lock yourself; use up your supply of magic rings and you’re screwed if you can’t find some more. There is a hint system of sorts built into the game, but it’s accessible only at the save points, and requires you to spend more magic rings to use it. In other words, the player who most needs a hint will be the least likely to have the resources to hand by which to get one. This is another running theme of Omikron: ideas that are progressive and player-friendly in an abstract sense, only to be implemented in a bizarrely regressive, player-hostile way. It bears all the telltale signs of a game that no one ever really tried to play before it was foisted on an unsuspecting public.

And then there are the places where Omikron suddenly decides to cease being an adventure game and become a beat-em-up, a first-person shooter, or a platformer. I hardly know how to describe just how jarring these transitions are, coming out of the blue with no warning whatsoever. You’ll be in a bar, chatting up the patrons for clues — and bam, you’re in shooter mode. You’ll be searching a locker room — and suddenly you’re playing Mortal Kombat against a dude in tighty-whities. These action modes play as if someone once told the people who made this game about Mortal Kombat and Quake and Tomb Raider, but said people have never actually experienced any of those genres for themselves.

I struggled mightily with the beat-em-up mode at first because I kept trying to play it like a real game of this type — watching my opponent, varying my attacks, trying to establish some sort of rhythm. Then a friend explained to me that you can win every fight just by picking one attack and pounding on that key like a hyperactive monkey, finesse and variety and rhythm be damned.

Alas, the FPS mode is a tougher nut to crack. The default controls are terrible, having nothing in common with any other shooter ever, but you can at least remap them. Sadly, the other problems have no similarly quick fix. Enemies can shoot you when they’re too far away for you to even see them; enemies can spawn out of nowhere right on top of you; your own movements are weirdly jerky, such that it’s hard to aim properly even in the best of circumstances. Just how ineptly is the FPS mode of Omikron implemented, you ask? So ineptly that you can’t even access your health packs during a fight. Again, it’s hard to believe that oversights like this one would have persisted if the developers had ever bothered to ask anyone at all to play their game before they stuck it in a box and shipped it.

The jumping sequences at least take place in the same interface paradigm as the adventure game, but the controls here are just as sloppy, enough to make Omikron the most infuriating platformer since Ultima VIII tarnished a proud legacy. And don’t even get me started on the swimming — your character is inexplicably buoyant, meaning you’re constantly battling to keep his head underwater rather than the opposite — or the excruciating number of times you’ll see the words “I don’t know what to do with that” flash across the screen because you aren’t standing just right in front of the elevator controls or the refrigerator or the vending machine. Even David Cage, a man not overly known for his modesty, confesses that “I wanted to mix different genres, but I wouldn’t say that we were 100-percent successful.” (What percentage successful would you say that you were, David?)

Then we have the writing, the one area where we might have expected Omikron to excel, based on the rhetoric surrounding it. It does not. The core premise, an invasion by demons of a city lifted straight out of Blade Runner, smacks more of adolescent fan fiction than the adult concerns David Cage yearns for games to learn to address. As I already noted, the plot grows steadily more incoherent as it unspools. Interesting, even disturbing elements do churn to the surface with reasonable frequency, but the script is bizarrely oblivious to them. As the game goes on, for instance, you acquire the ability to jump into other bodies than that of poor cuckolded Kay’l. Sometimes you have to sacrifice these bodies — murdering them from the point of view of the souls that call them home — in order to continue the story. The game never acknowledges that this is morally problematic, never so much as feints toward the notion of a greater good or ends justifying the means. This refusal of the game to address the deeper ramifications of its own fiction contributes as much as the half-realized city to giving the whole experience a shallow, plastic feel. Omikron brings up a lot of ideas, but seemingly only because David Cage thinks they sound cool; it has nothing to really say about anything.

Mind you, not having much of anything to say is by no means the kiss of death for a game; I’ve played and loved plenty of games with nothing in particular on their minds. But those games were, you know, fun in other ways. There’s very little fun to be had in Omikron. Everything is dismayingly literal; there isn’t a trace of humor or whimsy or poetry anywhere in the script. I found it to be one of the most oppressive virtual spaces I’ve ever had the misfortune to inhabit.

Among the many insufferable quotes attached to Omikron is the claim by Phil Campbell, a senior designer at Eidos who went on to become creative director at Quantic Dream, that the soul-transfer mechanic makes it “the world’s first Buddhist game.” A true believer who has drunk all the Kool Aid, Campbell thinks Cage is an auteur on par with François Truffaut.

Even the most-discussed aspect of Omikron, at the time of its release and ever since, winds up more confusing than effective. David Cage admits to being surprised by the songs that David Bowie turned up with a year after their first meeting. On the whole, they were sturdy songs if not great ones, unusually revealing and unaffected creations from a man who had made a career of trying on different personas. “I wanted to capture a kind of universal angst felt by many people of my age,” said the 52-year-old singer. The lyrics were full of thoughtful and sometimes disarmingly wise ruminations about growing older and learning to accept one’s place in the world, set in front of the most organic, least computerized backing tracks that Bowie had employed in quite some years. But the songs had little or nothing to do with Cage’s game, in either their lyrics or their sound. Cage claims that Bowie taught him a valuable lesson with his soundtrack: “It’s important that the music doesn’t say the same thing that the imagery does.” A more cynical but possibly more accurate explanation for the discrepancy is that Bowie pretty much forgot about the game and simply made the album he felt like making.

The one place where Omikron’s allegedly open world does reward exploration is the underground concerts you can discover and attend, by a band called the Dreamers who have as their lead singer a de-aged David Bowie. The virtual rock star’s name is a callback to the real star’s distant past: David Jones, the name Bowie was born with. He flounces around the stage like Ziggy Stardust in his prime, dressed in an outfit whose most prominent accessory is a giant furry codpiece. But the actual songs he sings are melancholy meditations on age and time, clearly not the output of a twenty-something glam-rocker. It’s just one more place where Omikron jarringly fails to come together to make a coherent whole, one more way in which it manages to be less than the sum of its parts.

That giant codpiece on young Mr. Jones brings me to one last complaint: this game is positively drenched in cheap, exploitive sex that’s more tacky than titillating. It’s this that turned my dislike for it to downright distaste. Strip clubs and peep shows and advertisements for “biochemical penis implants” abound. Of course, all those absurdly proportioned bodies and pixelated boobies threatening to take your eyes out look ridiculous rather than sexy, as they always do in 3D games from this era. At one point, you have to take over a woman’s body — a body modeled on that of David Bowie’s wife Iman, just to make it extra squicky — and promise sexual favors to a shopkeeper in order to advance the plot. At least you aren’t forced to follow through; thank God for small blessings.

The abject horniness makes Omikron feel more akin to that other kind of entertainment that’s labeled as “adult” —  you know, the kind that’s most voraciously consumed by people who aren’t quite adults yet — than it does to the highbrow films to which David Cage has so frequently paid lip service. I won’t accuse Cage of being a skeezy creep; after all, it’s not as if I know the guy. I will only say that, if a skeezy creep was to make a game, I could easily imagine it turning out something like this.

Omikron’s world is the definition of wide rather than deep, but the developers were careful to ensure that you can pee into every single toilet you come across. Make of that what you will.



Once ported to the Sega Dreamcast console in addition to Windows computers, Omikron sold about 400,000 copies in all in Europe, but no more than 50,000 in North America. “It was too arty, too French, too ‘something’ for the American market,” claims David Cage. (I can certainly think of some adjectives to insert there…) Even its European numbers were not good enough to get the direct sequel that Cage initially proposed funded, but were enough, once combined with his undeniable talent for self-marketing, to allow him to continue his career as a would-be gaming auteur. So, we’ll be meeting him again, but not for a few years. We’ll just have to hope that he’s improved his craft by that point.

When I think back on Omkiron, I find myself thinking about another French — or rather Francophone Belgian — game as a point of comparison. On the surface, Outcast, which was released the very same year as Omikron, possesses many of the same traits, being another genre-mixing open-world narrative-driven game with a diegetic emphasis that extends as far as the save system; even the name is vaguely similar. I tried it out some months ago at the request of a reader, going into it full of hard-earned skepticism toward what used to be called the “French Touch,” that combination of arty themes and aesthetics with, shall we say, less focus on the details of gameplay. Much to my own shock, I ended up kind of loving it. For the developers of Outcast did sweat those details, did everything they could to make sure their players had a good time instead of just indulging their own masturbatory fantasies about what a game could be. It turns out that some French games are generous, just like some of them from other cultures; others are full of themselves like Omikron.

To be sure, there are people who love this game too, even some who call it their favorite game ever, a cherished piece of semi-outsider interactive art. Far be it from me to tell these people not to feel as they do. Personally, though, I’ve learned to hate this pile of pretentious twaddle with a visceral passion. It’s been years since I’ve seen a game that fails so thoroughly at every single thing it tries to do. For that, Omikron deserves to be nominated as the Worst Game of 1999.



Did you enjoy this article? If so, please think about pitching in to help me make many more like it. You can pledge any amount you like.


Sources: The books The Complete David Bowie by Nicholas Pegg, Starman: David Bowie, The Definitive Biography by Paul Trynka, and Bowie: The Illustrated Story by Pat Gilbert. The manual for David Cage’s later game FahrenheitPC Zone of November 1999; Computer Gaming World of March 2000; Retro Gamer 153.

Online sources include “David Cage: From the Brink” at MCV, “The Making of Omikron: The Nomad Soul at Edge Online, Omikron Team Interviewed” at GameSpot, “How David Bowie’s Love for the Internet Led Him to Star in a Terrible Dreamcast Game” by Brian Feldman for New York Magazine, “Quantic Dream at 25: David Cage on David Bowie, Controversies, and the Elevation of Story” by Simon Parkin for Games Radar, “The Amazing Stories of a Man You’ve Never Heard of” by Robert Purchese for EuroGamer, “David Cage : « L’attitude de David Bowie m’a profondément marqué »” by William Audureau for Le Monde, “David Bowie’s 1999 Gaming Adventure and Virtual Album” by Richard MacManus for Cybercultural, Fahrenheit : Interview David Cage / part 1 : L’homme orchestre” by Francois Bliss de la Boissiere for OverGame.com, “Quantic Dream’s David Cage Talks about His Games, His Career, and the PS4: It Allows to ‘Go Even Further'” by Giuseppe Nelva for DualShockers, Quantic Dream’s own version of its history on the studio’s website, and a 2000 David Bowie interview with the BBC’s Jeremy Paxman.

Where to Get It: Omikron: The Nomad Soul is available as a digital purchase at GOG.com.


Renga in Blue

PRISM: Unspeakable Forms

(Continued from my previous posts.) First off, to share from the comments– Morpheus Kitami: The colored letters have different kinds of colors. Maybe instead of one word per page, it’s one sentence from all the differently colored letters. All the purple, blue, green, etc. This could be for each key, maybe this connects to the […]

(Continued from my previous posts.)

First off, to share from the comments–

Morpheus Kitami:

The colored letters have different kinds of colors. Maybe instead of one word per page, it’s one sentence from all the differently colored letters. All the purple, blue, green, etc. This could be for each key, maybe this connects to the words on-screen?

There are some pictures in real world locations, perhaps this is intended to be a clue? Is there a building that looks like the two pillar building in Syracuse?

Morpheus is referring specifically to this one:

From ern2150:

33 letters? 3 keys, is that enough to spell city/state abbreviations?

From Alastair:

Up north / Lines meet / Down south / Fates greet.

Is there a northern US state (or state or town) where lines of some sort (roads, railway lines, whatever) meet, and for a southern state where “fates greet” makes sense?

I think a good approach is to think of “small” mysteries, individual questions that might be answered or theorized about even if we don’t have a good approach to finding keys yet.

a.) What are the green letters KFGCEAK from the third image used for?

Most of the pages easily anagram. This one doesn’t, and another page you’ll see today doesn’t.

b.) What does 1 THRU 3 / OF EIGHT refer to?

I would guess the “standard” Venn diagram with red, green, and yellow circles overlapping. (Especially given the packaging says “each represents a primary color” in regard to the keys.) This makes seven colors, eight if you include black. The list (red, blue, yellow, green, magenta, orange, white, black) does seem to represent the full color spectrum of the game.

Perhaps something that’s colored in green (like the mystery-anagram) refers to blue and yellow keys specifically, but not red?

c) What does ONE OF TWO / TWO OF ONE / COLORS RED / WHITE AND BLUE refer to specifically?

Maybe the magenta part of the Venn diagram?

I want to do some big-picture analysis in my next post, so rather than waiting I’m giving the entire rest of the story. Get ready:

Yolvsa, Plane of Darkness. A hot, silent wind blew over the desolate landscape, and colors more hideous than the boy had ever imagined painted the cruel specter.

Rising from the bleak surroundings, Hubert discerned a reptilian tangle resembling nothing in his experience except a grotesquely upturned tree. Waving above its misshapen body, he beheld a vision of wildly twisting purple tentacles… monstrously flashing green teeth… yellow tongues flapping wordlessly in an impossible world of terror.

YOLVSA.

Now, Hubert’s only contact with his familiar, secure world was the PRISM he had so hastily thrust into his pocket. Sensing more than feeling the heat now emanating from it, he pulled it out and held it in his hand. From the mysterious crystal now came a pale, pulsating light.

Instinctively, Hubert knew that he was nearing his goal, and that the PRISM was guiding him inexorably toward it. Determined now to meet with success or accept his fate, the lad prepared to follow the all-compelling crystal wherever it led.

At that instant, the parched torrid wind arose with a roar, sweeping before it every pebble, jot of earth, and the hapless Hubert. Desperate, with no other shelter visible, he reached out to grasp a limb lashing in the tempest. He had found concealment behind the torturously twisted limbs of a mutant tree where he made himself as small as possible and inwardly quaked as he waited.

TRET? This is the other one that fails to anagram. The side text also doesn’t match the story or picture at all, suggesting a stand-alone riddle.

Huberts efforts were to no avail. A creature of unfathomable deformity, grotesque in feature and limb, materialized at his side and cast him to the ground. Grane, prince of Yolvsa, keeper of the thousand names of horror, gazed redly at the small, prone human.

With a malignant sound that the boy could only compare to laughter, the creature stared down at Hubert and, at last, spoke. ‘The Protectors send a mere child to do their bidding. O, powerless being, we of the darkness will teach you to confront the forces of Yolvsa. Away to my stronghold, where you will meet your inescapable destiny.’

The entrance to the stronghold of evil; a seething, snarling mass of unspeakable forms crying out for a share of the treat. Hubert could not mistake the fact that he was to form the basis of a savage ceremony. How they howled in the throes of unwholesome ecstacy!

(Note: “Huberts”, “gazed redly”, and “ecstacy” are transcribed correctly. Gazing redly could of course be a clue.)

GRANE, the name of the prince. Again the side text is more irregular than normal.

With monstrous majesty, Grane led the boy through a labyrinth of chambers and corridors into a vast, cold space. In it stood a twisted throne of immense magnitude upon which Grane seated himself. His red eyes stared down from his sinister face.

‘Resign yourself, whelp. Although you are an insignificant figure, you may yet furnish an interesting tidbit for my extremely large fangkat. Come, my lovely. . .

From the recesses of the darkest corner of the chamber slinked an indescribable apparition, a being of incredible hideousness and all too apparent appetite. Brave as Hubert was determined to appear, he quavered under the malicious stare of the creature.

With little hope of escape, Hubert’s glance darted wildly about the throne room, alert to any means of salvation. Transfixed with terror, he was still aware of the PRISM, now burning in his pocket. Its ancient purpose aroused at the nearness of the keys. Like a thing alive, it demanded to be set free! Hubert drew it forth, and like an extension of himself, flourished it in the faces of the Yolvsa horde.

XXXVI, that is, the number 36. (Or 34!)

As if with a will of its own, the PRISM whirred above their heads in the hands of the intrepid lad. The Keys were near, and Hubert would have them whatever! As swiftly as the thought had come, a glint of bright metal struck his eye.

‘A mere talisman — that trinket — will avail you not,’ raged Grane, ‘and we taunt you as you stand before us. Behold! The Keys are here in my hand — your first and last sight of them.’ He raised the keys in his twisted hand, daring the boy to marshall his last spark of courage and make a futile attempt to defend himself.

Hubert knew not what he did, but the PRISM guided his hand in a flashing arc. As he brandished it in Grane’s face, it glowed with a white-hot force which seemed to be drawn from the Keys the monster held. Enraged in the face of the burning crystal, Grane gave a mighty roar. . . and an eruption of color — the brilliance of the spectrum — burst upon the assemblage. Half blinded by the intensity, Hubert nonetheless heard the clatter of metal tinkling at his feet as Grane swayed on his throne of terror.

Hubert, his hands sprawled along the floor, felt desperately around him for the keys, trying to retain the direction of their ringing in his ears. After what seemed an eternity, his groping fingers felt a small metal object and, suddenly, Hubert had the magic keys of color grasped firmly in his trembling hands.

I still find interesting the notable lack of yellow.

Driven only by instinct, the boy crawled around the chamber, seeking the great iron doors which meant a passage to freedom. The PRISM, its colors shining with brutal intensity, masked his intent as he made his hurried way through the anarchy of Grane’s throne room.

Hubert reached the doors shakily, drawing great gulps of the fetid air into his aching chest. Quickly realizing he needed his sight, he pocketed the PRISM, extinguishing its blinding brilliance. As his eyes adjusted to the relative darkness, he hastily scanned the maze of corridors confronting him, struggling to recall Grane’s course when they entered. The awful sound of naked claws scraping and clattering on stone, spurred him to action.

He ran! He ran with a speed as great as his terror. First left, then right, then right again and miraculously, the great doors of the stronghold loomed up before him.

Out the door he flew, eyes wild and lungs burning from the noxious air. From within the loathsome building came the sound of a mighty bell, sounding the alarm to the minions of Yolvsa. Hubert jumped from the path and skittered down the embankment just as the pursuing creatures burst through the gates howling their terrible curses.

RUNNERS?

His forward motion carrying him, Hubert lunged–but in the same instant was pulled back sharply. Around his ankle wound a hot, purple tentacle dragging him relentlessly, remorselessly, back into the Plane of Darkness!

LIFE.

With his overtired mind and body reaching their utter limits, Hubert made the most important decision of his young life: If he could not survive, he would, at least, cheat Grane and his malignant forces of their victory.

Drawing back his arm, he hurled the Keys and the PRISM together, with all his might, through the rapidly narrowing space. The world he, himself, would never again behold would yet have its beauty restored.

Even as he swooned, a mightily sinewed arm reached through the prortal and pulled the boy across the threshold. A rush of cool, sweet air, and the darkness closed about him…

(Note: “prortal” correct.)

In the quiet of his own room, in his parent’s humble home, Hubert awoke as from a dream. There were no Keys, no sign of the glowing PRISM. Was it, then, a dream, or had he really seen and done the fantastic deeds he remembered now? And yet, as he roused himself wearily from his bed and silently pulled on his shoes — a single blade of grass, colored in a loathsome shade of purple, dropped from a shoelace. Hubert acknowledged his playful puppy’s kisses and, his face set in a mask of determination, finished dressing and headed out the door, Uanna barking and following close behind.

In a sequestered cavern, beyond mortal reckoning of time and space, a PRISM still glows quietly in the semi-dark.

Color of an uncertain brightness has returned to the world, but the rich tints and intense hues of a bygone time are only the stuff of legends, living in the memories of the very old.

Is the quest unfinished? Does the PRISM still burn to be reunited with the Keys of the spectrum, lost by Hubert’s heroic throw? You and I know, that somewhere on this terrestrial plane, the answer lies hidden. Will you follow the fearless Hubert and complete the task? To the Protectors of the PRISM falls the duty and honor of reuniting the keys with the PRISM and reaping their colorful reward.

With a little animating on the letters.

Hopefully there’s enough to chew on now! If nothing else the pages with “non-sequitur” phrases could really use some speculation. I’ll get into wild-analysis mode next time and try to sort things; one big question is “are the three keys all hidden by the same code, or are they clued in three entirely different ways?”

(OK, if you combine the two “unanagrams” you get KFGCEAKTRET which can make “keg fact trek” or “tack fret keg”. I don’t think either of those are intended.)

Thursday, 22. January 2026

My So Called Interactive Fiction Life

Sharpee.Net

Sharpee has it's own home outside of github now.Visit https://sharpee.net/.There are quick start and author guides along with the beta port of Mainframe Zork aka Dungeon.The platform is also in beta and can be used to create stories. I only have the thin

Sharpee has it's own home outside of github now.

Visit https://sharpee.net/.

There are quick start and author guides along with the beta port of Mainframe Zork aka Dungeon.

The platform is also in beta and can be used to create stories. I only have the thin web client implemented, but electron, React, and screen reader clients are on the docket.

You can report issues at https://github.com/ChicagoDave/sharpee/issues

I hired a fiverr graphic designer to make a logo and banner and I'll add those when they're ready.


Choice of Games LLC

Our animal games are on sale!

Celebrate animals both real and fantastical with our Creatures sale! Raise a baby gryphon in Runt of the Litter! Swashbuckle with pirate dogs in Pugmire: Treasure of the Sea Dogs. Make magical mischief in Fox Spirit: A Two-Tailed Adventures – or just regular mischief in Choice of the Cat. Ride a dinosaur to victory in DinoKnights, or travel back in time to pet the cutest baby duckbill in T-Re
Pugmire: Treasure of the Sea Dogs

Celebrate animals both real and fantastical with our Creatures sale!

Raise a baby gryphon in Runt of the Litter! Swashbuckle with pirate dogs in Pugmire: Treasure of the Sea Dogs. Make magical mischief in Fox Spirit: A Two-Tailed Adventures – or just regular mischief in Choice of the Cat. Ride a dinosaur to victory in DinoKnights, or travel back in time to pet the cutest baby duckbill in T-Rex Time Machine.

They’re all up to 40% off on all platforms: Steam, Android, our website, and on iOS in the “Choice of Games” app until January 29th!


Renga in Blue

PRISM: Colorless as a Tear

(Continued from my last post.) From a review by Brian Murphy (Creative Computing, May 1983) he writes that: I was unable to wrest any hints from ISM. Are the keys more than one hundred miles apart? Five hundred? No comment. Are the clues in the pictures only, in the pictures and inscriptions, or in the […]

(Continued from my last post.)

From a review by Brian Murphy (Creative Computing, May 1983) he writes that:

I was unable to wrest any hints from ISM. Are the keys more than one hundred miles apart? Five hundred? No comment. Are the clues in the pictures only, in the pictures and inscriptions, or in the text, pictures and inscriptions? No comment. The only help I got, which I pass on to you, is that the keys are in the 48 contiguous states… somewhere.

I did think it possible, given the office in England, that this might be a cross-continental game (enabled by having three keys!) Apparently not.

My commenters last time (ern2150, Voltgloss, Gus Brasil, arcanetrivia, matt w) noted that two of the graphics screens seem to involve anagrams; the letters of PRISM in the first and CLEAR in the second. The third, mystifyingly, seems to have no equivalent (I even checked the rest of the story in case of a proper name that matched).

I’ve added connections to the letters in case the idea is to make a shape that spells something out or keep an eye on what parts of the picture the “lines meet” at. In addition to this being open to interpretation, if the line idea is right, it isn’t clear what point each vertex should be touching (the center of a letter? right on the edge of the frame?) Perhaps the third non-anagram page is supposed to be more of a code?

One other major point to mention is that the three keys are given as Blue, Red, and Yellow, yet the colors of the screens are Red, Blue, and Green. Colors after are Red, Blue, Purple, Green, Red, Red, Orange, Blue, Purple, and Multicolor. While I’m not officially up to Multicolor yet, I wanted to share that screen early just because it is so notable.

The colors have their usual Apple II muddy effects going on so I can’t be certain, but I think the “A” on the page bottom is the only place a letter is colored yellow. (The anagram here, by the way, is Uanna, the name of the dog. The name is so unusual surely it is a significant clue? The review I mentioned earlier thought the dog’s name was Vanna, but cross checking a word starting with “V” later indicates the game definitely meant Uanna.)

In addition to maybe suggesting “up”, “advance”, “north”, “north”, “advance”, the presence of UAANNA here is notable in that it means this hunt is not exactly like Masquerade. (Again, no solution was published 1982, so there’s no way ISM could have copied the solution part, just the words and colored letters on the border.) The text in Masquerade was completely a red herring. (There were some riddles, but they led nowhere.) Here, the text seems to have at least a little relation to one of the images.

I’m going to pick up the story now all the way up to where Hubert enters the “other world” and the player is requested to swap disks.

Suddenly, Hubert found that he was standing in a vaulted cavern bathed in an eerie, muted light. Bewildered, Hubert glanced about for a familiar sign or friendly face. As his vision cleared, he beheld the figure who had brought him to this strange place, standing alongside a similarly dressed companion.

‘Why have I been brought here? Where am I, and who are you?’, asked Hubert of the steadfast guardians. Nothing met Hubert’s ears but the most profound silence. Then, suddenly. . .

‘You are the True Protector of the PRISM,’ pronounced a voice from the vastness. ‘You alone can retrieve the Keys and restore the powers of the PRISM to your world.

Even as the voice reverberated, the last vestiges of color were draining from sight. Boldly, the lad raised his eyes to the space above and asked again, ‘Where is this place, and why am I here?’.

From the void came the reply, ‘The location is of no matter. Only the fact that you are here, and you are the chosen Protector. Unto you has been given the task of restoring the keys to their hallowed resting place. Only then will color return to the world. Behold the PRISM, Lad, and see its despair.

As though his sight were guided, Hubert looked upon a pedestal in the center of the cavern. On it lay a translucent object of great beauty, as colorless as a tear. Above it on a shelf were three empty keyholes.

Animated rays like the sun was animated.

‘Find the keys, my boy, and return them to the Cavern of Color. Only then can the joy and beauty of color be restored.

Accepting the disembodied voice, brave Hubert asked, ‘Where have the Keys gone, and why am I chosen to search for them?’.

‘You are the chosen of the PRISM, for only the small and pure of heart can pass through the portal. Among your people, age brings wisdom of a sort, but with it a loss of the magic born into every child. No one of full growth, therefore, can slip through the walls of the world and bring back the beauty that has been taken from you. Ask no more questions, for even now the access narrows and further delay would mean all would be lost.

Red, White, and Blue are the colors mentioned here. White = yellow somehow?

‘You must summon all of your courage for this journey’, the voice continued. ‘Dark forces of great power will be arrayed against you. Grane, prince of Yolvsa, has breached the portal and stolen the keys to add color to his evil wastelands. Yet, he foolishly left the prism behind, not knowing its power of focus. Take the PRISM, Hubert. Go and be swift! For even as I speak, your moment is quickly departing. Behold, the portal!’

Piercing the darkness, Hubert beheld an aperture of odd configuration, rapidly diminishing, even as he stared. Clutching the PRISM tightly, he plunged into the darkness.

The anagrams HUES and PORTAL are there; other than that I’m going to keep any analysis for now in the comments.


My So Called Interactive Fiction Life

Little Bits and Pieces

In the last week I've been play-testing the port of Dungeon which has exposed many things about Sharpee and the Dungeon implementation. Many many things.Just the first ten to twenty turns of Dungeon have uncovered a lot of issues. The troll logic is actually quite complicated. Had

In the last week I've been play-testing the port of Dungeon which has exposed many things about Sharpee and the Dungeon implementation. Many many things.

Just the first ten to twenty turns of Dungeon have uncovered a lot of issues. The troll logic is actually quite complicated. Had to scour through the 1981 source for that logic.

I clarified with Claude that events in Sharpee are not true Domain Events and certainly not pub/sub events. They are Command Events and though they bear a striking similarity to Domain Events, there is not way to replay a list of them to reach the current state of the game. But this clarification cleaned up a lot of confusion in the layers and was a surprisingly easy refactor.

We refactored meta commands to execute outside of normal turn processing.

We implemented save/restore/restart/version/diagnose.

We added transcripts to the web client save command (it copies inner HTML, compresses it, and stores it with the save instance).

We added a proper banner, although I just realized the IFID is not displaying.

We added the grue->death logic.

We added the attic block (must be two items and one has to be the lamp).

We implemented dual mode for entities. The author can create their story using string literals OR push all strings through language packages and provide multilingual support and the client can switch languages mid-game.

We implemented player character variability so the author can define the PC, their identify, and switch between player characters at any time.

We fixed the leaflet and ABOUT text to match this implementation.

We implemented proper build versioning to platform, story, and client and created bash scripts to automate builds.

I'm sure I'm missing something, but a lot of nit picky changes that help move Sharpee and Dungeon to completion.


The People's Republic of Interactive Fiction

November 2025 Post Mortem

The People’s Republic of Interactive Fiction convened on Thursday, November 20, 2025 over Zoom. Stephen Eric Jablonski, Hugh,, Josh Grams, Michael Stage,   Matt Griffin, zarf,, Cidney Hamilton, Doug Orleans, David J Hall, and anjchang, welcomed newcomers and Monica Storss. Warning: What follows is probably not proper English, but just a log of notes from the meeting to […]

The People’s Republic of Interactive Fiction convened on Thursday, November 20, 2025 over Zoom. Stephen Eric Jablonski, Hugh,, Josh Grams, Michael Stage,   Matt Griffin, zarf,, Cidney Hamilton, Doug Orleans, David J Hall, and anjchang, welcomed newcomers and Monica StorssWarning: What follows is probably not proper English, but just a log of notes from the meeting to jog people’s memories.

In general, topics covered IF preservation news (Zork!), new tools/experiments (Ink + Godot, Bitsy exercises), community jams (EctoComp), and ongoing debates about IP openness vs. protection in interactive fiction/narrative games.

Major News & Announcements

Games & IFDB Entries Mentioned

People & Social/Media

  • Monica aka@digitalpoetics on Instagram, Discord, and other “agitprop” outlets (likely for experimental/digital poetics/narrative work).

Industry/IP Discussion

  • Many treat old games/code as effectively open source in practice, but companies vary wildly in handling legacy IP.

Narrative Engines & Tools Discussion

  • Why so many engines? People love experimenting and building their own (e.g., Twine, Ren’Py inspire lots of creators).
  • Mentioned projects/tools:
    • Domino Club / Domino Gallery: Loose collective for anonymous game jams, low-tech/digital art, narrative-heavy work, ditherpunk, etc. (focus on DIY, remix, glitches, queer themes, etc.).
      Link: https://domino.gallery/
    • Related piece: “good writers are perverts” manifesto/essay by DOMINO CLUB (interactive “tape window” format arguing for embracing “sicko” creative impulses).
      Link: https://dominoclub.itch.io/good-writers-are-perverts
  • Yack script example (Ink-based dialogue system, from Grumpy Gamer’s DeloresDev repo—likely Thimbleweed Park-related dev work).
    Link: https://github.com/grumpygamer/DeloresDev/blob/master/Scripts/Yacks/Sheriff.yack
  • Bitsy for game poems/tiny narratives: Limited text UI space; Pico-8 also noted for similar constraints.
    • Anna Anthropy’s Itsy Bitsy Exercises (Bitsy teaching exercises for narrative design—spatial movement, dialogue, etc.; full details in devlog posts).
      Link: https://w.itch.io/itsy-bitsy-exercises
  • Other platforms: Playdate handheld (crank + charger features).
    Links: https://play.date/games/blippo/ and https://play.date/

Design/Systems Discussion Highlights

  • Praise for a diagram-based approach (circuit-like, state-showing; “systems thinking”).
  • Idea: Can you build a game directly from a diagram? Potential for hybrid narrative modes (pause navigation for decisions).
  • Question raised: Handling state/history across geographical spaces (Metroidvania-style logic?).

Wednesday, 21. January 2026

Renga in Blue

PRISM (1982)

PRISM is an ISM Storydisk which tells the wonderous tale of the theft of the three ancient Keys of Color, and the adventures of the young boy who must seek them in the monstrous kingdom of Yolsva, Plane of Darkness. All is chaos, and the story contains many levels of hidden meaning through which the […]

PRISM is an ISM Storydisk which tells the wonderous tale of the theft of the three ancient Keys of Color, and the adventures of the young boy who must seek them in the monstrous kingdom of Yolsva, Plane of Darkness. All is chaos, and the story contains many levels of hidden meaning through which the Keys may be found and reunited with the prism. When this occurs, and only then, can the mysterious and magical ending of PRISM unfold.

— From the instructions for PRISM

Six years ago this blog tackled the game Alkemstone (1981), a contest leading to a buried treasure with clues in an Apple II game (the Alkemstone itself did not have value, but you could win money from the company for finding it). A year after Alkemstone there was another Apple II program, but this time hiding real buried treasure. As far as anyone knows this treasure is still buried.

In 1980, Stephen Brightbill founded International Software Marketing, Inc. in Syracuse, New York. They launched with the product MatheMagic in 1981, software that “harnesses the power of your Microcomputer to perform simple arithmetic to sophisticated mathematics.” It had versions for DOS, CP/M and Apple II and sold for $89.99.

Where this put them on their main product line was a 1982 extension, Graph Magic, which allowed for “figures in graphic form and full color”. From there they followed with Color Magic and essentially pivoted to graphic presentation software for the duration of their lifetime (folding in 1992, according to Brightbill, due to “competition” and the “rise of Windows”; they were DOS-only by this time).

The “International” part of the name is significant as while it might have been a little aspirational, they did list a UK office branch in their ads. This connection means they likely had strong familiarity with the book Masquerade which was still being a smash hit at the time.

I bet you can do something with books that no one has ever done before.

— Tom Maschler of the publisher Jonathan Cape, directed at the artist Kit Williams, author and illustrator of Masquerade

I’m not giving a history of Masquerade but rather deferring to Jimmy Maher; the important points are that it was a real-life treasure hunt for a buried hare designed by a real jeweler, and the hints to find it were inside the pages of a lavishly illustrated “children’s” book.

We’ve already encountered several “contest games” on this blog, including the previously mentioned Alkemstone, but also Krakit and Pimania. While it is almost certain they happened because of Masquerade-mania, none of them tried to match the form factor. Alkemstone had clues hidden in a first-person maze, Krakit just had a series of puzzles on ZX81 (and no buried treasure!), and Pimania was an adventure game where the clues suggested a particular time and place to go (but again, nothing buried).

That’s not the case for PRISM. PRISM has not just one buried treasure, but three: keys designed by the Syracuse Jewelry Manufacturing Co.

Blue: 18K gold key with 3/4 carat Blue/White Diamond

Red: 14K gold key with 3/4 carat Ruby

Yellow: 10K gold key with 3/4 carat Topaz

The value given by a 1983 review is $15,000 (I believe that’s all three keys together).

The people involved (besides presumably the CEO) are all listed. Mark Capella and Ronald Roberts are “co-designers”, Mike Sullivan did art, and Carol Keller did editing. We’ve seen Mark Capella here before; Mike Sullivan of Microstar Graphics later did the disk magazine PC Life. Relevant for today, here’s Sullivan’s “Musical Christmas Disk” called ‘Twas the Night Before Christmas disk from 1987 (if it embeds correctly, it is interactive and you can try it right in the browser):

If you’re wondering how a business-software company got involved with making a game, in some sense, it isn’t a game at all. The software is merely a “Storydisk” for Apple II which is a “slideshow” much like the ones people could make with their own software. It presents a book that bears strong similarity to Masquerade and hence PRISM represents the closest thing Masquerade had to an actual clone.

Now, a huge disclaimer: just like Alkemstone, it is quite possible the contest landed somewhere too ambiguous to solve (explaining why they never announced a winner, even though the company lasted for ten more years). On the other hand, we discovered things out of Alkemstone nobody had seen before, and there’s three locations rather than just one, so it is still faintly possible something of real money value may come from this exploration. I cannot prevent anyone searching on the basis of information here. I will state myself outright if I find anything myself personally I will be donating it to a gaming museum like The Strong. I cannot speak for anyone else. You can assume anything posted here is public.

The pages that do have art have some animations, so while I’m going to be showing pages from the “book”, there’s going to be a little more going on than with Masquerade; it’s even possible there’s “hidden keypresses” or the like which are part of the game. At least in general the only options are “left arrow” and “right arrow” to move between pages.

Not including the start and end, there’s forty pages total. I’m going to just give the first seven for now, but I’ll give out later sections in larger chunks. I expect to make at least six posts and possibly a few more; feel free to chime in with theories in the comments about what’s going on.

For the text-only pages I’m going to give text rather than screenshots, although I did want to show the first page off as an example.

Hubert stretched luxuriously in his comfortable bed, rubbed his eyes and met the brilliant colors of the morning with a smile. His first thought, as always, was of his favorite little puppy, Uanna. A whistle, a clap of his hands, and she was there on the coverlet, her playful green eyes urging him to get up and about for their morning frolic. Like any hearty lad, Hubert dressed without losing a moment… looking forward to the fun and sport he knew lay ahead. Calling the pup to his heel, he strode happily through the door.

It was a glorious day in spring, and the sun shone down on the myriad and beautiful colors of the world. The brightly clad people of Hubert’s town seemed to bloom with the splendor of the flowers around them. In the golden sunlight, the gentlefolk exchanged pleasantries and basked in the splendor of Nature.

I find the transcription much easier to read!

The rays do some color cycling.

The first graphical page; notice the words along the border as well as colored letters. These are both clones of Masquerade, although there is no implication they get used in the exact same way (the solution hadn’t been released yet of the original book!) Hence we have the curious situation of someone copying what a puzzle looks like but quite possibly doing something very different with it.

Hubert, a small but sturdy lad, smiled as he watched the congenial fellowship of his townspeople. Around them, the festively colored birds chatted as they built their nests, and the animals lazily stretched their muscles after a satisfying winter’s nap. With Uanna following close behind, the boy whistled as he strode down the road, with not a care in his mind.

And it was then that. . . A sudden hush descended upon the street. Hubert cast an anxious glance about, then started in disbelief. Around him, HIS WORLD WAS CHANGING !!!

Two more text pages (page 5 and page 6), and then I’ll give the image after, and that’ll be enough for today.

Where the warm golden sun had beamed, only a white blaze appeared. The gaily clad people looked down at themselves in disbelief as the colors slowly drained from their brilliant clothes. Before their eyes, their splendid world was turning black and white and every shade of grey in between!

Young Hubert felt a chill run through him as he witnessed this stupendous horror. ‘How can this be?’ he wondered. Even the animals seemed to sense the transformation as they scampered back into their burrows. The townsfolk silently dispersed, shaking their heads in wonderment.

Suddenly, Hubert found himself alone on the stark, black pavement, his puppy pressed up against his leg in her anxiety. The once, and so recently colorful world was rapidly beginning to resemble the pallid grey images on one of his grandmother’s old photographs. As he turned the corner in the direction of his home, he found himself confronting the gigantic figure of a strangely garbed individual. The apparition wordlessly reached for Hubert and as he lifted, they both seemed to fade into nothingness.

The above images animates with the two figures disappearing:

I’m stopping here (page 7) to give people time to comment and will continue on page 8 next time.

Tuesday, 20. January 2026

Renga in Blue

The Colonel’s House: Interview with the Author

(Continued from a post from a year ago. You should probably read that post before this one.) While I occasionally reach a videogame in the All the Adventures project which is famous enough to have existing interviews and memoirs to pull from (like The Hobbit and The Dark Crystal) oftentimes I have very little to […]

(Continued from a post from a year ago. You should probably read that post before this one.)

While I occasionally reach a videogame in the All the Adventures project which is famous enough to have existing interviews and memoirs to pull from (like The Hobbit and The Dark Crystal) oftentimes I have very little to start with. Even when an author gets some attention from later work they may never talk about their adventure game output (like with Stuart Marks’s biography pretending that Pillage Village didn’t exist).

Hence I was gratified when the author of The Colonel’s House (Rob Davis, 14 when he wrote the game) contacted me and not only was he willing to do an interview, he remembered this era well.

The first computer I experienced was a ZX-81 that my Maths teacher showed in the school staff room. I was immediately massively inspired by seeing it, and requested one for my birthday. I learnt to program BASIC on the ZX-81, and very quickly outgrew it and bought a VIC-20 where I continued to program BASIC and learnt Assembler.

Rob Davis first had contact with adventure games via a visit to a friend’s house; they had an Apple II and were playing Mission: Asteroid, “a really early graphic adventure that I remember involving a spaceship, and you had to work out which buttons to press on a very simple spaceship control panel, and it was a text adventure, but it was graphics, and I found that really exciting.”

He also had exposure to Mystery House (more on that in a moment) but otherwise this brief visit was his only exposure to adventure games (he played lots of games, “especially Jeff Minter ones”, but not adventures); that was enough to make him want to write his own.

I was just doing it in my own from my own inspiration it was just really that one game and really just one hour with that game that was the starting point for me.

He had no exposure to Crowther/Woods Adventure, or Scott Adams, or any of the VIC-20 adventure games coming out at this time.

I did it from scratch. I had read books about coding, but no, I had no guide to making adventure games or anything. I just started and I worked out how to build the engine for the adventure game, which was an engine that was able to kind of store room state, store player state, parse language, render rooms and react to your movements across the rooms and react to the objects changing state and all those kinds of things. So I wrote the engine for that from scratch from my own understanding of coding.

His VIC-20 had memory expansion; he wrote one game as a proof of concept (“a small map and was set on a desert island”) before writing The Colonel’s House.

More than games, I was inspired by the Omen movies on TV at that time, which had a set of seven daggers forged to kill the Antichrist.

He’s referring to The Seven Daggers of Megiddo. They are named after the seven churches from Revelation, and each one needs to be placed at a different point of the body to kill the Antichrist.

The Colonel’s House was a “private game” to just share with friends. Sometime after this, he had gone to a computer game show in London, where he found Rabbit Software, and the topic of his game came up:

I got talking to them, and they asked me to send them a tape of my game. I wasn’t going to send it, but a school friend persuaded me that I should, and Rabbit immediately offered to publish it.

They were “chaotic” and actually released the game without telling Davis; a school friend had said they’d seen it at a game store. Rob didn’t believe him but his friend offered to buy a copy.

That was also the first time I saw the cover art, which I didn’t approve at the time, though in hindsight it was OK.

I was able to discuss the content of the game a bit; he had a scene (which I didn’t hit while playing) where you can fall out a window; you’ll be alive, get picked up by an ambulance, but then the ambulance will get in a wreck on the way to the hospital and you’ll die. This comes directly from a death in Mystery House (when you leave the attic). Regarding the amount of the death the game has in general:

I mean, I’m casting myself back now to when I was 14, but I’m not sure that I would know mechanically how I wanted to treat players who had done something unwanted and kind of you know failed in one of the puzzles; like probably death was the only way to handle that. How do you cover the cases of the different failures of the puzzle? That might have been a complexity that I wasn’t sure what to do with … therefore game over seems like quite a kind of neat way to wrap up whatever kind of sequences of actions that haven’t got them (the player) to the right solution.

He did indeed have a grand plan for seven games total:

I had planned to make 7 adventure games, each to recover a different one of the 7 Knives of Eternity. The lore was that the knives were extremely powerful and when joined together, gave the holder ultimate powers. They had been hidden distributed throughout time and space for safety, but their locations had been compromised and others were seeking them. You were an agent who had to recover them and destroy them for good. I did complete the 2nd game, Escape from Detra Five, which had a knife hidden in an alien space station. Unfortunately it was never released because Rabbit went out of business.

He remembers Detra Five being at a computer show once so it is still faintly possible a copy escaped to the wild; he doesn’t have one he can find.

Rob Davis did eventually go on to be a full-time game developer, and there’s even an interview in The Guardian with him back when he was in charge of Solaris Media (“worked with Macromedia Flash for five years to build websites, online games and digital art installations”).

His more recent work includes Star Wars: Hunters, a free-to-play game which was only shut down in October of 2025; his current ongoing project is a game intended to fight climate change with planting trees.

Again, deep thanks to Rob Davis for his time, and of course (if he is the one reading these very words) feel free to drop any additional thoughts in the comments.

Monday, 19. January 2026

The People's Republic of Interactive Fiction

January meeting (online)

The Boston IF meetup for January will be Wednesday, January 21, 6:30 pm Eastern time. We will post the Google Meet link to the mailing list on the day of the meeting.

The Boston IF meetup for January will be Wednesday, January 21, 6:30 pm Eastern time. We will post the Google Meet link to the mailing list on the day of the meeting.


Renga in Blue

Sword of Raschkil: Supermoon Logic

I’ve finished the game; this continues directly from my previous post. I received warning on the puzzle I was stuck on from gschmidl that: “I have no idea how you’re supposed to figure it out.” The puzzle is so baffling I am coining a new term, supermoon logic. The term moon logic has not come […]

I’ve finished the game; this continues directly from my previous post.

Covers of the last three issues of the magazine (ending in August 1983).

I received warning on the puzzle I was stuck on from gschmidl that: “I have no idea how you’re supposed to figure it out.” The puzzle is so baffling I am coining a new term, supermoon logic.

The term moon logic has not come up as often on this blog as you might think; as I’ve mentioned before, I think the term gets applied far too widely to any kind of puzzle difficulty without any kind of care taken to if a puzzle is illogical or just difficult. Quoting myself on the game Katakombs:

I still think the term is useful, but I tend to narrow down to circumstances were cause and effect seem to be nearly at random; perhaps you understand from the animation why the bubble gum made the goat move, but the connection is one that could almost never have been predicted. There is a disjoint between action and result. Oddly, in text adventures, this shows up less than you might think, just because the requirement of a verb adds specificity to an action; you can’t just USE BUBBLEGUM ON GOAT and have the animation happen, but rather need to specify to (for sake of example) FEED BUBBLEGUM TO GOAT. The puzzle is still perhaps a bad one, but there’s at least a suspicion that something interesting might happen.

This puzzle is worse than that. Not only do cause and effect seem to be random, but even after seeing the result the sequence makes no sense. Put another way, if a game asks me to “guess what the author is thinking”, usually afterwards I can see how the author made the decision they did (even if it went spectacularly awry). Here, even knowing the particulars and combing the source code I can’t even begin to reconstruct what was going on. Perhaps you, the reader, can help demystify this, but for now I’m slotting this as the rare supermoon logic, where moon logic doesn’t even make sense after the fact.

Last time I was stuck with water in a jar (from a pond), a key (extracted from the bottom of the pond), a gold leaf, and a staff. I had dead-ended at a castle with a pit that you could use a staff to fly over and a wizard in a room with a cryptic sign.

The pit turned out to be a complete red herring; I am unclear why the flying scene was in the game. Only the wizard room is important:

? E
YOU ARE IN THE CASTLE ENTRY.
VISIBLE ITEMS:
NOTHING
? E
YOU ARE IN THE WIZARD’S ROOM.
THE WIZARD IS IN THIS ROOM.
A SIGN IS NEARBY.
VISIBLE ITEMS:
WIZARD
SIGN
? READ SIGN
IT SAYS, ‘I AM CLUTON. THROW A PIE AND YOU WILL DIE.’
? TAKE SIGN
THE WIZARD SAYS, ”LEAVE MY SHINGLE ALONE.”’

The hint that I needed to do an action I had already done was enough to get by, but only because I looked at my previous screenshots and saw an action that could be done in any room.

? DRINK WATER
O.K.
EVERYTHING BEGINS TO SPIN AROUND AND…
YOU ARE ON THE HEATH OF ORIONE’S MANOR.
TO THE NORTH IS A HOUSE, TO THE EAST, A DUMP.
VISIBLE ITEMS:
NOTHING

Anyone with an idea? I tried doing anagrams of “I AM CLUTON”; I tried poking the word (and the “throw a pie” phrase) into search engines to see if I had missed some obscure cultural reference. I tried checking the source code to see if I had missed a way of getting a hint. Drinking the water elsewhere gets the message “BOY THAT REALLY HIT THE SPOT!!!” which suggests nothing magical.

The other lesson from this is that magic is very dangerous for a game designer; it can be done to make arbitrary effects, but if a part of the game is based on that effect, it is almost certainly going to be frustrating for the player.

Moving on, as we aren’t too far from the end:

You can go south to loop back to the forest with the oak tree if for some reason you missed something; if you go east you end up at a DUMP with a RAT. This room serves only to kill you if you try to mess about with the rat.

Heading north instead into the house, there’s a series of locations that are room-name-only (YOU ARE IN THE ENTRY HALL, YOU ARE IN THE BACK ROOM, YOU ARE IN THE BACK PORCH). One side room is a kitchen with a pie, and at the end of the sequence is a ghost.

Given the sign earlier, it was impossible not to resist trying to THROW PIE while at the ghost.

YOU HIT THE GHOST WITH A PIE.
HE GETS MAD AND PUNCHES YOU, THE FORCE OF THE BLOW
IS SO GREAT THAT IT KILLS YOU.

I know people are still sore about the pie/yeti combo from one of the King’s Quest games; finally, the ghost gets revenge.

Thinking outside the box, I looped back around to the wizard Cluton and tried throwing the pie at him instead…

…the end result being that THROW PIE still somehow throws it at the ghost, even when you are nowhere nearby. OK, yes, the source code is a bit fragile. (I checked the late issues — see top of this post — for corrections, but couldn’t find any, but maybe the magazine ended too quickly for that.)

I tried EAT PIE instead and found a diamond. Knowing GIVE was on my verb list, I tried GIVE DIAMOND while at the ghost and it worked.

This isn’t supermoon level logic since “enemy accepts something valuable” makes retrospective sense (sort of), but I certainly didn’t use regular logic to solve; it’s just the game limits so heavily what options are available I didn’t have many choices to go through.

The ending had no puzzle at all because I had already found the key (if you didn’t find it earlier, you can go back and get it; you can even refill your water and do the DRINK WATER trick again).

My apologies to the author if he’s here Googling himself. I did indeed hit a puzzle so baffling I had to coin a new word to describe it. I did at least appreciate the “pure” feel of the game even with the bugs and puzzle illogic, and even with minimal description I did get the scent of another world.

It was also useful to see what sort of game H & E Computronics printed (and the fact they likely did not test the game for bugs at all); as I mentioned in my last post, we’ll visit them again sometime at least once more (I have not skimmed the complete catalog to be sure nothing else is missing).

Coming up: an interview with an author giving a snapshot of the chaotic UK game publishing scene, followed by an Apple II “contest game” with buried treasure.

Sunday, 18. January 2026

Renga in Blue

Sword of Raschkil (1981 / 1983)

Written in 1981, not published until 1983. Take your pick. I didn’t have this one on any of my lists but El Explorador de RPG recently pointed it out; since it was not preserved otherwise, gschmidl then put the source of the game on his Github. It was printed in the magazine H & E […]

Written in 1981, not published until 1983. Take your pick. I didn’t have this one on any of my lists but El Explorador de RPG recently pointed it out; since it was not preserved otherwise, gschmidl then put the source of the game on his Github.

It was printed in the magazine H & E Computronics, which has barely had any mention here at all, so a brief history–

From the first issue of the newsletter (July 1978) that would eventually be the magazine called H & E Computronics.

Howard Y. Gosman, former math teacher out of New York, ran one of the first personal computer magazines kicking off in July of 1978; their June 1979 issue specifically bragged they were “the first TRS-80 PUBLICATION to last a year” as well as “the largest publication devoted to a single computer (over 16,000).”

This is an oddly specific claim meant to work around existing alongside things like PCC’s newspaper/magazine which launched in the early 70s and Kilobaud launching in January of 1977 (“The Small Computer Magazine”). One of their main competitors was Softside which was still TRS-80-only from 1978 through 1979 although it launched later (October 1978). Softside has been mentioned here now quite a few times; they printed, for instance, Dog Star Adventure, the first full-parser adventure game in a magazine.

Softside tended to be quite game-friendly; with the exception of the tax software from the February 1979 issue, every issue from ’78 through ’79 featured a game on its cover.

While H & E included games once in a while, they tended to be a seller of “serious” software; their catalog was heavy on the business side and they even kept this going past their own magazine’s existence, selling their own VersaBusiness software into the late 80s on a variety of platforms.

They did have one gaming landmark worth noting, possibly a side effect of their “serious” positioning: they have the first ad I can find for an adult game. Back in that June 1979 issue the company Phase-80 includes a mention of their games Strip Dice and Strip Concentration. (“Each player must follow ALL directions of the computer … The game may be played by ‘CRT’ light if desired.”) H & E Computronics later sold the infamous “activity catalog” Interlude, which you might remember from City Adventure.

The Phase-80 ad notably beats out the first commercial adult game in Japan, Yakyūken, although Yakyūken is far more significant in being a single-player erogē rather than a “party game” facilitated by the computer. (Joey Wawzonek has a terrific essay here about the game, answering the question “why are we stripping while playing rock paper scissors in the first place?”)

After their August 1983 issue, the publication (not company) of H & E merged with Basic Magazine (formerly 80-U.S. Journal, another magazine founded almost exactly the same time as H & E). Today’s game, Sword of Raschkil by Mac Vaughn, came from one of their last issues, May 1983. Comments from the code identify Vaughn as being at Henderson High School in Georgia.

Our author is standing second from the right, clearly demonstrating that Math is Cool. Via one of his school yearbooks.

True to form, the magazine the game appears in has a super-serious cover. This seems to be why their games have generally been overlooked in the various TRS-80 archives, even though this isn’t the only game in this issue (although it is the only adventure). From a different issue, Castle Adventure is another game I need to loop back to that again seemingly was never archived.

Our objective is to find the long-lost sword of a warrior from the distant past.

Several hundred years ago, the warrior Raschkil was slain in battle. It was rumored that he had had a magical sword, but when it was not found on him, many assumed that it had never existed.

Just a few months ago, you were digging in a garden near your small house when you unearthed a small, unlocked iron box. Within it was a map giving the approximate location of the sword of Raschkil! How did it get under the soil of your garden? No one will ever know.

You decided to find the sword, and had little difficulty finding the area on the map: an area surrounding a small castle. Now, using your wits, you must find the sword within the area named. Any further instructions are included in the program. Good luck you’ll need it!

We start, as is tradition, in a forest.

The game fortunately does not start with a maze; the forest is tiny, and it leads to an even tinier castle. The starting area map first, though:

Just to the south is a “hole” where ENTER HOLE puts you on a ledge of a bottomless pit, with a staff you can take. You can only get out with CLIMB LADDER so you can’t take the ladder with you.

Heading further south, there’s a meadow followed by a large oak you can climb. Along the way you can pick up a “golden leaf” and the top of the tree has a jar because … squirrels need jars?

Back to the start, heading east you can find a pool; you can FILL JAR at the pool.

I was expecting the water to be toxic and kill you. I’ve been in too many death-every-corner games lately, I suppose. You can also POUR WATER in any room where it “makes a puddle on the floor.”

The game also lets you SWIM, and I was briefly worried I had a broken-code issue for a moment afterwards.

YOU ARE SWIMMING IN A POOL OF WATER.
AT THE BOTTOM OF THE POOL IS A KEY.
? GET KEY
I CAN’T DO THAT AT THIS TIME.

The reason for my concern is I had discovered by now the game has a bug: if you drop any item you can’t pick it up. DROP STAFF cheerfully gets the response of “O.K.” but then trying to GET STAFF yields the response I CAN’T DO THAT AT THIS TIME. I checked with gschmidl who assured me the game was beatable as is, before arriving at DIVE.

Just for reference, my verb list, based on typing in all my standard verbs:

CLIMB, SWIM, READ, DRINK, EAT, FILL, THROW, UNLOCK, LOCK, POUR, JUMP, GIVE, ENTER, DIVE

This was a bit fussy to get because typing CLIMB has the response

I DON’T KNOW HOW TO CLIMB SOMETHING!!!!

which is a touch deceptive. The command doesn’t work without a noun.

With all that taken care of (and shockingly, no DIG command used anywhere, not an understood verb!) let’s proceed on to the castle, which might seem a little underwhelming so far but I expect I’m missing a lot.

Heading into the NORTH WING indicates that you feel a DRAFT, indicating perhaps the author was familiar with Hunt the Wumpus, as to the east is a pit. If you’re holding the staff you’ll levitate; if you don’t have the staff you’ll fall.

Dropping the staff is accounted for.

From the east of the start is a wizard with a sign. I haven’t gotten anything to happen here.

Inside joke, maybe?

Finally, to the south is … nothing. Absolutely nothing.

Again, I’ve been assured the game is beatable, but I’m still starting to worry (given the drop bug) I’m running into some other code-related issue. I’ll take suggestions in the comments if anyone thinks there’s something I missed.

And very special thanks to Ethan Johnson for assistance with getting the picture of our author, Mac Vaughn.

Saturday, 17. January 2026

My So Called Interactive Fiction Life

Capability Dispatch: A Pattern for Extensible Action Resolution

White Paper on Sharpee Interactive Fiction Engine January 2026AbstractSharpee's Capability Dispatch system solves a fundamental problem in extensible software: how do you allow third-party code to modify the behavior of standard operations without sub-classing, monkey-patching, or invasive hooks?This paper describes a pattern combining&

White Paper on Sharpee Interactive Fiction Engine January 2026

Abstract

Sharpee's Capability Dispatch system solves a fundamental problem in extensible software: how do you allow third-party code to modify the behavior of standard operations without sub-classing, monkey-patching, or invasive hooks?

This paper describes a pattern combining double dispatchcomposition over inheritance, and a behavior registry to create a system where:

  • Standard actions have default semantics
  • Entities can override or block actions via traits
  • Behaviors are registered externally and resolved at runtime
  • The system is extensible at three levels: platform, extensions, and applications

While developed for interactive fiction, this pattern applies broadly to any domain with entities, operations, and extensibility requirements.


Table of Contents

  1. The Problem
  2. Traditional Solutions and Their Limitations
  3. Capability Dispatch Architecture
  4. Design Patterns Employed
  5. Implementation
  6. Real-World Analogies
  7. Benefits and Trade-offs
  8. Conclusion

The Problem

Consider a system where:

  • Entities exist with varying compositions (a door, a troll, an axe)
  • Actions can be performed on entities (take, open, attack)
  • Behaviors vary based on both the action AND the entity's characteristics

The naive approach leads to a combinatorial explosion:

M entity types × N actions = M×N behavior implementations

With 50 entity types and 40 actions, you'd need 2,000 specialized handlers. Worse, adding a new action requires touching every entity type, and adding a new entity type requires implementing every action.

The Interactive Fiction Example

In a text adventure game:

  • Player types TAKE AXE
  • Standard behavior: move axe to player's inventory
  • But THIS axe belongs to a living troll
  • Desired behavior: block with "The troll's axe seems white-hot. You can't hold on to it."

How do we let the axe (or more precisely, something about the axe) override the standard taking behavior?

The General Form

This problem appears whenever you have:

Entity (with attributes) × Operation → Behavior

And you want the behavior to be:

  1. Determined at runtime based on entity state
  2. Extensible without modifying core code
  3. Composable from multiple sources (platform, extensions, application)

Traditional Solutions and Their Limitations

Sub-classing (Inheritance)

class TrollAxe extends Axe {
  take(actor: Actor): Result {
    if (this.troll.isAlive) {
      return blocked("white_hot_message");
    }
    return super.take(actor);
  }
}

Problems:

  • Rigid hierarchy; an item can't be both a TrollAxe and a MagicWeapon
  • New actions require adding methods to base classes
  • Diamond inheritance problems
  • Can't add behaviors from external packages

Event Hooks (Observer Pattern)

world.on('before:take', (event) => {
  if (event.target.id === 'axe' && troll.isAlive) {
    event.cancel("white_hot_message");
  }
});

Problems:

  • Global handlers; hard to trace which handler affects which entity
  • Order-dependent; handlers fight for priority
  • Weak typing; handlers receive generic events
  • No structured way to register/un-register

Visitor Pattern

class TakeVisitor {
  visitAxe(axe: Axe): Result { /* standard */ }
  visitTrollAxe(axe: TrollAxe): Result { /* blocked */ }
  visitDoor(door: Door): Result { /* can't take */ }
}

Problems:

  • Visitor must know all entity types upfront
  • Adding new entity types requires modifying visitor
  • Entity types leak into action code

Strategy via Callbacks

axe.onTake = (actor) => {
  if (troll.isAlive) return blocked();
  return defaultTake(actor);
};

Problems:

  • Ad-hoc; no structure or discoverability
  • Can only have one handler per action
  • No composition or layering

Capability Dispatch Architecture

Capability Dispatch separates the problem into four concerns:

1. Traits (Capabilities Declaration)

Traits are composable units of data and capability claims attached to entities:

class TrollAxeTrait implements ITrait {
  static readonly type = 'dungeo.trait.troll_axe';
  static readonly capabilities = ['if.action.taking'] as const;

  guardianId: EntityId;  // Reference to the troll
}

Key properties:

  • Traits declare which actions they can handle via capabilities
  • Traits contain data, not behavior
  • Entities can have multiple traits
  • Traits are added/removed at runtime

2. Behaviors (Capability Implementation)

Behaviors implement the four-phase action pattern for a specific trait+action combination:

const TrollAxeTakingBehavior: CapabilityBehavior = {
  validate(entity, world, actorId, sharedData) {
    const trait = entity.get<TrollAxeTrait>('dungeo.trait.troll_axe');
    const guardian = world.getEntity(trait.guardianId);
    if (guardian && CombatBehavior.isAlive(guardian)) {
      return { valid: false, error: 'dungeo.axe.white_hot' };
    }
    return { valid: true };
  },

  execute(entity, world, actorId, sharedData) {
    // Not needed - standard taking handles it
  },

  report(entity, world, actorId, sharedData) {
    return [];
  },

  blocked(entity, world, actorId, error, sharedData) {
    return [{ type: 'action.blocked', payload: { messageId: error } }];
  }
};

3. Registry (Binding)

The registry connects trait types to behaviors for specific actions:

registerCapabilityBehavior(
  TrollAxeTrait.type,        // 'dungeo.trait.troll_axe'
  'if.action.taking',        // Action ID
  TrollAxeTakingBehavior     // Behavior implementation
);

The registry is a simple map:

Key: "{traitType}:{actionId}"
Value: CapabilityBehavior

4. Dispatch (Resolution)

At runtime, when an action executes:

// 1. Find trait on entity that claims this capability
const trait = findTraitWithCapability(entity, actionId);

// 2. If found, get the registered behavior
if (trait) {
  const behavior = getBehaviorForCapability(trait, actionId);

  // 3. Let behavior validate first (can block)
  const result = behavior.validate(entity, world, actorId, {});
  if (!result.valid) {
    return blocked(result.error);
  }
}

// 4. Proceed with standard action logic
return standardAction.validate(context);

The Flow

┌─────────────┐     ┌──────────────┐     ┌────────────────┐
│   Action    │────▶│   Entity     │────▶│    Trait       │
│  (taking)   │     │   (axe)      │     │ (TrollAxeTrait)│
└─────────────┘     └──────────────┘     └────────────────┘
                                                  │
                                                  │ claims 'if.action.taking'
                                                  ▼
                    ┌──────────────┐     ┌────────────────┐
                    │   Registry   │── ─▶│   Behavior     │
                    │              │     │ (validate/exec)│
                    └──────────────┘     └────────────────┘

Design Patterns Employed

Capability Dispatch combines several established patterns:

Double Dispatch

Traditional single dispatch selects a method based on one type (the receiver):

entity.take()  // Dispatch based on entity's class

Double dispatch selects based on TWO types:

Action Type × Trait Type → Behavior

This avoids the need for entity classes to know about all possible actions, and for actions to know about all possible entity types.

Strategy Pattern

Behaviors are interchangeable strategies implementing a common interface:

interface CapabilityBehavior {
  validate(entity, world, actorId, sharedData): ValidationResult;
  execute(entity, world, actorId, sharedData): void;
  report(entity, world, actorId, sharedData): Effect[];
  blocked(entity, world, actorId, error, sharedData): Effect[];
}

Different behaviors can be swapped in for the same trait+action combination (useful for testing or difficulty modes).

Registry Pattern

A central registry holds bindings and provides lookup:

const behaviorRegistry = new Map<string, TraitBehaviorBinding>();

function registerCapabilityBehavior(traitType, capability, behavior) {
  behaviorRegistry.set(`${traitType}:${capability}`, { ... });
}

function getBehaviorForCapability(trait, capability) {
  return behaviorRegistry.get(`${trait.type}:${capability}`)?.behavior;
}

Composition Over Inheritance

Entities don't inherit from specialized classes. Instead, they're composed of traits:

const axe = world.createEntity('axe', EntityType.ITEM);
axe.add(new IdentityTrait({ name: 'bloody axe', ... }));
axe.add(new TrollAxeTrait({ guardianId: troll.id }));
// axe.add(new MagicWeaponTrait({ ... }));  // Can add more!

An entity's behavior emerges from its trait composition, not its position in a class hierarchy.

Extension Object Pattern

Traits act as extension objects - they extend an entity's capabilities without modifying its core class. The entity doesn't need to know what traits might be attached to it.


Implementation

Trait Definition

// packages/world-model/src/traits/trait.ts
export interface ITrait {
  readonly type: string;
}

export interface ITraitConstructor {
  readonly type: string;
  readonly capabilities?: readonly string[];
  new(...args: any[]): ITrait;
}

Capability Discovery

// packages/world-model/src/capabilities/capability-discovery.ts
export function findTraitWithCapability(
  entity: IFEntity,
  capability: string
): ITrait | undefined {
  for (const trait of entity.traits) {
    const constructor = trait.constructor as ITraitConstructor;
    if (constructor.capabilities?.includes(capability)) {
      return trait;
    }
  }
  return undefined;
}

Behavior Registration

// packages/world-model/src/capabilities/capability-registry.ts
const behaviorRegistry = new Map<string, TraitBehaviorBinding>();

export function registerCapabilityBehavior(
  traitType: string,
  capability: string,
  behavior: CapabilityBehavior
): void {
  const key = `${traitType}:${capability}`;
  if (behaviorRegistry.has(key)) {
    throw new Error(`Behavior already registered for ${key}`);
  }
  behaviorRegistry.set(key, { traitType, capability, behavior });
}

Engine Integration

// packages/engine/src/action-executor.ts
private executeAction(action: Action, context: ActionContext): ActionResult {
  // Check for capability-based blocking BEFORE standard validation
  const blockResult = this.checkCapabilityBlocking(action, context);
  if (blockResult) {
    return this.handleBlocked(action, context, blockResult);
  }

  // Proceed with standard action flow
  const validationResult = action.validate(context);
  // ... rest of action execution
}

private checkCapabilityBlocking(
  action: Action,
  context: ActionContext
): ValidationResult | null {
  const target = context.command.directObject?.entity;
  if (!target) return null;

  const trait = findTraitWithCapability(target, action.id);
  if (!trait) return null;

  const behavior = getBehaviorForCapability(trait, action.id);
  if (!behavior) return null;

  const result = behavior.validate(target, context.world, context.player.id, {});
  return result.valid ? null : result;
}

Real-World Analogies

This pattern appears in many domains beyond interactive fiction:

Authorization / Policy Engines (ABAC)

Resource (attributes) × Action (operation) → Policy Decision

Examples: Open Policy Agent (OPA), AWS IAM, Azure RBAC

A request to DELETE a resource with SensitiveData=true attribute triggers a different policy than the same operation on a regular resource. The policy engine performs double dispatch based on resource attributes and requested operation.

Mapping:

SharpeeABAC
EntityResource
TraitResource Attribute
ActionOperation (read/write/delete)
BehaviorPolicy Rule
RegistryPolicy Store

HTTP Content Negotiation

Request (headers) × Route (endpoint) → Handler

Examples: Express.js middleware, ASP.NET Core, JAX-RS

POST /users request with Content-Type: application/json routes to a different handler than the same endpoint with Content-Type: application/xml. The framework dispatches based on route AND request attributes.

Mapping:

SharpeeHTTP
EntityRequest
TraitHeader (Content-Type, Accept-Language)
ActionRoute/Method
BehaviorHandler
RegistryRoute Table + Content Handlers

Business Rule Engines

Facts (entity state) × Event (trigger) → Rule Firing

Examples: Drools, IBM ODM, Azure Logic Apps

An insurance claim with ClaimType=Medical and Amount>10000 triggers different processing rules than a small auto claim. The rule engine matches facts against conditions and fires appropriate rules.

Mapping:

SharpeeRule Engine
EntityFact/Working Memory Object
TraitFact Attributes
ActionEvent/Trigger
BehaviorRule Consequence
RegistryRule Base

Plugin/Extension Systems

Context (host state) × Extension Point (hook) → Plugin Handler

Examples: VSCode extensions, WordPress hooks, Webpack plugins

A file with .md extension triggers the Markdown formatter plugin when the "format" command is invoked. The host dispatches based on context (file type) AND extension point (command).

Mapping:

SharpeePlugin System
EntityContext/Document
TraitContext Attributes (file type, mode)
ActionExtension Point/Hook
BehaviorPlugin Handler
RegistryExtension Registry

Medical Clinical Decision Support

Patient (conditions) × Order (medication) → CDS Alert

Examples: Epic CDS, Cerner Alerts, HL7 FHIR CDS Hooks

A patient with Condition=Diabetes receiving a prescription for a contraindicated medication triggers a clinical alert. The CDS system dispatches based on patient attributes AND the clinical action.

Mapping:

SharpeeMedical CDS
EntityPatient
TraitCondition/Allergy/Lab Result
ActionOrder/Prescription
BehaviorCDS Rule/Alert
RegistryKnowledge Base

The Common Thread

All these systems share the fundamental challenge:

How do you determine behavior based on BOTH what you're operating on AND what operation you're performing, in an extensible way?

The solutions converge on similar architectures:

  1. Entities/resources with composable attributes
  2. Operations/actions as first-class concepts
  3. External registration of handlers
  4. Runtime dispatch based on attribute+operation matching

Benefits and Trade-offs

Benefits

Extensibility Without Modification

  • Add new entity behaviors without changing entity classes
  • Add new actions without changing trait definitions
  • Three-tier extension: platform → extensions → application

Composition Over Inheritance

  • Entities combine multiple traits freely
  • No diamond inheritance problems
  • Behaviors compose naturally

Separation of Concerns

  • Traits define data and capability claims
  • Behaviors implement logic
  • Registry manages bindings
  • Actions orchestrate flow

Testability

  • Behaviors are pure functions (entity, world, actor → result)
  • Registry can be cleared/mocked for testing
  • No hidden global state in entities

Discoverability

  • getAllCapabilityBindings() shows all registered behaviors
  • Traits explicitly declare their capabilities
  • Clear audit trail of what handles what

Trade-offs

Indirection

  • Behavior isn't on the entity; must trace through registry
  • Debugging requires understanding the dispatch flow
  • IDE "go to definition" doesn't work naturally

Registration Timing

  • Behaviors must be registered before use
  • Order of registration matters for initialization
  • Missing registrations fail at runtime, not compile time

Single Behavior Per Trait+Action

  • Can't have multiple behaviors for same combination
  • Must compose within a single behavior if needed
  • No built-in priority/ordering for multiple handlers

Runtime Cost

  • Trait iteration and map lookup on every action
  • Negligible for IF (tens of entities) but consider for high-frequency systems

Mitigations

For Indirection:

  • Consistent naming: {Entity}{Action}Behavior
  • Logging/tracing in dispatch path
  • Documentation of capability chains

For Registration:

  • Fail-fast validation on startup
  • Type-safe registration helpers
  • Clear initialization order in stories

For Single Behavior:

  • Behaviors can delegate to sub-behaviors
  • Chain of responsibility within a behavior
  • Explicit composition patterns

Conclusion

Capability Dispatch provides a principled solution to the entity×operation combinatorial problem. By combining double dispatch, composition, and a behavior registry, it enables:

  • Platform code to define standard action semantics
  • Extension packages to add reusable mechanics
  • Application code to customize per-entity behavior

The pattern appears across diverse domains—authorization systems, HTTP frameworks, rule engines, plugin architectures, and clinical decision support—suggesting it addresses a fundamental need in extensible software design.

For Sharpee, Capability Dispatch means a text adventure's troll can have a "white-hot axe" that blocks taking with a custom message, without modifying the taking action, without sub-classing the axe, and without global event handlers. The troll story adds a trait, registers a behavior, and the engine handles the rest.

The axe doesn't know it's special. The taking action doesn't know about trolls. The magic happens in the space between them.


References

  • ADR-090: Entity-Centric Action Dispatch (Sharpee Architecture Decision Record)
  • Gamma et al.: Design Patterns (Visitor, Strategy, Registry patterns)
  • Fowler: Patterns of Enterprise Application Architecture (Plugin, Registry)
  • OASIS XACML: Attribute-Based Access Control specification
  • HL7 FHIR CDS Hooks: Clinical Decision Support specification

Sharpee is an open-source interactive fiction engine. For more information, see the project repository.

Friday, 16. January 2026

Renga in Blue

Haunted House: Pray Hard with a Vengeance

I’ve finished the game (prior posts here). It turned out I had one bottleneck (the wolf) which opened up the rest of the game, and “puzzles” I was spending time on (like the ghost and the lift) were complete red herrings. I’m unclear if they’re “intentional” or not; we’ve certainly had games before where I […]

I’ve finished the game (prior posts here).

It turned out I had one bottleneck (the wolf) which opened up the rest of the game, and “puzzles” I was spending time on (like the ghost and the lift) were complete red herrings. I’m unclear if they’re “intentional” or not; we’ve certainly had games before where I suspect the author just kept writing, ran out of disk space / motivation, and stopped with loose ends still left in. At least they became intentional, and I’ll explain what that means when I get to the end.

Games Computing, July 1984. Haunted House was renamed The House on the Misty Hill and re-purposed as a type-in for ZX Spectrum. More on that at the end as well.

Matt W. suggested using the generic “food” rather than the crisps with the wolf. Doing anything with the wolf that’s wrong will kill you so I hadn’t thoroughly tested all the items yet.

(The coffin contains a dead body; I tried carting the coffin over to the ghost in case they matched, but nothing happened. I didn’t know yet the ghost was a total red herring. I took the coffin back to the starting point and dropped it. Even though the wolf had left, this annoyed the wolf who came back and killed me. Whoops.)

Getting by the wolf opens up the graveyard, the only other section of the game. Heading directly north leads to a “shovel” next to a “newly dug grave” (shovel is total red herring, and I did waste time trying USE SHOVEL across the map a few places, ugh) and farther north you fall in the grave itself and get stuck unless you have the right item.

Specifically, this is where the rope is handy, although I spent some time trying to THROW ROPE and the like before realizing the game just let me CLIMB while holding the rope and the action after was implicit. The game is not consistent about this (implicit action while holding an item); this comes to give me trouble later.

Heading east from where the wolf was leads to a crossroads but also a vase of flowers.

I rather grumpily realized what was going on here, and took the flowers over to the princess who didn’t want to be rescued. I then dropped the vase of flowers on the ground, the customary romantic gesture.

She now is willing to tag along to be carted over to the front step of the house and dropped off. The vase of flowers incidentally stays in place and is left behind. It’s like the world’s worst dating simulator.

North of the crossroads you get shut into a shrine.

Having prayed earlier, it seemed the appropriate place; it was used to solve a puzzle, not just be a joke!

You are informed if you try to take the statue that you are not Superman. That’ll be the last treasure I get.

With that resolved I could head farther north in the shrine to find “an old rusty handcart” and a small alcove with a treasure.

It immediately occurred to me to take the cart over to the giant statue and try to take it, but I was still getting the same Superman message. It seemed fair that it’d be impossible to take the statue even with a handcart.

Leaving that behind for now, I checked to the east of the crossroads…

Complete red herring.

…and to the south.

Here my running gag finally paid off.

Coventry Live has a 2021 story about a dog who loves Quavers Crisps and eats them out of the bag, with a picture.

This leads, straightforwardly, to an “eerie tomb” with a CRUCIFIX. I nearly had all my treasures!

I still thought, perhaps, either the ghost or man in the stocks would help with the statue situation. It was an odd scenario where the game requires all treasures at a particular spot (at the front of the house) but given how close the statue was to the location it seemed almost ridiculous to require moving it.

I warned earlier about implicit actions being done with held items; this time, the action is not done while holding an item. I tried to use a handcart, but you’re supposed to drop it first, then GET STATUE, and the game will automatically load the cart from there.

I don’t necessarily have immediate issues with red herrings; they can add texture and atmosphere to an environment that can seem all too “neat” and like living in a cryptic crossword. However, the parser was so janky it was very hard to tell if I was supposed to, say, keep trying to move the lift, or keep trying to scare the ghost with the uniform; when a book is visible in one room while held but can’t be examined in another, pretty much anything is possible. Red herrings need to come along with a parser that the player trusts is working like they are expecting.

I tried a little bit of House on Misty Hill and it really is almost exactly the same; some rooms have a little more description (“a dirty kitchen is full of pots which haven’t been washed in years”) but the red herrings are “enhanced”. The man in the stocks cries for help, and the magazine is now a “monster gazette” which seems more likely to be helpful / not a red herring than the old magazine. Thus, Lucas was clearly happy solidifying the red herrings; that doesn’t mean they were introduced intentionally at first, especially given my suspicion this was the first game he wrote. There’s parser jank in Journey of a Space Traveller, but not nearly to the same level.

I checked his later books (or book, the Amstrad and MSX books about adventure programming merely convert the code) to look for comments on his philosophy on red herrings, and found two notes:

Ardent adventurers don’t like games where they lose their lives too often, so don’t go overboard with traps like this one and do try to keep the responses humorous.

Beware, however, of writing too many red herrings into your game as they can waste an enormous amount of RAM.

Death can represent a punch line of sorts; the issue here is that there is no punch line, just hanging puzzles that seem like they are bugs.

In addition to Misty Hill, the game has yet another remix (somewhat) in The Monster’s Final Hour which gets remade yet again into The Monster Returns. I only say kind of because what seems to have happened is two distinct rip-offs, both off the same game: John R. Olsen’s Frankenstein Adventure.

In Frankenstein Adventure, you need to revive the monster (and then kill the monster in the grand finale). Haunted House / Misty Hill instead grabs a few characters from the game, similar to what Peter Smith’s Hitch-Hiker did with the Supersoft Hitchhiker game. The wolf is in both games (with the same death-message, even); the bog you can fall in without a map is in.

The house structure is vaguely similar and there is a secret passage opened essentially the same way. Haunted House then veers course and has the monster already awake (and distracted by some electrodes); it’s like Lucas grabbed a couple themes to start and then went free-form from there.

Monster’s Final Hour (1985, see above) is much more directly a remake of Olsen’s Frankenstein, where the main goal (revive the monster) is maintained. You’ll also notice the verb list is quite different. So while it seems like Monster’s Final Hour might come from Haunted House, it’s really just that Lucas went back to the original source. A diagram to help:

Absolutely staggering. I can see why the games have been so hard to sort out.

We still have many Lucas games in the future, but coming up: another type-in, this one from the United States, followed by an Apple II game involving real buried treasure.

Thursday, 15. January 2026

Renga in Blue

Haunted House: Pray Harder

(Continued from my previous post.) Just to recap from last time, here was the state of my map, with special rooms marked. I also had access to a candle, a box of matches, a bottle of spirits, some food, a map (all used) as well as a book of ghost stories, a tray of drinks, […]

(Continued from my previous post.)

Just to recap from last time, here was the state of my map, with special rooms marked.

I also had access to a candle, a box of matches, a bottle of spirits, some food, a map (all used) as well as a book of ghost stories, a tray of drinks, a packet of crisps, a bar of soap, a knife, a uniform, a rope with hook, pots, a painting, some electrodes, and some tomatoes (all unused). I was facing a wolf by a coffin, a monster in a secret passage, a room getting locked with a princess, a lift that wasn’t moving, and a room blocked by a ghost (supposedly afraid of uniforms, but nothing I could do with uniform was triggering it!)

I went through my usual verb list with the catch this is generally a two-letter parser.

CL(IMB)
SW(IM)
RE(AD)
LI(GHT)
RU(B)
PR(AY)
PU(LL)
US(E)
EX(AMINE)
IN(SERT)
LE(AVE)
HI(T)
SH(OOT)
KI(LL)

HIT, SHOOT, and KILL all have a response about not being so violent, which suggests they don’t work at all. (It also explains when I tried KISS PRINCESS — it was required in Pillage Village, remember — that the response was “you’re not cruel.” It wasn’t trying to be progressive about kissing consent, the game thought that I was typing KILL PRINCESS.)

After multiple fruitless attempts and managing the uniform/ghost combo I started working on the monster instead. GIVE isn’t a verb but DROP is (drop is how I gave the spirits to the drunk) so I went through a variety of items just to test things out.

“But they’re Monster Munch! You don’t like them?”

I tried HELP out just in case this was the sort of game help is a required verb and the game informed me:

I suppose you could try praying!!

So I tried PRAY:

That didn’t seem to help!!
Maybe you didn’t try hard enough!!

Alas, PRAY HARDER gets no different reaction (I doubt the parser even looked at the second word, to be honest). I eventually hit upon dropping the electodes…

…which sort of makes sense if you squint, but not really.

Past the monster are two rooms.

With the antique my score was now safely 2 out of 7, and I thought it would become 3 out of 7 shortly with the keys. They do work in the princess room (USE KEYS)…

…but the princess refuses to move. This was the moment in Pillage Village where KISS was required. Princess, are you sure you want to hang out in the dungeon…?

The princess refuses.

With me befuddled, I tried more attempts at the ghost.

Maybe you’d prefer some Crispy Bacon Frazzles? I can’t eat them myself, there’s no EAT command.

The rest of my time was spent frustrated. I tried USE KEYS at the man the stocks and the tomatoes, no dice. I tried every verb on my list on the lift, again no dice. (“USE LIFT”: “You’re trying to confuse me!”) I am nearly guaranteed now to check either the walkthrough or at least the source code, but I wanted to report in on my progress here first. The main issue isn’t it doesn’t feel like I’m “stuck on a puzzle” as much as fighting against the system; I’m guessing at least once I’ve done the right thing, just expressed in the wrong way.

The wolf really doesn’t like crisps.

(Also, people picked up on last time there’s a certain other game from 1981 Lucas is “borrowing” from that is not by him, but I want to save getting into that for my final post.)

Wednesday, 14. January 2026

My So Called Interactive Fiction Life

Sharpee Parsing Comparison

Classic IF Systems and Sharpee A detailed comparison of how TADS, Inform 6, Inform 7, Hugo, and Sharpee handle the journey from player input to executed action. Overview All parser-based IF systems solve the same fundamental problem: transform natural language input into game actions. The solutions share common ancestry but

Classic IF Systems and Sharpee

A detailed comparison of how TADS, Inform 6, Inform 7, Hugo, and Sharpee handle the journey from player input to executed action.

Overview

All parser-based IF systems solve the same fundamental problem: transform natural language input into game actions. The solutions share common ancestry but diverge in philosophy and implementation.

Player Input: "put the red book on the wooden shelf"
                            ↓
              [GRAMMAR / PATTERN MATCHING]
                            ↓
              [SCOPE / ENTITY RESOLUTION]
                            ↓
              [VALIDATION / PRECONDITIONS]
                            ↓
              [EXECUTION / STATE CHANGE]
                            ↓
              [RESPONSE / OUTPUT]

Each system implements these stages differently. This document explores those differences without judgment—each approach reflects valid design tradeoffs.


1. Grammar Definition

How does each system define what commands look like?

TADS 2/3

TADS uses VerbRule declarations that combine syntax patterns with semantic requirements:

// TADS 3
VerbRule(PutOn)
    'put' dobjList 'on' singleIobj
    : PutOnAction
    verbPhrase = 'put/putting (what) (on what)'
;

// The grammar IS the action definition
// Verb synonyms defined separately
modify VerbRule(PutOn)
    'place' dobjList 'on' singleIobj : ;

Characteristics:

  • Grammar tightly coupled to action definitions
  • Verb phrases carry semantic metadata (for NPC commands, messages)
  • Slot types (dobjList, singleIobj) encode cardinality
  • Synonyms added via grammar inheritance/modification

Inform 6

Inform 6 uses Verb directives with pattern lines:

Verb 'put' 'place' 'drop'
    * held 'on' noun -> PutOn
    * held 'in' noun -> Insert
    * multiexcept 'on' noun -> PutOn
    * multiexcept 'in' noun -> Insert;

Characteristics:

  • Compact, terse syntax (classic Infocom heritage)
  • Token types define scope constraints: held, noun, creature, multi
  • Multiple patterns map to same action (PutOn)
  • Synonyms listed in verb header
  • Grammar INCLUDES scope requirements (held = must be carried)

Inform 7

Inform 7 uses natural language grammar definitions:

Understand "put [things preferably held] on [something]" as putting it on.
Understand "place [things preferably held] on [something]" as putting it on.

Putting it on is an action applying to two things.

Characteristics:

  • Human-readable grammar specifications
  • Bracketed tokens: [something], [things], [text]
  • Scope hints in token names: preferably held, visible, touchable
  • Actions declared separately from grammar
  • Multiple Understand lines for synonyms

Hugo

Hugo uses verb and xverb declarations with grammar patterns:

verb "put", "place"
    *                           DoVague
    * object "on" xobject       DoPutonGround
    * multi "on" xobject        DoPutAll

xverb "inventory", "i", "inv"
    *                           DoInventory

Characteristics:

  • verb for world-affecting actions, xverb for meta actions
  • Token types: object, xobject (indirect), multi, number, string
  • Routines named directly in grammar (DoPutonGround)
  • Concise, script-like syntax

Sharpee

Sharpee uses a fluent builder API with action-centric organization:

// Action-centric definition (preferred) - ADR-087
grammar
  .forAction('if.action.pushing')
  .verbs(['push', 'press', 'shove', 'move'])
  .pattern(':target')
  .build();

// Phrasal patterns with slot-specific trait constraints
// .hasTrait(slotName, traitType) - constrains which entities match that slot
grammar
  .define('put :item on :supporter')
  .hasTrait('supporter', TraitType.SUPPORTER)  // :supporter slot must have SUPPORTER trait
  .mapsTo('if.action.putting')
  .withPriority(100)
  .build();

// Container operations - same pattern
grammar
  .define('put :item in|into|inside :container')
  .hasTrait('container', TraitType.CONTAINER)  // :container slot must have CONTAINER trait
  .mapsTo('if.action.inserting')
  .withPriority(100)
  .build();

// Direction slots use type constraint, not trait
grammar
  .define('go :direction')
  .where('direction', { type: 'direction' })
  .mapsTo('if.action.going')
  .withPriority(100)
  .build();

Characteristics:

  • TypeScript fluent API with IDE autocompletion
  • Action ID is the organizing principle (not the verb)
  • Verb synonyms declared once per action via .verbs([...])
  • .hasTrait(slotName, traitType) — slot-specific semantic constraint
    • First arg: which slot (:container, :supporter, etc.)
    • Second arg: required trait (TraitType.CONTAINER, etc.)
  • NO scope/visibility in grammar — scope resolved at runtime by action
  • Grammar defines SYNTAX + semantic constraints only
  • Comments in grammar.ts explicitly note: "Scope handled by action validation"

Comparison Table: Grammar

Aspect TADS 3 Inform 6 Inform 7 Hugo Sharpee
Syntax style VerbRule classes Verb directives Natural language verb declarations Fluent builder API
Synonym handling Inheritance Verb header list Multiple Understand Verb header list .verbs([...]) array
Scope in grammar Implied by slot types Token types (held/noun) Token hints object/xobject None (action validates)
Semantic constraints Slot types Token types Token descriptions Slot types .hasTrait(slot, trait)
Multi-object dobjList/multiexcept multi/multiexcept [things] multi Handled by parser
Action binding VerbRule → Action Pattern → routine Understand → action Pattern → routine Pattern → action ID

2. Parsing and Tokenization

How does each system break apart player input?

TADS 3

TADS has a sophisticated tokenizer and grammar parser:

Input: "put the red book on shelf"
         ↓
Tokenizer: ["put", "the", "red", "book", "on", "shelf"]
         ↓
Grammar Parser: Match against VerbRules
         ↓
Best Match: VerbRule(PutOn) with dobj="red book", iobj="shelf"

Key features:

  • Built-in tokenizer handles contractions, abbreviations
  • Grammar is a true parser (can backtrack)
  • Disambiguation happens during parsing
  • Returns structured parse tree with action + objects

Inform 6

Inform 6 uses a two-pass parser:

Input: "put red book on shelf"
         ↓
Pass 1: Tokenize into dictionary words
         ↓
Pass 2: Match verb patterns, consume tokens left-to-right
         ↓
Match: Verb 'put' pattern "held 'on' noun"
         ↓
Scope Check: Is "red book" held? Is "shelf" in scope?

Key features:

  • Dictionary-based tokenization (words must be in game dictionary)
  • Left-to-right pattern matching (no backtracking)
  • Scope checking integrated into parsing
  • Parser decides entity resolution during parse

Inform 7

Inform 7 compiles to Inform 6, but adds:

Input: "put the red book on the shelf"
         ↓
Understanding Phase: Match against Understand patterns
         ↓
Disambiguation: "Which do you mean, the red book or the red apple?"
         ↓
Action Creation: Create "putting red book on shelf" action

Key features:

  • Same underlying I6 parser, but abstracted
  • Richer disambiguation ("Did you mean...")
  • Actions are first-class objects (can be stored, examined)
  • "Deciding the scope" activity for custom scope rules

Hugo

Hugo uses a simple token-based parser:

Input: "put book on shelf"
         ↓
Tokenize: Split on spaces, look up in dictionary
         ↓
VerbRoutine: Match verb, call FindObject for each slot
         ↓
Object Resolution: Search rooms, containers, inventory

Key features:

  • Straightforward, predictable parsing
  • FindObject routine handles scope
  • Less sophisticated disambiguation
  • Fast and efficient for simple games

Sharpee

Sharpee uses a multi-phase approach:

Input: "put the red book on the wooden shelf"
         ↓
Phase 1 - Tokenization:
  tokens: [{text: "put", ...}, {text: "the", ...}, ...]
  Each token gets vocabulary candidates (verb? preposition? noun?)
         ↓
Phase 2 - Pattern Matching (Grammar Engine):
  Try patterns by priority
  Match: "put :item on :supporter"
  Slots: item="the red book", supporter="the wooden shelf"
         ↓
Phase 3 - Output (Parser):
  IParsedCommand {
    action: 'if.action.putting_on',
    directObject: { text: 'the red book', entity: null },
    indirectObject: { text: 'the wooden shelf', entity: null }
  }

Key features:

  • Entities NOT resolved during parsing (text only)
  • Pattern matching is priority-ordered (story patterns > stdlib)
  • Confidence scoring for ambiguous matches
  • Parser output is intermediate representation (IR)

Comparison Table: Parsing

Aspect TADS 3 Inform 6 Inform 7 Hugo Sharpee
Tokenization Built-in sophisticated Dictionary-based I6-based Dictionary-based Vocabulary registry
Pattern matching Full grammar parser Left-to-right I6-based + rules Left-to-right Priority-ordered
Backtracking Yes No Limited No No (by design)
Entity resolution During parse During parse During parse During parse After parse (separate)
Output type Parse tree + objects Populated globals Action object Populated globals IParsedCommand (IR)

3. Scope and Entity Resolution

How does each system determine what the player can interact with?

TADS 3

TADS 3 has a comprehensive scope model:

// Scope is determined by sensory context
class Thing: object
    canSee(obj) { ... }
    canHear(obj) { ... }
    canSmell(obj) { ... }
    canReach(obj) { ... }

// Resolvers determine valid objects
class Resolver: object
    filterAmbiguous(lst) { ... }
    filterPossessive(lst) { ... }

Key features:

  • Multi-sensory scope (see, hear, smell, reach)
  • Resolver classes for different contexts
  • Disambiguation through resolver filtering
  • Scope is property of actor (NPCs have their own scope)

Inform 6

Inform 6 uses scope routines and token types:

! Token types define scope requirements
! held   = in inventory
! noun   = in scope (visible/touchable)
! creature = animate beings
! multi  = multiple objects

! Custom scope via scope_stage
[ InScope actor;
    PlaceInScope(lamp);  ! Always visible
    if (location == dark_room) {
        PlaceInScope(grue);  ! Only in this room
    }
];

Key features:

  • Scope types in grammar (held, noun, etc.)
  • InScope hook for dynamic scope
  • Darkness handling built-in
  • Scope is global state during parsing

Inform 7

Inform 7 abstracts scope through activities:

Definition: A thing is visible if the player can see it.
Definition: A thing is touchable if the player can touch it.

Before deciding the scope of the player when in darkness:
    place the glowing orb in scope.

The carrying capacity of the player is 7.

Key features:

  • Declarative visibility/touchability definitions
  • "Deciding the scope" activity for customization
  • Reaching inside rules for containers
  • Abstracted but still fundamentally I6 scope

Hugo

Hugo uses FindObject and scope flags:

! FindObject searches in order:
! 1. Held objects
! 2. Room contents
! 3. Objects in open containers

routine FindObject(obj, objloc)
{
    if Contains(player, obj) return true
    if Contains(location, obj) return true
    if obj in something && IsOpen(something) return true
    return false
}

Key features:

  • Procedural scope checking
  • Explicit search order
  • Simple, predictable rules
  • Game author controls via routine overrides

Sharpee

Sharpee uses a dedicated ScopeResolver with scope levels:

enum ScopeLevel {
  UNAWARE = 0,    // Doesn't know it exists
  AWARE = 1,      // Knows it exists (heard, smelled)
  VISIBLE = 2,    // Can see it
  REACHABLE = 3,  // Can touch it
  CARRIED = 4     // In inventory
}

// Resolution happens AFTER parsing
class CommandValidator {
  resolveNounPhrase(noun: INounPhrase, world: WorldModel) {
    // 1. Find entities matching noun text
    const candidates = world.findEntitiesByName(noun.head);

    // 2. Filter by adjectives
    const matching = candidates.filter(e =>
      this.adjectivesMatch(e, noun.adjectives)
    );

    // 3. Check scope for each candidate
    const inScope = matching.filter(e =>
      scopeResolver.getScope(actor, e) >= ScopeLevel.VISIBLE
    );

    // 4. Disambiguate
    return this.disambiguate(inScope, noun);
  }
}

Key features:

  • Scope is numeric level, not boolean
  • Resolution is separate phase after parsing
  • ScopeResolver handles all perception logic:
    • Darkness (need light source)
    • Container blocking (closed containers)
    • Distance (same room, adjacent room)
  • Actions specify required scope level
  • Adjective filtering is explicit step

Comparison Table: Scope

Aspect TADS 3 Inform 6 Inform 7 Hugo Sharpee
Scope model Multi-sensory Token types Activities FindObject Scope levels (0-4)
When resolved During parsing During parsing During parsing During parsing After parsing
Customization Resolver classes InScope hook Deciding scope Routine override ScopeResolver
Darkness Built-in Built-in Built-in Manual Built-in
NPC scope Per-actor Limited Per-actor Limited Per-actor

4. Action Validation and Execution

How does each system check preconditions and apply state changes?

TADS 3

TADS 3 uses action methods with implicit preconditions:

class PutOnAction: TIAction
    // Preconditions checked automatically
    preCond = [touchObj, objVisible]

    // Verify phase - soft checks
    verifyDobjPutOn() {
        if (!isDraggable) illogical('{I} {can\'t} move that.');
    }

    // Check phase - hard checks
    checkDobjPutOn() {
        if (getWeight > supporter.maxWeight)
            failCheck(tooHeavyMsg);
    }

    // Action phase - mutation
    actionDobjPutOn() {
        moveInto(gIobj);  // gIobj = indirect object
        say('Done.');
    }
;

Phases:

  1. PreCond - Automatic implicit actions (take if not held)
  2. Verify - Soft checks (illogical suggestions)
  3. Check - Hard preconditions (fail = block action)
  4. Action - State mutation + output

Key features:

  • Implicit actions (auto-take before put)
  • Verify vs Check distinction (suggestion vs error)
  • Preconditions are object properties
  • Failure messages in check phase

Inform 6

Inform 6 uses before/after rules:

[ PutOnSub;
    ! Parser has already checked scope
    if (noun notin player) {
        print "You need to pick that up first.^";
        rtrue;
    }
    if (second hasnt supporter) {
        print "That's not a surface.^";
        rtrue;
    }
    move noun to second;
    print "You put ", (the) noun, " on ", (the) second, ".^";
];

! Objects can intercept
Object -> table "wooden table"
    with before [;
        PutOn: if (children(self) >= 5) {
            print "The table is full.^";
            rtrue;
        }
    ];

Key features:

  • Single routine per action (PutOnSub)
  • Objects intercept via before and after
  • Return true to block, false to continue
  • No formal phase separation

Inform 7

Inform 7 uses rulebooks with explicit phases:

Before putting something on something:
    if the noun is not carried, try taking the noun.

Check putting something on something:
    if the second noun is not a supporter:
        say "[The second noun] isn't a surface." instead.

Carry out putting something on something:
    now the noun is on the second noun.

Report putting something on something:
    say "You put [the noun] on [the second noun]."

Phases:

  1. Before - Pre-processing, implicit actions
  2. Instead - Replace default behavior entirely
  3. Check - Preconditions (stop if failed)
  4. Carry out - State mutation
  5. After - Post-mutation, before report
  6. Report - Generate output

Key features:

  • Explicit named phases
  • "Instead" for complete override
  • Rules can be ordered (first/last)
  • Natural language syntax

Hugo

Hugo uses action routines with informal checks:

routine DoPutOn
{
    if not Contains(player, object)
    {
        "You need to be carrying that."
        return false
    }
    if xobject is not supporter
    {
        "That's not a surface."
        return false
    }
    move object to xobject
    print "You put "; The(object); " on "; The(xobject); "."
    return true
}

Key features:

  • Single routine per action
  • Checks and execution interleaved
  • Return true/false for success
  • Straightforward procedural style

Sharpee

Sharpee uses a strict four-phase pattern:

const puttingOnAction: Action = {
  id: 'if.action.putting_on',

  // Phase 1: VALIDATE - Check preconditions (no mutations)
  validate(context: ActionContext): ValidationResult {
    const item = context.command.directObject!.entity!;
    const supporter = context.command.indirectObject!.entity!;

    // Scope check
    if (!context.canReach(item)) {
      return { valid: false, error: 'cant_reach', params: { item: item.name } };
    }

    // Trait check
    if (!supporter.has(TraitType.SUPPORTER)) {
      return { valid: false, error: 'not_a_surface', params: { target: supporter.name } };
    }

    // Capacity check
    const capacity = supporter.get(TraitType.SUPPORTER)!.capacity;
    if (getChildCount(supporter) >= capacity) {
      return { valid: false, error: 'supporter_full', params: { target: supporter.name } };
    }

    return { valid: true };
  },

  // Phase 2: EXECUTE - Apply mutations (no output)
  execute(context: ActionContext): void {
    const item = context.command.directObject!.entity!;
    const supporter = context.command.indirectObject!.entity!;

    // Capture pre-mutation state
    context.sharedData.previousLocation = context.world.getLocation(item.id);

    // THE MUTATION
    context.world.moveEntity(item.id, supporter.id);
  },

  // Phase 3: REPORT - Generate success events (read-only)
  report(context: ActionContext): ISemanticEvent[] {
    const item = context.command.directObject!.entity!;
    const supporter = context.command.indirectObject!.entity!;

    return [
      context.event('if.event.put_on', {
        item: item.name,
        itemId: item.id,
        supporter: supporter.name,
        supporterId: supporter.id,
        previousLocation: context.sharedData.previousLocation
      }),
      context.event('action.success', {
        actionId: context.action.id,
        messageId: 'put_on',
        params: { item: item.name, supporter: supporter.name }
      })
    ];
  },

  // Phase 4: BLOCKED - Generate error events (on validation failure)
  blocked(context: ActionContext, result: ValidationResult): ISemanticEvent[] {
    return [
      context.event('action.blocked', {
        actionId: context.action.id,
        messageId: result.error,
        params: result.params
      })
    ];
  }
};

Phases:

  1. Validate - Preconditions only, no mutations, returns pass/fail
  2. Execute - Mutations only, no events
  3. Report - Success events (semantic, not text)
  4. Blocked - Error events (called instead of execute+report)

Key features:

  • Strict separation: mutations in execute, events in report
  • Events carry message IDs, not English text
  • Language layer converts IDs to prose
  • sharedData for inter-phase communication
  • Validation result passed to blocked phase
  • Multi-object support built into pattern

Comparison Table: Action Execution

Aspect TADS 3 Inform 6 Inform 7 Hugo Sharpee
Phases PreCond/Verify/Check/Action before/action/after Before/Instead/Check/Carry out/After/Report Single routine Validate/Execute/Report/Blocked
Implicit actions Built-in (preCond) Manual Before rules Manual Via event handlers
Mutation location Action phase In routine Carry out In routine Execute only
Output location In action In routine Report In routine Report (as events)
Override mechanism Object methods before blocks Instead rules Routine override Entity event handlers

5. Output and Response

How does each system generate player-facing text?

TADS 3

TADS 3 uses embedded text and message objects:

// Embedded in action
actionDobjTake() {
    "You pick up <<theName>>. ";
}

// Or via message objects
playerActionMessages: MessageHelper
    takeMsg = '{I} {take} {the dobj}. '
    alreadyHaveMsg = '{I} already {have} that. '
;

Key features:

  • Template strings with placeholders
  • Conjugation for perspective ({I}, {take})
  • Message objects for i18n potential
  • Text typically in action code

Inform 6

Inform 6 uses print statements with library messages:

[ PutOnSub;
    ! Direct printing
    print "You put ", (the) noun, " on ", (the) second, ".^";
];

! Or library messages
Object LibraryMessages
    with before [;
        PutOn: print "You put ", (the) noun, " on ", (the) second, ".^";
    ];

Key features:

  • Direct print in routines
  • Library message override for customization
  • (the), (a), (The) for article handling
  • ^caret for newlines

Inform 7

Inform 7 uses say phrases with text substitutions:

Report putting something on something:
    say "You put [the noun] on [the second noun]."

! Custom responses
Report taking the crystal ball:
    say "The ball pulses with inner light as you lift it."

Key features:

  • Natural language say phrases
  • Text substitutions [the noun], [a thing]
  • Adaptive text (he/she/they)
  • Unicode support

Hugo

Hugo uses print statements:

routine DoPutOn
{
    print "You put "; The(object); " on "; The(xobject); "."
}

Key features:

  • Procedural print statements
  • The(), Art() for articles
  • Simple string concatenation
  • Straightforward control

Sharpee

Sharpee uses semantic eventslanguage layer:

// In action (report phase)
report(context): ISemanticEvent[] {
  return [
    context.event('action.success', {
      messageId: 'put_on',
      params: { item: 'book', supporter: 'table' }
    })
  ];
}

// In language layer (lang-en-us)
const puttingOnMessages = {
  put_on: (p) => `You put ${p.item} on ${p.supporter}.`,
  not_a_surface: (p) => `${p.target} isn't a surface.`,
  supporter_full: (p) => `There's no room on ${p.target}.`,
};

Key features:

  • Complete separation: actions emit IDs, language layer emits text
  • Enables true i18n (lang-es-mx, lang-de-de)
  • Parameters passed to message functions
  • Perspective handling in language layer
  • Events can be intercepted/modified before rendering

Comparison Table: Output

Aspect TADS 3 Inform 6 Inform 7 Hugo Sharpee
Text location In actions or messages In routines Say phrases In routines Language layer only
Substitution Template strings Print macros [brackets] Print calls Function params
i18n support Message objects Library override Limited Limited First-class (message IDs)
Article handling {the}, {a} (the), (a) [the], [a] The(), Art() In language layer

6. What Sharpee Kept vs. Modernized

Kept from Classic Systems

Concept Origin Sharpee Implementation
Pattern-based grammar All systems Grammar builder with pattern matching
Scope concept All systems ScopeResolver with visibility/reachability
Action phases Inform 7, TADS 3 Four-phase pattern (validate/execute/report/blocked)
Trait/attribute system All systems (has/hasnt) TypeScript traits with behaviors
Multi-object commands All systems (multi/all) Built-in "all", "and", "except" handling
Implicit actions TADS 3 preCond Event handlers can trigger implicit takes
Object interception Inform before/after Entity event handlers

Modernized

Concept Classic Approach Sharpee Approach
Grammar binding Grammar → routine Grammar → action ID → action handler
Scope resolution During parsing After parsing (separate phase)
Text generation In action code Separate language layer (message IDs)
State management Global variables WorldModel with typed entities
Type safety Runtime only TypeScript compile-time checks
Action organization Per-verb files Grouped by semantic category
Extension points Object methods, rule ordering Event handlers, capability dispatch
Multi-object Grammar-level (multi token) Parser-level then action-level
Configuration Compile flags Runtime dependency injection

Key Philosophical Shifts

  1. Separation of Concerns

    • Classic: Grammar, scope, action, and text often intermingled
    • Sharpee: Each concern in its own layer with clean interfaces
  2. Event-Driven Architecture

    • Classic: Actions produce output directly
    • Sharpee: Actions produce events; language layer produces text
  3. Typed Everything

    • Classic: Dynamic typing, runtime discovery
    • Sharpee: TypeScript types, compile-time validation
  4. Action as First-Class

    • Classic: Actions tied to grammar patterns
    • Sharpee: Actions are independent handlers, grammar just routes to them
  5. Internationalization as Core

    • Classic: Afterthought, message object hacks
    • Sharpee: Message IDs from day one, language layer separation

7. Pipeline Diagram Comparison

Classic Model (Inform 6 style)

Input: "put book on table"
         ↓
┌────────────────────────────────────────┐
│  PARSER                                │
│  • Tokenize                            │
│  • Match grammar                       │
│  • Resolve entities (scope check)      │
│  • Populate noun/second globals        │
└────────────────────────────────────────┘
         ↓
┌────────────────────────────────────────┐
│  ACTION ROUTINE                        │
│  • Check preconditions                 │
│  • Apply mutations                     │
│  • Generate output                     │
│  (all interleaved in one routine)      │
└────────────────────────────────────────┘
         ↓
Output: "You put the book on the table."

Sharpee Model

Input: "put the red book on the wooden table"
         ↓
┌────────────────────────────────────────┐
│  PARSER (parser-en-us)                 │
│  • Tokenize                            │
│  • Match grammar patterns              │
│  • Output: IParsedCommand              │
│    (action ID + text slots, NO entities)│
└────────────────────────────────────────┘
         ↓
┌────────────────────────────────────────┐
│  VALIDATOR (stdlib)                    │
│  • Resolve entities from text          │
│  • Check scope (ScopeResolver)         │
│  • Disambiguate (adjectives, recency)  │
│  • Output: ValidatedCommand            │
│    (action ID + resolved entities)     │
└────────────────────────────────────────┘
         ↓
┌────────────────────────────────────────┐
│  ACTION EXECUTOR (engine)              │
│  • Look up action handler              │
│  • Call validate() - preconditions     │
│    ├── Pass? → execute() + report()    │
│    └── Fail? → blocked()               │
│  • Output: ISemanticEvent[]            │
└────────────────────────────────────────┘
         ↓
┌────────────────────────────────────────┐
│  EVENT PROCESSOR (engine)              │
│  • Call entity handlers                │
│  • Generate reaction events            │
│  • Sequence all events                 │
└────────────────────────────────────────┘
         ↓
┌────────────────────────────────────────┐
│  LANGUAGE LAYER (lang-en-us)           │
│  • Map message IDs → prose             │
│  • Apply perspective                   │
│  • Format parameters                   │
│  • Output: final text                  │
└────────────────────────────────────────┘
         ↓
Output: "You put the red book on the wooden table."

8. Summary

Each system reflects its era and design goals:

  • TADS 3: Most sophisticated classic system, OOP-based, multi-sensory scope, verify/check distinction
  • Inform 6: Compact and efficient, Infocom heritage, tight grammar-scope coupling
  • Inform 7: Natural language paradigm, explicit rulebook phases, accessible to non-programmers
  • Hugo: Practical and straightforward, clear procedural model, good balance of power/simplicity
  • Sharpee: Modern TypeScript, strict layer separation, event-driven, i18n-first, type-safe

Sharpee borrows liberally from all four systems while pushing toward:

  • Stronger typing
  • Cleaner separation of concerns
  • First-class internationalization
  • Event-driven extensibility

The core insight remains the same across all systems: transform natural language into structured commands, validate them against world state, execute them, and report the results. The differences lie in where boundaries are drawn and how flexibility is provided.

Tuesday, 13. January 2026

My So Called Interactive Fiction Life

Sharpee - The Final Design Conversation with Claude

Note: I did agree not to post AI material, but this is an important conversation I had with Claude. It's not Claude's ramblings about Sharpee. It's a Q&A design session that I believe merits sharing in full.Design Session: Text Service &
Sharpee - The Final Design Conversation with Claude

Note: I did agree not to post AI material, but this is an important conversation I had with Claude. It's not Claude's ramblings about Sharpee. It's a Q&A design session that I believe merits sharing in full.

Design Session: Text Service & Client Architecture

Date: 2026-01-13
Branch: chaining
Subject: The final design of how the text service and varying types of clients work together.
Participants: Dave Cornelson, Claude (Opus 4.5)
Status: Architecture finalized, ready for implementation


Overview

This session designed Sharpee's text output architecture from first principles, covering template syntax, TextBlock contracts, and client rendering. The design is inspired by FyreVM channel I/O (2009).


The Challenge

"We're going to test your ability to juggle complexity"

The goal: think through the entire text output system holistically:

  • lang-en-us: Templates, formatters, prose
  • text service: Middleware orchestration
  • client: How we display the story

Scoping the Problem

CLI

"I think we can say CLI is simple and we've more or less already proven how it works"

CLI is solved - just concatenate TextBlocks with whitespace.

GLK

"I would say glk is an interesting IF thing, but it's worth an ADR with identified as the status"

GLK is a known future concern - park it as ADR-099 with status "identified".

Screen Reader / Accessibility

"There are a lot of blind IF players so I really love the idea of making Sharpee an easy path for authors to make games accessible"

Accessibility is a priority, not an afterthought. ADR-100 for screen reader support.

React / Electron

"the big one is react/electron and I think we have to consider them side by side"

React is the main focus. Works in both browser and Electron contexts.


Unified Template Syntax

The Problem

ADR-091 (Text Decorations) and ADR-095 (Message Templates) had overlapping concerns:

  • ADR-095: {modifier:placeholder} for formatters
  • ADR-091: Needed decorations on both placeholders AND literal text

The Solution

Dave: "yes let's figure out a unified syntax"

Three distinct syntaxes for distinct purposes:

{formatter:placeholder}     - Transformations (a, the, list, cap)
[type:content]              - Semantic decorations (item, room, npc)
*emphasis* / **strong**     - Inline prose decoration

Can be combined:

[item:{a:item}]             - Resolve placeholder, then mark as item-type
*{adverb}*                  - Resolve placeholder, then emphasize

Key insight: Formatters transform, decorations annotate. Different operations, different syntax.


Single TextService + Multiple Renderers

DRY Principle Applied

Dave: "let's add some basic developer principles (DRY) into the mix"

With multiple text services, you'd repeat:

  • Template resolution logic
  • Formatter logic (articles, lists)
  • Decoration parsing
  • Language layer integration

What actually differs per client: only rendering.

Architecture

┌─────────────────────────────────────────────────────────┐
│                    lang-en-us                           │
│  Templates, formatters, noun types, prose               │
└─────────────────────────────────────────────────────────┘
                          │
                          ▼
┌─────────────────────────────────────────────────────────┐
│                    TextService                          │
│  Resolves templates → parses decorations → TextBlocks   │
│  (ONE implementation, shared)                           │
└─────────────────────────────────────────────────────────┘
                          │
                          ▼
                     TextBlocks
                          │
        ┌─────────────────┼─────────────────┐
        ▼                 ▼                 ▼
   ┌─────────┐       ┌─────────┐       ┌─────────┐
   │  React  │       │   CLI   │       │  JAWS   │
   │ Renderer│       │ Renderer│       │ Renderer│
   └─────────┘       └─────────┘       └─────────┘

Each renderer is small - just maps decoration types to platform output.


Formalized TextBlock Contract

Dave: "do we formalize the text blocks?"

Yes - TextBlocks become a concrete, typed contract.

Package Location

@sharpee/text-blocks - pure interfaces, no implementation

Interface Design

type TextContent = string | IDecoration;

interface IDecoration {
  type: string; // Open - 'em', 'item', 'photopia.red'
  content: TextContent[]; // Can nest
}

interface ITextBlock {
  key: string; // Channel - 'room.description', 'status.score'
  content: TextContent[];
}

Language Agnostic

Dave: "do text blocks need to be language specific: textblocks-en-us"

No. TextBlocks are a universal container format. The prose inside is localized, but the structure is the same.

// Same ITextBlock shape, different language content

// English
{ key: 'action.result', content: ['You take the sword.'] }

// German
{ key: 'action.result', content: ['Du nimmst das Schwert.'] }

FyreVM Channel I/O Inspiration

Dave: "you just reinvented fyrevm channel IO Mr. Claude (though I actually invented it in 2009 with help from Tara McGrew and inspired by Jeff Panici)"

Credit where due! The architecture draws from proven design.

Channel = Block Key

{ key: 'room.description', content: [...] }  // Channel: room
{ key: 'action.result', content: [...] }     // Channel: action
{ key: 'status.score', content: [...] }      // Channel: status

Key Conventions

Prefix Purpose Client Routing
room.* Room info Main transcript
action.* Action results Main transcript
status.* Status bar elements Fixed header slots
error System errors Main transcript (styled)
prompt Command prompt Input area
{story}.* Story-defined Configurable

Extensibility

Dave: "they start pre-defined, but I created a way for authors to make their own and use them in storytelling"

Same pattern in Sharpee:

  • Core keys defined by platform
  • Stories can define custom keys
  • Clients render unknown keys with sensible defaults

Browser Architecture

Dave: "the engine bundles game and sharpee to {game}.js and runs in the browser (we've already done this and it's fast)"

No server. No API layer. Everything runs client-side.

┌─────────────────────────────────────────────────────────┐
│  {game}.js (bundled)                                    │
│  Engine + WorldModel + Story + TextService + lang-en-us │
└─────────────────────────────────────────────────────────┘
                          │
                          │ on('turn-complete') → ITextBlock[]
                          ▼
┌─────────────────────────────────────────────────────────┐
│  React Client                                           │
│  Receives ITextBlock[], renders to DOM                  │
└─────────────────────────────────────────────────────────┘

Event-Based Client Communication

The IF Model

Dave: "in IF we have one stream of text blocks including any daemons and npcs - the client would never handle anything but one set of text blocks"

One stream. Everything mixed. Client just renders.

engine.on('turn-complete', (blocks: ITextBlock[]) => {
  // One array - command results, daemons, NPCs, everything
  setTranscript((prev) => [...prev, ...blocks]);
});

No routing logic. No "handling" different event types. Just:

  1. Receive blocks
  2. Append to transcript
  3. Render

Status Line Design

Not Special

Dave: "I see the status line as no different than any other rendered text block"

Status elements are just more blocks with status.* keys:

{ key: 'status.room', content: [{ type: 'room', content: ['West of House'] }] }
{ key: 'status.score', content: ['0'] }
{ key: 'status.turns', content: ['1'] }

Multiple Blocks, Not One Object

Dave: "B is the way I think" (choosing Option B: multiple sub-keyed blocks)

React routes by key to slots:

<StatusBar>
  {blocks.filter(b => b.key.startsWith('status.')).map(renderToSlot)}
</StatusBar>
<Transcript>
  {blocks.filter(b => !b.key.startsWith('status.')).map(renderBlock)}
</Transcript>

Story-Defined Colors (Photopia Pattern)

Dave: "think about how Sharpee would handle Adam Cadre's Photopia colors"

Photopia uses color as narrative. Authors need full creative control.

Solution

Authors define semantic color names in story config:

// stories/photopia/src/config.ts
export const storyColors = {
  'photopia.red': '#cc0000', // Alley's scenes
  'photopia.blue': '#0066cc', // Fantasy scenes
};

Templates use semantic names:

'[photopia.red:The light was red, like always.]'

Client looks up mapping, renders appropriately:

  • Web: actual CSS color
  • CLI: ANSI approximation
  • Screen reader: announces "red text" or ignores

IDecoration Type is Open

interface IDecoration {
  type: string; // Open - 'em', 'item', 'photopia.red'
  content: TextContent[];
}

Type is open string, not enum. Core types are conventions, not constraints.


Decoration Types

Semantic vs Presentational

Semantic Presentational
item em (italic)
room strong (bold)
npc underline
command strikethrough
direction super / sub
(story-defined) (story colors)

Decisions Summary

Topic Decision
Template syntax Unified: {formatter:placeholder}, [type:content], *emphasis*
TextService Single service, multiple renderers (DRY)
TextBlocks Formalized ITextBlock contract, language-agnostic
Decoration type Open string (not enum) for extensibility
Channel keys Core prefixes + story-extensible
Client communication Event-based: on('turn-complete')
Status line Multiple status.* blocks, not special
Colors Story-defined semantic names
Priority/role fields Dropped (YAGNI)

ADR Map

ADR Topic Action
091 Text Decorations Finalize - hybrid syntax decision
095 Message Templates Update - align with 091
096 Text Service New - architecture, ITextBlock, channels
097 React Client New - event-based, components
099 GLK Client New - status: identified
100 Screen Reader New - status: identified

Package Structure

New Packages

  • @sharpee/text-blocks - Interfaces (ITextBlock, IDecoration)
  • @sharpee/text-service - Single service implementation
  • @sharpee/client-react - React client (greenfield)

Archived

  • text-services → archive
  • text-service-browser → archive
  • text-service-template → archive

Key Quotes

"the Sharpee Way would be event based" - Dave

"you just reinvented fyrevm channel IO" - Dave (on the architecture)

"I'd toss the current implementation and design for what we're designing now" - Dave (clean slate)

"everything is greenfield Mr. Claude" - Dave


Next Steps

  1. Write/update ADRs (091, 095, 096, 097, 099, 100)
  2. Create @sharpee/text-blocks package
  3. Create @sharpee/text-service package
  4. Archive existing text-service packages
  5. Implement React client

This document preserves the design thinking and decisions from a pivotal architecture session.


Renga in Blue

Haunted House (Lucas, 1983)

Writing an adventure game is very similar to writing a novel. Everybody can write a few unrelated sentences, but the novelist’s skill comes from stringing sentences together in such a way as to create a tale combining imagination, flair and ingenuity. — From Steve Lucas, 1985, Adventure Programming on the Amstrad The British company ICL […]

Writing an adventure game is very similar to writing a novel. Everybody can write a few unrelated sentences, but the novelist’s skill comes from stringing sentences together in such a way as to create a tale combining imagination, flair and ingenuity.

— From Steve Lucas, 1985, Adventure Programming on the Amstrad

Two relevant places for today marked: Kidsgrove in red, Burton-Upon-Trent in blue to the southeast.

The British company ICL (International Computers, Limited) has come up here before; their game called Quest by Urquhart, Sheppard and McCarthy came from their computers as an after-hours project. They were curiously formed as sort of a forced integration of multiple companies from the 1960s. ICT (International Computers and Tabulators) was already a merger of elements from BTM (British Tabulating Machines), Powers-Sampas, and the computer divisions of GEC, EMI, and Ferranti; English Electric had merged in Leo, Marconi, and Eliot (changing names each time).

In certain contexts a government might be concerned about monopoly power, but the Wilson government of the late 60s decided the opposite; there was concern that the British computer market was simply going to collapse under outside pressure (especially from IBM). So, the government invoked the Industrial Expansion Act which pushed together the two companies into one in 1968, keeping the name ICL.

The resulting mammoth had a disparate variety of incompatible products; ICL decided to “start fresh” (with government money assistance, 40 million pounds) and develop the 2900 series. (Their own 1900 series was ailing and outdated, using only 6 bit characters.) At Kidsgrove in particular (site originally built by English Electric in the 60s) they made printed circuit boards but also were one of the sites developing software for the new device, in particular the (now well-regarded, unstable at the start) VME/B operating system.

From a 1976 booklet, via the Centre for Computing History.

Early releases of VME/B were characterised by one word – late. At one stage VME/B was being produced in Kidsgrove, but top management and validation remained in Bracknell. As days turned into weeks, management became increasingly impatient. “We haven’t finished it yet” was the reason for a conspicuous delay in handover to system test. “Then just put what you have finished on a tape and send it down here so that we can make a start on validation”.

A couple of days later a tape arrived. It was put up on a tape deck and the machine was booted up. Nothing happened. Consternation ensued. Much diagnostic effort was expended in trying to get the new version of VME to load. Eventually it transpired that the tape contained only an end of file mark.

“That tape you sent us – its completely empty.”

“But that’s what you asked for.” came the reply. Somehow a week’s delay was bought.

— Andrew Mason from Another ICL Anthology

One of the people hired around this time was Andrew Espeland. I’m unfortunately just guessing he was at Kidsgrove but I have decent evidence, as he worked at ICL starting around 1973, had an address at Burton-on-Trent in 1983 and went to Burton Grammar School in the 60s, meaning there’s a fair chance he stayed locally in between. The nearest ICL location from Burton-on-Trent was at Kidsgrove. In the later part of his time there it is possible he did some telework, as we know Kidsgrove specifically was set up for that. You can see a demo below of a worker with Airbus connecting to an ICL terminal, circa 1982:

While ICL expanded all through the 70s (helped along by the government policy of buying homegrown computers) they were starting to be in trouble in the 1980s. They were intending to expand to a factory in Winsford (about an hour northwest of Kidsgrove) and the local government “bent over backwards” to aid in this, with 1,500 new houses built and “sterilising a major factory site” but ICL started to backtrack; from the floor of Parliament:

The matter is urgent because the loss of 1,500 jobs is in an area where unemployment is already at 11 per cent. The only other large employer, Metal Box, is due to close at Christmas with the loss of 500 jobs, many of them directly affecting my constituents, [it] would push unemployment up to 15 per cent by the spring.

This is a death blow to Winsford. I have just learnt that the men’s bitterness is such that they have today occupied the factory, and I submit that the House has a special responsibility to air their grievances as urgently as possible.

While the situation at Kidsgrove wasn’t quite as bad, they still went from 33,000 to 20,000 employees from 1981 to 1984. So it is possible Andrew Espeland was one of the redundancies; whatever happened, he decided to strike it out on his own as a software publisher in mid-1983 and founded Silverlind. He posted solicitations for authors during this time.

Esperland gave an interview to his local newspaper (Burton Mail) on November 23, 1983, featuring the Silverlind Master Diet Planner (written by Professor C. V. Brown and Dr. E. J. Levin of the University of Stirling)…

…although it was the sort of interview where he was starting from scratch with teaching how computers work, including explaining to the reporter “that software and hardware were not related to pornography.”

Silverlind is like a book publishing company, only we sell tapes instead of books. We offer the amateur a chance to turn professional. Everyone who has a computer thinks he’s great at coming up with programs, but not many people have the resources to market them if they’re good. That’s where we come in.

Please note that he went straight from ICL to personal computer tape distribution; this is different from the situation at Sumlock I wrote about recently where there was a branch computer store in the late 1970s that led to software publishing. Put another way, Sumlock’s ads and packaging come across as being sold by someone with product and consumer experience, while Silverland’s come across as being made by someone who came straight from writing operating systems to running a company. Silverlind did not last long, with ads starting by the end of the year and petering out by early 1985 with no increase in catalog size. The late 1983 ads include three adventure games.

All three are (probably) all by the same author, one we’ve encountered before: Steve W. Lucas. He is, as I explained earlier, sort of the British version of Peter Kirsch, writing a staggering number of type-ins starting in 1983, although many are repurposed ones he had already written.

The reason for the “(probably)” is we only have copies of two of the Silverlind adventures: Haunted House and Passport to Death. Gateway to the Stars (AKA Journey to the Stars) is lost, but assuming it is by Lucas we might see it again under a different name anyway. (I’m suspicious of “A Journey Through Space” which is in his Adventure Programming on the Amstrad book; there’s no tiger or lizard woman but Lucas often renamed things. The book game is allegedly “buggy and impossible to finish” which is another thing common amongst Lucas games.)

Via Everygamegoing.

While the previous Lucas game we played had versions for Amstrad and Oric, this one is for BBC Micro! Just like the other Lucas games this does have a clone-situation but I’m going to focus on the original for now and visit the duplicate situation at the end.

I have the full instructions from the inside of the tape, but they don’t give any context other than “you are standing in the doorway of an old mansion” and “you must recover the six treasures”.

You have a lamp which won’t work, a note and a gun when you start. As you visit the other locations you will find a variety of objects which may be of use – or are they red herrings?

Regarding the note:

The note is from my great grandfather ARNOLD J HARBUTHNOT. It reads:

As my sole living heir, I have sent you on this dangerous mission to find 6 treasures and rescue the princess. you must deposit these items on the doorstep.

Apparently there’s a princess too? In a haunted house? Wouldn’t be the first time that’s happened. (I will find the princess this session, but not rescue her yet.)

The overall structure of the complex has a house to the north, a path in the middle, and a castle to the south. Despite the Haunted House name the castle is more extensive than the house, but let’s start with the house first.

There’s no descriptions of rooms beyond their names, so you need to use your imagination.

Doing a grand tour, east of the hallway is a bedroom with a pair of slippers, and “an old four poster bed” with a pillow. North leads to a kitchen with a box of matches, a bottle of spirits, and some food, and going west after leads to a “large dining room full of cobwebs” that contains a candle.

West of the hallways is a library with a map and a “pen in a golden holder”. The map curiously says “not at the moment” when you try to read it; this is a game where items often only can be used in very specific cases, even if there is no logical reason to restrict them (like books). Trying to GET PEN reveals a secret passage…

…and going in is death.

Well, to be fair, the game did start by announcing we had a dead lamp. With the matches and the candle you can LIGHT CANDLE (…normally, one time it caused my game to crash…) and go into the secret passage safely. Not far in, you get stopped by a monster.

There’s a “sharp knife” you can find later but if you try to KILL MONSTER the game says “you’re a coward”, which is rude but fair for a standard adventurer who will likely rely on trickery or some gizmo instead to get by. Let’s turn to the middle path area…

…where off an “old footpath” to start there is a “snarling wolf” at a “coffin”.

Trying to OPEN COFFIN gets a blank response from the game (another thing that’s pretty common; 98% sure this game was written before Journey of a Space Traveller because it has more jank). I can get a reaction from the wolf by trying to GET WOLF…

That makes it mad. It attacks me. I am DEAD

…but that isn’t helpful so let’s move on! Further south is another split in the path where a signpost informs us that “FOOTPATH WEST IS DANGEROUS. YOU NEED A MAP” and this is the one and only spot the map can be READ successfully.

(I originally died while holding the map thinking it would be used passively. Not only can the map only be read in the right room, but you have to do the READ command before moving otherwise you’ll die.)

This leads to an Old Barn with a *PEWTER* trinket and a book of ghost stories, and just past is a tiny cave which appears to be empty. I tried to do SWEEP even though I had no appropriate item and the game told me I couldn’t swim. This is a two-letter parser. (On the BBC Micro, why!)

Reading the book only works in this room.

Moving on you can find a drawbridge (no puzzle, just PULL LEVER) followed by a “drunken man” in a Castle Courtyard that is blocking your way west (you can pass south unfettered). If you take the spirits from the kitchen and drop them he will helpfully pass out.

Go farther west and you’ll find the princess! Except now you are locked in, and typing HELP as the game suggests indicates that if you don’t have a key you should reset your game.

Ignoring the drunk man for the moment and going south into the castle…

…you can do a sweep down various rooms to the south and west and find a sharp knife in a kitchen, a tray of drinks in a restroom, a bar of soap in a bathroom, a packet of crisps in a dormitory, and a uniform in a changing room. (You might think to WEAR UNIFORM while in that room, but there is no response to this.) There is cryptically also a “magazine dated 1893” where READ MAGAZINE gets the message “I can’t make it out.”

35% chance this is a red herring, 30% chance I need an item, 30% chance I need to bring the magazine somewhere else, 5% chance this is a bug.

Heading east instead leads to a most curious room for a game called Haunted House.

You can THROW TOMATOES (as the screen shows me doing) but FREE MAN and RELEASE MAN are right out. Maybe this scene is here to be funny? Just south of here is a “hand-operated lift” with a “rope with a hook” inside but no apparent way to operate the lift.

To the far east you can find a “pair of electrodes” intended for ??? and a painting which the main character is actively offended by.

South is a pottery room with some pots (spooky?) and to the north is a ghost (spooky!)

You might think, ah, the book says the uniform will scare ghosts, but I have not been able to wear the uniform, nor does it get used “passively”. I tried SCARE GHOST and since the game has a two-letter parser it read the command as SCORE instead, telling me I had 1 out of 7 points possible.

There is a solution on CASA and my pain tolerance will not be high, but I admit there are things I haven’t tried like giving the crisps to the wolf, or stabbing the princess with a knife, or entertaining the man in stocks with a puppet show using slippers on my hands. I will also take suggestions in the comments for next time.

Sunday, 11. January 2026

My So Called Interactive Fiction Life

Another Parser Refactor(ial) and Scope

In the process of porting Dungeo to Sharpee, we got to a completed implementation, but some unit tests missed important steps. When I started a "walkthrough" test in phases, we discovered a glaring gap in my grammar and parser implementation. I should say fundamental misunderstanding of what the

In the process of porting Dungeo to Sharpee, we got to a completed implementation, but some unit tests missed important steps. When I started a "walkthrough" test in phases, we discovered a glaring gap in my grammar and parser implementation. I should say fundamental misunderstanding of what the grammar definitions are responsible for, what the parser does, and what happens in actions in the standard library.

The grammar builder was trying to do some of the validation ahead of time. It took a few iterations to convince Claude this was incorrect (the stubbornness comes from all of the history of docs in the project, not Claude hallucinating).

We updated the Grammar Builder to be very simple. It connects patterns to actions and defines required Traits. Here's examples of the old builder and the new one.

OLD: Scope + boolean property matching in grammar

  grammar
    .define('put :item in :container')
    .where('item', (scope) => scope.carried())
    .where('container', (scope) => scope
                    .touchable()
                    .matching({ container: true }))
    .mapsTo('if.action.inserting')
    .build();

  grammar
    .define('board :vehicle')
    .where('vehicle', (scope) => scope
                    .visible()
                    .matching({ enterable: true }))
    .mapsTo('if.action.entering')
    .build();

  NEW: Traits only - scope moved to action validation

  grammar
    .define('put :item in :container')
    .hasTrait('container', TraitType.CONTAINER)
    .mapsTo('if.action.inserting')
    .build();

  grammar
    .define('board :vehicle')
    .hasTrait('vehicle', TraitType.ENTERABLE)
    .mapsTo('if.action.entering')
    .build();

  Key changes:
  - Removed .visible(), .touchable(), .carried()
        - scope now handled by action validate()
  - Replaced .matching({ container: true })
        with .hasTrait('slot', TraitType.CONTAINER)
  - Grammar declares only semantic constraints (what kind of entity),
    not scope (visibility/reachability)

And this leads to handling scope and validation more efficiently:

 Action Scope Validation (NEW)

  Scope is now handled in action validate() with a 4-tier system:

  /**
   * 4-tier scope hierarchy (ordered - higher implies lower)
   */
  enum ScopeLevel {
    UNAWARE = 0,    // Entity not known to player
    AWARE = 1,      // Player knows it exists (think about, ask about)
    VISIBLE = 2,    // Can see it (examine, look at, read)
    REACHABLE = 3,  // Can physically touch (take, push, open)
    CARRIED = 4     // In inventory (drop, eat, wear, insert)
  }

  Example: Opening Action

  export const openingAction: Action = {
    id: 'if.action.opening',

    // Document default scope for this action
    defaultScope: {
      target: ScopeLevel.REACHABLE
    },

    validate(context: ActionContext): ValidationResult {
      const target = context.command.directObject?.entity;

      if (!target) {
        return { valid: false, error: 'NO_TARGET' };
      }

      // Check scope - must be able to reach the target
      const scopeCheck = context.requireScope(target, ScopeLevel.REACHABLE);
      if (!scopeCheck.ok) {
        return scopeCheck.error!;  // Returns "You can't reach that" etc.
      }

      // Check trait - must be openable
      if (!target.has(TraitType.OPENABLE)) {
          return { valid: false, error: 'NOT_OPENABLE',
                params: { item: target.name } };
      }

      // Check state - must be closed
      if (!OpenableBehavior.canOpen(target)) {
        return { valid: false, error: 'ALREADY_OPEN',
                params: { item: target.name } };
      }

      return { valid: true };
    },
    // ...
  };

  Example: Examining Action (VISIBLE scope)

  export const examiningAction: Action = {
    id: 'if.action.examining',

    defaultScope: {
      target: ScopeLevel.VISIBLE  // Only need to see it, not touch
    },

    validate(context: ActionContext): ValidationResult {
      const target = context.command.directObject?.entity;

      if (!target) {
        return { valid: false, error: 'NO_TARGET' };
      }

      // Examining yourself always works
      if (target.id !== context.player.id) {
        const scopeCheck = context.requireScope(target, ScopeLevel.VISIBLE);
        if (!scopeCheck.ok) {
          return scopeCheck.error!;  // "You can't see any such thing"
        }
      }

      return { valid: true };
    },
    // ...
  };

The most important thing these changes enabled was composable traits. The previous implementation was unable to handle that and now we have working composition.

Saturday, 10. January 2026

Renga in Blue

Adventure 751: Into the Sunset

I’ve never spelunked, although I’ve been in a number of caves around the country as a tourist. Like Carlsbad Caverns, Lava River Cave here in Oregon, Cave of the Winds in Colorado and others I can’t recall. Most of my additions were suggested either by fantasy stories or the many geology texts I’ve read. — […]

I’ve never spelunked, although I’ve been in a number of caves around the country as a tourist. Like Carlsbad Caverns, Lava River Cave here in Oregon, Cave of the Winds in Colorado and others I can’t recall. Most of my additions were suggested either by fantasy stories or the many geology texts I’ve read.

— David Long

I’ve finished the game. You should read my previous posts about Adventure 751 before this one.

Three parts I needed to check the walkthrough on. Two puzzles were sort of fair. The third was absolutely off the charts unfair and I don’t know how anyone ever solved it.

CompuServe in 1995, via The Columbus Dispatch. They had 3.6 million customers, but four years later they would be bought out by AOL. When moving to a new interface, their text-based games shut down.

To start with, a classic, me missing a room exit. This is at the now-defeated leprechaun:

You’re at the east portal of the Gothic Cathedral.

GO NORTHEAST

You’re at sham rock.

GO UP

You are on top of a flat black rock.
There is a small briar pipe here.
There is a suede pouch here.

Whoops! There were “smoke rings” coming up from the rock and there’s also suspicious items on the map picture.

What happens next took place for me later, and is one of the puzzles I needed to just look up the answer. It’s clearer for me to explain it now. I’m referring here to the boulder just north of the sham rock:

Although the boulder moves a fraction of an inch, it is too heavy for you to roll away.

We’ve already had a “get strong” puzzle multiple times along our journey, so the thought passed my mind that this might come up, but I was expecting to find a different kind of mushroom or special cream; getting by the boulder instead involves the food from the beginning of the game.

The food tastes bland, but is not unpalatable.

In Normal Adventure it gets fed to the bear to make it happy; we swapped in the honeycomb in this game as the food is described as “watercress sandwiches” when you try to give them to the bear. The “bland” part of the description is the key, as you’re supposed to use one of your treasures (!) on top of the food (!!) and then eat it (!!!).

PUT SPICES ON FOOD

All the food needed was a bit of spicing up: it smells delicious!

EAT FOOD

Zam! What a meal! Now we’re ready for anything!

This does not consume the rare spices (unlike the cakes you ate to get small). Which makes sense in a pragmatic sense, but the general rule of this sort of game has been that eating something means that thing goes away. It’s still not obvious from the description, but now the boulder can be moved.

Grunt…Pant…You have pushed the boulder to one side, enough to permit you to squeeze past it.

GO NORTH

You are at the bottom of a vertical shaft, apparently a dry well, whose cylindrical wall is lined with smooth stone. Far above your head, you can see daylight!
A heavy iron handle, slotted at one end and rounded at the other, lies at your feet.

At least I knew immediately what the handle goes to!

Back to the castle we go:

You’re in the Central Court.

PUT HANDLE IN WINCH

The iron bar, evidently the winch handle, slips easily into the winch mechanism.

TURN HANDLE

Turning the winch slowly lowers the great wooden drawbridge.

This also suggested another puzzle solution, as this landed me at the ravine area right next to the angry centipede.

You are at cliff by west end of moat.

MOVE VINES

Parting the vines reveals a dim recess in the cliff wall.

IN

You are in the lair of Ralph the Giant Centipede. The air reeks with the stench of rotting bits of flesh. Giant centipedes, in general, are not partial to visitors.
A golden fleece is lying nearby!
A giant centipede is eyeing you with a none-too-friendly look.

GET FLEECE

You have snatched the centipede’s very own security blanket!

Provoked beyond endurance (centipedes have none), the indignant insect lurches to all of its feet and starts towards you.

OUT

You are at cliff by west end of moat.
The cantankerous cootie is heading towards you, and he definitely harbors no goodwill towards you.
A dim alcove can be seen behind the vines.

GO EAST

You’re beside moat.
The angry arthropod is definitely gaining on you. You had better either sprout several more legs or find some way to evade him.
A wooden drawbridge spans the moat.

GO NORTH

You’re in the Central Court.
The incensed insect is in full gear now. If you don’t move quickly, his monstrous mandibles may masticate you into murky mush!
A heavy iron handle is inserted into the winch.
A wooden drawbridge spans the moat.

TURN HANDLE

With a great creaking and groaning, the winch raises the drawbridge to a vertical position against the stone wall.

You have raised the bridge just in time. The centipede stamps furiously up and down in front of the moat, but, finding no way to cross, finally gives up and lumbers back to his cave.

I love “cantankerous cootie”; Ralph is so vivid I wonder if he’s supposed to be some sort of University of Chicago reference (not Atari Centipede, which wasn’t out yet). Moving on to the castle interior…

…as a reminder I had found a tapestry (treasure) and a black bird statue (not) as well as a door with colored tiles. I did not disclose the answer to the tile puzzle, and Voltgloss managed to work it out in the comments.

The key is the word FNORD, being spelled by the initial words of the colors. As Aula observes in the comments, the color names are decidedly odd, which might suggest thinking of initial letters.

You are inside a large steel vault.
Nearby is an intricately-wrought bronze shield bearing the escutcheon of Duke Aldor.

The other two places of note are the Secret Garden and the kitchen with the dumbwaiter. I already suspected what to do with the dumbwaiter as the puzzle is more or less wholesale stolen from Zork (I’ll get into that later) but let me get into the Secret Garden. You don’t enter it here at all, but rather an exit at the third helicopter stop I missed last time.

(Also, the knapsack with the silk sheets lets you refer to it as a PARACHUTE, which made me much more confident the following sequence would work before I tried it.)

You’re on the south end of a high narrow ridge, which is bounded on its east side by a high mountain. Dug into the mountainside is a ramshackle old mine entrance. The ridge drops off to the west in a rocky cliff. You might be able to climb down the cliff, but you probably won’t be able to get back up.
A helicopter is waiting nearby.

GO NORTH

You are on a narrow N/S ridge high above a stone wall and wide moat.

GO NORTH

You are at the northwest end of a narrow ridge high above the castle’s inner courtyard.

WEAR PARACHUTE

Ok

JUMP

After a few seconds in freefall your parachute opens with a sudden “Pop!” Several moments later you land unhurt. The magic ‘chute then folds itself back into the knapsack.
You are in an idyllic garden hidden in an inner courtyard of, and surrounded on three sides by, the Castle Keep. The far end of the garden is bounded by a high cliff.
A wooden door leads into the castle.
Lying in one corner of the garden is a golden apple!

From a game design angle, what I’m frustrated by here is how this is the only place the parachute works; jump in any other high place and you won’t get a description at all. I know that “magic” can technically hand-wave away anything, but inconsistency in magic use is one of my main teeth-grinders, especially in that it’d be fun to jump off in other high places.

Note as far as I know this loses the helicopter (remember we left at the ledge) so I ended up shuffling my sequence around to do the golden apple part last. So let’s warp back a little and go inside the mine instead.

You are in a gloomy tunnel, the entrance to a long-abandoned mine. All around is fallen rock and rotted timbers. To your left, a small room adjoins the main tunnel.

Arthur O’Dwyer mentioned I had missed an exit here, but at least this time I had fair reason. Going DOWN goes into the mine, and none of the other compass directions work. You’re supposed to go LEFT, which is counter to everything else in the entirety of the game.

You are in the engineering room. On a control panel on the wall are four buttons, colored green, brown, red and yellow; and a digital gauge.

Going down into the mine reveals it is flooded by water. The gauge currently reads 5, which tells you the flood level; pressing the “red button” and waiting will cause the water to go down. The frustrating aspect is that reading the gauge does not pass time.

PUSH RED BUTTON

From somewhere in the distance comes the deep throbbing of a heavy engine.

READ GAUGE

The meter reads “5”.

READ GAUGE

The meter reads “5”.

READ GAUGE

The meter reads “5”.

READ GAUGE

The meter reads “5”.

I was deeply confused for a while, because I knew I had at one point seen the meter go down, and had even had the engine explode because I didn’t turn it off. However, you need to do some command other than READ, like LOOK, and then READ GAUGE afterwards.

You are in the engineering room. On a control panel on the wall are four buttons, colored green, brown, red and yellow; and a digital gauge.
The deep hum of heavy machinery fills the control room.

READ GAUGE

The meter reads “1”.

LOOK

You are in the engineering room. On a control panel on the wall are four buttons, colored green, brown, red and yellow; and a digital gauge.
The deep hum of heavy machinery fills the control room.

READ GAUGE

The meter reads zero.

With this taken care of you can go to the bottom of the mine. There’s a passage there that’s too narrow to go through while holding items (like the one at the emerald / dark room).

You are at the bottom of the mine’s main shaft. Several passages, now all blocked by cave-ins, used to lead off in all directions.
To the north, the one remaining tunnel is partially blocked.

GO NORTH

The tunnel is a real squeaker. You’ll be lucky to get through with your clothes on, let alone anything else.
You’re at bottom of mine.

If you drop everything and go through, the room is too dark to see. I already suspected taking the puzzle from Zork when I saw the dumbwaiter back at the castle; you’re supposed to put a light source in there (lighting the candle back from the cathedral works, the one that I had previously used to burn the thicket except burning it was wrong) and then lower the dumbwaiter.

You are in a dead-end shaft formerly used for temporary storage.
The dumbwaiter is at this level.
It contains:
wax candle
There is a pile of silver ingots here!

You can put the ingots in the dumbwaiter, leave, go back to the castle, and then pull up the dumbwaiter to find the ingots waiting for you.

The water didn’t just disappear! It filled up the ravine.

You’re in an open field on the south side of a flooded ravine. South and west the land merges into nearly impassible swamp. In the muck is a fresh footprint! Incredibly, it looks very much like that of a Giant Devonian Rat, long thought extinct.

This ravine had a statue. The setup was that you could go in or out of the ravine while not holding anything, but you couldn’t take that valuable statue at the bottom with you. By filling up the ravine with water, you have softlocked the game.

I was incredibly stumped because I was looking for alternate exits, when instead I should have been thinking about getting the statue to rise with the water. I was imagining the statue as extremely heavy, so that this wouldn’t work:

You are at the east end of a steep ravine, near where a drainage pipe emerges from a rock wall.
There is an ancient marble statue lying here!

PUT STATUE IN BOX

Ok

DROP BOX

Dropped.

You’ll find the box with the statue sitting at the muddy ravine when it fills. This isn’t the puzzle I consider outrageously unfair, as at least conceptually this was neat, and we are down to not too many items to fiddle with.

Speaking of fiddling with items, remember that “briar pipe” and “suede pouch” from the start of the post? The pouch has tobacco, and you can use a match from the matchbox to light tobacco in the pipe. It wasn’t obvious what it was for, but I remembered (barely) there were some mosquitos out in the salt flats (just a bit south of the ravine) that I had never been able to bypass.

The air ahead is filled with huge mosquitos, with stingers the size of icepicks! The mosquitos haven’t yet caught your scent.
Do you really want to proceed?

YES

Your pipe fumes have effectively fumigated your flying foes. The bothersome bugs beat it as you approach.

You are enveloped in a cloud of noxious-smelling tobacco fumes.
You are on a small dry patch of earth, surrounded by dank swamp.
There is an old cracked shaving mug here.
There is a large cloth bag lying nearby.
There is a smooth, white pebble lying nearby.
An old shiny button is lying here.
An ancient mystic amulet, somewhat tarnished by the dampness, is lying here!

I never used the amulet for anything; it counts as a treasure. (Briefly searching through the walkthrough, it looks like it could be used to teleport, but that’s optional.)

Donovan fit almost everything into the art, but I’m not seeing which spot in the swamp would be the rat nest.

From here this was nearly done! If you’re wondering about the rope that was frustrating me before, you can drop it at the bottom of the well and play the flute to cause it to rise, giving another way to get into the castle (again optional). However, there was one item I had done nothing with and did not count as a treasure and here is the part that went off the charts:

There is a clay statue of a black bird here.

I kept trying to invoke it for some kind of magic? Maybe it would turn into a real bird and do something? Unfortunately I already “used” essentially everything so backwards thinking from my object list was no help.

The bird is dirty, you’re just supposed to clean it.

POUR WATER ON BIRD

The liquid reacts oddly with the black substance covering the statue of the bird. After a few moments, the black coating dissolves completely, revealing a statue of solid gold encrusted with priceless gems of every description!

INVENTORY

You are currently holding the following:
brass lantern
official document
knapsack
maltese falcon
glass bottle

At least I didn’t have to go through a complicated endgame. The way Crowther/Woods works is that once you’ve placed all the treasures, you hang out in the underground enough and there will be an announcement that the cave is closing; wait longer and you’ll get tossed into the endgame. There’s no surprises here other than the item catalog is different than original Crowther/Woods:

The sepulchral voice entones, “The cave is now closed.” As the echoes fade, there is a blinding flash of light (and a small puff of orange smoke). . . . As your eyes refocus, you look around and find… You are at the northeast end of an immense room, even larger than the Giant Room. It appears to be a repository for the “ADVENTURE” program. Massive torches far overhead bathe the room with smokey yellow light. Scattered about you can be seen a pile of bottles (all of them empty), a nursery of young beanstalks murmuring quietly, a bed of oysters, a bundle of black rods with rusty stars on their ends, and a collection of brass lanterns. Off to one side a great many dwarves are sleeping on the floor, snoring loudly. A sign nearby reads: “Do not disturb the dwarves!” An immense mirror is hanging against one wall, and stretches to the other end of the room, where various other sundry objects can be glimpsed dimly in the distance. An unoccupied telephone booth stands against the north wall.

GO SOUTHWEST

You are at the southwest end of the repository. To one side is a pit full of fierce green snakes. On the other side is a row of small wicker cages, each of which contains a little sulking bird. In one corner is a bundle of black rods with rusty marks on their ends. A large number of velvet pillows are scattered about on the floor. Beside one of the pillows is a large, dusty, leather-bound volume with the title “History of Adventure” embossed in pure gold. A vast mirror stretches off to the northeast, almost reaching the phone booth. At your feet is a large steel grate, next to which is a sign which reads, “Treasure Vault. Keys in Main Office.”
The grate is locked.

Mind you, figuring out what to do was hard in Crowther/Woods, but here it’s an identical solution, so I was able to claim victory.

GET ROD

Taken.

GO NORTHEAST

You’re at NE end.

DROP ROD

Dropped.

GO SOUTHWEST

You’re at SW end.
The grate is locked.

BLAST

There is a loud explosion, and a twenty-foot hole appears in the far wall, burying the dwarves in the rubble. You march through the hole and find yourself in the Main Office, where a cheering band of friendly elves carry the conquering adventurer off into the sunset.

You scored 667 out of a possible 751, using 1726 turns.

Your score puts you in Master Adventurer Class B.

I have no idea where the missing points are. Maybe this is a game like the “2.0” version Woods wrote which accounts for your turn count? I absolutely did not optimize. (Optimize light, sure, but there’s a fair amount of aboveground parts to this game, and I never tried to be efficient when it came to sorting inventory at the building/safe.)

That’s still enough to close out the game for good. I’ve known about this one for ages and I can’t describe how gratifying it was to finally play. Some of the mainframes are finally getting tape dumps and there’s more lost content likely that will be unearthed (I’m sure Rob is about to show up and announce another 30-hour game suddenly landing), but because I’ve been able to look at the picture (even using it to annotate other variants of Adventure!) Long’s Adventure 751 had a sense of absence that other games did not.

As far as game quality goes, it was mixed; I think it started to get to the point where it was too big. The new sections were intrinsically clever but they felt like they were part of another realm entirely, even when, say, the rat was using similar mechanics as the pirate. I would have loved to see what Long would have done with an entirely different game.

It is faintly possible there’s a little bit more. In Arthur O’Dwyer’s writeup he discusses a version of the history text file in the game where “more than double” is instead “more than triple”.

But does this indicate any actual expansion of the cave? The unearthed game already includes all of the features mentioned here. Was Long just massaging his messaging?

It is possible Long was able to noodle with the program more while it was on CompuServe, and while I don’t know the details yet, Rob has mentioned in the comments here that the commercial version will be forthcoming so we’ll get a chance to take a look.


Zarf Updates

2026 IGF nominees

Oh gosh! The IGF finalists are up. I played a bunch in the first judging round. Many of these are already in my review list, including The Drifter, Öoo, Strange Jigsaws, Type Help, The Roottrees Are Dead, and Mini Mini Golf Golf. I am amused ...

Oh gosh! The IGF finalists are up.

I played a bunch in the first judging round. Many of these are already in my review list, including The Drifter, Öoo, Strange Jigsaws, Type Help, The Roottrees Are Dead, and Mini Mini Golf Golf.

I am amused that four games in that IGF post wound up in my review post titled "Weird little games, summer edition". I didn't know they were IGF entries when I wrote that; I just knew they were little and weird. It's great to see the appreciation of weird little games is shared among the discerning game-playing community.

Of course I am happy to see that Roottrees and Type Help continue to get recognition. I can't wait for Incident at Galley House, the Type Help remake.

Games which I have not yet played but I clearly need to: Perfect Tides: Station to Station, Blippo+, Angelina Era, and all the other titles that I haven't mentioned but in no way mean to slight.

Extra shoutout to Titanium Court. I have not played this and I do not know a damn thing about it, but as soon as the IGF post dropped, my social circles were flooded by awesome game-design folks saying "Titanium Court! I can talk about it now! Titanium Court! You gotta play it!" (As soon as it's out -- no release date yet.) So, I guess I gotta play it.

Anyway, here's what you want: games that I have played but not yet discussed. This includes both IGF finalists and entries that didn't get an official mention but they're worth a word anyhow.

  • Arctic Awakening
  • Promise Mascot Agency
  • The Haunting of Joni Evers
  • Carceri
  • Prší
  • Kid Cosmo
  • and Roger
  • Jane

Arctic Awakening

A narrative exploration game in five episodes. You're stuck in Alaska with only the wreckage of your airplane and your court-assigned therapy bot for company. What's going on, and why do you keep discovering abandoned weird science labs?

I am mixed on this one. The dialogue and the voice acting are great. Grumpy Guy and Perky Bot are a solid double act, and I enjoyed spending time with them. But, to be clear, you spend a lot of time with them. Most of the game is walk-and-talking through the wilderness. To be fair, the wilderness has grandeur. Think Firewatch with snow -- not hyper-realistic, but great mountain vistas and charismatic megastructures.

There's light puzzling, mostly of the "find this object, it's around here somewhere" variety. This can get annoying if you happen to miss the object for a while. Just keep poking. Beyond that, the game tracks a lot of story state -- again, Firewatch-style. Minor story state, though; it's not a seriously branching plot.

I feel like the overall structure doesn't quite hang together. It's supposed to be a dual plot: discovering the secrets of the world, and working through your emotional issues. Thread #1 has a lot of meat on it, but doesn't exactly resolve; the last-act reveals are rushed, and manage to be both obvious and incomplete. As for thread #2, it mostly consists of your annoying bot friend trying to get you to open up about your life, while you tell him (correctly) that this is less important than getting home. It just doesn't really fit the ending they want you to arrive at.

I had a good time, but the game doesn't exceed the sum of its parts.

Promise Mascot Agency

Disgraced yakuza enforcer is sent to the town of out-of-work live mascots. Hijinks ensue.

This is very pleasant. (Once I got past the initial money crunch, which is a bit scary even in easy mode.) It's GTA with all the hostile cops and high-pressure race scenes stripped out, which is honestly a brilliant idea and exactly what I need in my life right now.

The setting is self-consciously ridiculous. Not as completely ridiculous as Paradise Killer, which was lofted entirely on its absurdist beach-town-of-Elder-God-Things vibe. But dead-serious yakuza mob war cheered on by a walking thumb and a block of sentient tofu are almost as good. All the characters are a joy to hang with, each in their own over-the-top way.

PK's plot was almost entirely backstory. I can see the designers are pushing to have a more active story this time, but the pacing isn't great. If you are assiduous about side missions (and why would you play a package-hunting game without lawnmowering the side missions?), then the plot hangs and hangs and then slams down on you at the end. It's good stuff, but the last half of the last act turns into a sequence of cut scenes. Sigh.

I guess my real complaint is that the setting is amusing, in its over-the-top Japanese mob-and-mascot schtick. (The entire voice track is subtitled Japanese -- remember that the developers are British!) But I didn't spend the game repeatedly shouting "They did what?!" Which was the Paradise Killer vibe, and I miss it.

Not enough weird cosmic horror in the mix, is what I'm saying. Not none! Karoushi kicks ass. Needs more though.

The Haunting of Joni Evers

Walking sim about a woman's hangups about her family.

This is well-presented, but it drags out a fairly simple idea rather too long. It's three hours of the narrator talking about her family memories. She does her damnedest but the characters never really came alive for me (pun half-intended) (they're ghosts or something, see). Without that, the whole thing felt stilted and overstuffed.

(With an evil spirit for punctuation, but he never becomes more than a spooky cartoon. Weakest part of the game, really; they could have left him out.)

This is notionally part of a horror anthology series, "Worlds Across the Causeway". I didn't get a sense of the larger world beyond the phrase, though. I'd play another one -- three hours isn't much time to invest! But I'm not yet convinced by the concept.

Carceri

A cheerful, talky platformer. You run around a candy-colored low-poly virtual world tagging little fox dudes. Sorry, I mean: infecting daemon processes with a sentient virus, which rewards you by levelling up your reality-warping powers. To wit: jump and then double-jump. (There's a third powerup but I won't spill the beans.)

At the end, you can listen to an hour-long philosophy discussion between the author and himself. It's like The Witness without any of those tedious puzzles!

...Okay, I'm being snarky. This is really very pleasant. The world is full of little corners to explore: libraries, art museums, a beach resort. Yes, a Piranesi-inspired prison labyrinth as well. All floating in a grand cyberspatial void. It reminded me of Fract: OSC, except that the only "puzzle" is not getting lost. The jumping isn't that hard either, and that's the whole game.

A complete run-through took me two hours. (I ignored all the in-game photo stuff and just explored.) The author says "virtual vacation" and honestly I was happy to take it.

Prší

One of the regulars in your favorite Czech dive bar has disappeared. What are you going to do about it? Play cards, ask questions, and drink a truly catastrophic volume of beer.

This is delightful. The dialogue UI is built on playing cards -- and drinking beer -- in a way that I haven't seen before. The bar is built in a warped claymation style, which entirely suits both the story and the cultural setting. (Švankmajer fan game!) Really, everything about this is perfect.

(Now I want someone to adapt Fritz Leiber's "Gonna Roll the Bones" in a similar way.)

Kid Cosmo

A narrative puzzle game about playing narrative puzzle games with your annoying sister in the alt-1980s.

This is well-built, but it felt a little unmotivated. There's some kind of alt-history leading to the Robot Uprising, which would be interesting if I knew anything about the tie-in movie or even the Simon Stålenhag book it's based on. But I don't. So it's two kids playing a videogame, plus the world has janitor robots and gas-pumping robots. The kids are cute but I don't see the theme.

I put this down after a few chapters. Maybe you'll be more into it.

(Also: I love a lot of break-the-fourth-wall game elements, but for some reason "use the physical tilt sensor" annoys me. Going back to the original release of The Room. I don't know why.)

(Outside-the-car lightning reflecting off the console case was jazz though.)

and Roger

I have seen several games on this theme. (Not spoiling, as the reveal is part of the narrative.) This one works.

The one-button control scheme is master-level. I can't imagine how hard it was to make it feel this easy and natural. And yet expressive, and a surprise each time. You could play the game in another language and get everything important from the button mechanics.

Really, that's all I have to say about it. Top-notch.

Jane

A very short mood piece. You wake up in the middle of the night and wander around the house in your underwear. There's exactly one thing to do.

This is nice! You can argue whether it's substantial enough to be an IGF entry, but IGF judging is done for the year so never mind that. One character, one moment, sweetly presented.

Friday, 09. January 2026

Renga in Blue

Adventure 751: A Section of the Castle In Which You Have No Business

(Continued from my previous posts.) The good news is I’m fully clear of the 501 content (1978) and now tangling directly with the 751 section (1980). The bad news is the author clearly thought going to the ’80 version that it was an opportune time to up the difficulty. At the very least, the sheer […]

(Continued from my previous posts.)

The good news is I’m fully clear of the 501 content (1978) and now tangling directly with the 751 section (1980). The bad news is the author clearly thought going to the ’80 version that it was an opportune time to up the difficulty.

At the very least, the sheer combinatorial explosion of the number of items the game now has makes each step much rougher than it needs to be.

TODAY, March 1983. The poster artist is Gray Morrow who is most famous for the Tarzan comic strips (post 1983) but also did work for both Marvel and DC.

Starting simple, I was running over my map trying to figure out the best spot for my shovel when I decided on the beach (even Pillage Village had us randomly dig at the beach, with no shovel at all!)

You’re on sandy beach.

DIG

You’ve dug yourself into a three foot hole in the sand.

DIG

You’re up to your waist in sand.

DIG

You’re in a deep pit in the sand.
You have unearthed a delicate, multi-hued conch.

That doesn’t mean I’m necessarily done with the shovel! None of the other candidates I’ve tried have panned out, though.

While out at the beach, I should mention the flute. Or rather, specifically the rat it summons: the rat has been roaming around aboveground the whole time, essentially the outdoors version of the pirate. I realize it was swapping useless items for useful items, so that “pebble” I found really was an item swap; I’ve also gotten an old shiny button where a pirate chest used to be (I had dropped the chest thinking it would be heavy and “protected” but it isn’t). The occasional bad odor also is from the rat.

The upshot here is rather than the rat being useful (as I was first thinking) is that I needed to get rid of the rat. The flute’s reference to the “pied piper” is the key here.

You’re at blackened shoals.

GO UP

You’re at Ocean Vista.

LOOK

You are on a high cliff overlooking the sea. Far below the rolling breakers smash into a jumble of blackened shoals.
The thunder of the surf is deafening.

PLAY FLUTE

After playing the flute for a few moments, you become aware of stealthy footsteps behind you.
The big rat, entranced by the music, blindly lurches over the edge of the cliff, only to be pounded to smithereens on the rocks below.

With this done, it is safe to put items on the ground in the building now. I used the opportunity to mop up a lot of the items I needed, like the vase (which is highly breakable and goes on a cushion). I also finally ran across the Wumpus corpse I had been looking for back at the Lost River section.

You are standing on a large flat rock table at the western end of Lost River Canyon. Beneath your feet, the river disappears amidst foam and spray into a large sinkhole. A gentle path leads east along the river’s south shore. Another leads sharply upward along the river’s north side.
Nearby is the smashed body of a defunct Wumpus.
On the Wumpus’ finger is a small gold ring.

It was, of course, one of the last sections I checked, but I should have been suspicious sooner, just in a structural-solving sense: there was otherwise a decent chunk of map that wouldn’t be used.

Six rooms otherwise not used. Crowther would be fine with a section like this, but not Long (who was the one who made this part).

One other item from the area I’ll mention now, although in practice it came much later than my other finds:

You are in the Conservatory, whence the gnomes often repair to relax with a little music. On one side of the room is an old upright piano.

OPEN PIANO

Ok

LOOK

You are in the Conservatory, whence the gnomes often repair to relax with a little music. On one side of the room is an old upright piano.
It contains:
official document

Oof. I was mentally sorting it as some kind of already-open grand piano even though it explicitly says in the text it is an upright. (I wasn’t trying to visualize it, though. I know there’s the aphantasia condition where people aren’t able to visualize and so they keep things in their head more conceptually; I don’t have it, but just because I’m good at visualizing doesn’t means I store everything visually. This is a case where my brain abstractly stored a “piano”.)

More on the official document shortly.

With all that I was still stuck on the “sham rock”, the centipede, and the statue in the ravine. I’m still stuck on all of them, more or less, although I got a little past the rock. Let me do an aside on the rose in the thorns right before the sham rock, first…

A NE passage is blocked by an impenetrable thicket of sharp thorny brambles.
Deep within the brambles is growing a perfect, blood-red rose!

…I had been burning them to get them away but this destroys the rose. You’re supposed to use the sword (pulled from the stone while wearing the crown) instead.

Your elfin sword makes short work of the brambles. After a few minutes work, you hack a large hole through the tangle.

If you just try to take the rose now, it will shrivel. That vase that was previously used for the break-if-you-don’t-drop-on-a-pillow puzzle is now repurposed:

PUT ROSE IN VASE

As you place the rose into the vase, the rose opens in full bloom, revealing a sachet of rare perfume inside.

(This is one of those puzzles where I was starting to feel the burn of having so many items.)

Past the thicket, the leprechaun was wanting me to vanquish “one much larger than I”. Oddly, I knew that I had tried going by with the bear, dragon, and Wumpus all killed, but no luck. Arthur O’Dwyer hinted I was on the right track but I needed “proof”. That would be either the rug at the dragon or the gold ring at the Wumpus; the latter sounded more elegant.

As you approach the rock, the leprechaun (for indeed that is what he is) notices your shamrock *and* your ring, and with a muttered curse, disappears.
You’re in a large chamber. All around are massive skeletons of long-dead members of the order proboscidea ungulata, who evidently used this room as their final resting place. Passages exit north and south.
There is a huge ivory tusk here!

You have to be wearing the ring too — first time I didn’t do that and had to make another full circle to test with the ring on. Grr.

The elephant resting place just serves to dish out a treasure (the tusk) and just past that is a passage blocked by a boulder.

PUSH BOULDER

Although the boulder moves a fraction of an inch, it is too heavy for you to roll away.

So you may wonder if I barely made progress on those three things I named, how I did get farther in? Well, back to that official document:

READ OFFICIAL DOCUMENT

The document is written in an undecipherable script. However, it bears the official seal of the Orcan government.

I hadn’t talked about the helicopter strangely at the start because I knew what they were looking for (a letter of transit) so it didn’t seem like an “open puzzle” really until I found the right item.

You’re at end of road again.

GO EAST

You’re in a flat circular clearing surrounded by dense forest.
Not far away is a helicopter. Its engine is idling slowly. Several jac-booted Orcs are standing guard around the aircraft.

IN

After inspecting your letter of transit, the Orcs sullenly stand aside to let you board the aircraft.
You are in the helicopter’s cramped passenger cabin. The only visible feature is a silver button on the wall.

PUSH BUTTON

The door slams shut as soon as you hit the button, followed by the sound of the engine revving up. After many minutes of noise and vibration, the engine falls silent and the door slides open.

OUT

You are in the West Courtyard, a wide flat area bounded on the north by a high cliff and on the south and west by the curve of the castle wall.
A helicopter is waiting nearby.

Huzzah, the castle! (I could have made it here a lot earlier, the Conservatory isn’t gated by any puzzle, it’s just a matter of opening the piano and finding the document.)

At least it feels appropriate for now to be the time to arrive in a dramatic sense.

Just to the east of the landing place is a winch. I have been unable to turn the winch; it presumably connects to the drawbridge.

You are at the base of the central portion of the courtyard near what appears to be some sort of large wooden door in the stone wall.
Attached to the wall is a heavy winch.

Neither wooden pole nor rope have been helpful, and generally the winch has been resistant to verbs in general. The game feels like it is pounding against the edge of what’s possible in a standard Crowther/Woods world model (yes, the containers are fancier and you can use more than two words, but it still doesn’t work as smoothly as, say, Infocom).

Farther along is a door with a slot; that’s where the card from nearby the phone booth goes.

You are at the entrance to Lords’ Keep.
A massive door of solid oak guards the castle entrance. In the center of the door is a small slot.

PUT CARD IN SLOT

From behind the door there is a whirring sound and the card is sucked from your hand. A moment later, the great oaken door swings open.

GO NORTH

You are inside Lords’ Keep, at the south end of the Great Hall. The room is lit by smokey torches hung high overhead. Several passages lead off to connecting rooms.
A priceless tapestry is hanging on the wall!

Side passages have an “aviary” with a “clay statue of a black bird”, and a room overlooking a “secret garden” where there’s a “knapsack” with “silk sheets”. I assume the latter is a parachute (I tried jumping at the ravine with it on but just died). The same room has a barred wooden door.

You are in a small room off the east hallway. Through a heavily barred window you can look out on a lovely secret garden.
A wooden door leads out to the garden.
There is a bulging knapsack here.

Near here is the Kitchen which includes a dumbwaiter. You can put items inside and send them down; to where I don’t know. I also don’t know why you’d need to (I assume I’ll find out soon).

Finally, there’s a puzzle I managed to actually solve:

The short hallway ends at a heavy steel door inlaid with enamelled tiles, each of which is a different color. The tiles, nine in all, are arranged in a 3×3 grid, thusly:

Above the door, a green light is shining.
The stainless steel door is locked.

I am not going to give the solution here, because I’m curious if it’s possible to solve it normally. (Try in the comments!) I did it by getting most of the way through via brute force before realizing the pattern. You need to push tiles in a particular sequence, and you have enough information (assuming you’ve read my previous posts) to solve it with what you know. Brute force requires a lot of reloading save files:

PUSH WHITE TILE

You are obviously attempting to intrude into a section of the castle in which you have no business. Faster than you can spit, a trapdoor springs open beneath you, catapulting you into a deep pit at the bottom of which a number of sharp, upright spikes have been affixed.

I’m not quite done yet with new stuff, because hopping back in the helicopter takes you to a third area.

You’re on the south end of a high narrow ridge, which is bounded on its east side by a high mountain. Dug into the mountainside is a ramshackle old mine entrance. The ridge drops off to the west in a rocky cliff. You might be able to climb down the cliff, but you probably won’t be able to get back up.
A helicopter is waiting nearby.

However, the mine just leads to a flooded tunnel; I’m not sure what’s going on here. Going west down the cliff leads to the caterpillar area. (I guess you could softlock if you hadn’t cleared the quicksand by the time you got here?)

I have to be hovering near the end because I’ve now seen the entire poster map. Other than the obstacles at the castle I’m still dealing with the same three as before (just the boulder past the sham rock rather than the cursed little man saying “fnord”).

Thursday, 08. January 2026

Choice of Games LLC

Throne of Blood—Heaven’s blood, Hell’s throne, your destiny.

Hosted Games has a new game for you to play! The throne of the demon realm calls for blood, and you’re next in line. As a half-angel heir scorned by your kin, you’re thrust into a brutal succession where only one of the Emperor’s children can survive. Outsmart your rivals, wield an ancient celestial power, and decide the fate of a realm that despises you. Throne of Blood is 30% off until January 15
Throne of Blood

Hosted Games has a new game for you to play!

The throne of the demon realm calls for blood, and you’re next in line. As a half-angel heir scorned by your kin, you’re thrust into a brutal succession where only one of the Emperor’s children can survive. Outsmart your rivals, wield an ancient celestial power, and decide the fate of a realm that despises you.

Throne of Blood is 30% off until January 15th!

Throne of Blood is a 295,000-word interactive novel by Kezia S. It’s entirely text-based, without graphics or sound effects, and fueled by the vast, unstoppable power of your imagination.

  • Forge your legacy as male, female, or nonbinary; gay, straight, bi, asexual, or poly.
  • Tap into your celestial heritage to unleash powerful, dangerous magic.
  • Shape the demon realm through reform, fear, or ruthless conquest.
  • Recruit and rule alongside three loyal retainers: a fiery dragonkin knight, a doting childhood friend, and a charming but mysterious knight-mage.
  • Pursue romance with one, two, or all three of your companions in a polyamorous court.
  • Navigate political intrigue and ancient prejudice as demons, angels, and monsters close in.

Kezia developed this game using ChoiceScript, a simple programming language for writing multiple-choice interactive novels like these. Writing games with ChoiceScript is easy and fun, even for authors with no programming experience. Write your own game and Hosted Games will publish it for you, giving you a share of the revenue your game produces.


Renga in Blue

Adventure 751: Ersatz Materials

(Continued from my previous posts.) Noble warriors of a distant age! Participate in the first-ever Nationwide Adventure Tournament on the CompuServe Information Service. Beginning at 6 p.m. local time on Friday, September 4 through 5 a.m. on Tuesday, September 8, slay evil dragons, carry off precious treasures and be proclaimed “Grand Master” of Adventure! Throughout […]

(Continued from my previous posts.)

Noble warriors of a distant age! Participate in the first-ever Nationwide Adventure Tournament on the CompuServe Information Service.

Beginning at 6 p.m. local time on Friday, September 4 through 5 a.m. on Tuesday, September 8, slay evil dragons, carry off precious treasures and be proclaimed “Grand Master” of Adventure!

Throughout the Labor Day Weekend, all entrants scoring the point total worthy of “Grand Master” status will be awarded two hours of free time and a CompuServe “Adventure” T-shirt. Runners-up will receive a T-shirt only, but still a prize worthy of the challenge!

Additionally, all entrants can receive on request a full size color version of the poster shown here. We’ll charge your account $1 for postage and handling. Check the “What’s New” section of Information Service prior to the contest for details and point total requirements.

Many will win the title “Grand Master.” Will your name be counted within their ranks?

— From TODAY magazine July 1981; the poster being referred to is the “sword and sandals” one I showed off previously

I don’t have a chunk of map to share this time; my progress has been filling in small holes of progress, enough to an extent that I can say I nearly have the 501 content wrapped up, just I’m having trouble making progress on the 751 content.

Ad from the first issue of CompuServe’s TODAY magazine, July 1981, offering the maps of both Adventure 350 and Adventure 751 for sale.

One bit of progress came just from idly checking the Adventure 751 map. I noticed there was an item that normally isn’t there on Adventure 350.

That box on the ground at the window is what I’m referring to. It connects to the Bedquilt room; I had tried earlier to go north at Bedquilt to get to there (as it specifies on my original Adv350 map) but I kept getting sent to the “Low room” instead so hadn’t really tested further. I already knew there was a “randomizing” effect with getting sent in a loop, but there’s some extra randomizing on top of that.

You are in Bedquilt, a long east/west passage with holes everywhere. To explore at random select north, south, up, or down.

GO NORTH

You have crawled around in some little holes and wound up back in the main passage.
You are in Bedquilt, a long east/west passage with holes everywhere. To explore at random select north, south, up, or down.

GO NORTH

You are in a large low room. Crawls lead north, NE, and SW.

The “large low room” isn’t the only possible destination (although it is the most frequent one). Raw persistence is the key, and I mean persistent: it took me about 50 tries to get to the right place.

You are in Bedquilt, a long east/west passage with holes everywhere. To explore at random select north, south, up, or down.

GO NORTH

You are in a secret canyon at a junction of three canyons, bearing north, south, and SE. The north one is as tall as the other two combined.

GO NORTH

You’re at a low window overlooking a huge pit, which extends up out of sight. A floor is indistinctly visible over 50 feet below. Traces of white mist cover the floor of the pit, becoming thicker to the left. Marks in the dust around the window would seem to indicate that someone has been here recently. Directly across the pit from you and 25 feet away there is a similar window looking into a lighted room. A shadowy figure can be seen there peering back at you.
There is a heavy, grey, metal cannister here.
The shadowy figure seems to be trying to attract your attention.

(The shadowy figure is just you in a mirror. I never understood this as a kid playing the game.)

I immediately recognized the canister, er, cannister, as the one I could put the radioactive rock into for safety.

You are at a high rock on the NE side of a watery chamber at the mouth of a small brook. An unknown gas bubbles up through the water from the chamber floor. A bluish light can be seen to the southwest.
Nearby, a strange, greenish stone is glowing brightly.

PUT STONE IN CANNISTER

Ok

CLOSE CANNISTER

Ok

Another puzzle I resolved is near here, so let’s get to that one next. Hop off the boat and head east and you’ll be at the Fairy Grotto.

You’re in Bubble Chamber.
There is a small wooden boat here.

GO EAST

It is now pitch dark. If you proceed you will likely fall into a pit.

LIGHT LAMP

Your lamp is now on.
You are in a sloping muddy defile, next to a tumbling brook.

GO EAST

You are in the Fairy Grotto. All around you innumerable stalactites, arranged in immense colonnades, form elegant arches. On every side you hear the dripping of water, like the footsteps of a thousand fairies. A small stream runs from the SW corner. A bright glow emanates from the south side of the grotto, and a steep passage descends to the east.

GO SOUTH

You go a short way down the bright passage, but the light grows to blinding intensity. You can’t continue.
You’re in the Fairy Grotto.

The game has the dark room in the middle because otherwise it would be easy to accidentally run into the solution: turn off the lamp. (The bright glow is already there, so we don’t need any other light!)

TURN OFF LAMP

Your lamp is now off.

GO SOUTH

You are in the Crystal Palace. An overhead vein of phosphorescent quartz casts a luminous glow which is reflected by countless chips of mica embedded in both walls, which consist of some sort of highly reflective glass, apparently of volcanic origin. A winding path of yellow sandstone leads west and rises steeply to the east.
There is a polished sphere of pure opal here!

The Crystal Palace connects the fairy room to the rainbow / lost river area…

…but before heading over there, I should return to the Fairy Grotto and mention I have the “cold corridor” problem resolved as well, and it was indeed how I guessed mid-post: the cloak is sufficient to protect you.

GO EAST

You’re in a steeply sloping passage. It is very cold here.

GO EAST

You are in the Hall of Ice, in the deepest part of the caverns. During winter, frigid outside air settles here, making this room extremely cold all year round. The walls and ceilings are covered with a thick coating of ice. An upward passage exits to the west.
There are diamonds here!

Now, about that Crystal Palace connection! It makes it easy to transport the cask down to the wine fountain and fill it up.

You are in the Winery, a cool dark room which extends some distance off to the east.
There is a fountain of sparkling vintage wine here!

FILL CASK WITH WINE

The cask is now full of wine.

(East from here are some “limestone pinnacles” and going up is where the cask is; you can take the cask straight back down over to the fountain, but there’s a chance that the cask will break. I spent longer than I needed to here as I assumed there was an extra gimmick, as it’s a “puzzle” that only has a certain percent chance of triggering and it gets bypassed merely by using a different route.)

Trudging past the “tongue of rock” back into the area with the phone booth…

The Conservatory is marked green because it’s in 751 only. It has the flute which is new for this game.

…I have the phone booth worked out, and the flute half-worked out. The phone booth had a gnome come in and use it; if you leave and come back, you can enter, and then get the item I believe was the whole intent of the scene.

You are standing in a telephone booth at the side of a large chamber. Hung on the wall is a banged-up pay telephone of ancient design.
The phone is ringing.

ANSWER PHONE

No one replies. The line goes dead with a faint “CLICK”.

HIT PHONE

A couple of lead slugs drop from the coinbox. (Gnomes are notoriously cheap….) But you’ve broken the phone beyond all hope.

The slugs can serve as a substitute for the coins in the machine that dispenses batteries for the lantern. The various remixes of Crowther/Woods have tended to be uncomfortable with the fact that the Maze of Twisty Passages, All Different doesn’t need to be entered at all because the only reward is the machine for extending battery life (and doing that burns one of your treasures, so you can’t get full points). Usually the resolution has been adding something extra (like hiding a passage behind the battery machine) but here the game slips in a way to use the machine as intended, just with something that isn’t a treasure.

(I still do not know what the plastic card outside the phone booth which says “Merkin Express” is for. It isn’t present in the 501 version.)

For the flute, trying PLAY FLUTE somewhere random gets you the message:

Sounds good. Are you in training to be the pied piper, or what?

If you instead use it at the salt flats (where we made concrete and fell into a bunch of quicksand):

PLAY FLUTE

After playing the flute for a few moments, you become aware of stealthy footsteps behind you.

PLAY FLUTE

You are being followed by a strangely docile giant Devonian rat!

Somehow this resulted in me getting a “smooth, white pebble” in the room just past the construction zone (I guess the rat brought it with them). I haven’t gotten any more use out of the rat; it doesn’t help with the mosquitoes (I thought maybe the bloodsuckers would focus on the critter and I’d be able to get through, no luck) and it doesn’t help with the centipede (ditto trying to make a distraction).

You are in the lair of Ralph the Giant Centipede. The air reeks with the stench of rotting bits of flesh. Giant centipedes, in general, are not partial to visitors.
A golden fleece is lying nearby!
A giant centipede is eyeing you with a none-too-friendly look.

PLAY FLUTE

After playing the flute for a few moments, you become aware of stealthy footsteps behind you.

PLAY FLUTE

You are being followed by a strangely docile giant Devonian rat!

One other quick puzzle, tracing to me still being confused as to what’s a treasure: the honey that you got from giving the flowers to the bees does not count as a treasure, but rather as food for the bear.

You are inside a barren room. The center of the room is completely empty except for some dust. Marks in the dust lead away toward the far end of the room. The only exit is the way you came in.
The bear is locked to the wall with a golden chain!
There is a ferocious cave bear eying you from the far end of the room!

THROW HONEYCOMB

The bear eagerly licks up the honeycomb, after which he seems to calm down considerably and even becomes rather friendly.

The bear not liking the lunch from the start building is the only change in this area.

From a totally different version of Adventure, Platt’s Adventure 551, which includes a new area past the Breathtaking View, the extra long volcano description that is there in Crowther/Woods just for scenery … and also in Adventure 751 just for scenery.

Finally, that leprechaun that was teleporting me with “fnord”: I made a little progress.

ENEMY NUMBER ONE.

I had found the four-leaf clover after the leprechaun and it seemed logical they’d go together, so I did item-juggling and made my way back. Unfortunately, it still doesn’t help:

You are in a dull N/S passage beside a tall black rock. On the rock is chisled the outline of a four-leafed clover, under which is the inscription: “Notice: This rock fabricated from ersatz materials.”

A sudden draft has extinguished your match.
Smoke rings curl upward from the rock.

INVENTORY

You are currently holding the following:
brass lantern
silver horn
ruby slippers
Holy Grail
shamrock
matchbox
wax candle

GO NORTH

As you approach the rock, the little man suddenly notices your shamrock. “Well, well,” says he, “you may be able to see me now, but you’ll never get by this place until you have vanquished one much larger than I! Fnord!”
You’re on grassy knoll.

I’ve tried defeating the dragon and bear but neither seem to satisfy. It could be the centipede?

Apologies about being so randomly scattered! That’s often how progress happens in one of these types of games. I’m left with, at least…

  • a shovel which I haven’t used yet
  • the centipede which chases the player up to a ravine
  • the statue stuck in the ravine (I think I know what to do here, I just need to setup the items to test)
  • still getting by the “ersatz rock”

…and one thing I remember from 501 that I haven’t done yet: finding the corpse of the Wumpus and getting a gold ring. I imagine this is just an exploration error, or rather, the fact I have a bunch of save games where progress hasn’t been consolidated (that is, the save file I explored on is not the same one I killed the Wumpus). I’m still under the feeling the final move count is going to be very tight, so when I realize a sequence could be better, I get the urge to redo it. It means I don’t even know how many points I could get maximum at this moment.

I’m stumped enough on the centipede and the rock I’m happy to get gentle rot13 hints. I suspect I’m about two posts away from a conclusion, although if the endgame is tough this might go out to three.