Released UnixFrotz232R2Std10.tar.gz
authorGalen Hazelwood <galenh@micron.net>
Fri, 17 Oct 1997 20:11:33 +0000 (20:11 +0000)
committerGalen Hazelwood <galenh@micron.net>
Fri, 17 Oct 1997 20:11:33 +0000 (20:11 +0000)
22 files changed:
Makefile [new file with mode: 0644]
Readme.unix [new file with mode: 0644]
Todo [new file with mode: 0644]
bcfrotz.h [deleted file]
bcinit.c [deleted file]
bcinput.c [deleted file]
bcmouse.c [deleted file]
bcpic.c [deleted file]
bcsample.c [deleted file]
bcscreen.c [deleted file]
bctext.c [deleted file]
fastmem.c
font.dat [deleted file]
frotz.6 [new file with mode: 0644]
frotz.h
ux_frotz.h [new file with mode: 0644]
ux_init.c [new file with mode: 0644]
ux_input.c [new file with mode: 0644]
ux_pic.c [new file with mode: 0644]
ux_sample.c [new file with mode: 0644]
ux_screen.c [new file with mode: 0644]
ux_text.c [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..21d055f
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,73 @@
+
+# Define your c compiler.  I recommend gcc if you've got it.
+#CC = cc
+CC = gcc
+
+# Define your optimization flags.  Most compilers understand -O and -O2,
+# Debugging (don't use)
+#OPTS = -Wall -g
+# Standard
+OPTS = -O2
+# Pentium with gcc 2.7.0 or better
+#OPTS = -O2 -fomit-frame-pointer -malign-functions=2 -malign-loops=2 \
+-malign-jumps=2
+
+# There are a few defines which may be necessary to make frotz compile on
+# your system.  Most of these are fairly straightforward.
+#    -DNO_MEMMOVE:    Use this if your not-so-standard c library lacks the
+#                     memmove(3) function. (SunOS, other old BSDish systems)
+#
+# You may need to define one of these to get the getopt prototypes:
+#    -DUSE_UNISTD_H:  Use this if your getopt prototypes are in unistd.h.
+#                     (Solaris?)
+#    -DUSE_GETOPT_H:  Use this if you have a separate /usr/include/getopt.h
+#                     file containing the getopt prototypes. (Linux, IRIX 5?)
+#    -DUSE_NOTHING:   I've heard reports of some systems defining getopt in
+#                     stdlib.h, which unix.c automatically includes.
+#                     (*BSD, Solaris?)
+#
+# If none of the above are defined, frotz will define the getopt prototypes
+# itself.
+#
+#    -DUSE_NCURSES_H: Use this if you want to include ncurses.h rather
+#                     than curses.h.
+#
+# These defines add various cosmetic features to the interpreter:
+#    -DCOLOR_SUPPORT: If the terminal you're using has color support, frotz
+#                     will use the curses color routines...if your curses
+#                     library supports color.
+#    -DEMACS_EDITING: This enables some of the standard emacs editing keys
+#                     (Ctrl-B,-F,-P,-N, etc.) to be used when entering
+#                     input.  I can't see any reason why you wouldn't want
+#                     to define it--it can't hurt anything--but you do
+#                     have that option.
+#
+#DEFS = -DUSE_GETOPT_H -DCOLOR_SUPPORT -DEMACS_EDITING
+DEFS =
+
+# This should point to the location of your curses or ncurses include file
+# if it's in a non-standard place.
+#INCL = -I/usr/local/include
+#INCL = -I/5usr/include
+INCL =
+
+# This should define the location and name of whatever curses library you're
+# linking with.
+#LIB = -L/usr/local/lib
+#CURSES = -lncurses
+#LIB = -L/5usr/lib
+LIB =
+CURSES = -lcurses
+
+# Nothing under this line should need to be changed.
+
+OBJECTS = buffer.o fastmem.o files.o hotkey.o input.o main.o math.o object.o \
+          process.o random.o redirect.o screen.o sound.o stream.o table.o \
+          text.o ux_init.o ux_input.o ux_pic.o ux_screen.o ux_sample.o \
+          ux_text.o variable.o
+
+CFLAGS = $(OPTS) $(DEFS) $(INCL)
+
+frotz: $(OBJECTS)
+       $(CC) -o frotz $(OBJECTS) $(LIB) $(CURSES)
+
diff --git a/Readme.unix b/Readme.unix
new file mode 100644 (file)
index 0000000..972b59e
--- /dev/null
@@ -0,0 +1,318 @@
+(This Readme file was adapted from the one released with the MS-DOS binary.)
+
+FROTZ V2.32 - an interpreter for all Infocom games. Complies with standard
+1.0 of Graham Nelson's specification. Written by Stefan Jokisch in 1995-7
+
+    This program once started as a re-make of Mark Howell's Zip, but
+    has grown into an utterly new interpreter.
+
+    Frotz is freeware: It may be used and distributed freely provided
+    no commercial profit is involved. (c) 1995-1997 Stefan Jokisch.
+
+    Please report bugs to s.jokisch@avu.de
+    Please report unix bugs to galenh@micron.net
+
+    This is the unix port of Stefan Jokisch's nifty-neato-cool Z-machine
+interpreter.  There are only two things you need to compile Frotz:
+
+      * Some variant of Unix with an ANSI C compiler (gcc works fine)
+      * A reasonably good SYSV derived curses library
+
+    Note that the second requirement is _very_ important.  I had several people
+send me complaints about Frotz not working, and found out they were unaware
+that their curses library was obsolete.  If your system curses won't work,
+pick up and compile the ncurses library from ftp://prep.ai.mit.edu/pub/gnu
+or any GNU mirror site.
+
+Changes since Release 1:
+
+      * Fixed problems with backspace
+      * Now supports "delete" key for editing
+      * Wired in tab completion support (which I stupidly missed)
+      * Added emacs editing key support (-DEMACS_EDITING)
+
+How to Compile:
+
+    This source distribution comes with a unsophisticated but functional
+Makefile.  Edit it to reflect your system; the comments are fairly self-
+explanatory.  Once that's done, just type "make".
+
+    Color support is available by putting -DCOLOR_SUPPORT in the designated
+spot.  I've added code in ux_init.c for sound hooks, but as no sound code is
+actually written, defining SOUND_SUPPORT will merely cause compilation to fail.
+
+    Thanks for giving this a try.  Any bug reports, success stories, or
+constructive criticism will be greatly appreciated.
+
+    -- Galen Hazelwood <galenh@micron.net>
+
+Syntax: frotz [options] story-file
+
+    -d       disable color
+
+    If frotz discovers that your terminal has color support, it will
+    enable it by default.  This switch overrides that behavior.
+
+    -f #     set the foreground colour
+    -b #     set the background colour
+
+    The color numbers are the Z-machine colors, which are as follows:
+        2  =  black   3 = red       4 = green    5 = yellow
+        6  =  blue    7 = magenta   8 = cyan     9 = white
+
+    If color support is disabled in the binary, or not available on
+    your terminal, these options do nothing.
+
+    -i      ignore runtime errors
+
+    Set this switch and Frotz no longer worries about anything the
+    game tries to do. This can help you to get around fatal errors.
+
+    -w #     set the screen width
+    -h #     set the screen height
+    -l #     set the left margin
+    -r #     set the right margin
+
+    Setting the screen format can be useful if you are running Frotz
+    under Microsoft Windows, or if you want to test a game on a more
+    narrow screen. Setting the margins is a matter of taste; Infocom
+    interpreters usually set a right margin of one character (-r1).
+
+    -S #     set the width of the transscript file
+
+    By default your transscript files are formatted to a width of 80
+    columns per line -- regardless of the current screen width. This
+    switch allows you to change this setting. In particular, use -S0
+    to deactivate automatic line splitting in transscript files.
+
+    -c #     set the number of context lines
+
+    When the game prints several pages of text in a row, Frotz stops
+    for a more prompt after each page. The first prompt appears when
+    your input reaches the top of the window. Further prompts appear
+    when the previous page has been scrolled off the window. You can
+    use this switch to make the latter more prompts appear earlier.
+
+    -u #     set the number of undo slots for multiple undo
+
+    Frotz tries to allocate as much conventional memory as possible
+    for multiple UNDO. If this strategy causes some kind of problem,
+    use this switch to set a tighter limit. In particular, you might
+    want to turn off the UNDO feature altogether by typing -u0.
+
+    -s #     set the random number seed
+
+    The given seed value is used as the initial seed value on every
+    restart. This is helpful for testing games like 'Curses' which
+    make random decisions before the first input (such that the hot
+    key Alt-S does not really help). The meaning of seed values is
+    explained in the next section.
+
+    -x       expand abbreviations (g, x, z ==> again, examine, wait)
+
+    This switch was made for old Infocom games that lack the common
+    abbreviations introduced in later games. Use it with caution: A
+    few games might use "g", "x" or "z" for different purposes.
+
+    -o       watch object movement
+    -O       watch object locating
+    -a       watch attribute assignment
+    -A       watch attribute testing
+
+    Although these switches may be of assistance while debugging new
+    games, they are are actually meant to be cheat functions. The -o
+    switch, for example, helps to locate the thief in 'Zork 1' and
+    the cat in 'Curses'. The other switches produce a lot of obscure
+    messages during the game; but some of these messages might give
+    you important clues if you watch carefully.
+
+    -t       set the Tandy bit
+
+    Some old Infocom games were sold by the Tandy Corporation. These
+    games behave slightly different when you use this option. For
+    example, 'The Witness' gets censored: bastards turn into idiots,
+    private dicks into private eyes and so on.
+
+    -p       plain ascii output only
+
+    This inhibits the output of accented letters and other characters
+    from the Latin-1 character set, replacing them with reasonable
+    alternatives.  This may be necessary on devices lacking these
+    characters.
+
+    -P       alter behaviour of piracy opcode
+
+    The piracy opcode was never used by Infocom, and this switch is
+    only useful for those who like to toy around with Z-code.
+
+Special keys:
+
+    Alt-D - toggle debugging options (-a, -A, -o, -O)
+    Alt-H - help on hot keys
+    Alt-N - new game (restart)
+    Alt-P - turn on input line playback
+    Alt-R - toggle input line recording on/off
+    Alt-S - set the random number seed
+    Alt-U - multiple undo, works even for old V1 to V4 games
+    Alt-X - exit game
+
+    When testing a text adventure it can be difficult to reproduce a
+    specific bug. To avoid this problem you should use the Alt-R key
+    to record all your inputs in a command file. Later you can press
+    Alt-P to feed the command file back into Frotz. In many cases,
+    however, you will find that the result is different because most
+    games contain random events. Luckily, Frotz provides a hot key
+    to control these events. Type Alt-S and you are asked for a seed
+    value, i.e. a value in the range from 1 to 32767. Normally, you
+    would choose a number >= 1000. Smaller values generate a special
+    sequence of random numbers as proposed by Nelson. (For instance,
+    the seed value 4 generates 1, 2, 3, 4, 1, 2, 3, 4, 1...). In any
+    case, random events become predictable until the next restart.
+
+    See also the command line option -s above.
+
+    cursor left/Ctrl-B - move one character to the left
+    cursor right/Ctrl-F        - move one character to the right
+    home/Ctrl-A                - move to beginning of line
+    end/Ctrl-E         - move to end of line
+    backspace          - delete character to the left
+    delete/Ctrl-D       - delete character below cursor
+    insert             - toggle overwrite mode on/off
+    escape/Ctrl-U      - delete whole input line
+    cursor up/Ctrl-P   - get previous command
+    cursor down/Ctrl-N - get next command
+    page up            - scroll status window up ('Beyond Zork')
+    page down          - scroll status window down ('Beyond Zork')
+    tab                        - word completion (like "tcsh" under Unix)
+
+    Note that the various Control aliases only function if emacs editing
+    support has been compiled into your binary.  See the Makefile for
+    more information.
+
+    When you need to type an unpleasantly long word, try to type the
+    first three or four letters then press the tabulator key. If you
+    are lucky, Frotz fills in some or all of the missing letters. A
+    high beep noise indicates that the word is ambiguous; a low beep
+    indicates that it does not exist. Apart from that, you can also
+    use the history feature to get to previous input lines. Type the
+    beginning of the input line you are looking for, then use cursor
+    up/down to scroll through all input lines matching that prefix.
+
+Questions and answers:
+
+    Q: What is Frotz?
+    A: Frotz runs text adventures which come in so-called story files:
+       ZORK1.DAT, TRINITY.DAT, CURSES.Z5, JIGSAW.Z8, ARTHUR.ZIP etc.
+
+    Q: Where can I find story files to use with Frotz?
+    A: First, you can use the files from your original Infocom games. It
+       is possible to play Atari ST, Amiga or Macintosh games on your PC
+       once you manage to transfer the story files. Some people even
+       extracted story files from old Atari 800, Apple II and C-64 disks
+       (ask your local 8bit guru). Second, there is an increasing number
+       of new games available on the Internet. Check the if-archive at
+       ftp.gmd.de.
+
+    Q: Why does Frotz stop with an error message?
+    A: It might have detected a bug in the story file other interpreters
+       overlooked. Use the -i switch to run your story file anyway. It's
+       also possible that the story file is corrupt; be sure to download
+       story files in binary mode, especially when you use a WWW browser.
+
+    Q: Is there a way to exit Frotz in emergency situations?
+    A: Try Ctrl-break, Ctrl-C, or Ctrl-Z.  The last one suspends your process
+       and returns you to the shell, allowing you to kill it.
+
+    Q: What do I need to play graphic games?
+    A: A different port of Frotz.  Try the MS-DOS version if you can use
+       it, or wait for the X Windows port.  You can run some of the V6 games
+       without graphics--Arthur and Journey seem to work, but not Shogun or
+       Zork Zero.  (Shogun dies because I can't backscroll; Zork 0 just
+       sputters and dies rather amusingly.)
+
+    Q: What do I need for sound?
+    A: A different port of Frotz, or a later version of this one.  Sound
+       support will first be available on Linux, and any other system which
+       can use the Open Sound System (or OSS/Lite).
+
+    Q: How can I send transscription to the printer?
+    A: Type PRN as file name.
+
+    Q: Why do I get weird characters instead of accented letters?
+    A: Because your display/terminal/window doesn't support the Latin-1
+       character set properly.  Use the -p flag, which uses plain ASCII
+       output and converts accented letters appropriately.
+
+    Q: Why don't the number pad keys work in 'Beyond Zork'?
+    A: Because curses dosen't seem to know how to handle them properly.
+       I might add a hack to support them later.
+
+    Q: How can I scroll the status window in 'Beyond Zork'?
+    A: Use page up/down instead of cursor up/down.
+
+    Q: Why are my default color selections so weird?
+    A: You're used to using the standard PC color values.  The unix port
+       wants color numbers in Z-machine form.  Quick reference:
+          2  =  black   3 = red       4 = green    5 = yellow
+          6  =  blue    7 = magenta   8 = cyan     9 = white
+
+
+List of fatal errors:
+
+    - "Bad stack frame"
+    - "Byte swapped story file"
+    - "Call to illegal address"
+    - "Call to non-routine" [1]
+    - "Cannot open story file"
+    - "Division by zero"
+    - "Error reading save file"
+    - "Illegal attribute"
+    - "Illegal object" [2]
+    - "Illegal window"
+    - "Illegal window property"
+    - "Jump to illegal address"
+    - "Nesting stream #3 too deep"
+    - "No such property"
+    - "Out of memory"
+    - "Print at illegal address"
+    - "Stack overflow" [3]
+    - "Stack underflow" [4]
+    - "Store out of dynamic memory"
+    - "Story file read error"
+    - "Text buffer overflow"
+    - "Unknown opcode"
+    - "Unknown Z-code version"
+    - "Can't Happen (os_scroll_area)" [5]
+
+    [1] The first byte of a routine must be less than 16.
+    [2] In V4 and above, object numbers > 2000 are considered illegal.
+    [3] Checked on every call instruction.
+    [4] Checked on every return from a subroutine.
+    [5] Unix-specific.  Should only happen in Shogun.
+
+Acknowledgements:
+
+    Many thanks to Paul D. Doherty for his continuing support of this
+    project. Thanks to everyone who sent bug reports, contributions or
+    helpful hints (in alphabetical order):
+
+    Thomas Biskup, Ian Carpenter, Graeme Cree, Jason Dyer,
+    Carl Edman, Julian Eggebrecht, Bernhard Fuchs, Joe Hachem,
+    John Kennedy, Kirk Klobe, Marnix Klooster, John Mackin,
+    Paul O'Brian, Magnus Olsson, Barry Prescott, L. Ross Raszewski,
+    Ambat Sasi Nair, Alan Sherrod, Linards Ticmanis and Paolo Vece.
+
+    Last but not least, thanks to the porters:
+
+    David Kinder (Amiga), Rich Lawrence (Windows 95/NT),
+    Andrew Holdsworth (RiscOS), Christos Dimitrakakis (HP-UX),
+    Christopher J. Madsen (OS/2), Galen Hazelwood (Unix curses library),
+    Ian Dean (Windows CE).
+
+    Executables are available from ftp.gmd.de and from
+
+       http://www.geocities.com/SiliconValley/Heights/3222/frotz.html
+
+    which is the Frotz home page maintained by Chris Madsen.
+
+
diff --git a/Todo b/Todo
new file mode 100644 (file)
index 0000000..b189a4e
--- /dev/null
+++ b/Todo
@@ -0,0 +1,12 @@
+Things to do and bugs to investigate
+------------------------------------
+
+* Write sound support.  This is on hold until frotz supports the new "Blorb"
+  format.
+
+* Border Zone has a strange status line feature, mixing bright and dull
+  whites.  Not sure what's going on here.
+
+* Add support for GNU readline/history libraries instead of the kludgy
+  editing routines I wrote.  If I can manage this, I'll probably release
+  it as a patch rather than part of a release.
diff --git a/bcfrotz.h b/bcfrotz.h
deleted file mode 100644 (file)
index 70c99a1..0000000
--- a/bcfrotz.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * "BCfrotz.h"
- *
- * Borland C interface, declarations
- *
- */
-
-#define byte0(v)       ((byte *)&v)[0]
-#define byte1(v)       ((byte *)&v)[1]
-#define byte2(v)       ((byte *)&v)[2]
-#define byte3(v)       ((byte *)&v)[3]
-#define word0(v)       ((word *)&v)[0]
-#define word1(v)       ((word *)&v)[1]
-
-#ifndef HISTORY_MIN_ENTRY
-#define HISTORY_MIN_ENTRY 1
-#endif
-
-#define SPECIAL_KEY_MIN 256
-#define SPECIAL_KEY_HOME 256
-#define SPECIAL_KEY_END 257
-#define SPECIAL_KEY_WORD_LEFT 258
-#define SPECIAL_KEY_WORD_RIGHT 259
-#define SPECIAL_KEY_DELETE 260
-#define SPECIAL_KEY_INSERT 261
-#define SPECIAL_KEY_PAGE_UP 262
-#define SPECIAL_KEY_PAGE_DOWN 263
-#define SPECIAL_KEY_TAB 264
-#define SPECIAL_KEY_MAX 264
-
-#define _MONO_ 0
-#define _TEXT_ 1
-#define _CGA_  2
-#define _MCGA_ 3
-#define _EGA_  4
-#define _AMIGA_        5
-
-typedef unsigned char byte;
-typedef unsigned short word;
-
-extern display;
-
-extern cursor_x;
-extern cursor_y;
-
-extern char latin1_to_ibm[];
-extern char latin1_to_ascii[];
-
-extern byte text_bg;
-extern byte text_fg;
-
-extern byte scrn_attr;
-
-extern user_background;
-extern user_foreground;
-extern user_emphasis;
-extern user_reverse_bg;
-extern user_reverse_fg;
-extern user_screen_height;
-extern user_screen_width;
-extern user_tandy_bit;
-extern user_bold_typing;
-extern user_random_seed;
-extern user_font;
-
-extern char stripped_story_name[];
-extern char *prog_name;
-
-extern current_bg;
-extern current_fg;
-extern current_style;
-extern current_font;
-
-extern scaler;
-
-/* BCinit  */  int     dectoi (const char *);
-/* BCinit  */  int     hextoi (const char *);
-/* BCmouse */  bool    detect_mouse (void);
-/* BCmouse */  int     read_mouse (void);
-/* BCpic   */  bool    init_pictures (void);
-/* BCpic   */  void    reset_pictures (void);
-/* BCsmpl  */  bool    init_sound (void);
-/* BCsmpl  */  void    reset_sound (void);
-/* BCtext  */  void    switch_scrn_attr (bool);
-/* BCtext  */  void    load_fonts (const char *);
diff --git a/bcinit.c b/bcinit.c
deleted file mode 100644 (file)
index 3fba0d9..0000000
--- a/bcinit.c
+++ /dev/null
@@ -1,755 +0,0 @@
-/*
- * file "BCinit.c"
- *
- * Borland C front end, initialisation
- *
- */
-
-#include <conio.h>
-#include <dos.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "frotz.h"
-#include "BCfrotz.h"
-
-#define INFORMATION "\
-\n\
-FROTZ V2.32 - interpreter for all Infocom games. Complies with standard\n\
-1.0 of Graham Nelson's specification. Written by Stefan Jokisch in 1995-7\n\
-\n\
-Syntax: frotz [options] story-file\n\
-\n\
-  -a   watch attribute setting  \t -l # left margin\n\
-  -A   watch attribute testing  \t -o   watch object movement\n\
-  -b # background colour        \t -O   watch object locating\n\
-  -B # reverse background colour\t -p   alter piracy opcode\n\
-  -c # context lines            \t -r # right margin\n\
-  -d # display mode (see below) \t -s # random number seed value\n\
-  -e # emphasis colour [mode 1] \t -S # transscript width\n\
-  -f # foreground colour        \t -t   set Tandy bit\n\
-  -F # reverse foreground colour\t -T   bold typing [modes 2+4+5]\n\
-  -g # font [mode 5] (see below)\t -u # slots for multiple undo\n\
-  -h # screen height            \t -w # screen width\n\
-  -i   ignore runtime errors    \t -x   expand abbreviations g/x/z\n\
-\n\
-Fonts are 0 (fixed), 1 (sans serif), 2 (comic), 3 (times), 4 (serif).\n\
-\n\
-Display modes are 0 (mono), 1 (text), 2 (CGA), 3 (MCGA), 4 (EGA), 5 (Amiga)."
-
-extern unsigned cdecl _heaplen = 0x800 + 4 * BUFSIZ;
-extern unsigned cdecl _stklen = 0x800;
-
-extern const char *optarg;
-extern int optind;
-
-int cdecl getopt (int, char *[], const char *);
-
-static const char *progname = NULL;
-
-extern char script_name[];
-extern char command_name[];
-extern char save_name[];
-extern char auxilary_name[];
-
-char stripped_story_name[10];
-
-int display = -1;
-
-int user_background = -1;
-int user_foreground = -1;
-int user_emphasis = -1;
-int user_bold_typing = -1;
-int user_reverse_bg = -1;
-int user_reverse_fg = -1;
-int user_screen_height = -1;
-int user_screen_width = -1;
-int user_tandy_bit = -1;
-int user_random_seed = -1;
-int user_font = 1;
-
-static byte old_video_mode = 0;
-
-static void interrupt (*oldvect) () = NULL;
-
-/*
- * dectoi
- *
- * Convert a string containing a decimal number to integer. The string may
- * be NULL, but it must not be empty.
- *
- */
-
-int dectoi (const char *s)
-{
-    int n = 0;
-
-    if (s != NULL)
-
-       do {
-
-           n = 10 * n + (*s & 15);
-
-       } while (*++s > ' ');
-
-    return n;
-
-}/* dectoi */
-
-/*
- * hextoi
- *
- * Convert a string containing a hex number to integer. The string may be
- * NULL, but it must not be empty.
- *
- */
-
-int hextoi (const char *s)
-{
-    int n = 0;
-
-    if (s != NULL)
-
-       do {
-
-           n = 16 * n + (*s & 15);
-
-           if (*s > '9')
-               n += 9;
-
-       } while (*++s > ' ');
-
-    return n;
-
-}/* hextoi */
-
-/*
- * cleanup
- *
- * Shut down the IO interface: free memory, close files, restore
- * interrupt pointers and return to the previous video mode.
- *
- */
-
-static void cleanup (void)
-{
-
-    reset_sound ();
-    reset_pictures ();
-
-    asm mov ah,0
-    asm mov al,old_video_mode
-    asm int 0x10
-
-    setvect (0x1b, oldvect);
-
-}/* cleanup */
-
-/*
- * fast_exit
- *
- * Handler routine to be called when the crtl-break key is pressed.
- *
- */
-
-static void interrupt fast_exit ()
-{
-
-    cleanup (); exit (EXIT_FAILURE);
-
-}/* fast_exit */
-
-/*
- * os_fatal
- *
- * Display error message and exit program.
- *
- */
-
-void os_fatal (const char *s)
-{
-
-    if (h_interpreter_number)
-       os_reset_screen ();
-
-    /* Display error message */
-
-    fputs ("\nFatal error: ", stderr);
-    fputs (s, stderr);
-    fputs ("\n", stderr);
-
-    /* Abort program */
-
-    exit (EXIT_FAILURE);
-
-}/* os_fatal */
-
-/*
- * parse_options
- *
- * Parse program options and set global flags accordingly.
- *
- */
-
-static void parse_options (int argc, char **argv)
-{
-    int c;
-
-    do {
-
-       int num = 0;
-
-       c = getopt (argc, argv, "aAb:B:c:d:e:f:F:g:h:il:oOpr:s:S:tTu:w:x");
-
-       if (optarg != NULL)
-           num = dectoi (optarg);
-
-       if (c == 'a')
-           option_attribute_assignment = 1;
-       if (c == 'A')
-           option_attribute_testing = 1;
-       if (c == 'b')
-           user_background = num;
-       if (c == 'B')
-           user_reverse_bg = num;
-       if (c == 'c')
-           option_context_lines = num;
-       if (c == 'd')
-           display = optarg[0] | 32;
-       if (c == 'e')
-           user_emphasis = num;
-       if (c == 'T')
-           user_bold_typing = 1;
-       if (c == 'f')
-           user_foreground = num;
-       if (c == 'F')
-           user_reverse_fg = num;
-       if (c == 'g')
-           user_font = num;
-       if (c == 'h')
-           user_screen_height = num;
-       if (c == 'i')
-           option_ignore_errors = 1;
-       if (c == 'l')
-           option_left_margin = num;
-       if (c == 'o')
-           option_object_movement = 1;
-       if (c == 'O')
-           option_object_locating = 1;
-       if (c == 'p')
-           option_piracy = 1;
-       if (c == 'r')
-           option_right_margin = num;
-       if (c == 's')
-           user_random_seed = num;
-       if (c == 'S')
-           option_script_cols = num;
-       if (c == 't')
-           user_tandy_bit = 1;
-       if (c == 'u')
-           option_undo_slots = num;
-       if (c == 'w')
-           user_screen_width = num;
-       if (c == 'x')
-           option_expand_abbreviations = 1;
-
-    } while (c != EOF);
-
-}/* parse_options */
-
-/*
- * os_process_arguments
- *
- * Handle command line switches. Some variables may be set to activate
- * special features of Frotz:
- *
- *     option_attribute_assignment
- *     option_attribute_testing
- *     option_context_lines
- *     option_object_locating
- *     option_object_movement
- *     option_left_margin
- *     option_right_margin
- *     option_ignore_errors
- *     option_piracy
- *     option_undo_slots
- *     option_expand_abbreviations
- *     option_script_cols
- *
- * The global pointer "story_name" is set to the story file name.
- *
- */
-
-void os_process_arguments (int argc, char *argv[])
-{
-    const char *p;
-    int i;
-
-    /* Parse command line options */
-
-    parse_options (argc, argv);
-
-    if (optind != argc - 1) {
-       puts (INFORMATION);
-       exit (EXIT_FAILURE);
-    }
-
-    /* Set the story file name */
-
-    story_name = argv[optind];
-
-    /* Strip path and extension off the story file name */
-
-    p = story_name;
-
-    for (i = 0; story_name[i] != 0; i++)
-       if (story_name[i] == '\\' || story_name[i] == ':')
-           p = story_name + i + 1;
-
-    for (i = 0; p[i] != 0 && p[i] != '.' && i < 8; i++)
-       stripped_story_name[i] = p[i];
-
-    stripped_story_name[i] = 0;
-
-    /* Create nice default file names */
-
-    strcpy (script_name, stripped_story_name);
-    strcpy (command_name, stripped_story_name);
-    strcpy (save_name, stripped_story_name);
-    strcpy (auxilary_name, stripped_story_name);
-
-    strcat (script_name, ".scr");
-    strcat (command_name, ".rec");
-    strcat (save_name, ".sav");
-    strcat (auxilary_name, ".aux");
-
-    /* Save the executable file name */
-
-    progname = argv[0];
-
-}/* os_process_arguments */
-
-/*
- * standard_palette
- *
- * Set palette registers to EGA default values and call VGA BIOS to
- * use DAC registers #0 to #63.
- *
- */
-
-static void standard_palette (void)
-{
-
-    static byte palette[] = {
-       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
-       0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
-       0x00 /* last one is the overscan register */
-    };
-
-    if (display == _AMIGA_) {
-       asm mov ax,0x1002
-       asm lea dx,palette
-       asm push ds
-       asm pop es
-       asm int 0x10
-       asm mov ax,0x1013
-       asm mov bx,0x0001
-       asm int 0x10
-    }
-
-}/* standard_palette */
-
-/*
- * special_palette
- *
- * Set palette register #i to value i and call VGA BIOS to use DAC
- * registers #64 to #127.
- *
- */
-
-static void special_palette (void)
-{
-
-    static byte palette[] = {
-       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-       0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
-       0x00 /* last one is the overscan register */
-    };
-
-    if (display == _AMIGA_) {
-       asm mov ax,0x1002
-       asm mov dx,offset palette
-       asm push ds
-       asm pop es
-       asm int 0x10
-       asm mov ax,0x1013
-       asm mov bx,0x0101
-       asm int 0x10
-    }
-
-}/* special_palette */
-
-/*
- * os_init_screen
- *
- * Initialise the IO interface. Prepare the screen and other devices
- * (mouse, sound board). Set various OS depending story file header
- * entries:
- *
- *     h_config (aka flags 1)
- *     h_flags (aka flags 2)
- *     h_screen_cols (aka screen width in characters)
- *     h_screen_rows (aka screen height in lines)
- *     h_screen_width
- *     h_screen_height
- *     h_font_height (defaults to 1)
- *     h_font_width (defaults to 1)
- *     h_default_foreground
- *     h_default_background
- *     h_interpreter_number
- *     h_interpreter_version
- *     h_user_name (optional; not used by any game)
- *
- * Finally, set reserve_mem to the amount of memory (in bytes) that
- * should not be used for multiple undo and reserved for later use.
- *
- */
-
-void os_init_screen (void)
-{
-    static byte zcolour[] = {
-       BLACK_COLOUR,
-       BLUE_COLOUR,
-       GREEN_COLOUR,
-       CYAN_COLOUR,
-       RED_COLOUR,
-       MAGENTA_COLOUR,
-       BROWN + 16,
-       LIGHTGRAY + 16,
-       GREY_COLOUR,
-       LIGHTBLUE + 16,
-       LIGHTGREEN + 16,
-       LIGHTCYAN + 16,
-       LIGHTRED + 16,
-       LIGHTMAGENTA + 16,
-       YELLOW_COLOUR,
-       WHITE_COLOUR
-    };
-
-    static struct {    /* information on modes 0 to 5 */
-       byte vmode;
-       word width;
-       word height;
-       byte font_width;
-       byte font_height;
-       byte fg;
-       byte bg;
-    } info[] = {
-       { 0x07,  80,  25,  1,  1, LIGHTGRAY + 16, BLACK_COLOUR }, /* MONO  */
-       { 0x03,  80,  25,  1,  1, LIGHTGRAY + 16, BLUE_COLOUR  }, /* TEXT  */
-       { 0x06, 640, 200,  8,  8, WHITE_COLOUR,   BLACK_COLOUR }, /* CGA   */
-       { 0x13, 320, 200,  5,  8, WHITE_COLOUR,   GREY_COLOUR  }, /* MCGA  */
-       { 0x0e, 640, 200,  8,  8, WHITE_COLOUR,   BLUE_COLOUR  }, /* EGA   */
-       { 0x12, 640, 400,  8, 16, WHITE_COLOUR,   BLACK_COLOUR }  /* AMIGA */
-    };
-
-    static struct {    /* information on modes A to E */
-       word vesamode;
-       word width;
-       word height;
-    } subinfo[] = {
-       { 0x001,  40, 25 },
-       { 0x109, 132, 25 },
-       { 0x10b, 132, 50 },
-       { 0x108,  80, 60 },
-       { 0x10c, 132, 60 }
-    };
-
-    int subdisplay;
-
-    /* Get the current video mode. This video mode will be selected
-       when the program terminates. It's also useful to auto-detect
-       monochrome boards. */
-
-    asm mov ah,15
-    asm int 0x10
-    asm mov old_video_mode,al
-
-    /* If the display mode has not already been set by the user then see
-       if this is a monochrome board. If so, set the display mode to 0.
-       Otherwise check the graphics flag of the story. Select a graphic
-       mode if it is set or if this is a V6 game. Select text mode if it
-       is not. */
-
-    if (display == -1)
-
-       if (old_video_mode == 7)
-           display = '0';
-       else if (h_version == V6 || (h_flags & GRAPHICS_FLAG))
-           display = '5';
-       else
-           display = '1';
-
-    /* Activate the desired display mode. All VESA text modes are very
-       similar to the standard text mode; in fact, only here we need to
-       know which VESA mode is used. */
-
-    if (display >= '0' && display <= '5') {
-       subdisplay = -1;
-       display -= '0';
-       _AL = info[display].vmode;
-       _AH = 0;
-    } else if (display == 'a') {
-       subdisplay = 0;
-       display = 1;
-       _AL = 0x01;
-       _AH = 0;
-    } else if (display >= 'b' && display <= 'e') {
-       subdisplay = display - 'a';
-       display = 1;
-       _BX = subinfo[subdisplay].vesamode;
-       _AX = 0x4f02;
-    }
-
-    geninterrupt (0x10);
-
-    /* Make various preparations */
-
-    if (display <= _TEXT_) {
-
-       /* Enable bright background colours */
-
-       asm mov ax,0x1003
-       asm mov bl,0
-       asm int 0x10
-
-       /* Turn off hardware cursor */
-
-       asm mov ah,1
-       asm mov cx,0xffff
-       asm int 0x10
-
-    } else {
-
-       load_fonts (progname);
-
-       if (display == _AMIGA_) {
-
-            scaler = 2;
-
-            /* Use resolution 640 x 400 instead of 640 x 480. BIOS doesn't
-               help us here since this is not a standard resolution. */
-
-            outportb (0x03c2, 0x63);
-
-            outport (0x03d4, 0x0e11);
-            outport (0x03d4, 0xbf06);
-            outport (0x03d4, 0x1f07);
-            outport (0x03d4, 0x9c10);
-            outport (0x03d4, 0x8f12);
-            outport (0x03d4, 0x9615);
-            outport (0x03d4, 0xb916);
-
-        }
-
-    }
-
-#if !defined(__SMALL__) && !defined (__TINY__) && !defined (__MEDIUM__)
-
-    /* Set the amount of memory to reserve for later use. It takes
-       some memory to open command, script and game files. If Frotz
-       is compiled in a small memory model then memory for opening
-       files is allocated on the "near heap" while other allocations
-       are made on the "far heap", i.e. we need not reserve memory
-       in this case. */
-
-    reserve_mem = 4 * BUFSIZ;
-
-#endif
-
-    /* Amiga emulation under V6 needs special preparation. */
-
-    if (display == _AMIGA_ && h_version == V6) {
-
-       user_reverse_fg = -1;
-       user_reverse_bg = -1;
-       zcolour[LIGHTGRAY] = LIGHTGREY_COLOUR;
-       zcolour[DARKGRAY] = DARKGREY_COLOUR;
-
-       special_palette ();
-
-    }
-
-    /* Set various bits in the configuration byte. These bits tell
-       the game which features are supported by the interpreter. */
-
-    if (h_version == V3 && user_tandy_bit != -1)
-       h_config |= CONFIG_TANDY;
-    if (h_version == V3)
-       h_config |= CONFIG_SPLITSCREEN;
-    if (h_version == V3 && (display == _MCGA_ || (display == _AMIGA_ && user_font != 0)))
-       h_config |= CONFIG_PROPORTIONAL;
-    if (h_version >= V4 && display != _MCGA_ && (user_bold_typing != -1 || display <= _TEXT_))
-       h_config |= CONFIG_BOLDFACE;
-    if (h_version >= V4)
-       h_config |= CONFIG_EMPHASIS | CONFIG_FIXED | CONFIG_TIMEDINPUT;
-    if (h_version >= V5 && display != _MONO_ && display != _CGA_)
-       h_config |= CONFIG_COLOUR;
-    if (h_version >= V5 && display >= _CGA_ && init_pictures ())
-       h_config |= CONFIG_PICTURES;
-
-    /* Handle various game flags. These flags are set if the game wants
-       to use certain features. The flags must be cleared if the feature
-       is not available. */
-
-    if (h_flags & GRAPHICS_FLAG)
-       if (display <= _TEXT_)
-           h_flags &= ~GRAPHICS_FLAG;
-    if (h_version == V3 && (h_flags & OLD_SOUND_FLAG))
-       if (!init_sound ())
-           h_flags &= ~OLD_SOUND_FLAG;
-    if (h_flags & SOUND_FLAG)
-       if (!init_sound ())
-           h_flags &= ~SOUND_FLAG;
-    if (h_version >= V5 && (h_flags & UNDO_FLAG))
-       if (!option_undo_slots)
-           h_flags &= ~UNDO_FLAG;
-    if (h_flags & MOUSE_FLAG)
-       if (subdisplay != -1 || !detect_mouse ())
-           h_flags &= ~MOUSE_FLAG;
-    if (h_flags & COLOUR_FLAG)
-       if (display == _MONO_ || display == _CGA_)
-           h_flags &= ~COLOUR_FLAG;
-    h_flags &= ~MENU_FLAG;
-
-    /* Set the screen dimensions, font size and default colour */
-
-    h_screen_width = info[display].width;
-    h_screen_height = info[display].height;
-    h_font_height = info[display].font_height;
-    h_font_width = info[display].font_width;
-    h_default_foreground = info[display].fg;
-    h_default_background = info[display].bg;
-
-    if (subdisplay != -1) {
-       h_screen_width = subinfo[subdisplay].width;
-       h_screen_height = subinfo[subdisplay].height;
-    }
-
-    if (user_screen_width != -1)
-       h_screen_width = user_screen_width;
-    if (user_screen_height != -1)
-       h_screen_height = user_screen_height;
-
-    h_screen_cols = h_screen_width / h_font_width;
-    h_screen_rows = h_screen_height / h_font_height;
-
-    if (user_foreground != -1)
-       h_default_foreground = zcolour[user_foreground];
-    if (user_background != -1)
-       h_default_background = zcolour[user_background];
-
-    /* Set the interpreter number (a constant telling the game which
-       operating system it runs on) and the interpreter version. The
-       interpreter number has effect on V6 games and "Beyond Zork". */
-
-    h_interpreter_number = INTERP_MSDOS;
-    h_interpreter_version = 'F';
-
-    if (display == _AMIGA_)
-       h_interpreter_number = INTERP_AMIGA;
-
-     /* Install the fast_exit routine to handle the ctrl-break key */
-
-    oldvect = getvect (0x1b); setvect (0x1b, fast_exit);
-
-}/* os_init_screen */
-
-/*
- * os_reset_screen
- *
- * Reset the screen before the program stops.
- *
- */
-
-void os_reset_screen (void)
-{
-
-    os_set_font (TEXT_FONT);
-    os_set_text_style (0);
-    os_display_string ((zchar *) "[Hit any key to exit.]");
-    os_read_key (0, TRUE);
-
-    cleanup ();
-
-}/* os_reset_screen */
-
-/*
- * os_restart_game
- *
- * This routine allows the interface to interfere with the process of
- * restarting a game at various stages:
- *
- *     RESTART_BEGIN - restart has just begun
- *     RESTART_WPROP_SET - window properties have been initialised
- *     RESTART_END - restart is complete
- *
- */
-
-void os_restart_game (int stage)
-{
-    int x, y;
-
-    if (story_id == BEYOND_ZORK)
-
-       if (stage == RESTART_BEGIN)
-
-           if ((display == _MCGA_ || display == _AMIGA_) && os_picture_data (1, &x, &y)) {
-
-               special_palette ();
-
-               asm mov ax,0x1010
-               asm mov bx,64
-               asm mov dh,0
-               asm mov ch,0
-               asm mov cl,0
-               asm int 0x10
-               asm mov ax,0x1010
-               asm mov bx,79
-               asm mov dh,0xff
-               asm mov ch,0xff
-               asm mov cl,0xff
-               asm int 0x10
-
-               os_draw_picture (1, 1, 1);
-               os_read_key (0, FALSE);
-
-               standard_palette ();
-
-           }
-
-}/* os_restart_game */
-
-/*
- * os_random_seed
- *
- * Return an appropriate random seed value in the range from 0 to
- * 32767, possibly by using the current system time.
- *
- */
-
-int os_random_seed (void)
-{
-
-    if (user_random_seed == -1) {
-
-       /* Use the time of day as seed value */
-
-       asm mov ah,0
-       asm int 0x1a
-
-       return _DX & 0x7fff;
-
-    } else return user_random_seed;
-
-}/* os_random_seed */
diff --git a/bcinput.c b/bcinput.c
deleted file mode 100644 (file)
index 04c6e0f..0000000
--- a/bcinput.c
+++ /dev/null
@@ -1,989 +0,0 @@
-/*
- * file "BCinput.c"
- *
- * Borland C front end, input functions
- *
- */
-
-#include <bios.h>
-#include <string.h>
-#include <stdio.h>
-#include "frotz.h"
-#include "BCfrotz.h"
-
-#ifndef HISTORY_BUFSIZE
-#define HISTORY_BUFSIZE 500
-#endif
-
-extern bool is_terminator (zchar);
-
-extern bool read_yes_or_no (const char *);
-extern void read_string (int, zchar *);
-
-extern int completion (const zchar *, zchar *);
-
-static long limit = 0;
-
-static struct {
-    zchar buffer[HISTORY_BUFSIZE];
-    int latest;
-    int current;
-    int prefix_len;
-} history;
-
-static struct {
-    zchar *buffer;
-    int pos;
-    int length;
-    int max_length;
-    int width;
-    int max_width;
-} input;
-
-static bool overwrite = FALSE;
-
-/*
- * swap_colours
- *
- * This is a small helper function for switch_cursor. It swaps the
- * current background and foreground colours.
- *
- */
-
-static void swap_colours (void)
-{
-
-    _AL = text_fg;
-    _AH = text_bg;
-    text_fg = _AH;
-    text_bg = _AL;
-
-}/* swap_colours */
-
-/*
- * switch_cursor
- *
- * Turn cursor on/off. If there is mouse support then turn the mouse
- * pointer on/off as well. The cursor should not be moved and the
- * contents of the screen should not be changed while the cursor is
- * visible (because of the primitive cursor emulation we use here).
- *
- */
-
-static void switch_cursor (bool cursor)
-{
-
-    if (display <= _TEXT_) {
-
-       /* Use hardware cursor in text mode */
-
-       if (display == _MONO_)
-           _CX = overwrite ? 0x080f : 0x0a0b;
-       else
-           _CX = overwrite ? 0x0408 : 0x0506;
-
-       if (!cursor)
-           _CX = 0xffff;
-
-       asm mov ah,2
-       asm mov bh,0
-       asm mov dh,byte ptr cursor_y
-       asm mov dl,byte ptr cursor_x
-       asm int 0x10
-       asm mov ah,1
-       asm int 0x10
-
-    } else {
-
-       int saved_x = cursor_x;
-
-       if (cursor)
-           swap_colours ();
-
-       if (input.pos < input.length)
-           os_display_char (input.buffer[input.pos]);
-       else
-           os_display_char (' ');
-
-       if (cursor)
-           swap_colours ();
-
-       cursor_x = saved_x;
-
-    }
-
-}/* switch_cursor */
-
-/*
- * get_current_time
- *
- * Return the current system time in 1/10 seconds.
- *
- */
-
-static long get_current_time (void)
-{
-    long time;
-
-    /* Get the current time of day measured in
-        65536 / 1,193,180 = 0.054925493
-       seconds. Multiply this value with
-        959 / 1746 = 0.54925544
-       to get the current time in 0.1 seconds. */
-
-    asm mov ah,0
-    asm int 0x1a
-    asm mov word ptr time,dx
-    asm mov word ptr time + 2,cx
-
-    return time * 959 / 1746;
-
-}/* get_current_time */
-
-/*
- * set_timer
- *
- * Set a time limit of timeout/10 seconds if timeout is not zero;
- * otherwise clear the time limit.
- *
- */
-
-static void set_timer (int timeout)
-{
-
-    limit = (timeout != 0) ? get_current_time () + timeout : 0;
-
-}/* set_timer */
-
-/*
- * time_limit_hit
- *
- * Return true if a previously set time limit has been exceeded.
- *
- */
-
-static bool out_of_time (void)
-{
-
-    if (limit != 0) {
-
-       long now = get_current_time ();
-
-       if (now < 1L * 3600 * 10 && limit > 23L * 3600 * 10)
-           now += 24L * 3600 * 10;
-
-       return now >= limit;
-
-    } else return FALSE;
-
-}/* out_of_time */
-
-/*
- * get_key
- *
- * Read a keypress or a mouse click. Returns...
- *
- *     ZC_TIME_OUT = time limit exceeded,
- *     ZC_BACKSPACE = the backspace key,
- *     ZC_RETURN = the return key,
- *     ZC_HKEY_MIN...ZC_HKEY_MAX = a hot key,
- *     ZC_ESCAPE = the escape key,
- *     ZC_ASCII_MIN...ZC_ASCII_MAX = ASCII character,
- *     ZC_ARROW_MIN...ZC_ARROW_MAX = an arrow key,
- *     ZC_FKEY_MIN...ZC_FKEY_MAX = a function key,
- *     ZC_NUMPAD_MIN...ZC_NUMPAD_MAX = a number pad key,
- *     ZC_SINGLE_CLICK = single mouse click,
- *     ZC_DOUBLE_CLICK = double mouse click,
- *     ZC_LATIN1_MIN+1...ZC_LATIN1_MAX = ISO Latin-1 character,
- *     SPECIAL_KEY_MIN...SPECIAL_KEY_MAX = a special editing key.
- *
- */
-
-static int get_key (bool cursor)
-{
-    static byte arrow_key_map[] = {
-       0x48, 0x50, 0x4b, 0x4d
-    };
-    static byte special_key_map[] = {
-       0x47, 0x4f, 0x73, 0x74, 0x53, 0x52, 0x49, 0x51, 0x0f
-    };
-    static byte hot_key_map[] = {
-       0x13, 0x19, 0x1f, 0x16, 0x31, 0x2d, 0x20, 0x23
-    };
-
-    int key;
-
-    /* Loop until a key was pressed */
-
-    if (cursor)
-       switch_cursor (TRUE);
-
-    if (h_flags & MOUSE_FLAG) {
-       asm mov ax,1
-       asm int 0x33
-    }
-
-    do {
-
-       if (_bios_keybrd (_KEYBRD_READY)) {
-
-           word code = _bios_keybrd (_KEYBRD_READ);
-
-           if (byte0 (code) != 0 && byte0 (code) != 9) {
-
-               for (key = ZC_NUMPAD_MIN; key <= ZC_NUMPAD_MAX; key++)
-                   if (byte0 (code) == key - ZC_NUMPAD_MIN + '0' && byte1 (code) >= 0x10)
-                       goto exit_loop;
-
-               for (key = ZC_LATIN1_MIN + 1; key <= ZC_LATIN1_MAX; key++)
-                   if (byte0 (code) == latin1_to_ibm[key - ZC_LATIN1_MIN])
-                       goto exit_loop;
-
-               key = byte0 (code);
-
-               if (key == ZC_BACKSPACE)
-                   goto exit_loop;
-               if (key == ZC_RETURN)
-                   goto exit_loop;
-               if (key == ZC_ESCAPE)
-                   goto exit_loop;
-               if (key >= ZC_ASCII_MIN && key <= ZC_ASCII_MAX)
-                   goto exit_loop;
-
-           } else {
-
-               for (key = ZC_ARROW_MIN; key <= ZC_ARROW_MAX; key++)
-                   if (byte1 (code) == arrow_key_map[key - ZC_ARROW_MIN])
-                       goto exit_loop;
-
-               for (key = ZC_FKEY_MIN; key <= ZC_FKEY_MAX - 2; key++)
-                  if (byte1 (code) == key - ZC_FKEY_MIN + 0x3b)
-                       goto exit_loop;
-
-               for (key = ZC_HKEY_MIN; key <= ZC_HKEY_MAX; key++)
-                   if (byte1 (code) == hot_key_map[key - ZC_HKEY_MIN])
-                       goto exit_loop;
-
-               for (key = SPECIAL_KEY_MIN; key <= SPECIAL_KEY_MAX; key++)
-                   if (byte1 (code) == special_key_map[key - SPECIAL_KEY_MIN])
-                       goto exit_loop;
-
-           }
-
-       } else {
-
-           int clicks = read_mouse ();
-
-           if (clicks == 1)
-               { key = ZC_SINGLE_CLICK; goto exit_loop; }
-           if (clicks == 2)
-               { key = ZC_DOUBLE_CLICK; goto exit_loop; }
-
-       }
-
-       key = ZC_TIME_OUT;
-
-    } while (!out_of_time ());
-
-exit_loop:
-
-    if (h_flags & MOUSE_FLAG) {
-       asm mov ax,2
-       asm int 0x33
-    }
-
-    if (cursor)
-       switch_cursor (FALSE);
-
-    return key;
-
-}/* get_key */
-
-/*
- * cursor_left
- *
- * Move the cursor one character to the left.
- *
- */
-
-static void cursor_left (void)
-{
-
-    if (input.pos > 0)
-       cursor_x -= os_char_width (input.buffer[--input.pos]);
-
-}/* cursor_left */
-
-/*
- * cursor_right
- *
- * Move the cursor one character to the right.
- *
- */
-
-static void cursor_right (void)
-{
-
-    if (input.pos < input.length)
-       cursor_x += os_char_width (input.buffer[input.pos++]);
-
-}/* cursor_right */
-
-/*
- * first_char
- *
- * Move the cursor to the beginning of the input line.
- *
- */
-
-static void first_char (void)
-{
-
-    while (input.pos > 0)
-       cursor_left ();
-
-}/* first_char */
-
-/*
- * last_char
- *
- * Move the cursor to the end of the input line.
- *
- */
-
-static void last_char (void)
-{
-
-    while (input.pos < input.length)
-       cursor_right ();
-
-}/* last_char */
-
-/*
- * prev_word
- *
- * Move the cursor to the start of the previous word.
- *
- */
-
-static void prev_word (void)
-{
-
-    do {
-
-       cursor_left ();
-
-       if (input.pos == 0)
-           return;
-
-    } while (input.buffer[input.pos] == ' ' || input.buffer[input.pos - 1] != ' ');
-
-}/* prev_word */
-
-/*
- * next_word
- *
- * Move the cursor to the start of the next word.
- *
- */
-
-static void next_word (void)
-{
-
-    do {
-
-       cursor_right ();
-
-       if (input.pos == input.length)
-           return;
-
-    } while (input.buffer[input.pos] == ' ' || input.buffer[input.pos - 1] != ' ');
-
-}/* next_word */
-
-/*
- * input_move
- *
- * Helper function to move parts of the input buffer:
- *
- *    newc != 0, oldc == 0: INSERT
- *    newc != 0, oldc != 0: OVERWRITE
- *    newc == 0, oldc != 0: DELETE
- *    newc == 0, oldc == 0: NO OPERATION
- *
- */
-
-#define H(x) (x ? 1 : 0)
-
-static void input_move (zchar newc, zchar oldc)
-{
-    int newwidth = (newc != 0) ? os_char_width (newc) : 0;
-    int oldwidth = (oldc != 0) ? os_char_width (oldc) : 0;
-
-    zchar *p = input.buffer + input.pos;
-
-    int saved_x = cursor_x;
-
-    int updated_width = input.width + newwidth - oldwidth;
-    int updated_length = input.length + H (newc) - H (oldc);
-
-    if (updated_width > input.max_width)
-       return;
-    if (updated_length > input.max_length)
-       return;
-
-    input.width = updated_width;
-    input.length = updated_length;
-
-    if (oldc != 0 && newc == 0)
-       memmove (p, p + 1, updated_length - input.pos + 1);
-    if (newc != 0 && oldc == 0)
-       memmove (p + 1, p, updated_length - input.pos);
-
-    if (newc != 0)
-       *p = newc;
-
-    os_display_string (p);
-
-    switch_scrn_attr (TRUE);
-
-    if (oldwidth > newwidth)
-
-       os_erase_area (
-           cursor_y + 1,
-           cursor_x + 1,
-           cursor_y + h_font_height,
-           cursor_x + oldwidth - newwidth);
-
-    switch_scrn_attr (FALSE);
-
-    cursor_x = saved_x;
-
-    if (newc != 0)
-       cursor_right ();
-
-}/* input_move */
-
-#undef H(x)
-
-/*
- * delete_char
- *
- * Delete the character below the cursor.
- *
- */
-
-static void delete_char (void)
-{
-
-    input_move (0, input.buffer[input.pos]);
-
-}/* delete_char */
-
-/*
- * delete_left
- *
- * Delete the character to the left of the cursor.
- *
- */
-
-static void delete_left (void)
-{
-
-    if (input.pos > 0) {
-       cursor_left ();
-       delete_char ();
-    }
-
-}/* delete_left */
-
-/*
- * truncate_line
- *
- * Truncate the input line to n characters.
- *
- */
-
-static void truncate_line (int n)
-{
-
-    last_char ();
-
-    while (input.length > n)
-       delete_left ();
-
-}/* truncate_line */
-
-/*
- * insert_char
- *
- * Insert a character into the input buffer.
- *
- */
-
-static void insert_char (zchar newc)
-{
-    zchar oldc = 0;
-
-    if (overwrite)
-       oldc = input.buffer[input.pos];
-
-    input_move (newc, oldc);
-
-}/* insert_char */
-
-/*
- * insert_string
- *
- * Add a string of characters to the input line.
- *
- */
-
-static void insert_string (const zchar *s)
-{
-
-    while (*s != 0) {
-
-       if (input.length + 1 > input.max_length)
-           break;
-       if (input.width + os_char_width (*s) > input.max_width)
-           break;
-
-       insert_char (*s++);
-
-    }
-
-}/* insert_string */
-
-/*
- * tabulator_key
- *
- * Complete the word at the end of the input line, if possible.
- *
- */
-
-static void tabulator_key (void)
-{
-    int status;
-
-    if (input.pos == input.length) {
-
-       zchar extension[10];
-
-       status = completion (input.buffer, extension);
-       insert_string (extension);
-
-    } else status = 2;
-
-    /* Beep if the completion was impossible or ambiguous */
-
-    if (status != 0)
-       os_beep (status);
-
-}/* tabulator_key */
-
-/*
- * store_input
- *
- * Copy the current input line to the history buffer.
- *
- */
-
-static void store_input (void)
-{
-
-    if (input.length >= HISTORY_MIN_ENTRY) {
-
-       const zchar *ptr = input.buffer;
-
-       do {
-
-           if (history.latest++ == HISTORY_BUFSIZE - 1)
-               history.latest = 0;
-
-           history.buffer[history.latest] = *ptr;
-
-       } while (*ptr++ != 0);
-
-    }
-
-}/* store_input */
-
-/*
- * fetch_entry
- *
- * Copy the current history entry to the input buffer and check if it
- * matches the prefix in the input buffer.
- *
- */
-
-static bool fetch_entry (zchar *buf, int entry)
-{
-    int i = 0;
-
-    zchar c;
-
-    do {
-
-       if (entry++ == HISTORY_BUFSIZE - 1)
-           entry = 0;
-
-       c = history.buffer[entry];
-
-       if (i < history.prefix_len && input.buffer[i] != c)
-           return FALSE;
-
-       buf[i++] = c;
-
-    } while (c != 0);
-
-    return (i > history.prefix_len) && (i > 1);
-
-}/* fetch_entry */
-
-/*
- * get_prev_entry
- *
- * Copy the previous history entry to the input buffer.
- *
- */
-
-static void get_prev_entry (void)
-{
-    zchar buf[INPUT_BUFFER_SIZE];
-
-    int i = history.current;
-
-    do {
-
-       do {
-
-           if (i-- == 0)
-               i = HISTORY_BUFSIZE - 1;
-
-           if (i == history.latest)
-               return;
-
-       } while (history.buffer[i] != 0);
-
-    } while (!fetch_entry (buf, i));
-
-    truncate_line (history.prefix_len);
-
-    insert_string (buf + history.prefix_len);
-
-    history.current = i;
-
-}/* get_prev_entry */
-
-/*
- * get_next_entry
- *
- * Copy the next history entry to the input buffer.
- *
- */
-
-static void get_next_entry (void)
-{
-    zchar buf[INPUT_BUFFER_SIZE];
-
-    int i = history.current;
-
-    truncate_line (history.prefix_len);
-
-    do {
-
-       do {
-
-           if (i == history.latest)
-               return;
-
-           if (i++ == HISTORY_BUFSIZE - 1)
-               i = 0;
-
-       } while (history.buffer[i] != 0);
-
-       if (i == history.latest)
-           goto no_further;
-
-    } while (!fetch_entry (buf, i));
-
-    insert_string (buf + history.prefix_len);
-
-no_further:
-
-    history.current = i;
-
-}/* get_next_entry */
-
-/*
- * os_read_line
- *
- * Read a line of input from the keyboard into a buffer. The buffer
- * may already be primed with some text. In this case, the "initial"
- * text is already displayed on the screen. After the input action
- * is complete, the function returns with the terminating key value.
- * The length of the input should not exceed "max" characters plus
- * an extra 0 terminator.
- *
- * Terminating keys are the return key (13) and all function keys
- * (see the Specification of the Z-machine) which are accepted by
- * the is_terminator function. Mouse clicks behave like function
- * keys except that the mouse position is stored in global variables
- * "mouse_x" and "mouse_y" (top left coordinates are (1,1)).
- *
- * Furthermore, Frotz introduces some special terminating keys:
- *
- *     ZC_HKEY_PLAYBACK (Alt-P)
- *     ZC_HKEY_RECORD (Alt-R)
- *     ZC_HKEY_SEED (Alt-S)
- *     ZC_HKEY_UNDO (Alt-U)
- *     ZC_HKEY_RESTART (Alt-N, "new game")
- *     ZC_HKEY_QUIT (Alt-X, "exit game")
- *     ZC_HKEY_DEBUGGING (Alt-D)
- *     ZC_HKEY_HELP (Alt-H)
- *
- * If the timeout argument is not zero, the input gets interrupted
- * after timeout/10 seconds (and the return value is 0).
- *
- * The complete input line including the cursor must fit in "width"
- * screen units.
- *
- * The function may be called once again to continue after timeouts,
- * misplaced mouse clicks or hot keys. In this case the "continued"
- * flag will be set. This information can be useful if the interface
- * implements input line history.
- *
- * The screen is not scrolled after the return key was pressed. The
- * cursor is at the end of the input line when the function returns.
- *
- * Since Inform 2.2 the helper function "completion" can be called
- * to implement word completion (similar to tcsh under Unix).
- *
- */
-
-#define new_history_search() \
-    { history.prefix_len = input.pos; history.current = history.latest; }
-
-zchar os_read_line (int max, zchar *buf, int timeout, int width, int continued)
-{
-    int key = continued ? 9999 : 0;
-
-    /* Initialise input variables */
-
-    input.buffer = buf;
-    input.pos = strlen ((char *) buf);
-    input.length = strlen ((char *) buf);
-    input.max_length = max;
-    input.width = os_string_width (buf);
-    input.max_width = width - os_char_width (' ');
-
-    /* Calculate time limit */
-
-    set_timer (timeout);
-
-    /* Loop until a terminator is found */
-
-    do {
-
-       if (key != 9999)
-           new_history_search ();
-
-       /* Get next key from mouse or keyboard */
-
-       key = get_key (TRUE);
-
-       if (key < ZC_ASCII_MIN || key > ZC_ASCII_MAX && key < ZC_LATIN1_MIN || key > ZC_LATIN1_MAX) {
-
-           /* Ignore time-outs if the cursor is not at end of the line */
-
-           if (key == ZC_TIME_OUT && input.pos < input.length)
-               key = 9999;
-
-           /* Backspace, return and escape keys */
-
-           if (key == ZC_BACKSPACE)
-               delete_left ();
-           if (key == ZC_RETURN)
-               store_input ();
-           if (key == ZC_ESCAPE)
-               truncate_line (0);
-
-           /* Editing keys */
-
-           if (cwin == 0) {
-
-               if (key == ZC_ARROW_UP)
-                   get_prev_entry ();
-               if (key == ZC_ARROW_DOWN)
-                   get_next_entry ();
-               if (key == ZC_ARROW_LEFT)
-                   cursor_left ();
-               if (key == ZC_ARROW_RIGHT)
-                   cursor_right ();
-
-               if (key >= ZC_ARROW_MIN && key <= ZC_ARROW_MAX)
-                   key = 9999;
-
-               if (key == SPECIAL_KEY_HOME)
-                   first_char ();
-               if (key == SPECIAL_KEY_END)
-                   last_char ();
-               if (key == SPECIAL_KEY_WORD_LEFT)
-                   prev_word ();
-               if (key == SPECIAL_KEY_WORD_RIGHT)
-                   next_word ();
-               if (key == SPECIAL_KEY_DELETE)
-                   delete_char ();
-               if (key == SPECIAL_KEY_INSERT)
-                   overwrite = !overwrite;
-               if (key == SPECIAL_KEY_TAB)
-                   tabulator_key ();
-
-           }
-
-           if (key == SPECIAL_KEY_PAGE_UP)
-               key = ZC_ARROW_UP;
-           if (key == SPECIAL_KEY_PAGE_DOWN)
-               key = ZC_ARROW_DOWN;
-
-       } else insert_char (key);
-
-    } while (key > 0xff || !is_terminator (key));
-
-    last_char ();
-
-    overwrite = FALSE;
-
-    /* Return terminating key */
-
-    return key;
-
-}/* os_read_line */
-
-#undef new_history_search()
-
-/*
- * os_read_key
- *
- * Read a single character from the keyboard (or a mouse click) and
- * return it. Input aborts after timeout/10 seconds.
- *
- */
-
-zchar os_read_key (int timeout, bool cursor)
-{
-    int key;
-
-    set_timer (timeout);
-
-    do {
-
-       key = get_key (cursor);
-
-    } while (key > 0xff);
-
-    return key;
-
-}/* os_read_key */
-
-/*
- * os_read_file_name
- *
- * Return the name of a file. Flag can be one of:
- *
- *    FILE_SAVE     - Save game file
- *    FILE_RESTORE  - Restore game file
- *    FILE_SCRIPT   - Transscript file
- *    FILE_RECORD   - Command file for recording
- *    FILE_PLAYBACK - Command file for playback
- *    FILE_SAVE_AUX - Save auxilary ("preferred settings") file
- *    FILE_LOAD_AUX - Load auxilary ("preferred settings") file
- *
- * The length of the file name is limited by MAX_FILE_NAME. Ideally
- * an interpreter should open a file requester to ask for the file
- * name. If it is unable to do that then this function should call
- * print_string and read_string to ask for a file name.
- *
- */
-
-int os_read_file_name (char *file_name, const char *default_name, int flag)
-{
-    char *extension;
-    FILE *fp;
-    bool terminal;
-    bool result;
-
-    bool saved_replay = istream_replay;
-    bool saved_record = ostream_record;
-
-    /* Turn off playback and recording temporarily */
-
-    istream_replay = FALSE;
-    ostream_record = FALSE;
-
-    /* Select appropriate extension */
-
-    extension = ".aux";
-
-    if (flag == FILE_SAVE || flag == FILE_RESTORE)
-       extension = ".sav";
-    if (flag == FILE_SCRIPT)
-       extension = ".scr";
-    if (flag == FILE_RECORD || flag == FILE_PLAYBACK)
-       extension = ".rec";
-
-    /* Input file name (reserve four bytes for a file name extension) */
-
-    print_string ("Enter file name (\"");
-    print_string (extension);
-    print_string ("\" will be added).\nDefault is \"");
-    print_string (default_name);
-    print_string ("\": ");
-
-    read_string (MAX_FILE_NAME - 4, (zchar *) file_name);
-
-    /* Use the default name if nothing was typed */
-
-    if (file_name[0] == 0)
-       strcpy (file_name, default_name);
-    if (strchr (file_name, '.') == NULL)
-       strcat (file_name, extension);
-
-    /* Make sure it is safe to use this file name */
-
-    result = TRUE;
-
-    /* OK if the file is opened for reading */
-
-    if (flag != FILE_SAVE && flag != FILE_SAVE_AUX && flag != FILE_RECORD)
-       goto finished;
-
-    /* OK if the file does not exist */
-
-    if ((fp = fopen (file_name, "rb")) == NULL)
-       goto finished;
-
-    /* OK if this is a pseudo-file (like PRN, CON, NUL) */
-
-    terminal = fp->flags & _F_TERM;
-
-    fclose (fp);
-
-    if (terminal)
-       goto finished;
-
-    /* OK if user wants to overwrite */
-
-    result = read_yes_or_no ("Overwrite existing file");
-
-finished:
-
-    /* Restore state of playback and recording */
-
-    istream_replay = saved_replay;
-    ostream_record = saved_record;
-
-    return result;
-
-}/* os_read_file_name */
diff --git a/bcmouse.c b/bcmouse.c
deleted file mode 100644 (file)
index ea8444b..0000000
--- a/bcmouse.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * file "BCmouse.c"
- *
- * Borland C front end, mouse support
- *
- */
-
-#include <dos.h>
-#include "frotz.h"
-#include "BCfrotz.h"
-
-/*
- * detect_mouse
- *
- * Return true if a mouse driver is present.
- *
- */
-
-bool detect_mouse (void)
-{
-
-    asm xor ax,ax
-    asm int 0x33
-
-    return _AX;
-
-}/* detect_mouse */
-
-/*
- * read_mouse
- *
- * Report any mouse clicks. Return 2 for a double click, 1 for a single
- * click or 0 if there was no mouse activity at all.
- *
- */
-
-int read_mouse (void)
-{
-    int click;
-
-    /* Read the current mouse status */
-
-    for (click = 0; click < 2; click++) {
-
-       if (click == 1)
-           delay (222);
-
-       asm mov ax,6
-       asm xor bx,bx
-       asm int 0x33
-
-       if (_BX == 0)
-           break;
-
-       mouse_x = _CX;
-       mouse_y = _DX;
-
-       if (display <= _TEXT_) {
-           mouse_x /= 8;
-           mouse_y /= 8;
-       }
-
-       if (display == _MCGA_)
-           mouse_x /= 2;
-
-       mouse_x++;
-       mouse_y++;
-
-    }
-
-    /* Return single or double click */
-
-    return click;
-
-}/* read_mouse */
diff --git a/bcpic.c b/bcpic.c
deleted file mode 100644 (file)
index 59115a9..0000000
--- a/bcpic.c
+++ /dev/null
@@ -1,677 +0,0 @@
-/*
- * "BCpic.c"
- *
- * Borland C front end, picture functions
- *
- */
-
-#include <alloc.h>
-#include <dos.h>
-#include <stdio.h>
-#include <string.h>
-#include "frotz.h"
-#include "BCfrotz.h"
-
-#define PIC_NUMBER 0
-#define PIC_WIDTH 2
-#define PIC_HEIGHT 4
-#define PIC_FLAGS 6
-#define PIC_DATA 8
-#define PIC_COLOUR 11
-
-#define READ_BYTE(v,p,o)       v = *(byte far *)(p+o)
-#define READ_WORD(v,p,o)       v = *(word far *)(p+o)
-
-extern byte far *get_scrnptr (int);
-
-static struct {
-    byte fileno;
-    byte flags;
-    word unused1;
-    word images;
-    word link;
-    byte entry_size;
-    byte padding;
-    word checksum;
-    word unused2;
-    word version;
-} gheader;
-
-int scaler = 1;
-
-static word pic_width = 0;
-static word pic_height = 0;
-static word pic_flags = 0;
-static long pic_data = 0;
-static long pic_colour = 0;
-
-static byte far *table_val = NULL;
-static word far *table_ref = NULL;
-
-static FILE *file = NULL;
-static byte far *info = NULL;
-
-/*
- * open_graphics_file
- *
- * Open a graphics file. EGA pictures may be stored in two separate
- * graphics files.
- *
- */
-
-static bool open_graphics_file (int number)
-{
-    char fname[MAX_FILE_NAME + 1];
-    char extension[4 + 1];
-
-    /* Build graphics file name */
-
-    extension[0] = '.';
-    extension[1] = "cmem"[display - 2];
-    extension[2] = 'g';
-    extension[3] = '0' + number;
-    extension[4] = 0;
-
-    strcpy (fname, stripped_story_name);
-    strcat (fname, extension);
-
-    /* Open file, load header, allocate memory, load picture directory */
-
-    if ((file = fopen (fname, "rb")) == NULL)
-       goto failure1;
-    if (fread (&gheader, sizeof (gheader), 1, file) != 1)
-       goto failure2;
-    if ((info = farmalloc (gheader.images * gheader.entry_size)) == NULL)
-       goto failure2;
-    if (fread (info, gheader.entry_size, gheader.images, file) != gheader.images)
-       goto failure3;
-    return TRUE;
-
-failure3:
-    farfree (info); info = NULL;
-failure2:
-    fclose (file); file = NULL;
-failure1:
-    return FALSE;
-
-}/* open_graphics_file */
-
-/*
- * close_graphics_file
- *
- * Free resources allocated for pictures.
- *
- */
-
-static void close_graphics_file (void)
-{
-
-    if (file != NULL)
-       { fclose (file); file = NULL; }
-    if (info != NULL)
-       { farfree (info); info = NULL; }
-
-}/* close_graphics_file */
-
-/*
- * init_pictures
- *
- * Prepare to draw pictures. Return true if pictures are available.
- *
- */
-
-bool init_pictures (void)
-{
-
-    /* Allocate memory for decompression */
-
-    table_val = (byte far *) farmalloc (3 * 3840);
-    table_ref = (word far *) (table_val + 3840);
-
-    if (table_val == NULL)
-       return FALSE;
-
-    /* Open the [first of two] graphics file[s] */
-
-    return open_graphics_file (1);
-
-}/* init_pictures */
-
-/*
- * reset_pictures
- *
- * Free resources allocated for decompression of pictures.
- *
- */
-
-void reset_pictures (void)
-{
-
-    if (table_val != NULL)
-       { farfree (table_val); table_val = NULL; }
-    if (file != NULL)
-       { fclose (file); file = NULL; }
-    if (info != NULL)
-       { farfree (info); info = NULL; }
-
-}/* reset_pictures */
-
-/*
- * load_picture_info
- *
- * Helper function for os_picture_data. Load all information about
- * the given picture from the graphics file and store it in global
- * variables.
- *
- */
-
-static bool load_picture_info (int picture)
-{
-    byte far *ptr;
-    byte fileno;
-
-    fileno = gheader.fileno;
-
-    do {
-
-       int i;
-
-       /* Abort if there is a problem with the graphics file */
-
-       if (file == NULL)
-           return FALSE;
-
-       /* Scan the directory of the current graphics file */
-
-       ptr = info;
-
-       for (i = 0; i < gheader.images; i++) {
-
-           if (picture == * (int far *) ptr) {
-
-               READ_WORD (pic_width, ptr, PIC_WIDTH);
-               READ_WORD (pic_height, ptr, PIC_HEIGHT);
-               READ_WORD (pic_flags, ptr, PIC_FLAGS);
-
-               pic_height *= scaler;
-               pic_width *= scaler;
-
-               READ_BYTE (byte0 (pic_data), ptr, PIC_DATA + 2);
-               READ_BYTE (byte1 (pic_data), ptr, PIC_DATA + 1);
-               READ_BYTE (byte2 (pic_data), ptr, PIC_DATA);
-
-               if (gheader.entry_size > PIC_COLOUR + 2) {
-
-                   READ_BYTE (byte0 (pic_colour), ptr, PIC_COLOUR + 2);
-                   READ_BYTE (byte1 (pic_colour), ptr, PIC_COLOUR + 1);
-                   READ_BYTE (byte2 (pic_colour), ptr, PIC_COLOUR);
-
-               } else pic_colour = 0;
-
-               return TRUE;
-
-           }
-
-           ptr += gheader.entry_size;
-
-       }
-
-       /* Close current graphics file */
-
-       close_graphics_file ();
-
-       /* Open next graphics file */
-
-       open_graphics_file ((gheader.link != 0) ? gheader.fileno + 1 : 1);
-
-    } while (fileno != gheader.fileno);
-
-    return FALSE;
-
-}/* load_picture_info */
-
-/*
- * load_colour_map
- *
- * Helper function for os_draw_picture. Load a colour map from the
- * graphics file then copy it to the palette registers.
- *
- */
-
-static void load_colour_map (int first_colour)
-{
-    byte rgb[42];
-    int n, i;
-
-    fseek (file, pic_colour, SEEK_SET);
-
-    /* Some pictures from Arthur mistakenly claim to have 16 colours */
-
-    if ((n = fgetc (file)) == 16)
-       n = 14;
-
-    /* Each colour is stored in three bytes R-G-B */
-
-    fread (rgb, 3, n, file);
-
-    /* MCGA boards can only handle R-G-B values from 0 to 63 */
-
-    for (i = 0; i < 42; i++)
-       rgb[i] = (rgb[i] * 63 + 128) / 255;
-
-    /* Synchronise with vertical retrace */
-
-    while ((inportb (0x03da) & 8) == 0);
-    while ((inportb (0x03da) & 8) == 8);
-
-    /* Copy colours to palette registers */
-
-    asm mov ax,0x1012
-    asm mov bx,first_colour
-    asm mov cx,n
-    asm lea dx,rgb
-    asm push ss
-    asm pop es
-    asm int 0x10
-
-}/* load_colour_map */
-
-/*
- * draw_picture
- *
- * Helper function for os_draw_picture. The real work of drawing a
- * picture happens here.
- *
- */
-
-#pragma warn -def
-
-static void pascal draw_picture (int y, int x)
-{
-    static int raise_bits[4] = {
-       0x0100, 0x0300, 0x0700, 0x0000
-    };
-
-    byte buf[512];
-    byte far *screen;
-    byte transparent;
-    byte colour_shift;
-    int first_colour;
-    int code, prev_code;
-    int next_entry;
-    int bits_per_code;
-    int bits_shift;
-    int bits;
-    int current_y;
-    int current_x;
-    int bufpos;
-    int pixels;
-    int i;
-
-    bufpos = 0;
-
-    /* When the given picture provides a colour map then activate it.
-       This is only used for MCGA pictures; the colour map affects
-       every picture on the screen. The first colour to be defined is
-       colour 2. Every map defines up to 14 colours (colour 2 to 15).
-       These colours are not related to the standard Z-machine colour
-       scheme which remains unchanged. (This is based on the Amiga
-       interpreter which had to work with 16 colours. Colours 0 and 1
-       were used for text; changing the text colours actually changed
-       palette entries 0 and 1. This interface uses the same trick in
-       Amiga mode.) */
-
-    if (display == _CGA_)
-       colour_shift = -2;
-    if (display == _EGA_)
-       colour_shift = 0;
-    if (display == _MCGA_)
-       { colour_shift = 32; first_colour = 34; }
-    if (display == _AMIGA_)
-       { colour_shift = -1; first_colour = 65; }
-
-    if (pic_colour != 0)
-       load_colour_map (first_colour);
-
-    fseek (file, pic_data, SEEK_SET);
-
-    /* Bit 0 of "flags" indicates that the picture uses a transparent
-       colour, the top four bits tell us which colour it is. For CGA
-       and MCGA pictures this is always 0; for EGA pictures it can be
-       any colour between 0 and 15. */
-
-    transparent = 0xff;
-
-    if (pic_flags & 1)
-       transparent = pic_flags >> 12;
-
-    /* Prepare EGA hardware for setting pixels */
-
-    if (display >= _EGA_) {
-       outport (0x03ce, 0x0205);
-       outport (0x03ce, 0xff08);
-    }
-
-    /* The uncompressed picture is a long sequence of bytes. Every
-       byte holds the colour of a pixel, starting at the top left,
-       stopping at the bottom right. We keep track of our position
-       in the current line. (There is a special case: CGA pictures
-       with no transparent colour are stored as bit patterns, i.e.
-       every byte holds the pattern for eight pixels. A pixel must
-       be white if the corresponding bit is set, otherwise it must
-       be black.) */
-
-    current_x = x + pic_width;
-    current_y = y - 1;
-
-    /* The compressed picture is a stream of bits. We read the file
-       byte-wise, storing the current byte in the variable "bits".
-       Several bits make one code; the variable "bits_shift" helps
-       us to build the next code. */
-
-    bits_shift = 0;
-    bits = 0;
-
-reset_table:
-
-    /* Clear the table. We use a table of 3840 entries. Each entry
-       consists of both a value and a reference to another table
-       entry. Following these references we get a sequence of
-       values. At the start of decompression all table entries are
-       undefined. Later we see how entries are set and used. */
-
-    next_entry = 1;
-
-    /* At the start of decompression 9 bits make one code; during
-       the process this can rise to 12 bits per code. 9 bits are
-       sufficient to address both 256 literal values and 256 table
-       entries; 12 bits are sufficient to address both 256 literal
-       values and all 3840 table entries. The number of bits per
-       code rises with the number of table entries. When the table
-       is cleared, the number of bits per code drops back to 9. */
-
-    bits_per_code = 9;
-
-next_code:
-
-    /* Read the next code from the graphics file. This requires
-       some confusing bit operations. Note that low bits always
-       come first. Usually there are a few bits left over from
-       the previous code; these bits must be used before further
-       bits are read from the graphics file. */
-
-    code = bits >> (8 - bits_shift);
-
-    do {
-
-       bits = fgetc (file);
-
-       code |= bits << bits_shift;
-
-       bits_shift += 8;
-
-    } while (bits_shift < bits_per_code);
-
-    bits_shift -= bits_per_code;
-
-    code &= 0xfff >> (12 - bits_per_code);
-
-    /* There are two codes with a special meaning. The first one
-       is 256 which clears the table and sets the number of bits
-       per code to 9. (This is necessary when the table is full.)
-       The second one is 257 which marks the end of the picture.
-       For the sake of efficiency, we drecement the code by 256. */
-
-    byte1 (code) --;
-
-    if (code == 0)
-       goto reset_table;
-    if (code == 1)
-       return;
-
-    /* Codes from 0 to 255 are literals, i.e. they represent a
-       plain byte value. Codes from 258 onwards are references
-       to table entries, i.e. they represent a sequence of byte
-       values (see the remarks on the table above). This means
-       that for each code one or several byte values are added
-       to the decompressed picture. But there is yet more work
-       to do: Every time we read a code one table entry is set.
-       As we said above, a table entry consist of both a value
-       and a reference to another table entry. If the current
-       code is a literal, then the value has to be set to this
-       literal; but if the code refers to a sequence of byte
-       values, then the value has to be set to the last byte of
-       this sequence. In any case, the reference is set to the
-       previous code. Finally, one should be aware that a code
-       may legally refer to the table entry which is currently
-       being set. This requires some extra care. */
-
-    table_ref[next_entry] = prev_code;
-
-    prev_code = code;
-
-    while (code >= 0) {
-       buf[bufpos++] = table_val[code];
-       code = (short) table_ref[code];
-    }
-
-    if (next_entry == prev_code)
-       buf[0] = code;
-
-    table_val[next_entry] = code;
-
-    /* The number of bits per code is incremented when the current
-       number of bits no longer suffices to address all defined
-       table entries; but in any case the number of bits may never
-       be greater than 12. */
-
-    next_entry++;
-
-    if (next_entry == raise_bits[bits_per_code - 9])
-       bits_per_code++;
-
-reverse_buffer:
-
-    /* Append the sequence of byte values (pixels) to the picture.
-       The order of the sequence must be reversed. (This is why we
-       have stored the sequence in a buffer; experiments show that
-       a buffer of 512 bytes suffices.) The sequence of values may
-       spread over several lines of the picture, so we must take
-       care to start a new line when we reach the right border of
-       the picture. */
-
-    if (current_x == x + pic_width) {
-
-       screen = get_scrnptr (current_y);
-
-       current_x -= pic_width;
-       current_y += scaler;
-
-    }
-
-    /* Either add a single pixel or a pattern of eight bits (b/w
-       CGA pictures without a transparent colour) to the current
-       line. Increment our position by 1 or 8 respectively. The
-       pixel may have to be painted several times if the scaling
-       factor is greater than one. */
-
-    if (display == _CGA_ && transparent == 0xff) {
-
-       pixels = x + pic_width - current_x;
-
-       if (pixels > 8)
-           pixels = 8;
-
-       asm les bx,screen
-       asm mov dx,current_x
-       asm dec dx
-       asm push dx
-       asm mov cl,3
-       asm shr dx,cl
-       asm add bx,dx
-       asm mov ax,es:[bx]
-       asm mov dx,0xffff
-       asm mov cl,byte ptr pixels
-       asm shr dl,cl
-       asm pop cx
-       asm and cl,7
-       asm ror dx,cl
-       asm and ax,dx
-       asm mov dx,code
-       asm inc dh
-       asm ror dx,cl
-       asm or ax,dx
-       asm mov es:[bx],ax
-
-       current_x += pixels;
-
-    } else for (i = 0; i < scaler; i++) {
-
-       _AH = code;
-
-       if (_AH != transparent) {
-
-           asm add ah,colour_shift
-           asm les bx,screen
-           asm mov dx,current_x
-           asm dec dx
-
-           if (display != _MCGA_) {
-
-               asm push dx
-               asm mov cl,3
-               asm shr dx,cl
-               asm pop cx
-               asm and cl,7
-               asm add bx,dx
-               asm mov al,es:[bx]
-
-               if (display == _CGA_) {
-                   asm mov dl,0x7f
-                   asm ror dl,cl
-                   asm and al,dl
-                   asm xor ah,1
-                   asm ror ah,1
-                   asm shr ah,cl
-                   asm or ah,al
-               } else {
-                   asm mov al,0x80
-                   asm shr al,cl
-                   asm mov dx,0x03cf
-                   asm out dx,al
-               }
-
-           } else asm add bx,dx
-
-           asm mov es:[bx],ah
-
-           if (display == _AMIGA_) {
-               asm add bx,80
-               asm mov al,es:[bx]
-               asm mov es:[bx],ah
-           }
-
-       }
-
-       current_x++;
-
-    }
-
-    /* If there are no more values in the buffer then read the
-       next code from the file. Otherwise fetch the next byte
-       value from the buffer and continue painting the picture. */
-
-    if (bufpos == 0)
-       goto next_code;
-
-    byte0 (code) = buf[--bufpos];
-
-    goto reverse_buffer;
-
-}/* draw_picture */
-
-#pragma warn +def
-
-/*
- * os_draw_picture
- *
- * Display a picture at the given coordinates. Top left is (1,1).
- *
- */
-
-void os_draw_picture (int picture, int y, int x)
-{
-
-    if (load_picture_info (picture))
-       draw_picture (y, x);
-
-}/* os_draw_picture */
-
-/*
- * os_peek_colour
- *
- * Return the colour of the pixel below the cursor. This is used
- * by V6 games to print text on top of pictures. The coulor need
- * not be in the standard set of Z-machine colours. To handle
- * this situation, Frotz extends the colour scheme: Values above
- * 15 (and below 256) may be used by the interface to refer to
- * non-standard colours. Of course, os_set_colour must be able to
- * deal with these colours. Interfaces which refer to characters
- * instead of pixels might return the current background colour
- * instead.
- *
- */
-
-int os_peek_colour (void)
-{
-
-    if (display >= _CGA_) {
-
-       asm mov ah,13
-       asm mov bh,0
-       asm mov cx,cursor_x
-       asm mov dx,cursor_y
-       asm int 0x10
-       asm mov ah,0
-
-       return _AX + 16;
-
-    } else return current_bg;
-
-}/* os_peek_colour */
-
-/*
- * os_picture_data
- *
- * Return true if the given picture is available. If so, write the
- * width and height of the picture into the appropriate variables.
- * Only when picture 0 is asked for, write the number of available
- * pictures and the release number instead.
- *
- */
-
-bool os_picture_data (int picture, int *height, int *width)
-{
-    bool avail;
-
-    if (picture == 0) {
-
-       avail = FALSE;
-
-       /* This is the special case mentioned above. In practice, only
-          the release number is used; and even this is only used by
-          the DOS version of "Zork Zero". Infocom's Amiga interpreter
-          could not handle this feature, and the Amiga version of the
-          story file does not use it. */
-
-       pic_height = gheader.images;
-       pic_width = gheader.version;
-
-    } else avail = load_picture_info (picture);
-
-    *height = pic_height;
-    *width = pic_width;
-
-    return avail;
-
-}/* os_picture_data */
diff --git a/bcsample.c b/bcsample.c
deleted file mode 100644 (file)
index bb50b23..0000000
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- * file "BCsample.c"
- *
- * Borland C front end, sound support
- *
- */
-
-#include <alloc.h>
-#include <dos.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include "frotz.h"
-#include "BCfrotz.h"
-
-#define SWAP_BYTES(v)  {_AX=v;asm xchg al,ah;v=_AX;}
-
-#define READ_DSP(v)    {while(!inportb(sound_adr+14)&0x80);v=inportb(sound_adr+10);}
-#define WRITE_DSP(v)   {while(inportb(sound_adr+12)&0x80);outportb(sound_adr+12,v);}
-
-extern void end_of_sound (void);
-
-static struct {
-    word prefix;
-    byte repeats;
-    byte base_note;
-    word frequency;
-    word unused;
-    word length;
-} sheader;
-
-static current_sample = 0;
-
-static void interrupt (*vect) (void) = NULL;
-
-static play_part = 0;
-static play_count = 0;
-
-static word sound_adr = 0;
-static word sound_irq = 0;
-static word sound_dma = 0;
-static word sound_int = 0;
-static word sound_ver = 0;
-
-static byte far *sample_data = NULL;
-
-static long sample_adr1 = 0;
-static long sample_adr2 = 0;
-static word sample_len1 = 0;
-static word sample_len2 = 0;
-
-/*
- * start_of_dma
- *
- * Start the DMA transfer to the sound board.
- *
- */
-
-static void start_of_dma (long address, unsigned length)
-{
-    static unsigned dma_page_port[] = {
-       0x87, 0x83, 0x81, 0x82
-    };
-
-    length--;
-
-    /* Set up DMA chip */
-
-    outportb (0x0a, 0x04 | sound_dma);
-    outportb (0x0c, 0x00);
-    outportb (0x0b, 0x48 | sound_dma);
-    outportb (2 * sound_dma, byte0 (address));
-    outportb (2 * sound_dma, byte1 (address));
-    outportb (dma_page_port[sound_dma], byte2 (address));
-    outportb (2 * sound_dma + 1, byte0 (length));
-    outportb (2 * sound_dma + 1, byte1 (length));
-    outportb (0x0a, sound_dma);
-
-    /* Play 8-bit mono sample */
-
-    WRITE_DSP (0x14)
-    WRITE_DSP (byte0 (length))
-    WRITE_DSP (byte1 (length))
-
-}/* start_of_dma */
-
-/*
- * end_of_dma
- *
- * This function is called when a hardware interrupt signals the
- * end of the current sound. We may have to play the second half
- * of the sound effect, or we may have to repeat it, or call the
- * end_of_sound function when we are finished.
- *
- */
-
-static void interrupt end_of_dma (void)
-{
-
-    /* Play the second half, play another cycle or finish */
-
-    if (play_part == 1 && sample_len2 != 0) {
-       play_part = 2;
-       start_of_dma (sample_adr2, sample_len2);
-    } else if (play_count == 255 || --play_count != 0) {
-       play_part = 1;
-       start_of_dma (sample_adr1, sample_len1);
-    } else {
-       play_part = 0;
-       end_of_sound ();
-    }
-
-    /* Tell interrupt controller(s) + sound board we are done */
-
-    outportb (0x20, 0x20);
-
-    if (sound_irq >= 8)
-       outportb (0xa0, 0x20);
-
-    inportb (sound_adr + 14);
-
-}/* end_of_dma */
-
-/*
- * init_sound
- *
- * Initialise the sound board and various sound related variables.
- *
- */
-
-bool init_sound (void)
-{
-    const char *settings = getenv ("BLASTER");
-    word irc_mask_port;
-
-    /* Read the IRQ, port address, DMA channel and SB version */
-
-    if ((settings = getenv ("BLASTER")) == NULL)
-       return FALSE;
-
-    sound_irq = dectoi (strchr (settings, 'I') + 1);
-    sound_adr = hextoi (strchr (settings, 'A') + 1);
-    sound_dma = dectoi (strchr (settings, 'D') + 1);
-    sound_ver = dectoi (strchr (settings, 'T') + 1);
-
-    /* Reset mixer chip and DSP */
-
-    outportb (sound_adr + 4, 0);
-    outportb (sound_adr + 5, 0);
-
-    outportb (sound_adr + 6, 1);
-    inportb (sound_adr + 6);
-    inportb (sound_adr + 6);
-    inportb (sound_adr + 6);
-    outportb (sound_adr + 6, 0);
-
-    /* Turn on speakers */
-
-    WRITE_DSP (0xd1)
-
-    /* Install the end_of_dma interrupt */
-
-    if (sound_irq < 8) {
-       irc_mask_port = 0x21;
-       sound_int = 0x08 + sound_irq;
-    } else {
-       irc_mask_port = 0xa1;
-       sound_int = 0x68 + sound_irq;
-    }
-
-    vect = getvect (sound_int); setvect (sound_int, end_of_dma);
-
-    /* Allocate 64KB RAM for sample data */
-
-    if ((sample_data = (byte far *) farmalloc (0x10000L)) == NULL)
-       return FALSE;
-
-    word0 (sample_adr1) = FP_OFF (sample_data) | (FP_SEG (sample_data) << 4);
-    word1 (sample_adr1) = FP_SEG (sample_data) >> 12;
-    word0 (sample_adr2) = 0;
-    word1 (sample_adr2) = word1 (sample_adr1) + 1;
-
-    /* Enable the end_of_dma interrupt */
-
-    outportb (0x20, 0x20);
-
-    if (sound_irq >= 8)
-       outportb (0xa0, 0x20);
-
-    outportb (irc_mask_port, inportb (irc_mask_port) & ~(1 << (sound_irq & 7)));
-
-    /* Indicate success */
-
-    return TRUE;
-
-}/* init_sound */
-
-/*
- * reset_sound
- *
- * Free resources allocated for playing samples.
- *
- */
-
-void reset_sound (void)
-{
-
-    os_stop_sample ();
-
-    if (sample_data != NULL)
-       { farfree (sample_data); sample_data = NULL; }
-    if (sound_adr != 0)
-       { setvect (sound_int, vect); sound_adr = 0; }
-
-}/* reset_sound */
-
-/*
- * os_beep
- *
- * Play a beep sound. Ideally, the sound should be high- (number == 1)
- * or low-pitched (number == 2).
- *
- */
-
-void os_beep (int number)
-{
-    word T = 888 * number;
-
-    outportb (0x43, 0xb6);
-    outportb (0x42, lo (T));
-    outportb (0x42, hi (T));
-    outportb (0x61, inportb (0x61) | 3);
-
-    delay (75);
-
-    outportb (0x61, inportb (0x61) & ~3);
-
-}/* os_beep */
-
-/*
- * os_prepare_sample
- *
- * Load the sample from the disk.
- *
- */
-
-void os_prepare_sample (int number)
-{
-
-    os_stop_sample ();
-
-    /* Exit if the sound board isn't set up properly */
-
-    if (sample_data == NULL)
-       return;
-    if (sound_adr == 0)
-       return;
-
-    /* Continue only if the desired sample is not already present */
-
-    if (current_sample != number) {
-
-       char sample_name[MAX_FILE_NAME + 1];
-       char numstr[2];
-       FILE *fp;
-
-       /* Build sample file name */
-
-       strcpy (sample_name, "sound\\");
-
-       numstr[0] = '0' + number / 10;
-       numstr[1] = '0' + number % 10;
-
-       strncat (sample_name, stripped_story_name, 6);
-       strncat (sample_name, numstr, 2);
-       strncat (sample_name, ".snd", 4);
-
-       /* Open sample file */
-
-       if ((fp = fopen (sample_name, "rb")) == NULL)
-           return;
-
-       /* Load header and sample data */
-
-       fread (&sheader, sizeof (sheader), 1, fp);
-
-       SWAP_BYTES (sheader.frequency)
-       SWAP_BYTES (sheader.length)
-
-       fread (sample_data, 1, sheader.length, fp);
-
-       sample_len1 = -word0 (sample_adr1);
-
-       if (sample_len1 > sheader.length || sample_len1 == 0)
-           sample_len1 = sheader.length;
-
-       sample_len2 = sheader.length - sample_len1;
-
-       WRITE_DSP (0x40)
-       WRITE_DSP (256 - 1000000L / sheader.frequency)
-
-       current_sample = number;
-
-       /* Close sample file */
-
-       fclose (fp);
-
-    }
-
-}/* os_prepare_sample */
-
-/*
- * os_start_sample
- *
- * Play the given sample at the given volume (ranging from 1 to 8 and
- * 255 meaning a default volume). The sound is played once or several
- * times in the background (255 meaning forever). The end_of_sound
- * function is called as soon as the sound finishes.
- *
- */
-
-void os_start_sample (int number, int volume, int repeats)
-{
-
-    os_stop_sample ();
-
-    /* Exit if the sound board isn't set up properly */
-
-    if (sample_data == NULL)
-       return;
-    if (sound_adr == 0)
-       return;
-
-    /* Load new sample */
-
-    os_prepare_sample (number);
-
-    /* Continue only if the sample's in memory now */
-
-    if (current_sample == number) {
-
-       play_count = repeats;
-
-       if (sound_ver < 6) {    /* Set up SB pro mixer chip */
-
-           volume = (volume != 255) ? 7 + volume : 15;
-
-           outportb (sound_adr + 4, 0x04);
-           outportb (sound_adr + 5, (volume << 4) | volume);
-           outportb (sound_adr + 4, 0x22);
-           outportb (sound_adr + 5, 0xff);
-
-       } else {                /* Set up SB16 mixer chip */
-
-           /* Many thanks to Linards Ticmanis for writing this part! */
-
-           volume = (volume != 255) ? 127 + 16 * volume : 255;
-
-           outportb (sound_adr + 4, 0x32);
-           outportb (sound_adr + 5, volume);
-           outportb (sound_adr + 4, 0x33);
-           outportb (sound_adr + 5, volume);
-           outportb (sound_adr + 4, 0x30);
-           outportb (sound_adr + 5, 0xff);
-           outportb (sound_adr + 4, 0x31);
-           outportb (sound_adr + 5, 0xff);
-
-       }
-
-       play_part = 1;
-       start_of_dma (sample_adr1, sample_len1);
-
-    }
-
-}/* os_start_sample */
-
-/*
- * os_stop_sample
- *
- * Turn off the current sample.
- *
- */
-
-void os_stop_sample (void)
-{
-
-    play_part = 0;
-
-    /* Exit if the sound board isn't set up properly */
-
-    if (sample_data == NULL)
-       return;
-    if (sound_adr == 0)
-       return;
-
-    /* Tell DSP to stop the current sample */
-
-    WRITE_DSP (0xd0)
-
-}/* os_stop_sample */
-
-/*
- * os_finish_with_sample
- *
- * Remove the current sample from memory (if any).
- *
- */
-
-void os_finish_with_sample (void)
-{
-
-    os_stop_sample ();         /* we keep 64KB allocated all the time */
-
-}/* os_finish_with_sample */
diff --git a/bcscreen.c b/bcscreen.c
deleted file mode 100644 (file)
index ed42e2e..0000000
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * file "BCscreen.c"
- *
- * Borland C front end, screen manipulation
- *
- */
-
-#include <dos.h>
-#include <mem.h>
-#include "frotz.h"
-#include "BCfrotz.h"
-
-/*
- * get_scrnptr
- *
- * Return a pointer to the given line in video RAM.
- *
- */
-
-byte far *get_scrnptr (int y)
-{
-
-    if (display == _CGA_)
-       return MK_FP ((y & 1) ? 0xba00 : 0xb800, 40 * (y & ~1));
-    else if (display == _MCGA_)
-       return MK_FP (0xa000, 320 * y);
-    else
-       return MK_FP (0xa000, 80 * y);
-
-}/* get_scrnptr */
-
-/*
- * clear_byte
- *
- * Helper function for clear_line.
- *
- */
-
-static void clear_byte (byte far *scrn, word mask)
-{
-
-    if (display == _CGA_)
-
-       if (scrn_attr == 0)
-           *scrn &= ~mask;
-       else
-           *scrn |= mask;
-
-    else {
-
-       outport (0x03ce, 0x0205);
-
-       outportb (0x03ce, 0x08);
-       outportb (0x03cf, mask);
-
-       asm les bx,scrn
-       asm mov al,es:[bx]
-       asm mov al,scrn_attr
-       asm mov es:[bx],al
-
-    }
-
-}/* clear_byte */
-
-/*
- * clear_line
- *
- * Helper function for os_erase_area.
- *
- */
-
-static void clear_line (int y, int left, int right)
-{
-    byte far *scrn = get_scrnptr (y);
-
-    if (display == _MCGA_)
-
-       _fmemset (scrn + left, scrn_attr, right - left + 1);
-
-    else {
-
-       word mask1 = 0x00ff >> (left & 7);
-       word mask2 = 0xff80 >> (right & 7);
-
-       int x = right / 8 - left / 8;
-
-       scrn += left / 8;
-
-       if (x == 0) {
-           mask1 &= mask2;
-           mask2 = 0;
-       }
-
-       /* Clear first byte */
-
-       clear_byte (scrn++, mask1);
-
-       /* Clear middle bytes */
-
-       if (display >= _EGA_)
-           outport (0x03ce, 0xff08);
-
-       while (--x > 0)
-           *scrn++ = scrn_attr;
-
-       /* Clear last byte */
-
-       clear_byte (scrn, mask2);
-
-    }
-
-}/* clear_line */
-
-/*
- * os_erase_area
- *
- * Fill a rectangular area of the screen with the current background
- * colour. Top left coordinates are (1,1). The cursor does not move.
- *
- */
-
-void os_erase_area (int top, int left, int bottom, int right)
-{
-    int y;
-
-    top--;
-    left--;
-    bottom--;
-    right--;
-
-    if (display <= _TEXT_) {
-
-       asm mov ax,0x0600
-       asm mov ch,byte ptr top
-       asm mov cl,byte ptr left
-       asm mov dh,byte ptr bottom
-       asm mov dl,byte ptr right
-       asm mov bh,scrn_attr
-       asm int 0x10
-
-    } else
-
-       for (y = top; y <= bottom; y++)
-           clear_line (y, left, right);
-
-}/* os_erase_area */
-
-/*
- * copy_byte
- *
- * Helper function for copy_line.
- *
- */
-
-static void copy_byte (byte far *scrn1, byte far *scrn2, byte mask)
-{
-    int i;
-
-    if (display == _CGA_)
-
-       *scrn1 = (*scrn1 & ~mask) | (*scrn2 & mask);
-
-    else {
-
-       outport (0x03ce, 0x0005);
-
-       outportb (0x03ce, 0x08);
-       outportb (0x03cf, mask);
-
-       outportb (0x03ce, 0x04);
-       outportb (0x03c4, 0x02);
-
-       for (i = 0; i < 4; i++) {
-
-           outportb (0x03cf, i);
-           outportb (0x03c5, 1 << i);
-
-           asm les bx,scrn2
-           asm mov ah,es:[bx]
-           asm les bx,scrn1
-           asm mov al,es:[bx]
-           asm mov es:[bx],ah
-
-       }
-
-       outportb (0x03c5, 0x0f);
-
-    }
-
-}/* copy_byte */
-
-/*
- * copy_line
- *
- * Helper function for os_scroll_area.
- *
- */
-
-static void copy_line (int y1, int y2, int left, int right)
-{
-    byte far *scrn1 = get_scrnptr (y1);
-    byte far *scrn2 = get_scrnptr (y2);
-
-    if (display == _MCGA_)
-
-       _fmemcpy (scrn1 + left, scrn2 + left, right - left + 1);
-
-    else {
-
-       word mask1 = 0x00ff >> (left & 7);
-       word mask2 = 0xff80 >> (right & 7);
-
-       int x = right / 8 - left / 8;
-
-       scrn1 += left / 8;
-       scrn2 += left / 8;
-
-       if (x == 0) {
-           mask1 &= mask2;
-           mask2 = 0;
-       }
-
-       /* Copy first byte */
-
-       copy_byte (scrn1++, scrn2++, mask1);
-
-       /* Copy middle bytes */
-
-       if (display >= _EGA_)
-           outport (0x03ce, 0x0105);
-
-       while (--x > 0)
-           *scrn1++ = *scrn2++;
-
-       /* Copy last byte */
-
-       copy_byte (scrn1, scrn2, mask2);
-
-    }
-
-}/* copy_line */
-
-/*
- * os_scroll_area
- *
- * Scroll a rectangular area of the screen up (units > 0) or down
- * (units < 0) and fill the empty space with the current background
- * colour. Top left coordinates are (1,1). The cursor stays put.
- *
- */
-
-void os_scroll_area (int top, int left, int bottom, int right, int units)
-{
-    int y;
-
-    top--;
-    left--;
-    bottom--;
-    right--;
-
-    if (display <= _TEXT_) {
-
-       asm mov ah,6
-       asm mov bx,units
-       asm cmp bx,0
-       asm jg scroll
-       asm mov ah,7
-       asm neg bx
-    scroll:
-       asm mov al,bl
-       asm mov ch,byte ptr top
-       asm mov cl,byte ptr left
-       asm mov dh,byte ptr bottom
-       asm mov dl,byte ptr right
-       asm mov bh,scrn_attr
-       asm int 0x10
-
-    } else
-
-       if (units > 0)
-
-           for (y = top; y <= bottom; y++)
-
-               if (y <= bottom - units)
-                   copy_line (y, y + units, left, right);
-               else
-                   clear_line (y, left, right);
-
-       else
-
-           for (y = bottom; y >= top; y--)
-
-               if (y >= top - units)
-                   copy_line (y, y + units, left, right);
-               else
-                   clear_line (y, left, right);
-
-}/* os_scroll_area */
diff --git a/bctext.c b/bctext.c
deleted file mode 100644 (file)
index 4ab9100..0000000
--- a/bctext.c
+++ /dev/null
@@ -1,842 +0,0 @@
-/*
- * file "BCtext.c"
- *
- * Borland C front end, text functions
- *
- */
-
-#include <alloc.h>
-#include <stdio.h>
-#include <string.h>
-#include <conio.h>
-#include <dos.h>
-#include "frotz.h"
-#include "BCfrotz.h"
-
-extern byte far *get_scrnptr (int);
-
-int current_bg = 0;
-int current_fg = 0;
-int current_style = 0;
-int current_font = 0;
-
-byte text_bg = 0;
-byte text_fg = 0;
-byte bg = 0;
-byte fg = 0;
-byte scrn_attr = 0;
-
-int cursor_x = 0;
-int cursor_y = 0;
-
-char latin1_to_ascii[] =
-    "   !  c  L  >o<Y  |  S  '' C  a  << not-  R  _  "
-    "^0 +/-^2 ^3 '  my P  .  ,  ^1 o  >> 1/41/23/4?  "
-    "A  A  A  A  Ae A  AE C  E  E  E  E  I  I  I  I  "
-    "Th N  O  O  O  O  Oe *  O  U  U  U  Ue Y  Th ss "
-    "a  a  a  a  ae a  ae c  e  e  e  e  i  i  i  i  "
-    "th n  o  o  o  o  oe :  o  u  u  u  ue y  th y  ";
-
-char latin1_to_ibm[] = {
-    0x20, 0xad, 0xbd, 0x9c, 0xcf, 0xbe, 0xdd, 0xf5,
-    0xf9, 0xb8, 0xa6, 0xae, 0xaa, 0xf0, 0xa9, 0xee,
-    0xf8, 0xf1, 0xfd, 0xfc, 0xef, 0xe6, 0xf4, 0xfa,
-    0xf7, 0xfb, 0xa7, 0xaf, 0xac, 0xab, 0xf3, 0xa8,
-    0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80,
-    0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8,
-    0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0x9e,
-    0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0xe1,
-    0x85, 0xa0, 0x83, 0xc6, 0x84, 0x86, 0x91, 0x87,
-    0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b,
-    0xd0, 0xa4, 0x95, 0xa2, 0x93, 0xe4, 0x94, 0xf6,
-    0x9b, 0x97, 0xa3, 0x96, 0x81, 0xec, 0xe7, 0x98
-};
-
-static byte far *graphics_font = NULL;
-static byte far *mcga_font = NULL;
-static byte far *mcga_width = NULL;
-static word far *serif_font = NULL;
-static byte far *serif_width = NULL;
-
-/*
- * get_font
- *
- * Helper function for load_fonts.
- *
- */
-
-static void far *get_chunk (FILE *fp, int num)
-{
-    static chunk_size[] = {
-       0x0300,
-       0x0360,
-       0x18c0,
-       0x18c0,
-       0x18c0,
-       0x18c0 };
-
-    void far *ptr;
-    long offs = 0;
-    int i;
-
-    ptr = farmalloc (chunk_size[num]);
-
-    for (i = 0; i <= num; i++)
-       offs -= chunk_size[i];
-
-    fseek (fp, offs, SEEK_END);
-
-    if (ptr == NULL || !fread (ptr, chunk_size[num], 1, fp))
-       os_fatal ("Cannot load fonts");
-
-    return ptr;
-
-}/* get_chunk */
-
-/*
- * load_fonts
- *
- * Load the proportional and graphics fonts. In the release version all
- * font data is appended to the end of the executable.
- *
- */
-
-void load_fonts (const char *progname)
-{
-    FILE *fp;
-
-    if ((fp = fopen (progname, "rb")) == NULL)
-       os_fatal ("Cannot load fonts");
-
-    if (display == _MCGA_) {
-
-       mcga_font = get_chunk (fp, 1);
-       mcga_width = (byte far *) mcga_font + 0x300;
-
-    } else graphics_font = get_chunk (fp, 0);
-
-    if (display == _AMIGA_ && user_font != 0) {
-
-       serif_font = get_chunk (fp, 1 + user_font);
-       serif_width = (byte far *) serif_font + 0x1800;
-
-    }
-
-    fclose (fp);
-
-}/* load_fonts */
-
-/*
- * os_font_data
- *
- * Return true if the given font is available. The font can be
- *
- *    TEXT_FONT
- *    PICTURE_FONT
- *    GRAPHICS_FONT
- *    FIXED_WIDTH_FONT
- *
- * The font size should be stored in "height" and "width". If the given
- * font is unavailable then these values must _not_ be changed.
- *
- */
-
-int os_font_data (int font, int *height, int *width)
-{
-
-    /* All fonts of this interface have the same size */
-
-    *height = h_font_height;
-    *width = h_font_width;
-
-    /* Not every font is available in every mode */
-
-    if (font == TEXT_FONT)
-       return TRUE;
-    if (font == GRAPHICS_FONT && (display == _CGA_ || display >= _EGA_))
-       return TRUE;
-    if (font == FIXED_WIDTH_FONT)
-       return TRUE;
-
-    /* Unavailable font */
-
-    return FALSE;
-
-}/* os_font_data */
-
-/*
- * switch_scrn_attr
- *
- * Parts of the screen are usually erased to background colour.  However,
- * for deleting text in the input routine it can be useful to erase to
- * the current text background colour.  The two colours can be different,
- * for example when the reverse text style is used.  This helper function
- * toggles between the two possible behaviours.
- *
- */
-
-void switch_scrn_attr (bool flag)
-{
-    byte scrn_bg;
-    byte scrn_fg;
-
-    if (flag) {
-       scrn_bg = text_bg;
-       scrn_fg = text_fg;
-    } else {
-       scrn_bg = bg;
-       scrn_fg = fg;
-    }
-
-    if (display <= _TEXT_)
-       scrn_attr = (scrn_bg << 4) | scrn_fg;
-    else if (display == _CGA_)
-       scrn_attr = (scrn_bg != BLACK) ? 0xff : 0x00;
-    else
-       scrn_attr = scrn_bg;
-
-}/* switch_scrn_attr */
-
-/*
- * adjust_style
- *
- * Set the current colours. This combines the current colour selection
- * and the current text style.
- *
- */
-
-static void adjust_style (void)
-{
-    static byte amiga_palette[][3] = {
-       { 0x00, 0x00, 0x00 },
-       { 0x2a, 0x00, 0x00 },
-       { 0x00, 0x2a, 0x00 },
-       { 0x3f, 0x3f, 0x15 },
-       { 0x00, 0x00, 0x2a },
-       { 0x2a, 0x00, 0x2a },
-       { 0x00, 0x2a, 0x2a },
-       { 0x3f, 0x3f, 0x3f },
-       { 0x30, 0x30, 0x30 },
-       { 0x20, 0x20, 0x20 },
-       { 0x10, 0x10, 0x10 },
-    };
-
-    static byte pc_colour[] = {
-       BLACK,
-       RED,
-       GREEN,
-       YELLOW,
-       BLUE,
-       MAGENTA,
-       CYAN,
-       WHITE,
-       DARKGRAY
-    };
-
-    static byte palette_bg = 0xff;
-    static byte palette_fg = 0xff;
-
-    fg = current_fg;
-    bg = current_bg;
-
-    /* V6 game, Amiga mode: Alter the palette registers if the colours
-       of window 0 have changed. DAC register #79 holds the foreground,
-       DAC register #64 the background colour. */
-
-    if (display == _AMIGA_ && h_version == V6 && cwin == 0) {
-
-       if (fg < 16 && fg != palette_fg) {
-
-           byte R = amiga_palette[fg - 2][0];
-           byte G = amiga_palette[fg - 2][1];
-           byte B = amiga_palette[fg - 2][2];
-
-           asm mov ax,0x1010
-           asm mov bx,79
-           asm mov dh,R
-           asm mov ch,G
-           asm mov cl,B
-           asm int 0x10
-
-           palette_fg = fg;
-
-       }
-
-       if (bg < 16 && bg != palette_bg) {
-
-           byte R = amiga_palette[bg - 2][0];
-           byte G = amiga_palette[bg - 2][1];
-           byte B = amiga_palette[bg - 2][2];
-
-           asm mov ax,0x1010
-           asm mov bx,64
-           asm mov dh,R
-           asm mov ch,G
-           asm mov cl,B
-           asm int 0x10
-
-           palette_bg = bg;
-
-       }
-
-    }
-
-    /* Handle colours */
-
-    if (fg < 16)
-
-       if (display == _MONO_)
-           fg = (fg == WHITE_COLOUR) ? LIGHTGRAY : BLACK;
-       else if (h_version == V6 && display == _AMIGA_)
-           fg = (palette_fg == fg) ? 15 : 0;
-       else
-           fg = pc_colour[fg - 2];
-
-    else fg -= 16;
-
-    if (bg < 16)
-
-       if (display == _MONO_)
-           bg = (bg == WHITE_COLOUR) ? LIGHTGRAY : BLACK;
-       else if (h_version == V6 && display == _AMIGA_)
-           bg = (palette_bg == bg) ? 0 : 15;
-       else
-           bg = pc_colour[bg - 2];
-
-    else bg -= 16;
-
-    /* Handle reverse text style */
-
-    if (current_style & REVERSE_STYLE) {
-       text_fg = (user_reverse_fg != -1) ? user_reverse_fg : bg;
-       text_bg = (user_reverse_bg != -1) ? user_reverse_bg : fg;
-    } else {
-       text_fg = fg;
-       text_bg = bg;
-    }
-
-    /* Handle emphasis style */
-
-    if (current_style & EMPHASIS_STYLE) {
-
-       if (display == _MONO_ && text_bg == BLACK)
-           text_fg = BLUE;     /* blue in monochrome mode is underlined */
-       if (display == _TEXT_)
-           text_fg = (user_emphasis != -1) ? user_emphasis : YELLOW;
-
-    }
-
-    /* Handle boldface style */
-
-    if (current_style & BOLDFACE_STYLE) {
-
-       if (display == _MONO_)
-           text_fg = WHITE;
-       if (display == _TEXT_)
-           text_fg ^= 8;
-
-    }
-
-    /* Set the screen attribute for scrolling and erasing */
-
-    switch_scrn_attr (FALSE);
-
-}/* adjust_style */
-
-/*
- * os_set_colour
- *
- * Set the foreground and background colours which can be:
- *
- *     DEFAULT_COLOUR
- *     BLACK_COLOUR
- *     RED_COLOUR
- *     GREEN_COLOUR
- *     YELLOW_COLOUR
- *     BLUE_COLOUR
- *     MAGENTA_COLOUR
- *     CYAN_COLOUR
- *     WHITE_COLOUR
- *
- *     MS-DOS 320 columns MCGA mode only:
- *
- *     GREY_COLOUR
- *
- *     Amiga only:
- *
- *     LIGHTGREY_COLOUR
- *     MEDIUMGREY_COLOUR
- *     DARKGREY_COLOUR
- *
- * There may be more colours in the range from 16 to 255; see the remarks
- * on os_peek_colour.
- *
- */
-
-void os_set_colour (int new_foreground, int new_background)
-{
-
-    current_fg = new_foreground;
-    current_bg = new_background;
-
-    /* Apply changes */
-
-    adjust_style ();
-
-}/* os_set_colour */
-
-/*
- * os_set_text_style
- *
- * Set the current text style. Following flags can be set:
- *
- *     REVERSE_STYLE
- *     BOLDFACE_STYLE
- *     EMPHASIS_STYLE (aka underline aka italics)
- *     FIXED_WIDTH_STYLE
- *
- */
-
-void os_set_text_style (int new_style)
-{
-
-    current_style = new_style;
-
-    /* Apply changes */
-
-    adjust_style ();
-
-}/* os_set_text_style */
-
-/*
- * os_set_font
- *
- * Set the font for text output. The interpreter takes care not to
- * choose fonts which aren't supported by the interface.
- *
- */
-
-void os_set_font (int new_font)
-{
-
-    current_font = new_font;
-
-}/* os_set_font */
-
-/*
- * write_pattern
- *
- * Helper function for drawing characters in EGA and Amiga mode.
- *
- */
-
-void write_pattern (byte far *screen, byte val, byte mask)
-{
-
-    if (mask != 0) {
-
-       if (display == _CGA_) {
-
-           if (text_bg == BLACK)
-               *screen &= ~mask;
-           if (text_bg == WHITE)
-               *screen |= mask;
-           if (text_fg != text_bg)
-               *screen ^= val;
-
-       } else if (display == _MCGA_) {
-
-           byte i;
-
-           for (i = 0x80; (mask & i) != 0; i >>= 1)
-               *screen++ = (val & i) ? text_fg : text_bg;
-
-       } else {
-
-           asm mov dx,0x03cf
-           asm mov al,mask
-           asm out dx,al
-           asm les bx,screen
-           asm mov ch,text_bg
-           asm mov al,es:[bx]
-           asm mov es:[bx],ch
-           asm mov al,val
-           asm out dx,al
-           asm mov ch,text_fg
-           asm mov al,es:[bx]
-           asm mov es:[bx],ch
-
-       }
-
-    }
-
-}/* write_pattern */
-
-/*
- * os_display_char
- *
- * Display a character of the current font using the current colours and
- * text style. The cursor moves to the next position. Printable codes are
- * all ASCII values from 32 to 126, ISO Latin-1 characters from 160 to
- * 255, ZC_GAP (gap between two sentences) and ZC_INDENT (paragraph
- * indentation). The screen should not be scrolled after printing to the
- * bottom right corner.
- *
- */
-
-void os_display_char (zchar c)
-{
-    int width = os_char_width (c);
-
-    /* Handle accented characters */
-
-    if (c >= ZC_LATIN1_MIN && (story_id != BEYOND_ZORK || (h_flags & GRAPHICS_FLAG)))
-
-       if (display == _CGA_ || display == _MCGA_) {
-
-           char *ptr = latin1_to_ascii + 3 * (c - ZC_LATIN1_MIN);
-
-           char c1 = *ptr++;
-           char c2 = *ptr++;
-           char c3 = *ptr++;
-
-           os_display_char (c1);
-
-           if (c2 != ' ')
-               os_display_char (c2);
-           if (c3 != ' ')
-               os_display_char (c3);
-
-           return;
-
-       } else if (display == _AMIGA_ && current_font == TEXT_FONT && !(current_style & FIXED_WIDTH_STYLE) && user_font != 0) {
-
-           if (c >= ZC_LATIN1_MIN)
-               c -= 32;
-
-       } else c = latin1_to_ibm[c - ZC_LATIN1_MIN];
-
-    /* Handle special indentations */
-
-    if (c == ZC_INDENT)
-       { os_display_char (' '); os_display_char (' '); os_display_char (' '); return; }
-    if (c == ZC_GAP)
-       { os_display_char (' '); os_display_char (' '); return; }
-
-    /* Display character */
-
-    if (display <= _TEXT_) {
-
-       asm mov ah,2
-       asm mov bh,0
-       asm mov dh,byte ptr cursor_y
-       asm mov dl,byte ptr cursor_x
-       asm int 0x10
-       asm mov ah,9
-       asm mov bh,0
-       asm mov bl,byte ptr text_bg
-       asm mov cl,4
-       asm shl bl,cl
-       asm or bl,byte ptr text_fg
-       asm mov cx,1
-       asm mov al,byte ptr c
-       asm int 0x10
-
-    } else {
-
-       void far *table;
-       word mask;
-       word val;
-       byte mask0;
-       byte mask1;
-       int align;
-       int underline;
-       int boldface;
-       int type;
-
-       int shift = (display != _MCGA_) ? cursor_x % 8 : 0;
-       int offset = (display != _MCGA_) ? cursor_x / 8 : cursor_x;
-
-       int i;
-
-       if (current_font == GRAPHICS_FONT) {
-           table = graphics_font + 8 * (c - 32);
-           mask = 0xff;
-           underline = -1;
-           boldface = -1;
-           align = 0;
-           type = 1;
-       } else if (display == _AMIGA_ && current_font == TEXT_FONT && !(current_style & FIXED_WIDTH_STYLE) && user_font != 0) {
-           table = serif_font + 16 * (c - 32);
-           mask = 0xffff << (16 - width);
-           underline = 14;
-           boldface = 1;
-           align = 0;
-           type = 2;
-       } else if (display == _CGA_) {
-           table = (byte far *) MK_FP (0xf000, 0xfa6e) + 8 * c;
-           mask = 0xff;
-           underline = 7;
-           boldface = (user_bold_typing != -1) ? 1 : -1;
-           align = 0;
-           type = 3;
-       } else if (display >= _EGA_) {
-           table = (byte far *) getvect (0x43) + h_font_height * c;
-           mask = 0xff;
-           underline = h_font_height - 1;
-           boldface = (user_bold_typing != -1) ? 1 : -1;
-           align = 0;
-           type = 3;
-       } else {
-           table = mcga_font + 8 * (c - 32);
-           mask = 0xff & (0xff << (8 - width));
-           underline = 7;
-           boldface = -1;
-           align = (width + 1 - mcga_width[c - 32]) / 2;
-           type = 3;
-       }
-
-       mask0 = mask >> shift;
-       mask1 = mask << (8 - shift);
-
-       if (!(current_style & BOLDFACE_STYLE))
-           boldface = -1;
-       if (!(current_style & EMPHASIS_STYLE))
-           underline = -1;
-
-       if (display >= _EGA_) {
-           outport (0x03ce, 0x0205);
-           outport (0x03ce, 0xff08);
-       }
-
-       for (i = 0; i < h_font_height; i++) {
-
-           byte far *screen = get_scrnptr (cursor_y + i) + offset;
-
-           if (type == 1)
-               val = *((byte far *) table + 8 * i / h_font_height);
-           if (type == 2)
-               val = *((word far *) table + i);
-           if (type == 3)
-               val = *((byte far *) table + i);
-
-           if (align != 0)
-               val >>= align;
-
-           if (boldface == 1)
-               val |= val >> 1;
-           if (underline == i)
-               val ^= mask;
-
-           if (type == 2)
-               write_pattern (screen++, val >> (8 + shift), mask >> (8 + shift));
-
-           write_pattern (screen + 0, val >> shift, mask0);
-           write_pattern (screen + 1, val << (8 - shift), mask1);
-
-       }
-
-    }
-
-    /* Move cursor to next position */
-
-    cursor_x += width;
-
-}/* os_display_char */
-
-/*
- * os_display_string
- *
- * Pass a string of characters to os_display_char.
- *
- */
-
-void os_display_string (const zchar *s)
-{
-
-    zchar c;
-
-    while ((c = *s++) != 0)
-
-       if (c == ZC_NEW_FONT || c == ZC_NEW_STYLE) {
-
-           int arg = *s++;
-
-           if (c == ZC_NEW_FONT)
-               os_set_font (arg);
-           if (c == ZC_NEW_STYLE)
-               os_set_text_style (arg);
-
-       } else os_display_char (c);
-
-}/* os_display_string */
-
-/*
- * os_char_width
- *
- * Return the width of the character in screen units.
- *
- */
-
-int os_char_width (zchar c)
-{
-
-    /* Handle accented characters */
-
-    if (c >= ZC_LATIN1_MIN && (story_id != BEYOND_ZORK || (h_flags & GRAPHICS_FLAG)))
-
-       if (display == _CGA_ || display == _MCGA_) {
-
-           const char *ptr = latin1_to_ascii + 3 * (c - ZC_LATIN1_MIN);
-
-           int width = 0;
-
-           char c1 = *ptr++;
-           char c2 = *ptr++;
-           char c3 = *ptr++;
-
-           width = os_char_width (c1);
-
-           if (c2 != ' ')
-               width += os_char_width (c2);
-           if (c3 != ' ')
-               width += os_char_width (c3);
-
-           return width;
-
-       } else if (display == _AMIGA_ && current_font == TEXT_FONT && !(current_style & FIXED_WIDTH_STYLE) && user_font != 0)
-
-           if (c >= ZC_LATIN1_MIN)
-               c -= 32;
-
-    /* Handle special indentations */
-
-    if (c == ZC_INDENT)
-       return 3 * os_char_width (' ');
-    if (c == ZC_GAP)
-       return 2 * os_char_width (' ');
-
-    /* Calculate width */
-
-    if (display <= _TEXT_)
-       return 1;
-    if (display == _CGA_)
-       return 8;
-    if (display == _EGA_)
-       return 8;
-
-    if (current_font == GRAPHICS_FONT)
-       return 8;
-    if (current_font == FIXED_WIDTH_FONT || (current_style & FIXED_WIDTH_STYLE) || (display == _AMIGA_ && user_font == 0))
-       return (display == _AMIGA_) ? 8 : 5;
-
-    if (display == _MCGA_)
-       return mcga_width[c - 32];
-    if (display == _AMIGA_)
-       return serif_width[c - 32] + ((current_style & BOLDFACE_STYLE) ? 1 : 0);
-
-    return 0;
-
-}/* os_char_width */
-
-/*
- * os_string_width
- *
- * Calculate the length of a word in screen units. Apart from letters,
- * the word may contain special codes:
- *
- *    ZC_NEW_STYLE - next character is a new text style
- *    ZC_NEW_FONT  - next character is a new font
- *
- */
-
-int os_string_width (const zchar *s)
-{
-    int width = 0;
-
-    int saved_font = current_font;
-    int saved_style = current_style;
-
-    zchar c;
-
-    while ((c = *s++) != 0)
-
-       if (c == ZC_NEW_STYLE || c == ZC_NEW_FONT) {
-
-           int arg = *s++;
-
-           if (c == ZC_NEW_FONT)
-               current_font = arg;
-           if (c == ZC_NEW_STYLE)
-               current_style = arg;
-
-       } else width += os_char_width (c);
-
-    current_font = saved_font;
-    current_style = saved_style;
-
-    return width;
-
-}/* os_string_width */
-
-/*
- * os_set_cursor
- *
- * Place the text cursor at the given coordinates. Top left is (1,1).
- *
- */
-
-void os_set_cursor (int y, int x)
-{
-
-    cursor_y = y - 1;
-    cursor_x = x - 1;
-
-}/* os_set_cursor */
-
-/*
- * os_more_prompt
- *
- * Display a MORE prompt, wait for a keypress and remove the MORE
- * prompt from the screen.
- *
- */
-
-void os_more_prompt (void)
-{
-    int saved_x;
-
-    /* Save text font and style */
-
-    int saved_font = current_font;
-    int saved_style = current_style;
-
-    /* Choose plain text style */
-
-    current_font = TEXT_FONT;
-    current_style = 0;
-
-    adjust_style ();
-
-    /* Wait until the user presses a key */
-
-    saved_x = cursor_x;
-
-    os_display_string ((zchar *) "[MORE]");
-    os_read_key (0, TRUE);
-
-    os_erase_area (cursor_y + 1,
-                  saved_x + 1,
-                  cursor_y + h_font_height,
-                  cursor_x + 1);
-
-    cursor_x = saved_x;
-
-    /* Restore text font and style */
-
-    current_font = saved_font;
-    current_style = saved_style;
-
-    adjust_style ();
-
-}/* os_more_prompt */
index d121f1bfdbcac192a0432a199683fc7d7aeeb98a..ea9b0019797e83939f5aaaec990cb6409b06366a 100644 (file)
--- a/fastmem.c
+++ b/fastmem.c
@@ -207,8 +207,26 @@ void init_memory (void)
 
     /* Open story file */
 
-    if ((story_fp = fopen (story_name, "rb")) == NULL)
-       os_fatal ("Cannot open story file");
+    if ((story_fp = fopen (story_name, "rb")) == NULL) {
+
+        char *path, *p, tmp[256];
+
+        /* Story file may be on INFOCOM_PATH, rather than current directory */
+        if ((path = getenv("INFOCOM_PATH")) == NULL)
+         os_fatal ("Cannot open story file");
+
+       p=strtok(path,":");
+       while (p != NULL) {
+           sprintf(tmp, "%s/%s", p, story_name);
+           if ((story_fp = fopen (tmp, "rb")) == NULL)
+             p = strtok(NULL, ":");
+           else
+             p = NULL;
+       }
+
+       if (story_fp == NULL)
+         os_fatal ("Cannot open story file");
+    }
 
     /* Allocate memory for story header */
 
diff --git a/font.dat b/font.dat
deleted file mode 100644 (file)
index fe9799c..0000000
Binary files a/font.dat and /dev/null differ
diff --git a/frotz.6 b/frotz.6
new file mode 100644 (file)
index 0000000..f5dd8fb
--- /dev/null
+++ b/frotz.6
@@ -0,0 +1,131 @@
+.\" -*- nroff -*-
+.TH FROTZ 6 2.32
+.SH NAME
+frotz \- interpreter for all Infocom games
+.SH SYNOPSIS
+.B frotz
+.RI [ options "] " file
+.SH DESCRIPTION
+.B Frotz
+is a Z-machine interpreter.  The Z-machine was a virtual machine designed
+by Infocom to run all of their text adventures.  It went through multiple
+revisions during the lifetime of the company, and two further revisions
+(V7 and V8) were created by Graham Nelson after the company's demise.
+The specification is now quite well documented; this version of frotz
+supports version 1.0.
+.SH OPTIONS
+.TP
+.B \-a
+Watch attribute setting.  Setting and clearing of attributes on objects
+will be noted in debugging messages.
+.TP
+.B \-A
+Watch attribute testing.  Every time the z-machine test an attribute value,
+the test and the result will be reported.
+.TP
+.B \-b N
+Sets the default background color.  N corresponds to one of the Z-machine
+colors, which are as follows:
+.br
+2  =  black   3 = red       4 = green    5 = yellow
+.br
+6  =  blue    7 = magenta   8 = cyan     9 = white
+.br
+If color support is disabled in the binary, or not
+available on your terminal, this option does nothing.
+.TP
+.B \-c N
+Sets the number of context lines used.  By default, after a ``[MORE]''
+prompt, and assuming there is enough output pending, frotz will allow all
+the currently visible lines to scroll off the screen before prompting
+again.  This switch specifies how many lines of text frotz will hold
+over and display at the top of the next screen.
+.TP
+.B \-d
+Disables color.  If frotz discovers that your terminal has color support,
+it will enable it by default.  This switch overrides that behavior.
+.TP
+.B \-f N
+Sets the default foreground color.  N is a number corresponding to one of
+the Z-machine colors, as listed above.  If color support is disabled in
+the binary, or not available on your terminal, this option does nothing.
+.TP
+.B \-h N
+Manually sets the screen height.  Though most curses libraries are intelligent
+enough to determine the current width from the terminal, it may sometimes
+be necessary to use this option to override the default.
+.TP
+.B \-i
+Ignore runtime errors.  Set this switch and Frotz no longer worries about
+anything the game tries to do. This can help you to get around fatal errors.
+.TP
+.B \-l N
+Sets the left margin, for those who might have specific formatting needs.
+.TP
+.B \-o
+Watch object movement.  This option enables debugging messages from the
+interpreter which detail the moving of objects in the object tree.
+.TP
+.B \-O
+Watch object location.  These debugging messages detail the locations of
+objects in the object tree.
+.TP
+.B \-p
+Plain ASCII output only.  This inhibits the output of accented letters
+and other characters from the Latin-1 character set, replacing them with
+reasonable alternatives.  This may be necessary on devices lacking these
+characters.
+.TP
+.B \-P
+Alter the piracy opcode.  The piracy opcode was never used by Infocom, and
+this switch is only useful for those who like to toy around with Z-code.
+.TP
+.B \-r N
+Sets the right margin.
+.TP
+.B \-s N
+Set the random number seed value.  The given seed value is used as the initial
+seed value on every restart. This is helpful for testing games like
+.B Curses
+which make random decisions before the first input (such that the hot
+key Alt\-S does not really help).
+.TP
+.B \-S N
+Set the transcript width.  By default your transscript files are formatted
+to a width of 80 columns per line, regardless of the current screen width.
+This switch allows you to change this setting. In particular, use \-S 0
+to deactivate automatic line splitting in transscript files.
+.TP
+.B \-t
+Sets the z-machine's
+.I Tandy bit,
+which may affect the behavior of certain Infocom games.  For example,
+Zork I pretends not to have sequals, and Witness has it's language
+toned down.
+.TP
+.B \-u N
+Sets the number of slots available for frotz's multiple undo hotkey (see
+below).  This defaults to twenty, which should be sufficient for most
+purposes.  Setting too high a number here may be dangerous on machines
+with limited memory.
+.TP
+.B \-w N
+Manually sets the screen width.  Again, this should not be necessary
+except in special circumstances.
+.TP
+.B \-x
+Expand the abbreviations "g","x", and "z" to "again", "examine", and "wait".
+This switch was made for old Infocom games that lack the common
+abbreviations introduced in later games. Use it with caution: A
+few games might use "g", "x" or "z" for different purposes.
+.SH ENVIRONMENT
+If the INFOCOM_PATH environment variable is defined, frotz will search
+those paths for game files.
+.SH "SEE ALSO"
+.SH CAVEATS
+.SH BUGS
+This program has no bugs.  no bugs.  no bugs.  no *WHAP* thank you.
+.SH AUTHOR
+.B Frotz
+was written by Stefan Jokisch in 1995-7.  The unix port (and this man
+page) were done by Galen Hazelwood.
diff --git a/frotz.h b/frotz.h
index 93a2c96b7d16f67725916071db9f6cea8d70f842..b62bc8389c6484c73b7b5121865e27f2e7aaf046 100644 (file)
--- a/frotz.h
+++ b/frotz.h
@@ -5,10 +5,16 @@
  *
  */
 
+/* Unfortunately, frotz's bool definition conflicts with that of curses.
+   But since no os_* function uses it, it's safe to let the frotz core see
+   this definition, but have the unix port see the curses version. */
+
+#ifndef __UNIX_PORT_FILE
 typedef int bool;
 
 #define TRUE 1
 #define FALSE 0
+#endif
 
 typedef unsigned char zbyte;
 typedef unsigned short zword;
diff --git a/ux_frotz.h b/ux_frotz.h
new file mode 100644 (file)
index 0000000..dc23873
--- /dev/null
@@ -0,0 +1,10 @@
+/*
+ * ux_frotz.h
+ *
+ * Unix interface, declarations
+ *
+ */
+
+extern int current_text_style;    /* ux_init */
+extern char unix_plain_ascii;     /* ux_init */
+extern int current_color;         /* ux_text */
diff --git a/ux_init.c b/ux_init.c
new file mode 100644 (file)
index 0000000..b2f528e
--- /dev/null
+++ b/ux_init.c
@@ -0,0 +1,385 @@
+/*
+ * ux_init.c
+ *
+ * Unix interface, initialisation
+ *
+ */
+
+#define __UNIX_PORT_FILE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <time.h>
+
+/* Prototypes for getopt */
+#ifdef USE_UNISTD_H
+#include <unistd.h>
+#elif USE_GETOPT_H
+#include <getopt.h>
+#else
+#ifndef USE_NOTHING
+extern int getopt(int, char **, char *);
+extern int optind, opterr;
+extern char *optarg;
+#endif
+#endif
+
+#ifdef USE_NCURSES_H
+#include <ncurses.h>
+#else
+#include <curses.h>
+#endif
+
+#include "frotz.h"
+#include "ux_frotz.h"
+
+#define INFORMATION "\
+\n\
+FROTZ V2.32 - interpreter for all Infocom games. Complies with standard\n\
+1.0 of Graham Nelson's specification. Written by Stefan Jokisch in 1995-7\n\
+\n\
+Syntax: frotz [options] story-file\n\
+\n\
+  -a   watch attribute setting  \t -l # left margin\n\
+  -A   watch attribute testing  \t -o   watch object movement\n\
+  -b # background colour        \t -O   watch object locating\n\
+                                \t -p   plain ASCII output only\n\
+                                \t -P   alter piracy opcode\n\
+  -c # context lines            \t -r # right margin\n\
+  -d   disable color            \t -s # random number seed value\n\
+                                \t -S # transscript width\n\
+  -f # foreground colour        \t -t   set Tandy bit\n\
+                                \t -u # slots for multiple undo\n\
+  -h # screen height            \t -w # screen width\n\
+  -i   ignore runtime errors    \t -x   expand abbreviations g/x/z\n"
+
+static int user_disable_color = 0;
+static int user_foreground_color = -1;
+static int user_background_color = -1;
+static int user_screen_width = -1;
+static int user_screen_height = -1;
+static int user_random_seed = -1;
+static int user_tandy_bit = 0;
+
+static int curses_active = 0; /* true if os_init_screen has been run */
+int current_text_style = 0;           /* Since I can't use attr_get, which
+                                     would make things easier, I need to
+                                     use the same hack the MS-DOS port
+                                     does...keep the current style in a
+                                     global variable. */
+char unix_plain_ascii = 0;    /* true if user wants to disable latin-1 */
+
+/*
+ * os_fatal
+ *
+ * Display error message and exit program.
+ *
+ */
+
+void os_fatal (const char *s)
+{
+
+    if (curses_active) {
+      os_display_string("\n\n");
+      beep();
+      os_set_text_style(BOLDFACE_STYLE);
+      os_display_string("Fatal error: ");
+      os_set_text_style(0);
+      os_display_string(s);
+      os_display_string("\n");
+      os_reset_screen();
+      exit(1);
+    }
+
+    fputs ("\nFatal error: ", stderr);
+    fputs (s, stderr);
+    fputs ("\n\n", stderr);
+
+    exit (1);
+
+}/* os_fatal */
+
+extern char script_name[];
+extern char command_name[];
+extern char save_name[];
+extern char auxilary_name[];
+
+/*
+ * os_process_arguments
+ *
+ * Handle command line switches. Some variables may be set to activate
+ * special features of Frotz:
+ *
+ *     option_attribute_assignment
+ *     option_attribute_testing
+ *     option_context_lines
+ *     option_object_locating
+ *     option_object_movement
+ *     option_left_margin
+ *     option_right_margin
+ *     option_ignore_errors
+ *     option_piracy
+ *     option_undo_slots
+ *     option_expand_abbreviations
+ *     option_script_cols
+ *
+ * The global pointer "story_name" is set to the story file name.
+ *
+ */
+
+void os_process_arguments (int argc, char *argv[])
+{
+    int c, i;
+    char stripped_story_name[MAX_FILE_NAME];
+    char *p = NULL;
+
+    /* Parse the options */
+
+    do {
+
+       c = getopt(argc, argv, "aAb:c:df:h:il:oOpPr:s:S:tu:w:x");
+
+       switch(c) {
+         case 'a': option_attribute_assignment = 1; break;
+         case 'A': option_attribute_testing = 1; break;
+         case 'b': user_background_color = atoi(optarg);
+                   if ((user_background_color < 2) ||
+                       (user_background_color > 9))
+                     user_background_color = -1;
+                   break;
+         case 'c': option_context_lines = atoi(optarg); break;
+         case 'd': user_disable_color = 1; break;
+         case 'f': user_foreground_color = atoi(optarg);
+                   if ((user_foreground_color < 2) ||
+                       (user_foreground_color > 9))
+                     user_foreground_color = -1;
+                   break;
+          case 'h': user_screen_height = atoi(optarg); break;
+         case 'i': option_ignore_errors = 1; break;
+         case 'l': option_left_margin = atoi(optarg); break;
+         case 'o': option_object_movement = 1; break;
+         case 'O': option_object_locating = 1; break;
+         case 'p': unix_plain_ascii = 1; break;
+         case 'P': option_piracy = 1; break;
+         case 'r': option_right_margin = atoi(optarg); break;
+         case 's': user_random_seed = atoi(optarg); break;
+         case 'S': option_script_cols = atoi(optarg); break;
+         case 't': user_tandy_bit = 1; break;
+         case 'u': option_undo_slots = atoi(optarg); break;
+         case 'w': user_screen_width = atoi(optarg); break;
+         case 'x': option_expand_abbreviations = 1; break;
+       }
+
+    } while (c != EOF);
+
+    if (optind != argc - 1) {
+       puts (INFORMATION);
+       exit (1);
+    }
+
+    /* Save the story file name */
+
+    story_name = argv[optind];
+
+    /* Strip path off the story file name */
+
+    p = story_name;
+
+    for (i = 0; story_name[i] != 0; i++)
+        if (story_name[i] == '/')
+         p = story_name + i + 1;
+
+    for (i = 0; p[i] != '\0' && p[i] != '.'; i++)
+        stripped_story_name[i] = p[i];
+    stripped_story_name[i] = '\0';
+
+    /* Create nice default file names */
+
+    strcpy (script_name, stripped_story_name);
+    strcpy (command_name, stripped_story_name);
+    strcpy (save_name, stripped_story_name);
+    strcpy (auxilary_name, stripped_story_name);
+
+    /* Don't forget the extensions */
+
+    strcat (script_name, ".scr");
+    strcat (command_name, ".rec");
+    strcat (save_name, ".sav");
+    strcat (auxilary_name, ".aux");
+
+}/* os_process_arguments */
+
+/*
+ * os_init_screen
+ *
+ * Initialise the IO interface. Prepare the screen and other devices
+ * (mouse, sound board). Set various OS depending story file header
+ * entries:
+ *
+ *     h_config (aka flags 1)
+ *     h_flags (aka flags 2)
+ *     h_screen_cols (aka screen width in characters)
+ *     h_screen_rows (aka screen height in lines)
+ *     h_screen_width
+ *     h_screen_height
+ *     h_font_height (defaults to 1)
+ *     h_font_width (defaults to 1)
+ *     h_default_foreground
+ *     h_default_background
+ *     h_interpreter_number
+ *     h_interpreter_version
+ *     h_user_name (optional; not used by any game)
+ *
+ * Finally, set reserve_mem to the amount of memory (in bytes) that
+ * should not be used for multiple undo and reserved for later use.
+ *
+ * (Unix has a non brain-damaged memory model which dosen't require such
+ *  ugly hacks, neener neener neener. --GH :)
+ *
+ */
+
+void os_init_screen (void)
+{
+
+    /*trace(TRACE_CALLS);*/
+    curses_active = 1;          /* Let os_fatal know curses is running */
+    initscr();                  /* Set up curses */
+    cbreak();                   /* Raw input mode, no line processing */
+    noecho();                   /* No input echo */
+    nonl();                     /* No newline translation */
+    intrflush(stdscr, TRUE);    /* Flush output on interrupt */
+    keypad(stdscr, TRUE);       /* Enable the keypad and function keys */
+    scrollok(stdscr, FALSE);    /* No scrolling unless explicitly asked for */
+
+    if (h_version == V3 && user_tandy_bit != 0)
+        h_config |= CONFIG_TANDY;
+
+    if (h_version == V3)
+       h_config |= CONFIG_SPLITSCREEN;
+
+    if (h_version >= V4)
+       h_config |= CONFIG_BOLDFACE | CONFIG_EMPHASIS | CONFIG_FIXED | CONFIG_TIMEDINPUT;
+
+#ifndef SOUND_SUPPORT
+    if (h_version >= V5)
+      h_flags &= ~(GRAPHICS_FLAG | SOUND_FLAG | MOUSE_FLAG | MENU_FLAG);
+
+    if (h_version == V3)
+       h_flags &= ~OLD_SOUND_FLAG;
+#else
+    if (h_version >= V5)
+      h_flags &= ~(GRAPHICS_FLAG | MOUSE_FLAG | MENU_FLAG);
+
+    if ((h_version >= 5) && (h_flags & SOUND_FLAG)) {
+      if (unix_init_sound())
+       h_flags |= SOUND_FLAG;
+      else
+       h_flags &= ~SOUND_FLAG;
+    }
+    if ((h_version == 3) && (h_flags & OLD_SOUND_FLAG)) {
+      if (unix_init_sound())
+       h_flags |= OLD_SOUND_FLAG;
+      else
+       h_flags &= ~OLD_SOUND_FLAG;
+    }
+#endif
+
+    if (h_version >= V5 && (h_flags & UNDO_FLAG))
+        if (option_undo_slots == 0)
+            h_flags &= ~UNDO_FLAG;
+
+    getmaxyx(stdscr, h_screen_rows, h_screen_cols);
+
+    if (user_screen_height != -1)
+       h_screen_rows = user_screen_height;
+    if (user_screen_width != -1)
+       h_screen_cols = user_screen_width;
+
+    h_screen_width = h_screen_cols;
+    h_screen_height = h_screen_rows;
+
+    h_font_width = 1;
+    h_font_height = 1;
+
+    h_interpreter_number = INTERP_DEC_20; /* We is a DECsystem-20 :) */
+    h_interpreter_version = 'F';
+
+#ifdef COLOR_SUPPORT
+    if (has_colors() && !user_disable_color) {
+        h_config |= CONFIG_COLOUR;
+        h_flags |= COLOUR_FLAG; /* FIXME: beyond zork handling? */
+        start_color();
+       if (user_foreground_color != -1)
+         h_default_foreground = user_foreground_color;
+       else
+         h_default_foreground = WHITE_COLOUR;
+       if (user_background_color != -1)
+         h_default_background = user_background_color;
+       else
+         h_default_background = BLUE_COLOUR;
+       os_set_colour(h_default_foreground, h_default_background);
+       bkgdset(current_color);
+       erase();
+       /*os_erase_area(1, 1, h_screen_rows, h_screen_cols);*/
+    }
+    else
+      if (h_flags & COLOUR_FLAG) h_flags &= ~COLOUR_FLAG;
+#endif
+
+    refresh();
+
+}/* os_init_screen */
+
+/*
+ * os_reset_screen
+ *
+ * Reset the screen before the program stops.
+ *
+ */
+
+void os_reset_screen (void)
+{
+
+    os_set_text_style(0);
+    os_display_string((zchar *) "[Hit any key to exit.]");
+    os_read_key(0, FALSE);
+    scrollok(stdscr, TRUE); scroll(stdscr);
+    refresh(); endwin();
+
+}/* os_reset_screen */
+
+/*
+ * os_restart_game
+ *
+ * This routine allows the interface to interfere with the process of
+ * restarting a game at various stages:
+ *
+ *     RESTART_BEGIN - restart has just begun
+ *     RESTART_WPROP_SET - window properties have been initialised
+ *     RESTART_END - restart is complete
+ *
+ */
+
+void os_restart_game (int stage)
+{
+}
+
+/*
+ * os_random_seed
+ *
+ * Return an appropriate random seed value in the range from 0 to
+ * 32767, possibly by using the current system time.
+ *
+ */
+
+int os_random_seed (void)
+{
+
+    if (user_random_seed == -1)
+      /* Use the epoch as seed value */
+      return (time(0) & 0x7fff);
+    else return user_random_seed;
+
+}/* os_random_seed */
diff --git a/ux_input.c b/ux_input.c
new file mode 100644 (file)
index 0000000..3676162
--- /dev/null
@@ -0,0 +1,489 @@
+/*
+ * ux_input.c
+ *
+ * Unix interface, input functions
+ *
+ */
+
+#define __UNIX_PORT_FILE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/time.h>
+
+#ifdef USE_NCURSES_H
+#include <ncurses.h>
+#else
+#include <curses.h>
+#endif
+
+#include "frotz.h"
+#include "ux_frotz.h"
+
+static struct timeval global_timeout;
+
+#define MAX_HISTORY 20
+static char *history_buffer[MAX_HISTORY];
+static short history_pointer = 0; /* Pointer to next available slot */
+static short history_frame = 0; /* Pointer to what the user's looking at */
+
+extern bool is_terminator (zchar);
+extern void read_string (int, zchar *);
+extern int completion (const zchar *, zchar *);
+
+/*
+ * unix_set_global_timeout
+ *
+ * This sets up a time structure to determine when unix_read_char should
+ * return zero (representing input timeout).  When current system time
+ * equals global_timeout, boom.
+ *
+ */
+
+static void unix_set_global_timeout(int timeout)
+{
+    if (!timeout) global_timeout.tv_sec = 0;
+    else {
+        gettimeofday(&global_timeout, NULL);
+        global_timeout.tv_sec += (timeout/10);
+        global_timeout.tv_usec += ((timeout%10)*100000);
+        if (global_timeout.tv_usec > 999999) {
+          global_timeout.tv_sec++;
+          global_timeout.tv_usec -= 1000000;
+        }
+    }
+}
+
+/*
+ * unix_read_char
+ *
+ * This uses the curses getch() routine to get the next character typed,
+ * and returns it unless the global timeout is reached.  It returns values
+ * which the standard considers to be legal input, and also returns editing
+ * and frotz hot keys.  If called with a non-zero flag, it will also return
+ * line-editing keys like INSERT, etc,
+ *
+ */
+
+static int unix_read_char(int flag)
+{
+    int c;
+    struct timeval ctime;
+
+    while(1) {
+      /* Timed keyboard input.  Crude but functional. */
+      if (global_timeout.tv_sec) {
+         nodelay(stdscr, TRUE);
+         do {
+              c = getch();
+              if (c == ERR) {
+                  gettimeofday(&ctime, NULL);
+                  if ((ctime.tv_sec >= global_timeout.tv_sec) &&
+                      (ctime.tv_usec >= global_timeout.tv_usec)) {
+                      nodelay(stdscr, FALSE);
+                      return 0;
+                  }
+              }
+          } while (c == ERR);
+          nodelay(stdscr, FALSE);
+      }
+      /* The easy way. */
+      else c = getch();
+
+      /* Catch 98% of all input right here... */
+      if ( ((c >= 32) && (c <= 126)) || (c == 13) || (c == 8))
+        return c;
+
+      /* ...and the other 2% makes up 98% of the code. :( */
+      switch(c) {
+        /* Lucian P. Smith reports KEY_ENTER on Irix 5.3.  10 has never
+           been reported, but I'm leaving it in just in case. */
+        case 10: case KEY_ENTER: return 13;
+        /* I've seen KEY_BACKSPACE returned on some terminals. */
+        case KEY_BACKSPACE: return 8;
+        /* On seven-bit connections, "Alt-Foo" is returned as an escape
+           followed by the ASCII value of the letter.  We have to decide
+           here whether to return a single escape or a frotz hot key. */
+        case 27: nodelay(stdscr, TRUE); c = getch(); nodelay(stdscr, FALSE);
+                 if (c == ERR) return 27;
+                 switch(c) {
+                   case 112: return ZC_HKEY_PLAYBACK; /* Alt-P */
+                   case 114: return ZC_HKEY_RECORD; /* Alt-R */
+                   case 115: return ZC_HKEY_SEED; /* Alt-S */
+                   case 117: return ZC_HKEY_UNDO; /* Alt-U */
+                   case 110: return ZC_HKEY_RESTART; /* Alt-N */
+                   case 120: return ZC_HKEY_QUIT; /* Alt-X */
+                  case 100: return ZC_HKEY_DEBUG; /* Alt-D */
+                  case 104: return ZC_HKEY_HELP; /* Alt-H */
+                   default: return 27;
+                 }
+                 break;
+       /* The standard function key block. */
+        case KEY_UP: return 129;
+        case KEY_DOWN: return 130;
+        case KEY_LEFT: return 131;
+        case KEY_RIGHT: return 132;
+        case KEY_F(1): return 133; case KEY_F(2): return 134;
+        case KEY_F(3): return 135; case KEY_F(4): return 136;
+        case KEY_F(5): return 137; case KEY_F(6): return 138;
+        case KEY_F(7): return 139; case KEY_F(8): return 140;
+        case KEY_F(9): return 141; case KEY_F(10): return 142;
+        case KEY_F(11): return 143; case KEY_F(12): return 144;
+        /* Curses can't differentiate keypad numbers from cursor keys. Damn. */
+        /* This will catch the alt-keys on 8-bit clean input streams... */
+        case 240: return ZC_HKEY_PLAYBACK; /* Alt-P */
+        case 242: return ZC_HKEY_RECORD; /* Alt-R */
+        case 243: return ZC_HKEY_SEED; /* Alt-S */
+        case 245: return ZC_HKEY_UNDO; /* Alt-U */
+        case 238: return ZC_HKEY_RESTART; /* Alt-N */
+        case 248: return ZC_HKEY_QUIT; /* Alt-X */
+        case 228: return ZC_HKEY_DEBUG; /* Alt-D */
+        case 232: return ZC_HKEY_HELP; /* Alt-H */
+#ifdef EMACS_EDITING
+        case 21: return 27; /* Ctrl-U, erase line */
+        case 2: return 131; /* Ctrl-B, left arrow  */
+        case 6: return 132; /* Ctrl-F, right arrow */
+        case 16: return 129; /* Ctrl-P, up arrow */
+        case 14: return 130; /* Ctrl-N, down arrow */
+        case 1: c = KEY_HOME; break; /* Ctrl-A */
+        case 4: c = 127; break; /* Ctrl-D */
+        case 5: c = KEY_END; break; /* Ctrl-E */
+#endif
+       default: break; /* Who knows? */
+      }
+
+      /* Finally, if we're in full line mode (os_read_line), we might return
+         codes which aren't legal Z-machine keys but are used by the editor. */
+      if (flag) return c;
+    }
+}
+
+
+/*
+ * unix_add_to_history
+ *
+ * Add the given string to the next available history buffer slot.  Commandeer
+ * that slot if necessary using realloc.
+ *
+ */
+
+static void unix_add_to_history(zchar *str)
+{
+
+    if (history_buffer[history_pointer] == NULL)
+      history_buffer[history_pointer] = (char *) malloc(strlen(str) + 1);
+    else
+      history_buffer[history_pointer] =
+        (char *) realloc(history_buffer[history_pointer], strlen(str) + 1);
+    strcpy(history_buffer[history_pointer], str);
+    history_pointer = ((history_pointer + 1) % MAX_HISTORY);
+    history_frame = history_pointer; /* Reset user frame after each line */
+}
+
+/*
+ * unix_history_back
+ *
+ * Copy last available string to str, if possible.  Return 1 if successful.
+ *
+ */
+
+static int unix_history_back(zchar *str)
+{
+
+    history_frame--; if (history_frame==-1) history_frame = (MAX_HISTORY - 1);
+    if ((history_frame == history_pointer) ||
+        (history_buffer[history_frame] == NULL)) {
+        beep(); history_frame = (history_frame + 1) % MAX_HISTORY;
+        return 0;
+    }
+    strcpy(str, history_buffer[history_frame]);
+    return 1;
+
+}
+
+/*
+ * unix_history_forward
+ *
+ * Opposite of unix_history_back, and works in the same way.
+ *
+ */
+
+static int unix_history_forward(zchar *str)
+{
+
+    history_frame = (history_frame + 1) % MAX_HISTORY;
+    if ((history_frame == history_pointer) ||
+        (history_buffer[history_frame] == NULL)) {
+        beep(); history_frame--; if (history_frame == -1) history_frame =
+                                                            (MAX_HISTORY - 1);
+        return 0;
+    }
+    strcpy(str, history_buffer[history_frame]);
+    return 1;
+
+}
+
+/*
+ * os_read_line
+ *
+ * Read a line of input from the keyboard into a buffer. The buffer
+ * may already be primed with some text. In this case, the "initial"
+ * text is already displayed on the screen. After the input action
+ * is complete, the function returns with the terminating key value.
+ * The length of the input should not exceed "max" characters plus
+ * an extra 0 terminator.
+ *
+ * Terminating keys are the return key (13) and all function keys
+ * (see the Specification of the Z-machine) which are accepted by
+ * the is_terminator function. Mouse clicks behave like function
+ * keys except that the mouse position is stored in global variables
+ * "mouse_x" and "mouse_y" (top left coordinates are (1,1)).
+ *
+ * Furthermore, Frotz introduces some special terminating keys:
+ *
+ *     ZC_HKEY_KEY_PLAYBACK (Alt-P)
+ *     ZC_HKEY_RECORD (Alt-R)
+ *     ZC_HKEY_SEED (Alt-S)
+ *     ZC_HKEY_UNDO (Alt-U)
+ *     ZC_HKEY_RESTART (Alt-N, "new game")
+ *     ZC_HKEY_QUIT (Alt-X, "exit game")
+ *     ZC_HKEY_DEBUGGING (Alt-D)
+ *     ZC_HKEY_HELP (Alt-H)
+ *
+ * If the timeout argument is not zero, the input gets interrupted
+ * after timeout/10 seconds (and the return value is 0).
+ *
+ * The complete input line including the cursor must fit in "width"
+ * screen units.
+ *
+ * The function may be called once again to continue after timeouts,
+ * misplaced mouse clicks or hot keys. In this case the "continued"
+ * flag will be set. This information can be useful if the interface
+ * implements input line history.
+ *
+ * The screen is not scrolled after the return key was pressed. The
+ * cursor is at the end of the input line when the function returns.
+ *
+ * Since Inform 2.2 the helper function "completion" can be called
+ * to implement word completion (similar to tcsh under Unix).
+ *
+ */
+
+zchar os_read_line (int max, zchar *buf, int timeout, int width, int continued)
+{
+    int ch, scrpos, pos, y, x;
+    char insert_flag = 1;  /* Insert mode is now default */
+
+    scrpos = pos = strlen((char *) buf);
+
+    if (!continued)
+      history_frame = history_pointer;  /* Reset user's history view */
+
+    unix_set_global_timeout(timeout);
+
+    getyx(stdscr, y, x);
+
+    do {
+        refresh(); /* Shouldn't be necessary, but is, to print spaces */
+
+        ch = unix_read_char(1);
+
+       /* Backspace */
+        if ((ch == 8) && (scrpos)) {
+            mvdelch(y, --x);
+            pos--; scrpos--;
+            if (scrpos != pos)
+              memmove(&(buf[scrpos]), &(buf[scrpos+1]), pos-scrpos);
+        }
+
+       /* Delete */
+       if (((ch == 127) || (ch == KEY_DC)) && (scrpos < pos)) {
+           delch(); pos--;
+           memmove(&(buf[scrpos]), &(buf[scrpos+1]), pos-scrpos);
+       }
+
+        /* Left key */
+        if ((ch == 131) && (scrpos)) {
+            scrpos--;
+            move(y, --x);
+        }
+        /* Right key */
+        if ((ch == 132) && (scrpos < pos)) {
+            scrpos++;
+            move(y, ++x);
+        }
+
+        /* Home */
+        if (ch == KEY_HOME) {
+            x -= scrpos; scrpos = 0;
+            move(y, x);
+        }
+        /* End */
+        if (ch == KEY_END) {
+            x += (pos - scrpos); scrpos = pos;
+            move(y,x);
+        }
+
+        /* Insert */
+        if (ch == KEY_IC)
+          insert_flag = (insert_flag ? 0 : 1);
+
+        /* Up and down keys */
+        if (ch == 129) {
+            if (unix_history_back(buf)) {
+              x -= scrpos;
+              move(y, x);
+              while (scrpos) {addch(' '); scrpos--;}
+              move(y, x);
+              addstr(buf);
+              scrpos = pos = strlen(buf);
+              x += scrpos;
+            }
+        }
+        if (ch == 130) {
+            if (unix_history_forward(buf)) {
+              x -= scrpos;
+              move(y, x);
+              while(scrpos) {addch(' '); scrpos--;}
+              move(y, x);
+              addstr(buf);
+              scrpos = pos = strlen(buf);
+              x += scrpos;
+            }
+        }
+
+       /* Page up/down (passthrough as up/down arrows for beyond zork) */
+        if (ch == KEY_PPAGE) ch = 129;
+        if (ch == KEY_NPAGE) ch = 130;
+
+        /* Escape */
+        if (ch == 27) {
+           /* Move cursor to end of buffer first */
+            x += (pos - scrpos); scrpos = pos; move(y,x);
+            x -= scrpos;
+            move(y, x);
+            while (scrpos) {addch(' '); scrpos--;}
+            move(y, x); pos = 0;
+        }
+
+       /* Tab */
+       if ((ch == 9) && (scrpos == pos)) {
+           int status;
+           zchar extension[10];
+
+           status = completion(buf, extension);
+           if (status != 2) {
+             addstr(extension);
+             strcpy(&buf[pos], extension);
+             pos += strlen(extension); scrpos += strlen(extension);
+           }
+           if (status) beep();
+       }
+
+        /* ASCII printable */
+        if ((ch >= 32) && (ch <= 126)) {
+            if (pos == scrpos) {
+                /* Append to end of buffer */
+                if ((pos < max) && (pos < width)) {
+                    buf[pos++] = (char) ch;
+                    addch(ch);
+                    scrpos++; x++;
+                } else beep();
+            }
+            else {
+                /* Insert/overwrite in middle of buffer */
+                if (insert_flag) {
+                    memmove(&buf[scrpos+1], &buf[scrpos], pos-scrpos);
+                    buf[scrpos++] = (char) ch;
+                    insch(ch);
+                    pos++; x++; move(y, x);
+                } else {
+                    buf[scrpos++] = (char) ch;
+                    addch(ch);
+                    x++;
+                }
+            }
+        }
+    } while (!is_terminator(ch));
+
+    buf[pos] = '\0';
+    if (ch == 13) unix_add_to_history(buf);
+    return ch;
+
+}/* os_read_line */
+
+/*
+ * os_read_key
+ *
+ * Read a single character from the keyboard (or a mouse click) and
+ * return it. Input aborts after timeout/10 seconds.
+ *
+ */
+
+zchar os_read_key (int timeout, int cursor)
+{
+    zchar c;
+
+    refresh();
+    if (!cursor) curs_set(0);
+
+    unix_set_global_timeout(timeout);
+    c = (zchar) unix_read_char(0);
+
+    if (!cursor) curs_set(1);
+    return c;
+
+}/* os_read_key */
+
+/*
+ * os_read_file_name
+ *
+ * Return the name of a file. Flag can be one of:
+ *
+ *    FILE_SAVE     - Save game file
+ *    FILE_RESTORE  - Restore game file
+ *    FILE_SCRIPT   - Transscript file
+ *    FILE_RECORD   - Command file for recording
+ *    FILE_PLAYBACK - Command file for playback
+ *    FILE_SAVE_AUX - Save auxilary ("preferred settings") file
+ *    FILE_LOAD_AUX - Load auxilary ("preferred settings") file
+ *
+ * The length of the file name is limited by MAX_FILE_NAME. Ideally
+ * an interpreter should open a file requester to ask for the file
+ * name. If it is unable to do that then this function should call
+ * print_string and read_string to ask for a file name.
+ *
+ */
+
+int os_read_file_name (char *file_name, const char *default_name, int flag)
+{
+
+    int saved_replay = istream_replay;
+    int saved_record = ostream_record;
+
+    /* Turn off playback and recording temporarily */
+
+    istream_replay = 0;
+    ostream_record = 0;
+
+    print_string ("Enter a file name.\nDefault is \"");
+    print_string (default_name);
+    print_string ("\": ");
+
+    read_string (MAX_FILE_NAME, file_name);
+
+    /* Use the default name if nothing was typed */
+
+    if (file_name[0] == 0)
+        strcpy (file_name, default_name);
+
+    /* Restore state of playback and recording */
+
+    istream_replay = saved_replay;
+    ostream_record = saved_record;
+
+    return 1;
+
+} /* os_read_file_name */
diff --git a/ux_pic.c b/ux_pic.c
new file mode 100644 (file)
index 0000000..39e343b
--- /dev/null
+++ b/ux_pic.c
@@ -0,0 +1,61 @@
+/*
+ * ux_pic.c
+ *
+ * Unix interface, stubs for picture functions
+ *
+ */
+
+/*
+ * os_draw_picture
+ *
+ * Display a picture at the given coordinates. Top left is (1,1).
+ *
+ */
+
+void os_draw_picture (int picture, int y, int x)
+{
+
+    /* Not Implemented */
+
+}/* os_draw_picture */
+
+/*
+ * os_peek_colour
+ *
+ * Return the colour of the pixel below the cursor. This is used
+ * by V6 games to print text on top of pictures. The coulor need
+ * not be in the standard set of Z-machine colours. To handle
+ * this situation, Frotz extends the colour scheme: Values above
+ * 15 (and below 256) may be used by the interface to refer to
+ * non-standard colours. Of course, os_set_colour must be able to
+ * deal with these colours. Interfaces which refer to characters
+ * instead of pixels might return the current background colour
+ * instead.
+ *
+ */
+
+int os_peek_colour (void)
+{
+
+    /* Not Implemented */
+    return 0;
+
+}/* os_peek_colour */
+
+/*
+ * os_picture_data
+ *
+ * Return true if the given picture is available. If so, write the
+ * width and height of the picture into the appropriate variables.
+ * Only when picture 0 is asked for, write the number of available
+ * pictures and the release number instead.
+ *
+ */
+
+int os_picture_data (int picture, int *height, int *width)
+{
+
+    /* Not implemented */
+    return 0;
+
+}/* os_picture_data */
diff --git a/ux_sample.c b/ux_sample.c
new file mode 100644 (file)
index 0000000..1fa1871
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * ux_sample.c
+ *
+ * Unix interface, sound support
+ *
+ */
+
+#define __UNIX_PORT_FILE
+
+#ifdef USE_NCURSES_H
+#include <ncurses.h>
+#else
+#include <curses.h>
+#endif
+
+#include "frotz.h"
+#include "ux_frotz.h"
+
+/*
+ * os_beep
+ *
+ * Play a beep sound. Ideally, the sound should be high- (number == 1)
+ * or low-pitched (number == 2).
+ *
+ */
+
+void os_beep (int number)
+{
+
+    beep();
+
+}/* os_beep */
+
+/*
+ * os_prepare_sample
+ *
+ * Load the sample from the disk.
+ *
+ */
+
+void os_prepare_sample (int number)
+{
+
+    /* Not implemented */
+
+}/* os_prepare_sample */
+
+/*
+ * os_start_sample
+ *
+ * Play the given sample at the given volume (ranging from 1 to 8 and
+ * 255 meaning a default volume). The sound is played once or several
+ * times in the background (255 meaning forever). In Z-code 3 the
+ * repeats value is always 0 and the number of repeats is taken from
+ * the sound file itself. The end_of_sound function is called as soon
+ * as the sound finishes.
+ *
+ */
+
+void os_start_sample (int number, int volume, int repeats)
+{
+
+    /* Not implemented */
+
+}/* os_start_sample */
+
+/*
+ * os_stop_sample
+ *
+ * Turn off the current sample.
+ *
+ */
+
+void os_stop_sample (void)
+{
+
+    /* Not implemented */
+
+}/* os_stop_sample */
+
+/*
+ * os_finish_with_sample
+ *
+ * Remove the current sample from memory (if any).
+ *
+ */
+
+void os_finish_with_sample (void)
+{
+
+    /* Not implemented */
+
+}/* os_finish_with_sample */
+
+/*
+ * os_wait_sample
+ *
+ * Stop repeating the current sample and wait until it finishes.
+ *
+ */
+
+void os_wait_sample (void)
+{
+
+    /* Not implemented */
+
+}/* os_wait_sample */
diff --git a/ux_screen.c b/ux_screen.c
new file mode 100644 (file)
index 0000000..879cd28
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * ux_screen.c
+ *
+ * Unix interface, screen manipulation
+ *
+ */
+
+#define __UNIX_PORT_FILE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef USE_NCURSES_H
+#include <ncurses.h>
+#else
+#include <curses.h>
+#endif
+
+#include "frotz.h"
+#include "ux_frotz.h"
+
+/*
+ * os_erase_area
+ *
+ * Fill a rectangular area of the screen with the current background
+ * colour. Top left coordinates are (1,1). The cursor does not move.
+ *
+ */
+
+void os_erase_area (int top, int left, int bottom, int right)
+{
+    int y, x, i, j;
+    int saved_style;
+
+    /* Catch the most common situation and do things the easy way */
+    if ((top == 1) && (bottom == h_screen_rows) &&
+       (left == 1) && (right == h_screen_cols))
+      erase();
+    else {
+        /* Sigh... */
+        getyx(stdscr, y, x);
+       saved_style = current_text_style;
+       os_set_text_style(0);
+       top--; left--; bottom--; right--;
+       for (i = top; i <= bottom; i++) {
+         move(i, left);
+         for (j = left; j <= right; j++)
+           addch(' ');
+       }
+
+       os_set_text_style(saved_style);
+       move(y, x);
+    }
+
+    refresh();
+
+}/* os_erase_area */
+
+/*
+ * os_scroll_area
+ *
+ * Scroll a rectangular area of the screen up (units > 0) or down
+ * (units < 0) and fill the empty space with the current background
+ * colour. Top left coordinates are (1,1). The cursor stays put.
+ *
+ */
+
+static int old_scroll_top = 0;
+static int old_scroll_bottom = 0;
+
+void os_scroll_area (int top, int left, int bottom, int right, int units)
+{
+#ifdef COLOR_SUPPORT
+    int y, x, i;
+    int saved_style;
+#endif
+
+    if (units != 1) os_fatal("Can't Happen (os_scroll_area)"); /* FIXME */
+
+    if (!((old_scroll_top == top) && (old_scroll_bottom == bottom))) {
+        old_scroll_top = top; old_scroll_bottom = bottom;
+        setscrreg(--top, --bottom);
+    }
+    scrollok(stdscr, TRUE);
+    scroll(stdscr);
+    scrollok(stdscr, FALSE);
+
+#ifdef COLOR_SUPPORT
+    if (h_flags & COLOUR_FLAG) {
+        getyx(stdscr, y, x);
+       move(old_scroll_bottom, 0);
+       saved_style = current_text_style;
+       os_set_text_style(0);
+       for (i = 0; i <= right; i++) addch(' ');
+       os_set_text_style(saved_style);
+       move(y, x);
+    }
+#endif
+
+}/* os_scroll_area */
diff --git a/ux_text.c b/ux_text.c
new file mode 100644 (file)
index 0000000..ccb933c
--- /dev/null
+++ b/ux_text.c
@@ -0,0 +1,354 @@
+/*
+ * ux_text.c
+ *
+ * Unix interface, text functions
+ *
+ */
+
+#define __UNIX_PORT_FILE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef USE_NCURSES_H
+#include <ncurses.h>
+#else
+#include <curses.h>
+#endif
+
+#include "frotz.h"
+#include "ux_frotz.h"
+
+#ifdef COLOR_SUPPORT
+int current_color = 0;
+#endif
+
+static char latin1_to_ascii[] =
+    "   !  c  L  >o<Y  |  S  '' C  a  << not-  R  _  "
+    "^0 +/-^2 ^3 '  my P  .  ,  ^1 o  >> 1/41/23/4?  "
+    "A  A  A  A  Ae A  AE C  E  E  E  E  I  I  I  I  "
+    "Th N  O  O  O  O  Oe *  O  U  U  U  Ue Y  Th ss "
+    "a  a  a  a  ae a  ae c  e  e  e  e  i  i  i  i  "
+    "th n  o  o  o  o  oe :  o  u  u  u  ue y  th y  ";
+/*
+ * os_font_data
+ *
+ * Return true if the given font is available. The font can be
+ *
+ *    TEXT_FONT
+ *    PICTURE_FONT
+ *    GRAPHICS_FONT
+ *    FIXED_WIDTH_FONT
+ *
+ * The font size should be stored in "height" and "width". If
+ * the given font is unavailable then these values must _not_
+ * be changed.
+ *
+ */
+
+int os_font_data (int font, int *height, int *width)
+{
+
+    if (font == TEXT_FONT) {
+      *height = 1; *width = 1; return 1; /* Truth in advertising */
+    }
+    return 0;
+
+}/* os_font_data */
+
+#ifdef COLOR_SUPPORT
+/*
+ * unix_convert
+ *
+ * Converts frotz's (and Infocom's) color values to ncurses color values.
+ *
+ */
+
+static int unix_convert(int color)
+{
+  switch(color) {
+        case BLACK_COLOUR: return COLOR_BLACK;
+        case RED_COLOUR: return COLOR_RED;
+        case GREEN_COLOUR: return COLOR_GREEN;
+        case YELLOW_COLOUR: return COLOR_YELLOW;
+        case BLUE_COLOUR: return COLOR_BLUE;
+        case MAGENTA_COLOUR: return COLOR_MAGENTA;
+        case CYAN_COLOUR: return COLOR_CYAN;
+        case WHITE_COLOUR: return COLOR_WHITE;
+  }
+  return 0;
+}
+#endif
+
+/*
+ * os_set_colour
+ *
+ * Set the foreground and background colours which can be:
+ *
+ *     DEFAULT_COLOUR
+ *     BLACK_COLOUR
+ *     RED_COLOUR
+ *     GREEN_COLOUR
+ *     YELLOW_COLOUR
+ *     BLUE_COLOUR
+ *     MAGENTA_COLOUR
+ *     CYAN_COLOUR
+ *     WHITE_COLOUR
+ *
+ *     MS-DOS 320 columns MCGA mode only:
+ *
+ *     GREY_COLOUR
+ *
+ *     Amiga only:
+ *
+ *     LIGHTGREY_COLOUR
+ *     MEDIUMGREY_COLOUR
+ *     DARKGREY_COLOUR
+ *
+ * There may be more colours in the range from 16 to 255; see the
+ * remarks on os_peek_colour.
+ *
+ */
+
+#ifdef COLOR_SUPPORT
+static int colorspace[10][10];
+static int count = 0;
+#endif
+
+void os_set_colour (int new_foreground, int new_background)
+{
+#ifdef COLOR_SUPPORT
+    int saved_style;
+
+    saved_style = current_text_style;
+    if (new_foreground == 1) new_foreground = h_default_foreground;
+    if (new_background == 1) new_background = h_default_background;
+    if (!colorspace[new_foreground][new_background]) {
+      init_pair(++count, unix_convert(new_foreground), unix_convert(new_background));
+      colorspace[new_foreground][new_background] = count;
+    }
+    current_color = COLOR_PAIR(colorspace[new_foreground][new_background]);
+    os_set_text_style(saved_style);
+
+#endif
+}/* os_set_colour */
+
+/*
+ * os_set_text_style
+ *
+ * Set the current text style. Following flags can be set:
+ *
+ *     REVERSE_STYLE
+ *     BOLDFACE_STYLE
+ *     EMPHASIS_STYLE (aka underline aka italics)
+ *     FIXED_WIDTH_STYLE
+ *
+ */
+
+void os_set_text_style (int new_style)
+{
+    int temp = 0;
+
+    current_text_style = new_style;
+    if (new_style & REVERSE_STYLE) temp |= A_REVERSE;
+    if (new_style & BOLDFACE_STYLE) temp |= A_BOLD;
+    if (new_style & EMPHASIS_STYLE) temp |= A_UNDERLINE;
+#ifdef COLOR_SUPPORT
+    attrset(temp | current_color);
+#else
+    attrset(temp);
+#endif
+
+}/* os_set_text_style */
+
+/*
+ * os_set_font
+ *
+ * Set the font for text output. The interpreter takes care not to
+ * choose fonts which aren't supported by the interface.
+ *
+ */
+
+void os_set_font (int new_font)
+{
+
+    /* Not implemented */
+
+}/* os_set_font */
+
+/*
+ * os_display_char
+ *
+ * Display a character of the current font using the current colours and
+ * text style. The cursor moves to the next position. Printable codes are
+ * all ASCII values from 32 to 126, ISO Latin-1 characters from 160 to
+ * 255, ZC_GAP (gap between two sentences) and ZC_INDENT (paragraph
+ * indentation). The screen should not be scrolled after printing to the
+ * bottom right corner.
+ *
+ */
+
+void os_display_char (zchar c)
+{
+
+    if (c >= ZC_LATIN1_MIN && c <= ZC_LATIN1_MAX) {
+        if (unix_plain_ascii) {
+
+         char *ptr = latin1_to_ascii + 3 * (c - ZC_LATIN1_MIN);
+         char c1 = *ptr++;
+         char c2 = *ptr++;
+         char c3 = *ptr++;
+
+         addch(c1);
+
+         if (c2 != ' ')
+           addch(c2);
+         if (c3 != ' ')
+           addch(c3);
+
+       } else
+         addch(c);
+       return;
+    }
+    if (c >= 32 && c <= 126) {
+        addch(c);
+       return;
+    }
+    if (c == ZC_INDENT) {
+      addch(' '); addch(' '); addch(' ');
+      return;
+    }
+    if (c == ZC_GAP) {
+      addch(' '); addch(' ');
+      return;
+    }
+
+}/* os_display_char */
+
+/*
+ * os_display_string
+ *
+ * Pass a string of characters to os_display_char.
+ *
+ */
+
+void os_display_string (const zchar *s)
+{
+
+    zchar c;
+
+    while ((c = (unsigned char) *s++) != 0)
+
+        if (c == ZC_NEW_FONT || c == ZC_NEW_STYLE) {
+
+            int arg = (unsigned char) *s++;
+
+            if (c == ZC_NEW_FONT)
+                os_set_font (arg);
+            if (c == ZC_NEW_STYLE)
+                os_set_text_style (arg);
+
+        } else os_display_char (c);
+
+}/* os_display_string */
+
+/*
+ * os_char_width
+ *
+ * Return the width of the character in screen units.
+ *
+ */
+
+int os_char_width (zchar c)
+{
+
+    if (c >= ZC_LATIN1_MIN && c <= ZC_LATIN1_MAX && unix_plain_ascii) {
+
+        int width = 0;
+        const char *ptr = latin1_to_ascii + 3 * (c - ZC_LATIN1_MIN);
+       char c1 = *ptr++;
+       char c2 = *ptr++;
+       char c3 = *ptr++;
+
+       width++;
+       if (c2 != ' ')
+         width++;
+       if (c3 != ' ')
+         width++;
+       return width;
+    }
+    return 1;
+
+}/* os_char_width*/
+
+/*
+ * os_string_width
+ *
+ * Calculate the length of a word in screen units. Apart from letters,
+ * the word may contain special codes:
+ *
+ *    NEW_STYLE - next character is a new text style
+ *    NEW_FONT  - next character is a new font
+ *
+ */
+
+int os_string_width (const zchar *s)
+{
+    int width = 0;
+    zchar c;
+
+    while ((c = *s++) != 0)
+
+      if (c == ZC_NEW_STYLE || c == ZC_NEW_FONT) {
+
+       s++;
+       /* No effect */
+
+      } else width += os_char_width(c);
+
+    return width;
+
+}/* os_string_width */
+
+/*
+ * os_set_cursor
+ *
+ * Place the text cursor at the given coordinates. Top left is (1,1).
+ *
+ */
+
+void os_set_cursor (int y, int x)
+{
+
+    /* Curses thinks the top left is (0,0) */
+    move(--y, --x);
+
+}/* os_set_cursor */
+
+/*
+ * os_more_prompt
+ *
+ * Display a MORE prompt, wait for a keypress and remove the MORE
+ * prompt from the screen.
+ *
+ */
+
+void os_more_prompt (void)
+{
+    int saved_style, saved_x, saved_y;
+
+    /* Save some useful information */
+    saved_style = current_text_style;
+    getyx(stdscr, saved_y, saved_x);
+
+    os_set_text_style(0);
+    addstr("[MORE]");
+    os_read_key(0, TRUE);
+
+    move(saved_y, saved_x);
+    addstr("      ");
+    move(saved_y, saved_x);
+    os_set_text_style(saved_style);
+
+}/* os_more_prompt */