Open Adventure 1.1, and some thoughts on software preservation

Open Adventure 1.1 has shipped. There are a lot more changes under the hood than are readily apparent. In fact there have been no changes in gameplay at all, and only minor changes to the UI (reversible with the -o oldstyle switch).

We (Jason Ninneman, Per Vorpaev, Aaron Traas, Peje Nilsson and I) could have taken the approach of changing the original rather ugly C code (mechanically translated from FORTRAN) as little as possible, simply packaging it for compilation and release in a modern environment.

I elected not to do that, one reason being that I think we honor hacker tradition better by bring the code forward as a dynamic, living artifact that invites being hacked on than museumizing it as a static one. There’s also the fact that the extreme obscurity of the code made it difficult to appreciate what a work of genius Adventure actually was. (The code we inherited had over 350 gotos in it – rather hard to see past those.)

So we’ve taken a different path. We’ve translated the code into (almost) fully idiomatic C (but not trying to introduce pointer idioms; that should make translation to future languages easier). We’ve replaced the rather cryptic custom text database file that used to define the dungeon with a YAML document that is orders of magnitude easier to read and modify. We haven’t hesitated to use technology that wasn’t even a gleam in anyone’s eye when Adventure originated – the YAML is compiled to C structures at build time by a Python script.

The effect (we hope) is Adventure as it would have been written if Crowther & Woods had had today’s tools to do it – the same vision and design logic, expressed in modern coding idioms. Worth doing, because there are still some things to be learned from this design.

Probably the single cleverest thing in it – which pretty much has to go back to Crowther, Woods couldn’t have bolted it on afterwards – is the way movement in the dungeon is handled. The dungeon’s topology is expressed by a kind of pseudocode broadly resembling the microcode found underneath a lot of processor architectures; movement consists of dispatching to the sequence of opcodes corresponding to the current room and figuring out which one to fire depending not only on the motion verb the user entered but also on conditionals in the pseudocode that can test for the presence or absence of objects and their state.

It was hard to fully understand and appreciate this before, because the code was a spaghetti tangle in what looks today like a shockingly primitive style. The abstraction of the dungeon topology into a declarative specification that – in effect – loads microcode into the game engine was a thing you could half-see, but the impact was blunted by the unreadability of both the code and the specification format. Lifting the specification to YAML was like polishing a rough diamond, revealing beauty and brilliance.

And that’s before we even get to Adventure considered as a work of communicative art. It’s had so many successful descendants – like, every dungeon-crawling game ever, and every text adventure ever – that it’s difficult to see with fresh eyes. But if you make the effort, it is astonishing how mature the wry, quirkily humorous, slightly surrealistic style of this very first game seems. The authors weren’t fumbling for an idiom that would be greatly improved by later artists more sure of themselves; instead, they achieved a consistent and (at the time, unique) style that would be closely emulated by pretty much everyone who followed them in text adventures, and not much improved on as style, even though the technology of the game engines improved by leaps and bounds.

I don’t know how they did it, and the authors would probably not be able to explain if we asked. But I think it is damned impressive how well this game has aged – the code may have needed a refresh, but the design still shines. I’m proud to have helped restore it, and hope I have brought it to a state where it can be forward-ported to future languages for as long as programming is a living art.

18 thoughts on “Open Adventure 1.1, and some thoughts on software preservation

  1. And that’s before we even get to Adventure considered as a work of communicative art. It’s had so many successful descendants – like, every dungeon-crawling game ever, and every text adventure ever – that it’s difficult to see with fresh eyes.

    Its legacy extends beyond even that. Through nethack there is a thread of influence that leads to the “Immersive Sim”, a genre? meta-genre? design philosophy? (wiki claims genre, I don’t think that fits) that emphasizes simulation and emergent gameplay from a consistent set of rules rather than scripting.

    Though there aren’t very many Immersive Sims, those that exist are almost universally praised as among the best that videogames have to offer. Funnily enough this includes praise for story, not just gameplay.

  2. Bravo. The first thing that came to mind when you mentioned ‘gotos’ was BASIC; I cut my programming teeth on that language, and it is famous for its use of GOTO. But you’ve taken what is beauty hidden in ugly, primitive code and hacked it for modern-day use, where anyone with programming experience can see what the original programmers intended. Trying to wade your way through that messy-looking code could not have been an easy task, yet you managed, and that quite nicely. This is the finest example of open source practice that exists anywhere.

  3. I guess I’m a newb, I get the following

    RobMacBookPro:open-adventure rob$ make
    python3 make_dungeon.py
    cc -std=c99 -D _DEFAULT_SOURCE -Wpedantic -O2 -c main.c
    main.c:25:10: fatal error: ‘linenoise/linenoise.h’ file not found
    #include “linenoise/linenoise.h”
    ^
    1 error generated.
    make: *** [main.o] Error 1

    There is a “line noise” directory, but it is empty…

  4. A feat of engineering and artistry — like an Imogen Heap song. I had no idea Adventure was like this. Then again, maybe that was the point.

  5. It’s been loads of fun working on this. Lots of fun little puzzles in the code to hunt down. I’ve never done this thorough level of automated testing or any coverage analysis, and this has been a great learning experience. The project was just the right size to learn this — not too big and complex to be impenetrable, but also not so small and simple as to be completely trivial.

    Also the first time I’ve written any C in years, and this was a nice refresher, even though my changes to the source itself were minimal.

    Is there any desire in the future to make the save files human readable (JSON or YAML) or at least normalized in terms of endianness so they’re portable?

    • >I’ve never done this thorough level of automated testing or any coverage analysis, and this has been a great learning experience.

      I’ve done automated testing this thoroughly before – notably on reoposurgon and cvs-fast-export and INTERCAL and GPSD – but it’s also my first time using coverage testing this systematically. As you said, a good learning experience.

      >Is there any desire in the future to make the save files human readable (JSON or YAML) or at least normalized in terms of endianness so they’re portable?

      Possibly, but it’s way down the priority list.

  6. > We’ve replaced the rather cryptic custom text database file that used to define the dungeon with a YAML document that is orders of magnitude easier to read and modify.

    I’m curious as to why you used YAML, as opposed to say, JSON or XML or some other markup language. (Especially why not JSON, as then you could have reused your itty bitty parser library.)

    • >I’m curious as to why you used YAML, as opposed to say, JSON or XML or some other markup language.

      Applying my JSON parser wouldn’t have been a win as no C code needs to parse the dungeon description; that’s done by a Python helper.

      YAML is better than JSON when your markup is as text-heavy as adventure.yaml needs to be. JSON is better (less weight) for small datagram-like things. Credit where due: going to YAML was Jason Ninneman’s idea, and he was right.

  7. > I’m curious as to why you used YAML, as opposed to say, JSON or XML or some other markup language.

    JSON was the first thing I reached for. I switched to YAML once I realized I couldn’t comment the JSON source.

  8. Thank you so much for this! My dad introduced me to an Adventure derivative he cobbled together from some source he copied at work (he was with a contractor for the Airforce so got access to that kind of thing on the early networks and workstations) and re-built it for the TRS-80’s version of BASIC. He used it to introduce me to programming, something that stuck with me through some really dark days in my life.

    Now I can introduce my daughter to programming using the same game I learned with! She’s only 9, but loves learning about things she’s interested in that her parents or grandparents also were interested in when they were her age. I can’t wait to show this to her!

Leave a Reply

Your email address will not be published. Required fields are marked *