Building A-code games from C sources

(A-code version 12.91)


Derived C sources

A-code games are, naturally enough, written in A-code, which is an IF writing language originally created by David Platt when developing his Adv550 superset of the original Adventure. However, the first step of converting A-code source files into an executable involves translating them into ANSI C. This is done by the acdc A-code to C translator and the process is covered in a separate document. Here I assume that you already have the derived C sources either downloaded as a part of the overall A-code tarball or produced by running the acdc translator yourself. The translator ANSI C sources are also included in the same tarball.

Building an executable from the C sources

A-code games can be built in 5 distinct modes: console, browser, single turn, HTML/JavaScript and library. This document explains the differences between these modes, their respective uses and the ways of building corresponding game versions from C sources.

If your system does not have the unistd.h header file, you should add -DNO_UNISTD to all compilation commands given below. An appendix lists and explains all compilation symbols that may be used in compiling A-code game C sources.

The console mode

The console mode is how the original Adventure was initially played. It takes input directly from the player and outputs any responses in plain text to a "computer terminal" – these days most likely a terminal emulator window. Some players still prefer this mode and it is also very handy for debugging.

While it still defaults to the dimensions of displays of ancient VDUs (24 lines and 80 fixed font characters per line), other dimensions can be specified on the invocation command line by means of the -s option. The kernel also provides the necessary hooks for a game to permit changes to these defaults while playing.

The console mode also offers a unique opportunity to experience an A-code game the way the original Adventure was played in 1970s/80s. The -o command line option allows the output speed to be set to the baud rate of 110 (a teletype), 300 (earliest VDUs), 600, 1200, 2400, 4800 and 9600. Younger players are hereby invited to marvel at the patience required to play at the lower speeds (as we did!).

For the full list of console mode command line options, please see the document describing command line invocation of A-code games.

If you have the readline and ncurses libraries installed and available for linking (which probably needs a readline development package), all you need to do is to use an ANSI C compiler to compile and link the C files, specifying the console mode:

cc -DCONSOLE *.c -lreadline -lncurses -o <game-name>

If you do not have those libraries installed, you can still build a console mode executable, which will lack the facility of recalling and editing previous commands. To do so, just tell the compiler not to use readline:

cc *.c -DCONSOLE -DNO_READLINE -o <game-name>

The browser mode

In the browser mode, A-code games do not interact with the player directly, but instead invoke a local browser and use that to render game's output and to obtain player's commands. In this mode, an A-code game acts as a very simple HTTP server.

Unless otherwise specified, the player's default browser is invoked, but another browser can be specified either on the invocation command line or by modifying the acode.config file created by the A-code kernel.

The browser build of an A-code game automatically includes the console build (but not the other way around!). Thus a browser-build game can be invoked in the console mode by adding -C to the invocation command line.

Building a browser mode executable is virtually the same as building a console mode one – you just drop the -DCONSOLE from the parameters given to the compiler. When a browser is being used to render game's output, there is no need for the readline library, so the basic browser mode build looks like this:

cc *.c -DNO_READLINE -o <game-name>

If you want the executable to offer command editing when run in the console mode, you will need to link in the two additional libraries:

cc *.c -lreadline -lncurses -o <game-name> *.c

The single turn mode

Originally developed for CGI operation, games build in this mode are only suitable for running in a cloud, via a suitable front-end script, e.g. a cgi-bin or a PHP one. In this mode, the game executable is supplied a single command as a parameter on the invocation command line, sends the text generated in response to standard output and exits. (See the the command line options document for details.)

The actual interaction with the player is carried out by the front end script, which repeatedly invokes the executable for successive game turns. The secret sauce is, of course, the player-invisible save and restore of the current state of the game. This mechanism got later adapted for use by other game modes, automatically giving all A-code games a persistent state.

In this mode all text output is HTML-formatted, though this can be overridden if necessary. All such text is also prefixed by a single character, which provides information to the wrapper script and is not expected to be displayed to the player.

To build a single turn mode executable is very simple:

cc *.c -DTURN -o <game-name>

In this mode the executable is not responsible for acquiring player commands and thus there is no need to signal the absence of the readline library -- this is assumed automatically.

The HTML/JavaScript mode

Thanks to the magic of emscripten, A-code games can be built as pure (and purely local, with no network dependencies) HTML/JavaScript page, usable by any HTML5 compliant browser. In this mode, A-code games run entirely within the player's browser and use browser's own sand-boxed file system for saving and restoring games.

For building games in this mode you will need emscripten installed as well as its dependencies (clang and cmake). Actually building a game involves two steps. Firstly the derived C sources (plus the kernel ones) are converted to JavaScript via this one-line command:

emcc -Os -s ASM_JS=1 -s WASM=0 -s ENVIRONMENT=web -DJS adv*.c -Wno-parentheses-equality -lidbfs.js -s "EXTRA_EXPORTED_RUNTIME_METHODS=['cwrap']" --memory-init-file 0 -o acode.js -s EXPORTED_FUNCTIONS="['_advturn']"

(That's the command line for Emscripten 1.39.6 -- experience suggests that later versions may require a change in some of the arguments.)

Secondly, the resulting acode.js file has to be merged into the acode.html template, which can be found in the tools directory to be found in the relevant A-code tarballs. This merging is achieved by (a) replacing all occurrences of the string %NAME% in the template by the name of the game being builds and (b) replacing the line consisting of the single token %JAVASCRIPT% with the contents of the JavaScript file generated by emcc.

The resulting HTML file can be called anything you like, but it seems a good idea to replace 'acode' in its name with the actual name of the game.

The library mode

In some cases it is not feasible or appropriate for an A-code game to drive its own commend/response loop. App frameworks generally expect to do so themselves. This situation is handled by compiling derived C sources in the library mode:

cc -c *.c -DADVLIB

Compiled this way, instead of having a main() routine, the game has an advturn() one, which expects player input to be supplied via its arguments and returns a pointer to a text buffer containing the resulting text. As in the single turn mode, the returned text is prefixed with a single character denoting the nature of the text.

A separate document explains the details of the advturn() interface. However, for testing/debugging purposes I had to develop a simple C program, which uses the library mode and can be run in any terminal emulator. It's source, libtest.c can be found in the tools directory of an A-code tarball.

Appendix 1: Deprecated text data handling

By default, since version 12.01 of A-code, all text data is preloaded by the acdc translator into the game C-source, whereas previous versions by default stored text data in a separate .dat file. The current arrangement is the simplest and most sensible one for most machines these days, but a few years ago I still saw some not entirely obsolete machines baulking at the size of adv770 executable with preloaded data. Hence other options are also on offer, even if you don't have access to game A-code sources.

Appendix 2: Kernel compilation symbols

Compilation symbols listed below can be added to the compilation command line as -D<symbol> when building A-code games. There is a number of other symbols being defined and used by kernel source files, which you should leave well alone.

The main mode symbols have been already referenced above.

CONSOLE Specifies console-only mode

CGI Specifies single turn mode

HTTP Specifies combined browser/console mode – this is the default

JS Specifies JavaScript/HTML mode

ADVLIB Specifies library mode

Four additional symbols can be used to control what system routines the game executable needs from the system.

NO_UNISTD Signals absence of the unistd.h header file. Use it in all modes if you do not have the unistd library.

NO_READLINE Suppresses use of the readline library (only relevant in the console and browser/console modes – ignored otherwise).

NO_SLOW Suppresses the ability to slow down game's output (only relevant in the console and browser/console modes – ignored otherwise).

PAUSE Prevents immediate exit on game completion (useful when running in console mode in a window which automatically closes on game's exit).

Three further symbols which are only required in kernel development work and/or in special builds.

IOS Signals iOS build.

DEBUG Enables various debug messages from the kernel.

DIRECT Prevents the HTTP server being daemonised in the browser mode – makes debugging easier!

Finally, there are the deprecated symbols specifying ways of dealing with a separate text data file, if there is one. Note that these symbols override whatever text data arrangement was specified in running acdc to convert A-code sources into C.

MEMORY Text data file to be loaded into memory on startup.

FILE Text to be retrieved as required directly from the data file.

SWAP[=<page_buffers>] Text is to be paged in executables 1KB page buffers. The default is 32 such buffers, but another number can be specified between 16 and 128 inclusive.

Back to the documentation index
To the Mipmip home page
Feel free to leave a comment!
Mike Arnautov (27 March 2023)