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 balking 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.
- Creating the text data file
Even though game C sources no longer come with the .dat text data file,
this file can get automatically constructed by the game executable. To
do this, first build the executable in one of the three ways described
below (for preloading, paging or reading of the data file), and then run
the resulting executable in the directory containing the C sources.
Failing to find the .dat file, but finding adv6.h instead, the game will
construct the .dat file from the .h one. From then on the game will run
normally, getting its text data from the .dat file, which should be kept
in the same place as the executable (but see the separate document
on game invocation command options for
an alternative).
- Loading text data on game startup
If -DMEMORY is added to any of the C compilation commands suggested
above, the text data file will be preloaded into a dynamically allocated
buffer on game startup. This used to be the default arrangement in
A-code versions 10 and 11.
- Reading data from the text file
If your memory is constrained, but disk I/O is reasonably quick (which it
would be unless you are running the game from a floppy disk), you can
use the -DFILE compilation flag. This causes the game to read from the
data file with no paging of its own, though one hopes that *some* paging
will be done by the OS. As a guess, such machines will have no GUI
browsers, so -DCONSOLE should also be added to compilation flags.
- Keeping recent text data in memory
If -DSWAP is added to any of the C compilation commands suggested above,
all access to the text data file will be through an internal paging
system of 32 1KB buffers, paging data in and out on the
first-in-first-out basis. The number of swap buffers can be modified
by defining the SWAP symbol to have a particular value, e.g. -DSWAP=40.
The number of buffers will be coerced into the range from 16 to 128
inclusive.
This method is only useful for the oldest and slowest machines.
Again, it probably makes sense to add -DCONSOLE as well, since a machine
with such a limited amount of memory is unlikely to sport a GUI-based browser.
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.