--- /dev/null
+
+# 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)
+
--- /dev/null
+(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.
+
+
--- /dev/null
+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.
+++ /dev/null
-/*
- * "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 *);
+++ /dev/null
-/*
- * 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 */
+++ /dev/null
-/*
- * 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 */
+++ /dev/null
-/*
- * 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 */
+++ /dev/null
-/*
- * "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 */
+++ /dev/null
-/*
- * 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 */
+++ /dev/null
-/*
- * 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 */
+++ /dev/null
-/*
- * 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 */
/* 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 */
--- /dev/null
+.\" -*- 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.
*
*/
+/* 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;
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */