From bb56b28408fdf1a30ca323b89169ff29c5ca4d95 Mon Sep 17 00:00:00 2001 From: Galen Hazelwood Date: Fri, 17 Oct 1997 20:11:33 +0000 Subject: [PATCH] Released UnixFrotz232R2Std10.tar.gz --- Makefile | 73 ++++ Readme.unix | 318 +++++++++++++++++ Todo | 12 + bcfrotz.h | 85 ----- bcinit.c | 755 --------------------------------------- bcinput.c | 989 ---------------------------------------------------- bcmouse.c | 75 ---- bcpic.c | 677 ----------------------------------- bcsample.c | 414 ---------------------- bcscreen.c | 298 ---------------- bctext.c | 842 -------------------------------------------- fastmem.c | 22 +- font.dat | Bin 26976 -> 0 bytes frotz.6 | 131 +++++++ frotz.h | 6 + ux_frotz.h | 10 + ux_init.c | 385 ++++++++++++++++++++ ux_input.c | 489 ++++++++++++++++++++++++++ ux_pic.c | 61 ++++ ux_sample.c | 107 ++++++ ux_screen.c | 101 ++++++ ux_text.c | 354 +++++++++++++++++++ 22 files changed, 2067 insertions(+), 4137 deletions(-) create mode 100644 Makefile create mode 100644 Readme.unix create mode 100644 Todo delete mode 100644 bcfrotz.h delete mode 100644 bcinit.c delete mode 100644 bcinput.c delete mode 100644 bcmouse.c delete mode 100644 bcpic.c delete mode 100644 bcsample.c delete mode 100644 bcscreen.c delete mode 100644 bctext.c delete mode 100644 font.dat create mode 100644 frotz.6 create mode 100644 ux_frotz.h create mode 100644 ux_init.c create mode 100644 ux_input.c create mode 100644 ux_pic.c create mode 100644 ux_sample.c create mode 100644 ux_screen.c create mode 100644 ux_text.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..21d055f --- /dev/null +++ b/Makefile @@ -0,0 +1,73 @@ + +# Define your c compiler. I recommend gcc if you've got it. +#CC = cc +CC = gcc + +# Define your optimization flags. Most compilers understand -O and -O2, +# Debugging (don't use) +#OPTS = -Wall -g +# Standard +OPTS = -O2 +# Pentium with gcc 2.7.0 or better +#OPTS = -O2 -fomit-frame-pointer -malign-functions=2 -malign-loops=2 \ +-malign-jumps=2 + +# There are a few defines which may be necessary to make frotz compile on +# your system. Most of these are fairly straightforward. +# -DNO_MEMMOVE: Use this if your not-so-standard c library lacks the +# memmove(3) function. (SunOS, other old BSDish systems) +# +# You may need to define one of these to get the getopt prototypes: +# -DUSE_UNISTD_H: Use this if your getopt prototypes are in unistd.h. +# (Solaris?) +# -DUSE_GETOPT_H: Use this if you have a separate /usr/include/getopt.h +# file containing the getopt prototypes. (Linux, IRIX 5?) +# -DUSE_NOTHING: I've heard reports of some systems defining getopt in +# stdlib.h, which unix.c automatically includes. +# (*BSD, Solaris?) +# +# If none of the above are defined, frotz will define the getopt prototypes +# itself. +# +# -DUSE_NCURSES_H: Use this if you want to include ncurses.h rather +# than curses.h. +# +# These defines add various cosmetic features to the interpreter: +# -DCOLOR_SUPPORT: If the terminal you're using has color support, frotz +# will use the curses color routines...if your curses +# library supports color. +# -DEMACS_EDITING: This enables some of the standard emacs editing keys +# (Ctrl-B,-F,-P,-N, etc.) to be used when entering +# input. I can't see any reason why you wouldn't want +# to define it--it can't hurt anything--but you do +# have that option. +# +#DEFS = -DUSE_GETOPT_H -DCOLOR_SUPPORT -DEMACS_EDITING +DEFS = + +# This should point to the location of your curses or ncurses include file +# if it's in a non-standard place. +#INCL = -I/usr/local/include +#INCL = -I/5usr/include +INCL = + +# This should define the location and name of whatever curses library you're +# linking with. +#LIB = -L/usr/local/lib +#CURSES = -lncurses +#LIB = -L/5usr/lib +LIB = +CURSES = -lcurses + +# Nothing under this line should need to be changed. + +OBJECTS = buffer.o fastmem.o files.o hotkey.o input.o main.o math.o object.o \ + process.o random.o redirect.o screen.o sound.o stream.o table.o \ + text.o ux_init.o ux_input.o ux_pic.o ux_screen.o ux_sample.o \ + ux_text.o variable.o + +CFLAGS = $(OPTS) $(DEFS) $(INCL) + +frotz: $(OBJECTS) + $(CC) -o frotz $(OBJECTS) $(LIB) $(CURSES) + diff --git a/Readme.unix b/Readme.unix new file mode 100644 index 0000000..972b59e --- /dev/null +++ b/Readme.unix @@ -0,0 +1,318 @@ +(This Readme file was adapted from the one released with the MS-DOS binary.) + +FROTZ V2.32 - an interpreter for all Infocom games. Complies with standard +1.0 of Graham Nelson's specification. Written by Stefan Jokisch in 1995-7 + + This program once started as a re-make of Mark Howell's Zip, but + has grown into an utterly new interpreter. + + Frotz is freeware: It may be used and distributed freely provided + no commercial profit is involved. (c) 1995-1997 Stefan Jokisch. + + Please report bugs to s.jokisch@avu.de + Please report unix bugs to galenh@micron.net + + This is the unix port of Stefan Jokisch's nifty-neato-cool Z-machine +interpreter. There are only two things you need to compile Frotz: + + * Some variant of Unix with an ANSI C compiler (gcc works fine) + * A reasonably good SYSV derived curses library + + Note that the second requirement is _very_ important. I had several people +send me complaints about Frotz not working, and found out they were unaware +that their curses library was obsolete. If your system curses won't work, +pick up and compile the ncurses library from ftp://prep.ai.mit.edu/pub/gnu +or any GNU mirror site. + +Changes since Release 1: + + * Fixed problems with backspace + * Now supports "delete" key for editing + * Wired in tab completion support (which I stupidly missed) + * Added emacs editing key support (-DEMACS_EDITING) + +How to Compile: + + This source distribution comes with a unsophisticated but functional +Makefile. Edit it to reflect your system; the comments are fairly self- +explanatory. Once that's done, just type "make". + + Color support is available by putting -DCOLOR_SUPPORT in the designated +spot. I've added code in ux_init.c for sound hooks, but as no sound code is +actually written, defining SOUND_SUPPORT will merely cause compilation to fail. + + Thanks for giving this a try. Any bug reports, success stories, or +constructive criticism will be greatly appreciated. + + -- Galen Hazelwood + +Syntax: frotz [options] story-file + + -d disable color + + If frotz discovers that your terminal has color support, it will + enable it by default. This switch overrides that behavior. + + -f # set the foreground colour + -b # set the background colour + + The color numbers are the Z-machine colors, which are as follows: + 2 = black 3 = red 4 = green 5 = yellow + 6 = blue 7 = magenta 8 = cyan 9 = white + + If color support is disabled in the binary, or not available on + your terminal, these options do nothing. + + -i ignore runtime errors + + Set this switch and Frotz no longer worries about anything the + game tries to do. This can help you to get around fatal errors. + + -w # set the screen width + -h # set the screen height + -l # set the left margin + -r # set the right margin + + Setting the screen format can be useful if you are running Frotz + under Microsoft Windows, or if you want to test a game on a more + narrow screen. Setting the margins is a matter of taste; Infocom + interpreters usually set a right margin of one character (-r1). + + -S # set the width of the transscript file + + By default your transscript files are formatted to a width of 80 + columns per line -- regardless of the current screen width. This + switch allows you to change this setting. In particular, use -S0 + to deactivate automatic line splitting in transscript files. + + -c # set the number of context lines + + When the game prints several pages of text in a row, Frotz stops + for a more prompt after each page. The first prompt appears when + your input reaches the top of the window. Further prompts appear + when the previous page has been scrolled off the window. You can + use this switch to make the latter more prompts appear earlier. + + -u # set the number of undo slots for multiple undo + + Frotz tries to allocate as much conventional memory as possible + for multiple UNDO. If this strategy causes some kind of problem, + use this switch to set a tighter limit. In particular, you might + want to turn off the UNDO feature altogether by typing -u0. + + -s # set the random number seed + + The given seed value is used as the initial seed value on every + restart. This is helpful for testing games like 'Curses' which + make random decisions before the first input (such that the hot + key Alt-S does not really help). The meaning of seed values is + explained in the next section. + + -x expand abbreviations (g, x, z ==> again, examine, wait) + + This switch was made for old Infocom games that lack the common + abbreviations introduced in later games. Use it with caution: A + few games might use "g", "x" or "z" for different purposes. + + -o watch object movement + -O watch object locating + -a watch attribute assignment + -A watch attribute testing + + Although these switches may be of assistance while debugging new + games, they are are actually meant to be cheat functions. The -o + switch, for example, helps to locate the thief in 'Zork 1' and + the cat in 'Curses'. The other switches produce a lot of obscure + messages during the game; but some of these messages might give + you important clues if you watch carefully. + + -t set the Tandy bit + + Some old Infocom games were sold by the Tandy Corporation. These + games behave slightly different when you use this option. For + example, 'The Witness' gets censored: bastards turn into idiots, + private dicks into private eyes and so on. + + -p plain ascii output only + + This inhibits the output of accented letters and other characters + from the Latin-1 character set, replacing them with reasonable + alternatives. This may be necessary on devices lacking these + characters. + + -P alter behaviour of piracy opcode + + The piracy opcode was never used by Infocom, and this switch is + only useful for those who like to toy around with Z-code. + +Special keys: + + Alt-D - toggle debugging options (-a, -A, -o, -O) + Alt-H - help on hot keys + Alt-N - new game (restart) + Alt-P - turn on input line playback + Alt-R - toggle input line recording on/off + Alt-S - set the random number seed + Alt-U - multiple undo, works even for old V1 to V4 games + Alt-X - exit game + + When testing a text adventure it can be difficult to reproduce a + specific bug. To avoid this problem you should use the Alt-R key + to record all your inputs in a command file. Later you can press + Alt-P to feed the command file back into Frotz. In many cases, + however, you will find that the result is different because most + games contain random events. Luckily, Frotz provides a hot key + to control these events. Type Alt-S and you are asked for a seed + value, i.e. a value in the range from 1 to 32767. Normally, you + would choose a number >= 1000. Smaller values generate a special + sequence of random numbers as proposed by Nelson. (For instance, + the seed value 4 generates 1, 2, 3, 4, 1, 2, 3, 4, 1...). In any + case, random events become predictable until the next restart. + + See also the command line option -s above. + + cursor left/Ctrl-B - move one character to the left + cursor right/Ctrl-F - move one character to the right + home/Ctrl-A - move to beginning of line + end/Ctrl-E - move to end of line + backspace - delete character to the left + delete/Ctrl-D - delete character below cursor + insert - toggle overwrite mode on/off + escape/Ctrl-U - delete whole input line + cursor up/Ctrl-P - get previous command + cursor down/Ctrl-N - get next command + page up - scroll status window up ('Beyond Zork') + page down - scroll status window down ('Beyond Zork') + tab - word completion (like "tcsh" under Unix) + + Note that the various Control aliases only function if emacs editing + support has been compiled into your binary. See the Makefile for + more information. + + When you need to type an unpleasantly long word, try to type the + first three or four letters then press the tabulator key. If you + are lucky, Frotz fills in some or all of the missing letters. A + high beep noise indicates that the word is ambiguous; a low beep + indicates that it does not exist. Apart from that, you can also + use the history feature to get to previous input lines. Type the + beginning of the input line you are looking for, then use cursor + up/down to scroll through all input lines matching that prefix. + +Questions and answers: + + Q: What is Frotz? + A: Frotz runs text adventures which come in so-called story files: + ZORK1.DAT, TRINITY.DAT, CURSES.Z5, JIGSAW.Z8, ARTHUR.ZIP etc. + + Q: Where can I find story files to use with Frotz? + A: First, you can use the files from your original Infocom games. It + is possible to play Atari ST, Amiga or Macintosh games on your PC + once you manage to transfer the story files. Some people even + extracted story files from old Atari 800, Apple II and C-64 disks + (ask your local 8bit guru). Second, there is an increasing number + of new games available on the Internet. Check the if-archive at + ftp.gmd.de. + + Q: Why does Frotz stop with an error message? + A: It might have detected a bug in the story file other interpreters + overlooked. Use the -i switch to run your story file anyway. It's + also possible that the story file is corrupt; be sure to download + story files in binary mode, especially when you use a WWW browser. + + Q: Is there a way to exit Frotz in emergency situations? + A: Try Ctrl-break, Ctrl-C, or Ctrl-Z. The last one suspends your process + and returns you to the shell, allowing you to kill it. + + Q: What do I need to play graphic games? + A: A different port of Frotz. Try the MS-DOS version if you can use + it, or wait for the X Windows port. You can run some of the V6 games + without graphics--Arthur and Journey seem to work, but not Shogun or + Zork Zero. (Shogun dies because I can't backscroll; Zork 0 just + sputters and dies rather amusingly.) + + Q: What do I need for sound? + A: A different port of Frotz, or a later version of this one. Sound + support will first be available on Linux, and any other system which + can use the Open Sound System (or OSS/Lite). + + Q: How can I send transscription to the printer? + A: Type PRN as file name. + + Q: Why do I get weird characters instead of accented letters? + A: Because your display/terminal/window doesn't support the Latin-1 + character set properly. Use the -p flag, which uses plain ASCII + output and converts accented letters appropriately. + + Q: Why don't the number pad keys work in 'Beyond Zork'? + A: Because curses dosen't seem to know how to handle them properly. + I might add a hack to support them later. + + Q: How can I scroll the status window in 'Beyond Zork'? + A: Use page up/down instead of cursor up/down. + + Q: Why are my default color selections so weird? + A: You're used to using the standard PC color values. The unix port + wants color numbers in Z-machine form. Quick reference: + 2 = black 3 = red 4 = green 5 = yellow + 6 = blue 7 = magenta 8 = cyan 9 = white + + +List of fatal errors: + + - "Bad stack frame" + - "Byte swapped story file" + - "Call to illegal address" + - "Call to non-routine" [1] + - "Cannot open story file" + - "Division by zero" + - "Error reading save file" + - "Illegal attribute" + - "Illegal object" [2] + - "Illegal window" + - "Illegal window property" + - "Jump to illegal address" + - "Nesting stream #3 too deep" + - "No such property" + - "Out of memory" + - "Print at illegal address" + - "Stack overflow" [3] + - "Stack underflow" [4] + - "Store out of dynamic memory" + - "Story file read error" + - "Text buffer overflow" + - "Unknown opcode" + - "Unknown Z-code version" + - "Can't Happen (os_scroll_area)" [5] + + [1] The first byte of a routine must be less than 16. + [2] In V4 and above, object numbers > 2000 are considered illegal. + [3] Checked on every call instruction. + [4] Checked on every return from a subroutine. + [5] Unix-specific. Should only happen in Shogun. + +Acknowledgements: + + Many thanks to Paul D. Doherty for his continuing support of this + project. Thanks to everyone who sent bug reports, contributions or + helpful hints (in alphabetical order): + + Thomas Biskup, Ian Carpenter, Graeme Cree, Jason Dyer, + Carl Edman, Julian Eggebrecht, Bernhard Fuchs, Joe Hachem, + John Kennedy, Kirk Klobe, Marnix Klooster, John Mackin, + Paul O'Brian, Magnus Olsson, Barry Prescott, L. Ross Raszewski, + Ambat Sasi Nair, Alan Sherrod, Linards Ticmanis and Paolo Vece. + + Last but not least, thanks to the porters: + + David Kinder (Amiga), Rich Lawrence (Windows 95/NT), + Andrew Holdsworth (RiscOS), Christos Dimitrakakis (HP-UX), + Christopher J. Madsen (OS/2), Galen Hazelwood (Unix curses library), + Ian Dean (Windows CE). + + Executables are available from ftp.gmd.de and from + + http://www.geocities.com/SiliconValley/Heights/3222/frotz.html + + which is the Frotz home page maintained by Chris Madsen. + + diff --git a/Todo b/Todo new file mode 100644 index 0000000..b189a4e --- /dev/null +++ b/Todo @@ -0,0 +1,12 @@ +Things to do and bugs to investigate +------------------------------------ + +* Write sound support. This is on hold until frotz supports the new "Blorb" + format. + +* Border Zone has a strange status line feature, mixing bright and dull + whites. Not sure what's going on here. + +* Add support for GNU readline/history libraries instead of the kludgy + editing routines I wrote. If I can manage this, I'll probably release + it as a patch rather than part of a release. diff --git a/bcfrotz.h b/bcfrotz.h deleted file mode 100644 index 70c99a1..0000000 --- a/bcfrotz.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * "BCfrotz.h" - * - * Borland C interface, declarations - * - */ - -#define byte0(v) ((byte *)&v)[0] -#define byte1(v) ((byte *)&v)[1] -#define byte2(v) ((byte *)&v)[2] -#define byte3(v) ((byte *)&v)[3] -#define word0(v) ((word *)&v)[0] -#define word1(v) ((word *)&v)[1] - -#ifndef HISTORY_MIN_ENTRY -#define HISTORY_MIN_ENTRY 1 -#endif - -#define SPECIAL_KEY_MIN 256 -#define SPECIAL_KEY_HOME 256 -#define SPECIAL_KEY_END 257 -#define SPECIAL_KEY_WORD_LEFT 258 -#define SPECIAL_KEY_WORD_RIGHT 259 -#define SPECIAL_KEY_DELETE 260 -#define SPECIAL_KEY_INSERT 261 -#define SPECIAL_KEY_PAGE_UP 262 -#define SPECIAL_KEY_PAGE_DOWN 263 -#define SPECIAL_KEY_TAB 264 -#define SPECIAL_KEY_MAX 264 - -#define _MONO_ 0 -#define _TEXT_ 1 -#define _CGA_ 2 -#define _MCGA_ 3 -#define _EGA_ 4 -#define _AMIGA_ 5 - -typedef unsigned char byte; -typedef unsigned short word; - -extern display; - -extern cursor_x; -extern cursor_y; - -extern char latin1_to_ibm[]; -extern char latin1_to_ascii[]; - -extern byte text_bg; -extern byte text_fg; - -extern byte scrn_attr; - -extern user_background; -extern user_foreground; -extern user_emphasis; -extern user_reverse_bg; -extern user_reverse_fg; -extern user_screen_height; -extern user_screen_width; -extern user_tandy_bit; -extern user_bold_typing; -extern user_random_seed; -extern user_font; - -extern char stripped_story_name[]; -extern char *prog_name; - -extern current_bg; -extern current_fg; -extern current_style; -extern current_font; - -extern scaler; - -/* BCinit */ int dectoi (const char *); -/* BCinit */ int hextoi (const char *); -/* BCmouse */ bool detect_mouse (void); -/* BCmouse */ int read_mouse (void); -/* BCpic */ bool init_pictures (void); -/* BCpic */ void reset_pictures (void); -/* BCsmpl */ bool init_sound (void); -/* BCsmpl */ void reset_sound (void); -/* BCtext */ void switch_scrn_attr (bool); -/* BCtext */ void load_fonts (const char *); diff --git a/bcinit.c b/bcinit.c deleted file mode 100644 index 3fba0d9..0000000 --- a/bcinit.c +++ /dev/null @@ -1,755 +0,0 @@ -/* - * file "BCinit.c" - * - * Borland C front end, initialisation - * - */ - -#include -#include -#include -#include -#include -#include "frotz.h" -#include "BCfrotz.h" - -#define INFORMATION "\ -\n\ -FROTZ V2.32 - interpreter for all Infocom games. Complies with standard\n\ -1.0 of Graham Nelson's specification. Written by Stefan Jokisch in 1995-7\n\ -\n\ -Syntax: frotz [options] story-file\n\ -\n\ - -a watch attribute setting \t -l # left margin\n\ - -A watch attribute testing \t -o watch object movement\n\ - -b # background colour \t -O watch object locating\n\ - -B # reverse background colour\t -p alter piracy opcode\n\ - -c # context lines \t -r # right margin\n\ - -d # display mode (see below) \t -s # random number seed value\n\ - -e # emphasis colour [mode 1] \t -S # transscript width\n\ - -f # foreground colour \t -t set Tandy bit\n\ - -F # reverse foreground colour\t -T bold typing [modes 2+4+5]\n\ - -g # font [mode 5] (see below)\t -u # slots for multiple undo\n\ - -h # screen height \t -w # screen width\n\ - -i ignore runtime errors \t -x expand abbreviations g/x/z\n\ -\n\ -Fonts are 0 (fixed), 1 (sans serif), 2 (comic), 3 (times), 4 (serif).\n\ -\n\ -Display modes are 0 (mono), 1 (text), 2 (CGA), 3 (MCGA), 4 (EGA), 5 (Amiga)." - -extern unsigned cdecl _heaplen = 0x800 + 4 * BUFSIZ; -extern unsigned cdecl _stklen = 0x800; - -extern const char *optarg; -extern int optind; - -int cdecl getopt (int, char *[], const char *); - -static const char *progname = NULL; - -extern char script_name[]; -extern char command_name[]; -extern char save_name[]; -extern char auxilary_name[]; - -char stripped_story_name[10]; - -int display = -1; - -int user_background = -1; -int user_foreground = -1; -int user_emphasis = -1; -int user_bold_typing = -1; -int user_reverse_bg = -1; -int user_reverse_fg = -1; -int user_screen_height = -1; -int user_screen_width = -1; -int user_tandy_bit = -1; -int user_random_seed = -1; -int user_font = 1; - -static byte old_video_mode = 0; - -static void interrupt (*oldvect) () = NULL; - -/* - * dectoi - * - * Convert a string containing a decimal number to integer. The string may - * be NULL, but it must not be empty. - * - */ - -int dectoi (const char *s) -{ - int n = 0; - - if (s != NULL) - - do { - - n = 10 * n + (*s & 15); - - } while (*++s > ' '); - - return n; - -}/* dectoi */ - -/* - * hextoi - * - * Convert a string containing a hex number to integer. The string may be - * NULL, but it must not be empty. - * - */ - -int hextoi (const char *s) -{ - int n = 0; - - if (s != NULL) - - do { - - n = 16 * n + (*s & 15); - - if (*s > '9') - n += 9; - - } while (*++s > ' '); - - return n; - -}/* hextoi */ - -/* - * cleanup - * - * Shut down the IO interface: free memory, close files, restore - * interrupt pointers and return to the previous video mode. - * - */ - -static void cleanup (void) -{ - - reset_sound (); - reset_pictures (); - - asm mov ah,0 - asm mov al,old_video_mode - asm int 0x10 - - setvect (0x1b, oldvect); - -}/* cleanup */ - -/* - * fast_exit - * - * Handler routine to be called when the crtl-break key is pressed. - * - */ - -static void interrupt fast_exit () -{ - - cleanup (); exit (EXIT_FAILURE); - -}/* fast_exit */ - -/* - * os_fatal - * - * Display error message and exit program. - * - */ - -void os_fatal (const char *s) -{ - - if (h_interpreter_number) - os_reset_screen (); - - /* Display error message */ - - fputs ("\nFatal error: ", stderr); - fputs (s, stderr); - fputs ("\n", stderr); - - /* Abort program */ - - exit (EXIT_FAILURE); - -}/* os_fatal */ - -/* - * parse_options - * - * Parse program options and set global flags accordingly. - * - */ - -static void parse_options (int argc, char **argv) -{ - int c; - - do { - - int num = 0; - - c = getopt (argc, argv, "aAb:B:c:d:e:f:F:g:h:il:oOpr:s:S:tTu:w:x"); - - if (optarg != NULL) - num = dectoi (optarg); - - if (c == 'a') - option_attribute_assignment = 1; - if (c == 'A') - option_attribute_testing = 1; - if (c == 'b') - user_background = num; - if (c == 'B') - user_reverse_bg = num; - if (c == 'c') - option_context_lines = num; - if (c == 'd') - display = optarg[0] | 32; - if (c == 'e') - user_emphasis = num; - if (c == 'T') - user_bold_typing = 1; - if (c == 'f') - user_foreground = num; - if (c == 'F') - user_reverse_fg = num; - if (c == 'g') - user_font = num; - if (c == 'h') - user_screen_height = num; - if (c == 'i') - option_ignore_errors = 1; - if (c == 'l') - option_left_margin = num; - if (c == 'o') - option_object_movement = 1; - if (c == 'O') - option_object_locating = 1; - if (c == 'p') - option_piracy = 1; - if (c == 'r') - option_right_margin = num; - if (c == 's') - user_random_seed = num; - if (c == 'S') - option_script_cols = num; - if (c == 't') - user_tandy_bit = 1; - if (c == 'u') - option_undo_slots = num; - if (c == 'w') - user_screen_width = num; - if (c == 'x') - option_expand_abbreviations = 1; - - } while (c != EOF); - -}/* parse_options */ - -/* - * os_process_arguments - * - * Handle command line switches. Some variables may be set to activate - * special features of Frotz: - * - * option_attribute_assignment - * option_attribute_testing - * option_context_lines - * option_object_locating - * option_object_movement - * option_left_margin - * option_right_margin - * option_ignore_errors - * option_piracy - * option_undo_slots - * option_expand_abbreviations - * option_script_cols - * - * The global pointer "story_name" is set to the story file name. - * - */ - -void os_process_arguments (int argc, char *argv[]) -{ - const char *p; - int i; - - /* Parse command line options */ - - parse_options (argc, argv); - - if (optind != argc - 1) { - puts (INFORMATION); - exit (EXIT_FAILURE); - } - - /* Set the story file name */ - - story_name = argv[optind]; - - /* Strip path and extension off the story file name */ - - p = story_name; - - for (i = 0; story_name[i] != 0; i++) - if (story_name[i] == '\\' || story_name[i] == ':') - p = story_name + i + 1; - - for (i = 0; p[i] != 0 && p[i] != '.' && i < 8; i++) - stripped_story_name[i] = p[i]; - - stripped_story_name[i] = 0; - - /* Create nice default file names */ - - strcpy (script_name, stripped_story_name); - strcpy (command_name, stripped_story_name); - strcpy (save_name, stripped_story_name); - strcpy (auxilary_name, stripped_story_name); - - strcat (script_name, ".scr"); - strcat (command_name, ".rec"); - strcat (save_name, ".sav"); - strcat (auxilary_name, ".aux"); - - /* Save the executable file name */ - - progname = argv[0]; - -}/* os_process_arguments */ - -/* - * standard_palette - * - * Set palette registers to EGA default values and call VGA BIOS to - * use DAC registers #0 to #63. - * - */ - -static void standard_palette (void) -{ - - static byte palette[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x00 /* last one is the overscan register */ - }; - - if (display == _AMIGA_) { - asm mov ax,0x1002 - asm lea dx,palette - asm push ds - asm pop es - asm int 0x10 - asm mov ax,0x1013 - asm mov bx,0x0001 - asm int 0x10 - } - -}/* standard_palette */ - -/* - * special_palette - * - * Set palette register #i to value i and call VGA BIOS to use DAC - * registers #64 to #127. - * - */ - -static void special_palette (void) -{ - - static byte palette[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x00 /* last one is the overscan register */ - }; - - if (display == _AMIGA_) { - asm mov ax,0x1002 - asm mov dx,offset palette - asm push ds - asm pop es - asm int 0x10 - asm mov ax,0x1013 - asm mov bx,0x0101 - asm int 0x10 - } - -}/* special_palette */ - -/* - * os_init_screen - * - * Initialise the IO interface. Prepare the screen and other devices - * (mouse, sound board). Set various OS depending story file header - * entries: - * - * h_config (aka flags 1) - * h_flags (aka flags 2) - * h_screen_cols (aka screen width in characters) - * h_screen_rows (aka screen height in lines) - * h_screen_width - * h_screen_height - * h_font_height (defaults to 1) - * h_font_width (defaults to 1) - * h_default_foreground - * h_default_background - * h_interpreter_number - * h_interpreter_version - * h_user_name (optional; not used by any game) - * - * Finally, set reserve_mem to the amount of memory (in bytes) that - * should not be used for multiple undo and reserved for later use. - * - */ - -void os_init_screen (void) -{ - static byte zcolour[] = { - BLACK_COLOUR, - BLUE_COLOUR, - GREEN_COLOUR, - CYAN_COLOUR, - RED_COLOUR, - MAGENTA_COLOUR, - BROWN + 16, - LIGHTGRAY + 16, - GREY_COLOUR, - LIGHTBLUE + 16, - LIGHTGREEN + 16, - LIGHTCYAN + 16, - LIGHTRED + 16, - LIGHTMAGENTA + 16, - YELLOW_COLOUR, - WHITE_COLOUR - }; - - static struct { /* information on modes 0 to 5 */ - byte vmode; - word width; - word height; - byte font_width; - byte font_height; - byte fg; - byte bg; - } info[] = { - { 0x07, 80, 25, 1, 1, LIGHTGRAY + 16, BLACK_COLOUR }, /* MONO */ - { 0x03, 80, 25, 1, 1, LIGHTGRAY + 16, BLUE_COLOUR }, /* TEXT */ - { 0x06, 640, 200, 8, 8, WHITE_COLOUR, BLACK_COLOUR }, /* CGA */ - { 0x13, 320, 200, 5, 8, WHITE_COLOUR, GREY_COLOUR }, /* MCGA */ - { 0x0e, 640, 200, 8, 8, WHITE_COLOUR, BLUE_COLOUR }, /* EGA */ - { 0x12, 640, 400, 8, 16, WHITE_COLOUR, BLACK_COLOUR } /* AMIGA */ - }; - - static struct { /* information on modes A to E */ - word vesamode; - word width; - word height; - } subinfo[] = { - { 0x001, 40, 25 }, - { 0x109, 132, 25 }, - { 0x10b, 132, 50 }, - { 0x108, 80, 60 }, - { 0x10c, 132, 60 } - }; - - int subdisplay; - - /* Get the current video mode. This video mode will be selected - when the program terminates. It's also useful to auto-detect - monochrome boards. */ - - asm mov ah,15 - asm int 0x10 - asm mov old_video_mode,al - - /* If the display mode has not already been set by the user then see - if this is a monochrome board. If so, set the display mode to 0. - Otherwise check the graphics flag of the story. Select a graphic - mode if it is set or if this is a V6 game. Select text mode if it - is not. */ - - if (display == -1) - - if (old_video_mode == 7) - display = '0'; - else if (h_version == V6 || (h_flags & GRAPHICS_FLAG)) - display = '5'; - else - display = '1'; - - /* Activate the desired display mode. All VESA text modes are very - similar to the standard text mode; in fact, only here we need to - know which VESA mode is used. */ - - if (display >= '0' && display <= '5') { - subdisplay = -1; - display -= '0'; - _AL = info[display].vmode; - _AH = 0; - } else if (display == 'a') { - subdisplay = 0; - display = 1; - _AL = 0x01; - _AH = 0; - } else if (display >= 'b' && display <= 'e') { - subdisplay = display - 'a'; - display = 1; - _BX = subinfo[subdisplay].vesamode; - _AX = 0x4f02; - } - - geninterrupt (0x10); - - /* Make various preparations */ - - if (display <= _TEXT_) { - - /* Enable bright background colours */ - - asm mov ax,0x1003 - asm mov bl,0 - asm int 0x10 - - /* Turn off hardware cursor */ - - asm mov ah,1 - asm mov cx,0xffff - asm int 0x10 - - } else { - - load_fonts (progname); - - if (display == _AMIGA_) { - - scaler = 2; - - /* Use resolution 640 x 400 instead of 640 x 480. BIOS doesn't - help us here since this is not a standard resolution. */ - - outportb (0x03c2, 0x63); - - outport (0x03d4, 0x0e11); - outport (0x03d4, 0xbf06); - outport (0x03d4, 0x1f07); - outport (0x03d4, 0x9c10); - outport (0x03d4, 0x8f12); - outport (0x03d4, 0x9615); - outport (0x03d4, 0xb916); - - } - - } - -#if !defined(__SMALL__) && !defined (__TINY__) && !defined (__MEDIUM__) - - /* Set the amount of memory to reserve for later use. It takes - some memory to open command, script and game files. If Frotz - is compiled in a small memory model then memory for opening - files is allocated on the "near heap" while other allocations - are made on the "far heap", i.e. we need not reserve memory - in this case. */ - - reserve_mem = 4 * BUFSIZ; - -#endif - - /* Amiga emulation under V6 needs special preparation. */ - - if (display == _AMIGA_ && h_version == V6) { - - user_reverse_fg = -1; - user_reverse_bg = -1; - zcolour[LIGHTGRAY] = LIGHTGREY_COLOUR; - zcolour[DARKGRAY] = DARKGREY_COLOUR; - - special_palette (); - - } - - /* Set various bits in the configuration byte. These bits tell - the game which features are supported by the interpreter. */ - - if (h_version == V3 && user_tandy_bit != -1) - h_config |= CONFIG_TANDY; - if (h_version == V3) - h_config |= CONFIG_SPLITSCREEN; - if (h_version == V3 && (display == _MCGA_ || (display == _AMIGA_ && user_font != 0))) - h_config |= CONFIG_PROPORTIONAL; - if (h_version >= V4 && display != _MCGA_ && (user_bold_typing != -1 || display <= _TEXT_)) - h_config |= CONFIG_BOLDFACE; - if (h_version >= V4) - h_config |= CONFIG_EMPHASIS | CONFIG_FIXED | CONFIG_TIMEDINPUT; - if (h_version >= V5 && display != _MONO_ && display != _CGA_) - h_config |= CONFIG_COLOUR; - if (h_version >= V5 && display >= _CGA_ && init_pictures ()) - h_config |= CONFIG_PICTURES; - - /* Handle various game flags. These flags are set if the game wants - to use certain features. The flags must be cleared if the feature - is not available. */ - - if (h_flags & GRAPHICS_FLAG) - if (display <= _TEXT_) - h_flags &= ~GRAPHICS_FLAG; - if (h_version == V3 && (h_flags & OLD_SOUND_FLAG)) - if (!init_sound ()) - h_flags &= ~OLD_SOUND_FLAG; - if (h_flags & SOUND_FLAG) - if (!init_sound ()) - h_flags &= ~SOUND_FLAG; - if (h_version >= V5 && (h_flags & UNDO_FLAG)) - if (!option_undo_slots) - h_flags &= ~UNDO_FLAG; - if (h_flags & MOUSE_FLAG) - if (subdisplay != -1 || !detect_mouse ()) - h_flags &= ~MOUSE_FLAG; - if (h_flags & COLOUR_FLAG) - if (display == _MONO_ || display == _CGA_) - h_flags &= ~COLOUR_FLAG; - h_flags &= ~MENU_FLAG; - - /* Set the screen dimensions, font size and default colour */ - - h_screen_width = info[display].width; - h_screen_height = info[display].height; - h_font_height = info[display].font_height; - h_font_width = info[display].font_width; - h_default_foreground = info[display].fg; - h_default_background = info[display].bg; - - if (subdisplay != -1) { - h_screen_width = subinfo[subdisplay].width; - h_screen_height = subinfo[subdisplay].height; - } - - if (user_screen_width != -1) - h_screen_width = user_screen_width; - if (user_screen_height != -1) - h_screen_height = user_screen_height; - - h_screen_cols = h_screen_width / h_font_width; - h_screen_rows = h_screen_height / h_font_height; - - if (user_foreground != -1) - h_default_foreground = zcolour[user_foreground]; - if (user_background != -1) - h_default_background = zcolour[user_background]; - - /* Set the interpreter number (a constant telling the game which - operating system it runs on) and the interpreter version. The - interpreter number has effect on V6 games and "Beyond Zork". */ - - h_interpreter_number = INTERP_MSDOS; - h_interpreter_version = 'F'; - - if (display == _AMIGA_) - h_interpreter_number = INTERP_AMIGA; - - /* Install the fast_exit routine to handle the ctrl-break key */ - - oldvect = getvect (0x1b); setvect (0x1b, fast_exit); - -}/* os_init_screen */ - -/* - * os_reset_screen - * - * Reset the screen before the program stops. - * - */ - -void os_reset_screen (void) -{ - - os_set_font (TEXT_FONT); - os_set_text_style (0); - os_display_string ((zchar *) "[Hit any key to exit.]"); - os_read_key (0, TRUE); - - cleanup (); - -}/* os_reset_screen */ - -/* - * os_restart_game - * - * This routine allows the interface to interfere with the process of - * restarting a game at various stages: - * - * RESTART_BEGIN - restart has just begun - * RESTART_WPROP_SET - window properties have been initialised - * RESTART_END - restart is complete - * - */ - -void os_restart_game (int stage) -{ - int x, y; - - if (story_id == BEYOND_ZORK) - - if (stage == RESTART_BEGIN) - - if ((display == _MCGA_ || display == _AMIGA_) && os_picture_data (1, &x, &y)) { - - special_palette (); - - asm mov ax,0x1010 - asm mov bx,64 - asm mov dh,0 - asm mov ch,0 - asm mov cl,0 - asm int 0x10 - asm mov ax,0x1010 - asm mov bx,79 - asm mov dh,0xff - asm mov ch,0xff - asm mov cl,0xff - asm int 0x10 - - os_draw_picture (1, 1, 1); - os_read_key (0, FALSE); - - standard_palette (); - - } - -}/* os_restart_game */ - -/* - * os_random_seed - * - * Return an appropriate random seed value in the range from 0 to - * 32767, possibly by using the current system time. - * - */ - -int os_random_seed (void) -{ - - if (user_random_seed == -1) { - - /* Use the time of day as seed value */ - - asm mov ah,0 - asm int 0x1a - - return _DX & 0x7fff; - - } else return user_random_seed; - -}/* os_random_seed */ diff --git a/bcinput.c b/bcinput.c deleted file mode 100644 index 04c6e0f..0000000 --- a/bcinput.c +++ /dev/null @@ -1,989 +0,0 @@ -/* - * file "BCinput.c" - * - * Borland C front end, input functions - * - */ - -#include -#include -#include -#include "frotz.h" -#include "BCfrotz.h" - -#ifndef HISTORY_BUFSIZE -#define HISTORY_BUFSIZE 500 -#endif - -extern bool is_terminator (zchar); - -extern bool read_yes_or_no (const char *); -extern void read_string (int, zchar *); - -extern int completion (const zchar *, zchar *); - -static long limit = 0; - -static struct { - zchar buffer[HISTORY_BUFSIZE]; - int latest; - int current; - int prefix_len; -} history; - -static struct { - zchar *buffer; - int pos; - int length; - int max_length; - int width; - int max_width; -} input; - -static bool overwrite = FALSE; - -/* - * swap_colours - * - * This is a small helper function for switch_cursor. It swaps the - * current background and foreground colours. - * - */ - -static void swap_colours (void) -{ - - _AL = text_fg; - _AH = text_bg; - text_fg = _AH; - text_bg = _AL; - -}/* swap_colours */ - -/* - * switch_cursor - * - * Turn cursor on/off. If there is mouse support then turn the mouse - * pointer on/off as well. The cursor should not be moved and the - * contents of the screen should not be changed while the cursor is - * visible (because of the primitive cursor emulation we use here). - * - */ - -static void switch_cursor (bool cursor) -{ - - if (display <= _TEXT_) { - - /* Use hardware cursor in text mode */ - - if (display == _MONO_) - _CX = overwrite ? 0x080f : 0x0a0b; - else - _CX = overwrite ? 0x0408 : 0x0506; - - if (!cursor) - _CX = 0xffff; - - asm mov ah,2 - asm mov bh,0 - asm mov dh,byte ptr cursor_y - asm mov dl,byte ptr cursor_x - asm int 0x10 - asm mov ah,1 - asm int 0x10 - - } else { - - int saved_x = cursor_x; - - if (cursor) - swap_colours (); - - if (input.pos < input.length) - os_display_char (input.buffer[input.pos]); - else - os_display_char (' '); - - if (cursor) - swap_colours (); - - cursor_x = saved_x; - - } - -}/* switch_cursor */ - -/* - * get_current_time - * - * Return the current system time in 1/10 seconds. - * - */ - -static long get_current_time (void) -{ - long time; - - /* Get the current time of day measured in - 65536 / 1,193,180 = 0.054925493 - seconds. Multiply this value with - 959 / 1746 = 0.54925544 - to get the current time in 0.1 seconds. */ - - asm mov ah,0 - asm int 0x1a - asm mov word ptr time,dx - asm mov word ptr time + 2,cx - - return time * 959 / 1746; - -}/* get_current_time */ - -/* - * set_timer - * - * Set a time limit of timeout/10 seconds if timeout is not zero; - * otherwise clear the time limit. - * - */ - -static void set_timer (int timeout) -{ - - limit = (timeout != 0) ? get_current_time () + timeout : 0; - -}/* set_timer */ - -/* - * time_limit_hit - * - * Return true if a previously set time limit has been exceeded. - * - */ - -static bool out_of_time (void) -{ - - if (limit != 0) { - - long now = get_current_time (); - - if (now < 1L * 3600 * 10 && limit > 23L * 3600 * 10) - now += 24L * 3600 * 10; - - return now >= limit; - - } else return FALSE; - -}/* out_of_time */ - -/* - * get_key - * - * Read a keypress or a mouse click. Returns... - * - * ZC_TIME_OUT = time limit exceeded, - * ZC_BACKSPACE = the backspace key, - * ZC_RETURN = the return key, - * ZC_HKEY_MIN...ZC_HKEY_MAX = a hot key, - * ZC_ESCAPE = the escape key, - * ZC_ASCII_MIN...ZC_ASCII_MAX = ASCII character, - * ZC_ARROW_MIN...ZC_ARROW_MAX = an arrow key, - * ZC_FKEY_MIN...ZC_FKEY_MAX = a function key, - * ZC_NUMPAD_MIN...ZC_NUMPAD_MAX = a number pad key, - * ZC_SINGLE_CLICK = single mouse click, - * ZC_DOUBLE_CLICK = double mouse click, - * ZC_LATIN1_MIN+1...ZC_LATIN1_MAX = ISO Latin-1 character, - * SPECIAL_KEY_MIN...SPECIAL_KEY_MAX = a special editing key. - * - */ - -static int get_key (bool cursor) -{ - static byte arrow_key_map[] = { - 0x48, 0x50, 0x4b, 0x4d - }; - static byte special_key_map[] = { - 0x47, 0x4f, 0x73, 0x74, 0x53, 0x52, 0x49, 0x51, 0x0f - }; - static byte hot_key_map[] = { - 0x13, 0x19, 0x1f, 0x16, 0x31, 0x2d, 0x20, 0x23 - }; - - int key; - - /* Loop until a key was pressed */ - - if (cursor) - switch_cursor (TRUE); - - if (h_flags & MOUSE_FLAG) { - asm mov ax,1 - asm int 0x33 - } - - do { - - if (_bios_keybrd (_KEYBRD_READY)) { - - word code = _bios_keybrd (_KEYBRD_READ); - - if (byte0 (code) != 0 && byte0 (code) != 9) { - - for (key = ZC_NUMPAD_MIN; key <= ZC_NUMPAD_MAX; key++) - if (byte0 (code) == key - ZC_NUMPAD_MIN + '0' && byte1 (code) >= 0x10) - goto exit_loop; - - for (key = ZC_LATIN1_MIN + 1; key <= ZC_LATIN1_MAX; key++) - if (byte0 (code) == latin1_to_ibm[key - ZC_LATIN1_MIN]) - goto exit_loop; - - key = byte0 (code); - - if (key == ZC_BACKSPACE) - goto exit_loop; - if (key == ZC_RETURN) - goto exit_loop; - if (key == ZC_ESCAPE) - goto exit_loop; - if (key >= ZC_ASCII_MIN && key <= ZC_ASCII_MAX) - goto exit_loop; - - } else { - - for (key = ZC_ARROW_MIN; key <= ZC_ARROW_MAX; key++) - if (byte1 (code) == arrow_key_map[key - ZC_ARROW_MIN]) - goto exit_loop; - - for (key = ZC_FKEY_MIN; key <= ZC_FKEY_MAX - 2; key++) - if (byte1 (code) == key - ZC_FKEY_MIN + 0x3b) - goto exit_loop; - - for (key = ZC_HKEY_MIN; key <= ZC_HKEY_MAX; key++) - if (byte1 (code) == hot_key_map[key - ZC_HKEY_MIN]) - goto exit_loop; - - for (key = SPECIAL_KEY_MIN; key <= SPECIAL_KEY_MAX; key++) - if (byte1 (code) == special_key_map[key - SPECIAL_KEY_MIN]) - goto exit_loop; - - } - - } else { - - int clicks = read_mouse (); - - if (clicks == 1) - { key = ZC_SINGLE_CLICK; goto exit_loop; } - if (clicks == 2) - { key = ZC_DOUBLE_CLICK; goto exit_loop; } - - } - - key = ZC_TIME_OUT; - - } while (!out_of_time ()); - -exit_loop: - - if (h_flags & MOUSE_FLAG) { - asm mov ax,2 - asm int 0x33 - } - - if (cursor) - switch_cursor (FALSE); - - return key; - -}/* get_key */ - -/* - * cursor_left - * - * Move the cursor one character to the left. - * - */ - -static void cursor_left (void) -{ - - if (input.pos > 0) - cursor_x -= os_char_width (input.buffer[--input.pos]); - -}/* cursor_left */ - -/* - * cursor_right - * - * Move the cursor one character to the right. - * - */ - -static void cursor_right (void) -{ - - if (input.pos < input.length) - cursor_x += os_char_width (input.buffer[input.pos++]); - -}/* cursor_right */ - -/* - * first_char - * - * Move the cursor to the beginning of the input line. - * - */ - -static void first_char (void) -{ - - while (input.pos > 0) - cursor_left (); - -}/* first_char */ - -/* - * last_char - * - * Move the cursor to the end of the input line. - * - */ - -static void last_char (void) -{ - - while (input.pos < input.length) - cursor_right (); - -}/* last_char */ - -/* - * prev_word - * - * Move the cursor to the start of the previous word. - * - */ - -static void prev_word (void) -{ - - do { - - cursor_left (); - - if (input.pos == 0) - return; - - } while (input.buffer[input.pos] == ' ' || input.buffer[input.pos - 1] != ' '); - -}/* prev_word */ - -/* - * next_word - * - * Move the cursor to the start of the next word. - * - */ - -static void next_word (void) -{ - - do { - - cursor_right (); - - if (input.pos == input.length) - return; - - } while (input.buffer[input.pos] == ' ' || input.buffer[input.pos - 1] != ' '); - -}/* next_word */ - -/* - * input_move - * - * Helper function to move parts of the input buffer: - * - * newc != 0, oldc == 0: INSERT - * newc != 0, oldc != 0: OVERWRITE - * newc == 0, oldc != 0: DELETE - * newc == 0, oldc == 0: NO OPERATION - * - */ - -#define H(x) (x ? 1 : 0) - -static void input_move (zchar newc, zchar oldc) -{ - int newwidth = (newc != 0) ? os_char_width (newc) : 0; - int oldwidth = (oldc != 0) ? os_char_width (oldc) : 0; - - zchar *p = input.buffer + input.pos; - - int saved_x = cursor_x; - - int updated_width = input.width + newwidth - oldwidth; - int updated_length = input.length + H (newc) - H (oldc); - - if (updated_width > input.max_width) - return; - if (updated_length > input.max_length) - return; - - input.width = updated_width; - input.length = updated_length; - - if (oldc != 0 && newc == 0) - memmove (p, p + 1, updated_length - input.pos + 1); - if (newc != 0 && oldc == 0) - memmove (p + 1, p, updated_length - input.pos); - - if (newc != 0) - *p = newc; - - os_display_string (p); - - switch_scrn_attr (TRUE); - - if (oldwidth > newwidth) - - os_erase_area ( - cursor_y + 1, - cursor_x + 1, - cursor_y + h_font_height, - cursor_x + oldwidth - newwidth); - - switch_scrn_attr (FALSE); - - cursor_x = saved_x; - - if (newc != 0) - cursor_right (); - -}/* input_move */ - -#undef H(x) - -/* - * delete_char - * - * Delete the character below the cursor. - * - */ - -static void delete_char (void) -{ - - input_move (0, input.buffer[input.pos]); - -}/* delete_char */ - -/* - * delete_left - * - * Delete the character to the left of the cursor. - * - */ - -static void delete_left (void) -{ - - if (input.pos > 0) { - cursor_left (); - delete_char (); - } - -}/* delete_left */ - -/* - * truncate_line - * - * Truncate the input line to n characters. - * - */ - -static void truncate_line (int n) -{ - - last_char (); - - while (input.length > n) - delete_left (); - -}/* truncate_line */ - -/* - * insert_char - * - * Insert a character into the input buffer. - * - */ - -static void insert_char (zchar newc) -{ - zchar oldc = 0; - - if (overwrite) - oldc = input.buffer[input.pos]; - - input_move (newc, oldc); - -}/* insert_char */ - -/* - * insert_string - * - * Add a string of characters to the input line. - * - */ - -static void insert_string (const zchar *s) -{ - - while (*s != 0) { - - if (input.length + 1 > input.max_length) - break; - if (input.width + os_char_width (*s) > input.max_width) - break; - - insert_char (*s++); - - } - -}/* insert_string */ - -/* - * tabulator_key - * - * Complete the word at the end of the input line, if possible. - * - */ - -static void tabulator_key (void) -{ - int status; - - if (input.pos == input.length) { - - zchar extension[10]; - - status = completion (input.buffer, extension); - insert_string (extension); - - } else status = 2; - - /* Beep if the completion was impossible or ambiguous */ - - if (status != 0) - os_beep (status); - -}/* tabulator_key */ - -/* - * store_input - * - * Copy the current input line to the history buffer. - * - */ - -static void store_input (void) -{ - - if (input.length >= HISTORY_MIN_ENTRY) { - - const zchar *ptr = input.buffer; - - do { - - if (history.latest++ == HISTORY_BUFSIZE - 1) - history.latest = 0; - - history.buffer[history.latest] = *ptr; - - } while (*ptr++ != 0); - - } - -}/* store_input */ - -/* - * fetch_entry - * - * Copy the current history entry to the input buffer and check if it - * matches the prefix in the input buffer. - * - */ - -static bool fetch_entry (zchar *buf, int entry) -{ - int i = 0; - - zchar c; - - do { - - if (entry++ == HISTORY_BUFSIZE - 1) - entry = 0; - - c = history.buffer[entry]; - - if (i < history.prefix_len && input.buffer[i] != c) - return FALSE; - - buf[i++] = c; - - } while (c != 0); - - return (i > history.prefix_len) && (i > 1); - -}/* fetch_entry */ - -/* - * get_prev_entry - * - * Copy the previous history entry to the input buffer. - * - */ - -static void get_prev_entry (void) -{ - zchar buf[INPUT_BUFFER_SIZE]; - - int i = history.current; - - do { - - do { - - if (i-- == 0) - i = HISTORY_BUFSIZE - 1; - - if (i == history.latest) - return; - - } while (history.buffer[i] != 0); - - } while (!fetch_entry (buf, i)); - - truncate_line (history.prefix_len); - - insert_string (buf + history.prefix_len); - - history.current = i; - -}/* get_prev_entry */ - -/* - * get_next_entry - * - * Copy the next history entry to the input buffer. - * - */ - -static void get_next_entry (void) -{ - zchar buf[INPUT_BUFFER_SIZE]; - - int i = history.current; - - truncate_line (history.prefix_len); - - do { - - do { - - if (i == history.latest) - return; - - if (i++ == HISTORY_BUFSIZE - 1) - i = 0; - - } while (history.buffer[i] != 0); - - if (i == history.latest) - goto no_further; - - } while (!fetch_entry (buf, i)); - - insert_string (buf + history.prefix_len); - -no_further: - - history.current = i; - -}/* get_next_entry */ - -/* - * os_read_line - * - * Read a line of input from the keyboard into a buffer. The buffer - * may already be primed with some text. In this case, the "initial" - * text is already displayed on the screen. After the input action - * is complete, the function returns with the terminating key value. - * The length of the input should not exceed "max" characters plus - * an extra 0 terminator. - * - * Terminating keys are the return key (13) and all function keys - * (see the Specification of the Z-machine) which are accepted by - * the is_terminator function. Mouse clicks behave like function - * keys except that the mouse position is stored in global variables - * "mouse_x" and "mouse_y" (top left coordinates are (1,1)). - * - * Furthermore, Frotz introduces some special terminating keys: - * - * ZC_HKEY_PLAYBACK (Alt-P) - * ZC_HKEY_RECORD (Alt-R) - * ZC_HKEY_SEED (Alt-S) - * ZC_HKEY_UNDO (Alt-U) - * ZC_HKEY_RESTART (Alt-N, "new game") - * ZC_HKEY_QUIT (Alt-X, "exit game") - * ZC_HKEY_DEBUGGING (Alt-D) - * ZC_HKEY_HELP (Alt-H) - * - * If the timeout argument is not zero, the input gets interrupted - * after timeout/10 seconds (and the return value is 0). - * - * The complete input line including the cursor must fit in "width" - * screen units. - * - * The function may be called once again to continue after timeouts, - * misplaced mouse clicks or hot keys. In this case the "continued" - * flag will be set. This information can be useful if the interface - * implements input line history. - * - * The screen is not scrolled after the return key was pressed. The - * cursor is at the end of the input line when the function returns. - * - * Since Inform 2.2 the helper function "completion" can be called - * to implement word completion (similar to tcsh under Unix). - * - */ - -#define new_history_search() \ - { history.prefix_len = input.pos; history.current = history.latest; } - -zchar os_read_line (int max, zchar *buf, int timeout, int width, int continued) -{ - int key = continued ? 9999 : 0; - - /* Initialise input variables */ - - input.buffer = buf; - input.pos = strlen ((char *) buf); - input.length = strlen ((char *) buf); - input.max_length = max; - input.width = os_string_width (buf); - input.max_width = width - os_char_width (' '); - - /* Calculate time limit */ - - set_timer (timeout); - - /* Loop until a terminator is found */ - - do { - - if (key != 9999) - new_history_search (); - - /* Get next key from mouse or keyboard */ - - key = get_key (TRUE); - - if (key < ZC_ASCII_MIN || key > ZC_ASCII_MAX && key < ZC_LATIN1_MIN || key > ZC_LATIN1_MAX) { - - /* Ignore time-outs if the cursor is not at end of the line */ - - if (key == ZC_TIME_OUT && input.pos < input.length) - key = 9999; - - /* Backspace, return and escape keys */ - - if (key == ZC_BACKSPACE) - delete_left (); - if (key == ZC_RETURN) - store_input (); - if (key == ZC_ESCAPE) - truncate_line (0); - - /* Editing keys */ - - if (cwin == 0) { - - if (key == ZC_ARROW_UP) - get_prev_entry (); - if (key == ZC_ARROW_DOWN) - get_next_entry (); - if (key == ZC_ARROW_LEFT) - cursor_left (); - if (key == ZC_ARROW_RIGHT) - cursor_right (); - - if (key >= ZC_ARROW_MIN && key <= ZC_ARROW_MAX) - key = 9999; - - if (key == SPECIAL_KEY_HOME) - first_char (); - if (key == SPECIAL_KEY_END) - last_char (); - if (key == SPECIAL_KEY_WORD_LEFT) - prev_word (); - if (key == SPECIAL_KEY_WORD_RIGHT) - next_word (); - if (key == SPECIAL_KEY_DELETE) - delete_char (); - if (key == SPECIAL_KEY_INSERT) - overwrite = !overwrite; - if (key == SPECIAL_KEY_TAB) - tabulator_key (); - - } - - if (key == SPECIAL_KEY_PAGE_UP) - key = ZC_ARROW_UP; - if (key == SPECIAL_KEY_PAGE_DOWN) - key = ZC_ARROW_DOWN; - - } else insert_char (key); - - } while (key > 0xff || !is_terminator (key)); - - last_char (); - - overwrite = FALSE; - - /* Return terminating key */ - - return key; - -}/* os_read_line */ - -#undef new_history_search() - -/* - * os_read_key - * - * Read a single character from the keyboard (or a mouse click) and - * return it. Input aborts after timeout/10 seconds. - * - */ - -zchar os_read_key (int timeout, bool cursor) -{ - int key; - - set_timer (timeout); - - do { - - key = get_key (cursor); - - } while (key > 0xff); - - return key; - -}/* os_read_key */ - -/* - * os_read_file_name - * - * Return the name of a file. Flag can be one of: - * - * FILE_SAVE - Save game file - * FILE_RESTORE - Restore game file - * FILE_SCRIPT - Transscript file - * FILE_RECORD - Command file for recording - * FILE_PLAYBACK - Command file for playback - * FILE_SAVE_AUX - Save auxilary ("preferred settings") file - * FILE_LOAD_AUX - Load auxilary ("preferred settings") file - * - * The length of the file name is limited by MAX_FILE_NAME. Ideally - * an interpreter should open a file requester to ask for the file - * name. If it is unable to do that then this function should call - * print_string and read_string to ask for a file name. - * - */ - -int os_read_file_name (char *file_name, const char *default_name, int flag) -{ - char *extension; - FILE *fp; - bool terminal; - bool result; - - bool saved_replay = istream_replay; - bool saved_record = ostream_record; - - /* Turn off playback and recording temporarily */ - - istream_replay = FALSE; - ostream_record = FALSE; - - /* Select appropriate extension */ - - extension = ".aux"; - - if (flag == FILE_SAVE || flag == FILE_RESTORE) - extension = ".sav"; - if (flag == FILE_SCRIPT) - extension = ".scr"; - if (flag == FILE_RECORD || flag == FILE_PLAYBACK) - extension = ".rec"; - - /* Input file name (reserve four bytes for a file name extension) */ - - print_string ("Enter file name (\""); - print_string (extension); - print_string ("\" will be added).\nDefault is \""); - print_string (default_name); - print_string ("\": "); - - read_string (MAX_FILE_NAME - 4, (zchar *) file_name); - - /* Use the default name if nothing was typed */ - - if (file_name[0] == 0) - strcpy (file_name, default_name); - if (strchr (file_name, '.') == NULL) - strcat (file_name, extension); - - /* Make sure it is safe to use this file name */ - - result = TRUE; - - /* OK if the file is opened for reading */ - - if (flag != FILE_SAVE && flag != FILE_SAVE_AUX && flag != FILE_RECORD) - goto finished; - - /* OK if the file does not exist */ - - if ((fp = fopen (file_name, "rb")) == NULL) - goto finished; - - /* OK if this is a pseudo-file (like PRN, CON, NUL) */ - - terminal = fp->flags & _F_TERM; - - fclose (fp); - - if (terminal) - goto finished; - - /* OK if user wants to overwrite */ - - result = read_yes_or_no ("Overwrite existing file"); - -finished: - - /* Restore state of playback and recording */ - - istream_replay = saved_replay; - ostream_record = saved_record; - - return result; - -}/* os_read_file_name */ diff --git a/bcmouse.c b/bcmouse.c deleted file mode 100644 index ea8444b..0000000 --- a/bcmouse.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * file "BCmouse.c" - * - * Borland C front end, mouse support - * - */ - -#include -#include "frotz.h" -#include "BCfrotz.h" - -/* - * detect_mouse - * - * Return true if a mouse driver is present. - * - */ - -bool detect_mouse (void) -{ - - asm xor ax,ax - asm int 0x33 - - return _AX; - -}/* detect_mouse */ - -/* - * read_mouse - * - * Report any mouse clicks. Return 2 for a double click, 1 for a single - * click or 0 if there was no mouse activity at all. - * - */ - -int read_mouse (void) -{ - int click; - - /* Read the current mouse status */ - - for (click = 0; click < 2; click++) { - - if (click == 1) - delay (222); - - asm mov ax,6 - asm xor bx,bx - asm int 0x33 - - if (_BX == 0) - break; - - mouse_x = _CX; - mouse_y = _DX; - - if (display <= _TEXT_) { - mouse_x /= 8; - mouse_y /= 8; - } - - if (display == _MCGA_) - mouse_x /= 2; - - mouse_x++; - mouse_y++; - - } - - /* Return single or double click */ - - return click; - -}/* read_mouse */ diff --git a/bcpic.c b/bcpic.c deleted file mode 100644 index 59115a9..0000000 --- a/bcpic.c +++ /dev/null @@ -1,677 +0,0 @@ -/* - * "BCpic.c" - * - * Borland C front end, picture functions - * - */ - -#include -#include -#include -#include -#include "frotz.h" -#include "BCfrotz.h" - -#define PIC_NUMBER 0 -#define PIC_WIDTH 2 -#define PIC_HEIGHT 4 -#define PIC_FLAGS 6 -#define PIC_DATA 8 -#define PIC_COLOUR 11 - -#define READ_BYTE(v,p,o) v = *(byte far *)(p+o) -#define READ_WORD(v,p,o) v = *(word far *)(p+o) - -extern byte far *get_scrnptr (int); - -static struct { - byte fileno; - byte flags; - word unused1; - word images; - word link; - byte entry_size; - byte padding; - word checksum; - word unused2; - word version; -} gheader; - -int scaler = 1; - -static word pic_width = 0; -static word pic_height = 0; -static word pic_flags = 0; -static long pic_data = 0; -static long pic_colour = 0; - -static byte far *table_val = NULL; -static word far *table_ref = NULL; - -static FILE *file = NULL; -static byte far *info = NULL; - -/* - * open_graphics_file - * - * Open a graphics file. EGA pictures may be stored in two separate - * graphics files. - * - */ - -static bool open_graphics_file (int number) -{ - char fname[MAX_FILE_NAME + 1]; - char extension[4 + 1]; - - /* Build graphics file name */ - - extension[0] = '.'; - extension[1] = "cmem"[display - 2]; - extension[2] = 'g'; - extension[3] = '0' + number; - extension[4] = 0; - - strcpy (fname, stripped_story_name); - strcat (fname, extension); - - /* Open file, load header, allocate memory, load picture directory */ - - if ((file = fopen (fname, "rb")) == NULL) - goto failure1; - if (fread (&gheader, sizeof (gheader), 1, file) != 1) - goto failure2; - if ((info = farmalloc (gheader.images * gheader.entry_size)) == NULL) - goto failure2; - if (fread (info, gheader.entry_size, gheader.images, file) != gheader.images) - goto failure3; - return TRUE; - -failure3: - farfree (info); info = NULL; -failure2: - fclose (file); file = NULL; -failure1: - return FALSE; - -}/* open_graphics_file */ - -/* - * close_graphics_file - * - * Free resources allocated for pictures. - * - */ - -static void close_graphics_file (void) -{ - - if (file != NULL) - { fclose (file); file = NULL; } - if (info != NULL) - { farfree (info); info = NULL; } - -}/* close_graphics_file */ - -/* - * init_pictures - * - * Prepare to draw pictures. Return true if pictures are available. - * - */ - -bool init_pictures (void) -{ - - /* Allocate memory for decompression */ - - table_val = (byte far *) farmalloc (3 * 3840); - table_ref = (word far *) (table_val + 3840); - - if (table_val == NULL) - return FALSE; - - /* Open the [first of two] graphics file[s] */ - - return open_graphics_file (1); - -}/* init_pictures */ - -/* - * reset_pictures - * - * Free resources allocated for decompression of pictures. - * - */ - -void reset_pictures (void) -{ - - if (table_val != NULL) - { farfree (table_val); table_val = NULL; } - if (file != NULL) - { fclose (file); file = NULL; } - if (info != NULL) - { farfree (info); info = NULL; } - -}/* reset_pictures */ - -/* - * load_picture_info - * - * Helper function for os_picture_data. Load all information about - * the given picture from the graphics file and store it in global - * variables. - * - */ - -static bool load_picture_info (int picture) -{ - byte far *ptr; - byte fileno; - - fileno = gheader.fileno; - - do { - - int i; - - /* Abort if there is a problem with the graphics file */ - - if (file == NULL) - return FALSE; - - /* Scan the directory of the current graphics file */ - - ptr = info; - - for (i = 0; i < gheader.images; i++) { - - if (picture == * (int far *) ptr) { - - READ_WORD (pic_width, ptr, PIC_WIDTH); - READ_WORD (pic_height, ptr, PIC_HEIGHT); - READ_WORD (pic_flags, ptr, PIC_FLAGS); - - pic_height *= scaler; - pic_width *= scaler; - - READ_BYTE (byte0 (pic_data), ptr, PIC_DATA + 2); - READ_BYTE (byte1 (pic_data), ptr, PIC_DATA + 1); - READ_BYTE (byte2 (pic_data), ptr, PIC_DATA); - - if (gheader.entry_size > PIC_COLOUR + 2) { - - READ_BYTE (byte0 (pic_colour), ptr, PIC_COLOUR + 2); - READ_BYTE (byte1 (pic_colour), ptr, PIC_COLOUR + 1); - READ_BYTE (byte2 (pic_colour), ptr, PIC_COLOUR); - - } else pic_colour = 0; - - return TRUE; - - } - - ptr += gheader.entry_size; - - } - - /* Close current graphics file */ - - close_graphics_file (); - - /* Open next graphics file */ - - open_graphics_file ((gheader.link != 0) ? gheader.fileno + 1 : 1); - - } while (fileno != gheader.fileno); - - return FALSE; - -}/* load_picture_info */ - -/* - * load_colour_map - * - * Helper function for os_draw_picture. Load a colour map from the - * graphics file then copy it to the palette registers. - * - */ - -static void load_colour_map (int first_colour) -{ - byte rgb[42]; - int n, i; - - fseek (file, pic_colour, SEEK_SET); - - /* Some pictures from Arthur mistakenly claim to have 16 colours */ - - if ((n = fgetc (file)) == 16) - n = 14; - - /* Each colour is stored in three bytes R-G-B */ - - fread (rgb, 3, n, file); - - /* MCGA boards can only handle R-G-B values from 0 to 63 */ - - for (i = 0; i < 42; i++) - rgb[i] = (rgb[i] * 63 + 128) / 255; - - /* Synchronise with vertical retrace */ - - while ((inportb (0x03da) & 8) == 0); - while ((inportb (0x03da) & 8) == 8); - - /* Copy colours to palette registers */ - - asm mov ax,0x1012 - asm mov bx,first_colour - asm mov cx,n - asm lea dx,rgb - asm push ss - asm pop es - asm int 0x10 - -}/* load_colour_map */ - -/* - * draw_picture - * - * Helper function for os_draw_picture. The real work of drawing a - * picture happens here. - * - */ - -#pragma warn -def - -static void pascal draw_picture (int y, int x) -{ - static int raise_bits[4] = { - 0x0100, 0x0300, 0x0700, 0x0000 - }; - - byte buf[512]; - byte far *screen; - byte transparent; - byte colour_shift; - int first_colour; - int code, prev_code; - int next_entry; - int bits_per_code; - int bits_shift; - int bits; - int current_y; - int current_x; - int bufpos; - int pixels; - int i; - - bufpos = 0; - - /* When the given picture provides a colour map then activate it. - This is only used for MCGA pictures; the colour map affects - every picture on the screen. The first colour to be defined is - colour 2. Every map defines up to 14 colours (colour 2 to 15). - These colours are not related to the standard Z-machine colour - scheme which remains unchanged. (This is based on the Amiga - interpreter which had to work with 16 colours. Colours 0 and 1 - were used for text; changing the text colours actually changed - palette entries 0 and 1. This interface uses the same trick in - Amiga mode.) */ - - if (display == _CGA_) - colour_shift = -2; - if (display == _EGA_) - colour_shift = 0; - if (display == _MCGA_) - { colour_shift = 32; first_colour = 34; } - if (display == _AMIGA_) - { colour_shift = -1; first_colour = 65; } - - if (pic_colour != 0) - load_colour_map (first_colour); - - fseek (file, pic_data, SEEK_SET); - - /* Bit 0 of "flags" indicates that the picture uses a transparent - colour, the top four bits tell us which colour it is. For CGA - and MCGA pictures this is always 0; for EGA pictures it can be - any colour between 0 and 15. */ - - transparent = 0xff; - - if (pic_flags & 1) - transparent = pic_flags >> 12; - - /* Prepare EGA hardware for setting pixels */ - - if (display >= _EGA_) { - outport (0x03ce, 0x0205); - outport (0x03ce, 0xff08); - } - - /* The uncompressed picture is a long sequence of bytes. Every - byte holds the colour of a pixel, starting at the top left, - stopping at the bottom right. We keep track of our position - in the current line. (There is a special case: CGA pictures - with no transparent colour are stored as bit patterns, i.e. - every byte holds the pattern for eight pixels. A pixel must - be white if the corresponding bit is set, otherwise it must - be black.) */ - - current_x = x + pic_width; - current_y = y - 1; - - /* The compressed picture is a stream of bits. We read the file - byte-wise, storing the current byte in the variable "bits". - Several bits make one code; the variable "bits_shift" helps - us to build the next code. */ - - bits_shift = 0; - bits = 0; - -reset_table: - - /* Clear the table. We use a table of 3840 entries. Each entry - consists of both a value and a reference to another table - entry. Following these references we get a sequence of - values. At the start of decompression all table entries are - undefined. Later we see how entries are set and used. */ - - next_entry = 1; - - /* At the start of decompression 9 bits make one code; during - the process this can rise to 12 bits per code. 9 bits are - sufficient to address both 256 literal values and 256 table - entries; 12 bits are sufficient to address both 256 literal - values and all 3840 table entries. The number of bits per - code rises with the number of table entries. When the table - is cleared, the number of bits per code drops back to 9. */ - - bits_per_code = 9; - -next_code: - - /* Read the next code from the graphics file. This requires - some confusing bit operations. Note that low bits always - come first. Usually there are a few bits left over from - the previous code; these bits must be used before further - bits are read from the graphics file. */ - - code = bits >> (8 - bits_shift); - - do { - - bits = fgetc (file); - - code |= bits << bits_shift; - - bits_shift += 8; - - } while (bits_shift < bits_per_code); - - bits_shift -= bits_per_code; - - code &= 0xfff >> (12 - bits_per_code); - - /* There are two codes with a special meaning. The first one - is 256 which clears the table and sets the number of bits - per code to 9. (This is necessary when the table is full.) - The second one is 257 which marks the end of the picture. - For the sake of efficiency, we drecement the code by 256. */ - - byte1 (code) --; - - if (code == 0) - goto reset_table; - if (code == 1) - return; - - /* Codes from 0 to 255 are literals, i.e. they represent a - plain byte value. Codes from 258 onwards are references - to table entries, i.e. they represent a sequence of byte - values (see the remarks on the table above). This means - that for each code one or several byte values are added - to the decompressed picture. But there is yet more work - to do: Every time we read a code one table entry is set. - As we said above, a table entry consist of both a value - and a reference to another table entry. If the current - code is a literal, then the value has to be set to this - literal; but if the code refers to a sequence of byte - values, then the value has to be set to the last byte of - this sequence. In any case, the reference is set to the - previous code. Finally, one should be aware that a code - may legally refer to the table entry which is currently - being set. This requires some extra care. */ - - table_ref[next_entry] = prev_code; - - prev_code = code; - - while (code >= 0) { - buf[bufpos++] = table_val[code]; - code = (short) table_ref[code]; - } - - if (next_entry == prev_code) - buf[0] = code; - - table_val[next_entry] = code; - - /* The number of bits per code is incremented when the current - number of bits no longer suffices to address all defined - table entries; but in any case the number of bits may never - be greater than 12. */ - - next_entry++; - - if (next_entry == raise_bits[bits_per_code - 9]) - bits_per_code++; - -reverse_buffer: - - /* Append the sequence of byte values (pixels) to the picture. - The order of the sequence must be reversed. (This is why we - have stored the sequence in a buffer; experiments show that - a buffer of 512 bytes suffices.) The sequence of values may - spread over several lines of the picture, so we must take - care to start a new line when we reach the right border of - the picture. */ - - if (current_x == x + pic_width) { - - screen = get_scrnptr (current_y); - - current_x -= pic_width; - current_y += scaler; - - } - - /* Either add a single pixel or a pattern of eight bits (b/w - CGA pictures without a transparent colour) to the current - line. Increment our position by 1 or 8 respectively. The - pixel may have to be painted several times if the scaling - factor is greater than one. */ - - if (display == _CGA_ && transparent == 0xff) { - - pixels = x + pic_width - current_x; - - if (pixels > 8) - pixels = 8; - - asm les bx,screen - asm mov dx,current_x - asm dec dx - asm push dx - asm mov cl,3 - asm shr dx,cl - asm add bx,dx - asm mov ax,es:[bx] - asm mov dx,0xffff - asm mov cl,byte ptr pixels - asm shr dl,cl - asm pop cx - asm and cl,7 - asm ror dx,cl - asm and ax,dx - asm mov dx,code - asm inc dh - asm ror dx,cl - asm or ax,dx - asm mov es:[bx],ax - - current_x += pixels; - - } else for (i = 0; i < scaler; i++) { - - _AH = code; - - if (_AH != transparent) { - - asm add ah,colour_shift - asm les bx,screen - asm mov dx,current_x - asm dec dx - - if (display != _MCGA_) { - - asm push dx - asm mov cl,3 - asm shr dx,cl - asm pop cx - asm and cl,7 - asm add bx,dx - asm mov al,es:[bx] - - if (display == _CGA_) { - asm mov dl,0x7f - asm ror dl,cl - asm and al,dl - asm xor ah,1 - asm ror ah,1 - asm shr ah,cl - asm or ah,al - } else { - asm mov al,0x80 - asm shr al,cl - asm mov dx,0x03cf - asm out dx,al - } - - } else asm add bx,dx - - asm mov es:[bx],ah - - if (display == _AMIGA_) { - asm add bx,80 - asm mov al,es:[bx] - asm mov es:[bx],ah - } - - } - - current_x++; - - } - - /* If there are no more values in the buffer then read the - next code from the file. Otherwise fetch the next byte - value from the buffer and continue painting the picture. */ - - if (bufpos == 0) - goto next_code; - - byte0 (code) = buf[--bufpos]; - - goto reverse_buffer; - -}/* draw_picture */ - -#pragma warn +def - -/* - * os_draw_picture - * - * Display a picture at the given coordinates. Top left is (1,1). - * - */ - -void os_draw_picture (int picture, int y, int x) -{ - - if (load_picture_info (picture)) - draw_picture (y, x); - -}/* os_draw_picture */ - -/* - * os_peek_colour - * - * Return the colour of the pixel below the cursor. This is used - * by V6 games to print text on top of pictures. The coulor need - * not be in the standard set of Z-machine colours. To handle - * this situation, Frotz extends the colour scheme: Values above - * 15 (and below 256) may be used by the interface to refer to - * non-standard colours. Of course, os_set_colour must be able to - * deal with these colours. Interfaces which refer to characters - * instead of pixels might return the current background colour - * instead. - * - */ - -int os_peek_colour (void) -{ - - if (display >= _CGA_) { - - asm mov ah,13 - asm mov bh,0 - asm mov cx,cursor_x - asm mov dx,cursor_y - asm int 0x10 - asm mov ah,0 - - return _AX + 16; - - } else return current_bg; - -}/* os_peek_colour */ - -/* - * os_picture_data - * - * Return true if the given picture is available. If so, write the - * width and height of the picture into the appropriate variables. - * Only when picture 0 is asked for, write the number of available - * pictures and the release number instead. - * - */ - -bool os_picture_data (int picture, int *height, int *width) -{ - bool avail; - - if (picture == 0) { - - avail = FALSE; - - /* This is the special case mentioned above. In practice, only - the release number is used; and even this is only used by - the DOS version of "Zork Zero". Infocom's Amiga interpreter - could not handle this feature, and the Amiga version of the - story file does not use it. */ - - pic_height = gheader.images; - pic_width = gheader.version; - - } else avail = load_picture_info (picture); - - *height = pic_height; - *width = pic_width; - - return avail; - -}/* os_picture_data */ diff --git a/bcsample.c b/bcsample.c deleted file mode 100644 index bb50b23..0000000 --- a/bcsample.c +++ /dev/null @@ -1,414 +0,0 @@ -/* - * file "BCsample.c" - * - * Borland C front end, sound support - * - */ - -#include -#include -#include -#include -#include -#include "frotz.h" -#include "BCfrotz.h" - -#define SWAP_BYTES(v) {_AX=v;asm xchg al,ah;v=_AX;} - -#define READ_DSP(v) {while(!inportb(sound_adr+14)&0x80);v=inportb(sound_adr+10);} -#define WRITE_DSP(v) {while(inportb(sound_adr+12)&0x80);outportb(sound_adr+12,v);} - -extern void end_of_sound (void); - -static struct { - word prefix; - byte repeats; - byte base_note; - word frequency; - word unused; - word length; -} sheader; - -static current_sample = 0; - -static void interrupt (*vect) (void) = NULL; - -static play_part = 0; -static play_count = 0; - -static word sound_adr = 0; -static word sound_irq = 0; -static word sound_dma = 0; -static word sound_int = 0; -static word sound_ver = 0; - -static byte far *sample_data = NULL; - -static long sample_adr1 = 0; -static long sample_adr2 = 0; -static word sample_len1 = 0; -static word sample_len2 = 0; - -/* - * start_of_dma - * - * Start the DMA transfer to the sound board. - * - */ - -static void start_of_dma (long address, unsigned length) -{ - static unsigned dma_page_port[] = { - 0x87, 0x83, 0x81, 0x82 - }; - - length--; - - /* Set up DMA chip */ - - outportb (0x0a, 0x04 | sound_dma); - outportb (0x0c, 0x00); - outportb (0x0b, 0x48 | sound_dma); - outportb (2 * sound_dma, byte0 (address)); - outportb (2 * sound_dma, byte1 (address)); - outportb (dma_page_port[sound_dma], byte2 (address)); - outportb (2 * sound_dma + 1, byte0 (length)); - outportb (2 * sound_dma + 1, byte1 (length)); - outportb (0x0a, sound_dma); - - /* Play 8-bit mono sample */ - - WRITE_DSP (0x14) - WRITE_DSP (byte0 (length)) - WRITE_DSP (byte1 (length)) - -}/* start_of_dma */ - -/* - * end_of_dma - * - * This function is called when a hardware interrupt signals the - * end of the current sound. We may have to play the second half - * of the sound effect, or we may have to repeat it, or call the - * end_of_sound function when we are finished. - * - */ - -static void interrupt end_of_dma (void) -{ - - /* Play the second half, play another cycle or finish */ - - if (play_part == 1 && sample_len2 != 0) { - play_part = 2; - start_of_dma (sample_adr2, sample_len2); - } else if (play_count == 255 || --play_count != 0) { - play_part = 1; - start_of_dma (sample_adr1, sample_len1); - } else { - play_part = 0; - end_of_sound (); - } - - /* Tell interrupt controller(s) + sound board we are done */ - - outportb (0x20, 0x20); - - if (sound_irq >= 8) - outportb (0xa0, 0x20); - - inportb (sound_adr + 14); - -}/* end_of_dma */ - -/* - * init_sound - * - * Initialise the sound board and various sound related variables. - * - */ - -bool init_sound (void) -{ - const char *settings = getenv ("BLASTER"); - word irc_mask_port; - - /* Read the IRQ, port address, DMA channel and SB version */ - - if ((settings = getenv ("BLASTER")) == NULL) - return FALSE; - - sound_irq = dectoi (strchr (settings, 'I') + 1); - sound_adr = hextoi (strchr (settings, 'A') + 1); - sound_dma = dectoi (strchr (settings, 'D') + 1); - sound_ver = dectoi (strchr (settings, 'T') + 1); - - /* Reset mixer chip and DSP */ - - outportb (sound_adr + 4, 0); - outportb (sound_adr + 5, 0); - - outportb (sound_adr + 6, 1); - inportb (sound_adr + 6); - inportb (sound_adr + 6); - inportb (sound_adr + 6); - outportb (sound_adr + 6, 0); - - /* Turn on speakers */ - - WRITE_DSP (0xd1) - - /* Install the end_of_dma interrupt */ - - if (sound_irq < 8) { - irc_mask_port = 0x21; - sound_int = 0x08 + sound_irq; - } else { - irc_mask_port = 0xa1; - sound_int = 0x68 + sound_irq; - } - - vect = getvect (sound_int); setvect (sound_int, end_of_dma); - - /* Allocate 64KB RAM for sample data */ - - if ((sample_data = (byte far *) farmalloc (0x10000L)) == NULL) - return FALSE; - - word0 (sample_adr1) = FP_OFF (sample_data) | (FP_SEG (sample_data) << 4); - word1 (sample_adr1) = FP_SEG (sample_data) >> 12; - word0 (sample_adr2) = 0; - word1 (sample_adr2) = word1 (sample_adr1) + 1; - - /* Enable the end_of_dma interrupt */ - - outportb (0x20, 0x20); - - if (sound_irq >= 8) - outportb (0xa0, 0x20); - - outportb (irc_mask_port, inportb (irc_mask_port) & ~(1 << (sound_irq & 7))); - - /* Indicate success */ - - return TRUE; - -}/* init_sound */ - -/* - * reset_sound - * - * Free resources allocated for playing samples. - * - */ - -void reset_sound (void) -{ - - os_stop_sample (); - - if (sample_data != NULL) - { farfree (sample_data); sample_data = NULL; } - if (sound_adr != 0) - { setvect (sound_int, vect); sound_adr = 0; } - -}/* reset_sound */ - -/* - * os_beep - * - * Play a beep sound. Ideally, the sound should be high- (number == 1) - * or low-pitched (number == 2). - * - */ - -void os_beep (int number) -{ - word T = 888 * number; - - outportb (0x43, 0xb6); - outportb (0x42, lo (T)); - outportb (0x42, hi (T)); - outportb (0x61, inportb (0x61) | 3); - - delay (75); - - outportb (0x61, inportb (0x61) & ~3); - -}/* os_beep */ - -/* - * os_prepare_sample - * - * Load the sample from the disk. - * - */ - -void os_prepare_sample (int number) -{ - - os_stop_sample (); - - /* Exit if the sound board isn't set up properly */ - - if (sample_data == NULL) - return; - if (sound_adr == 0) - return; - - /* Continue only if the desired sample is not already present */ - - if (current_sample != number) { - - char sample_name[MAX_FILE_NAME + 1]; - char numstr[2]; - FILE *fp; - - /* Build sample file name */ - - strcpy (sample_name, "sound\\"); - - numstr[0] = '0' + number / 10; - numstr[1] = '0' + number % 10; - - strncat (sample_name, stripped_story_name, 6); - strncat (sample_name, numstr, 2); - strncat (sample_name, ".snd", 4); - - /* Open sample file */ - - if ((fp = fopen (sample_name, "rb")) == NULL) - return; - - /* Load header and sample data */ - - fread (&sheader, sizeof (sheader), 1, fp); - - SWAP_BYTES (sheader.frequency) - SWAP_BYTES (sheader.length) - - fread (sample_data, 1, sheader.length, fp); - - sample_len1 = -word0 (sample_adr1); - - if (sample_len1 > sheader.length || sample_len1 == 0) - sample_len1 = sheader.length; - - sample_len2 = sheader.length - sample_len1; - - WRITE_DSP (0x40) - WRITE_DSP (256 - 1000000L / sheader.frequency) - - current_sample = number; - - /* Close sample file */ - - fclose (fp); - - } - -}/* os_prepare_sample */ - -/* - * os_start_sample - * - * Play the given sample at the given volume (ranging from 1 to 8 and - * 255 meaning a default volume). The sound is played once or several - * times in the background (255 meaning forever). The end_of_sound - * function is called as soon as the sound finishes. - * - */ - -void os_start_sample (int number, int volume, int repeats) -{ - - os_stop_sample (); - - /* Exit if the sound board isn't set up properly */ - - if (sample_data == NULL) - return; - if (sound_adr == 0) - return; - - /* Load new sample */ - - os_prepare_sample (number); - - /* Continue only if the sample's in memory now */ - - if (current_sample == number) { - - play_count = repeats; - - if (sound_ver < 6) { /* Set up SB pro mixer chip */ - - volume = (volume != 255) ? 7 + volume : 15; - - outportb (sound_adr + 4, 0x04); - outportb (sound_adr + 5, (volume << 4) | volume); - outportb (sound_adr + 4, 0x22); - outportb (sound_adr + 5, 0xff); - - } else { /* Set up SB16 mixer chip */ - - /* Many thanks to Linards Ticmanis for writing this part! */ - - volume = (volume != 255) ? 127 + 16 * volume : 255; - - outportb (sound_adr + 4, 0x32); - outportb (sound_adr + 5, volume); - outportb (sound_adr + 4, 0x33); - outportb (sound_adr + 5, volume); - outportb (sound_adr + 4, 0x30); - outportb (sound_adr + 5, 0xff); - outportb (sound_adr + 4, 0x31); - outportb (sound_adr + 5, 0xff); - - } - - play_part = 1; - start_of_dma (sample_adr1, sample_len1); - - } - -}/* os_start_sample */ - -/* - * os_stop_sample - * - * Turn off the current sample. - * - */ - -void os_stop_sample (void) -{ - - play_part = 0; - - /* Exit if the sound board isn't set up properly */ - - if (sample_data == NULL) - return; - if (sound_adr == 0) - return; - - /* Tell DSP to stop the current sample */ - - WRITE_DSP (0xd0) - -}/* os_stop_sample */ - -/* - * os_finish_with_sample - * - * Remove the current sample from memory (if any). - * - */ - -void os_finish_with_sample (void) -{ - - os_stop_sample (); /* we keep 64KB allocated all the time */ - -}/* os_finish_with_sample */ diff --git a/bcscreen.c b/bcscreen.c deleted file mode 100644 index ed42e2e..0000000 --- a/bcscreen.c +++ /dev/null @@ -1,298 +0,0 @@ -/* - * file "BCscreen.c" - * - * Borland C front end, screen manipulation - * - */ - -#include -#include -#include "frotz.h" -#include "BCfrotz.h" - -/* - * get_scrnptr - * - * Return a pointer to the given line in video RAM. - * - */ - -byte far *get_scrnptr (int y) -{ - - if (display == _CGA_) - return MK_FP ((y & 1) ? 0xba00 : 0xb800, 40 * (y & ~1)); - else if (display == _MCGA_) - return MK_FP (0xa000, 320 * y); - else - return MK_FP (0xa000, 80 * y); - -}/* get_scrnptr */ - -/* - * clear_byte - * - * Helper function for clear_line. - * - */ - -static void clear_byte (byte far *scrn, word mask) -{ - - if (display == _CGA_) - - if (scrn_attr == 0) - *scrn &= ~mask; - else - *scrn |= mask; - - else { - - outport (0x03ce, 0x0205); - - outportb (0x03ce, 0x08); - outportb (0x03cf, mask); - - asm les bx,scrn - asm mov al,es:[bx] - asm mov al,scrn_attr - asm mov es:[bx],al - - } - -}/* clear_byte */ - -/* - * clear_line - * - * Helper function for os_erase_area. - * - */ - -static void clear_line (int y, int left, int right) -{ - byte far *scrn = get_scrnptr (y); - - if (display == _MCGA_) - - _fmemset (scrn + left, scrn_attr, right - left + 1); - - else { - - word mask1 = 0x00ff >> (left & 7); - word mask2 = 0xff80 >> (right & 7); - - int x = right / 8 - left / 8; - - scrn += left / 8; - - if (x == 0) { - mask1 &= mask2; - mask2 = 0; - } - - /* Clear first byte */ - - clear_byte (scrn++, mask1); - - /* Clear middle bytes */ - - if (display >= _EGA_) - outport (0x03ce, 0xff08); - - while (--x > 0) - *scrn++ = scrn_attr; - - /* Clear last byte */ - - clear_byte (scrn, mask2); - - } - -}/* clear_line */ - -/* - * os_erase_area - * - * Fill a rectangular area of the screen with the current background - * colour. Top left coordinates are (1,1). The cursor does not move. - * - */ - -void os_erase_area (int top, int left, int bottom, int right) -{ - int y; - - top--; - left--; - bottom--; - right--; - - if (display <= _TEXT_) { - - asm mov ax,0x0600 - asm mov ch,byte ptr top - asm mov cl,byte ptr left - asm mov dh,byte ptr bottom - asm mov dl,byte ptr right - asm mov bh,scrn_attr - asm int 0x10 - - } else - - for (y = top; y <= bottom; y++) - clear_line (y, left, right); - -}/* os_erase_area */ - -/* - * copy_byte - * - * Helper function for copy_line. - * - */ - -static void copy_byte (byte far *scrn1, byte far *scrn2, byte mask) -{ - int i; - - if (display == _CGA_) - - *scrn1 = (*scrn1 & ~mask) | (*scrn2 & mask); - - else { - - outport (0x03ce, 0x0005); - - outportb (0x03ce, 0x08); - outportb (0x03cf, mask); - - outportb (0x03ce, 0x04); - outportb (0x03c4, 0x02); - - for (i = 0; i < 4; i++) { - - outportb (0x03cf, i); - outportb (0x03c5, 1 << i); - - asm les bx,scrn2 - asm mov ah,es:[bx] - asm les bx,scrn1 - asm mov al,es:[bx] - asm mov es:[bx],ah - - } - - outportb (0x03c5, 0x0f); - - } - -}/* copy_byte */ - -/* - * copy_line - * - * Helper function for os_scroll_area. - * - */ - -static void copy_line (int y1, int y2, int left, int right) -{ - byte far *scrn1 = get_scrnptr (y1); - byte far *scrn2 = get_scrnptr (y2); - - if (display == _MCGA_) - - _fmemcpy (scrn1 + left, scrn2 + left, right - left + 1); - - else { - - word mask1 = 0x00ff >> (left & 7); - word mask2 = 0xff80 >> (right & 7); - - int x = right / 8 - left / 8; - - scrn1 += left / 8; - scrn2 += left / 8; - - if (x == 0) { - mask1 &= mask2; - mask2 = 0; - } - - /* Copy first byte */ - - copy_byte (scrn1++, scrn2++, mask1); - - /* Copy middle bytes */ - - if (display >= _EGA_) - outport (0x03ce, 0x0105); - - while (--x > 0) - *scrn1++ = *scrn2++; - - /* Copy last byte */ - - copy_byte (scrn1, scrn2, mask2); - - } - -}/* copy_line */ - -/* - * os_scroll_area - * - * Scroll a rectangular area of the screen up (units > 0) or down - * (units < 0) and fill the empty space with the current background - * colour. Top left coordinates are (1,1). The cursor stays put. - * - */ - -void os_scroll_area (int top, int left, int bottom, int right, int units) -{ - int y; - - top--; - left--; - bottom--; - right--; - - if (display <= _TEXT_) { - - asm mov ah,6 - asm mov bx,units - asm cmp bx,0 - asm jg scroll - asm mov ah,7 - asm neg bx - scroll: - asm mov al,bl - asm mov ch,byte ptr top - asm mov cl,byte ptr left - asm mov dh,byte ptr bottom - asm mov dl,byte ptr right - asm mov bh,scrn_attr - asm int 0x10 - - } else - - if (units > 0) - - for (y = top; y <= bottom; y++) - - if (y <= bottom - units) - copy_line (y, y + units, left, right); - else - clear_line (y, left, right); - - else - - for (y = bottom; y >= top; y--) - - if (y >= top - units) - copy_line (y, y + units, left, right); - else - clear_line (y, left, right); - -}/* os_scroll_area */ diff --git a/bctext.c b/bctext.c deleted file mode 100644 index 4ab9100..0000000 --- a/bctext.c +++ /dev/null @@ -1,842 +0,0 @@ -/* - * file "BCtext.c" - * - * Borland C front end, text functions - * - */ - -#include -#include -#include -#include -#include -#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> 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 */ diff --git a/fastmem.c b/fastmem.c index d121f1b..ea9b001 100644 --- a/fastmem.c +++ b/fastmem.c @@ -207,8 +207,26 @@ void init_memory (void) /* Open story file */ - if ((story_fp = fopen (story_name, "rb")) == NULL) - os_fatal ("Cannot open story file"); + if ((story_fp = fopen (story_name, "rb")) == NULL) { + + char *path, *p, tmp[256]; + + /* Story file may be on INFOCOM_PATH, rather than current directory */ + if ((path = getenv("INFOCOM_PATH")) == NULL) + os_fatal ("Cannot open story file"); + + p=strtok(path,":"); + while (p != NULL) { + sprintf(tmp, "%s/%s", p, story_name); + if ((story_fp = fopen (tmp, "rb")) == NULL) + p = strtok(NULL, ":"); + else + p = NULL; + } + + if (story_fp == NULL) + os_fatal ("Cannot open story file"); + } /* Allocate memory for story header */ diff --git a/font.dat b/font.dat deleted file mode 100644 index fe9799ca6d3dd437be5ea902fca948f7cf4edbea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26976 zcmcIsZ;V~XRUhwr`~K|O?z3ZH0pq=EZ>d`$v?)>KMq6jR*|_V-N;jcJA&SaN*0>Q( z%S&6xmRjp^u*7~qXp4%J3R*T26!Xm=`k|F7^q>+7Qa@CDifEB;MMVIKYAcXfMC9f7 zn{&^-Gxyzl*OA&YyLbMaIcLtCnLGE)oO_=!_XXC3fh0DfTQ>~#aLO=jnezy5`?_K6 zff<-3vxZ<1_Yl?)CkPoNOLonznFr03X^(r!iDY4H73brD=X~BhVBTvUH!J3GcOk-y z^iffiVOvrsycQC$l({&tRA68}VlLo+5OFPM*v}jIZ>}X&%1Ce^GwHOE56QkUUS@id0^NM2L^aw++4= zA&dV3((RBeOW*LZT+8T!PWgm2D8Gykdry$7Pa5OqZIXN_xsrtsjT3V^LrFwh-oa-P zE}Bc`lKYnkzhxGDxR}KYxYq-4XWWA0`1pX-f;khQ4ep9_X2B&AfIWwj5Vp{6ViwIZ z{@H`GF@NM@e1e$}K+*pAlCubjnGev$eI}FpQI#JhA&h*hY*|CZANRiA7ZUH7G$c2# zK)yxH?j`&$BE4`3{{?e1q#qC6gFd{^F)X^p@$ZCqw}G|sL9Bi6HSb0^hwyTUhqj^r zB2?&~Bg?Ry^)T*V6@ACF@-}W{)TEdG#qB?2u9{VhKJWiFQrFBgIV}?Iz-{~a$$2Ir znt%ED$SmVEnm?G0n3G-xdD4(a0AK&l!Q+F+le5WL`%?_A=OX<0`+iQIG)ECmQdi^e z2js@{r*=+N%V!SEtLT^B!wF{n10FgO*8InV>n5Ul}n_%0Q@qngq6INN%^lw^w#I37P*)CPvWJP^K`}t zsm+sUZ4O9ZWI^>E(%=MwR06 z;e0NmHsCc^xw|LZxyS_!xi`+dOWQNwlD$ipWQar znU5myUY-Qfla_bW4=2$mqwbV{Vs05~p1z!=A*k)e`k)I@3&peiIvb{F$%B$YGzlN01NG;kQq)uSTQToMr{Wo9pYs%LqS!N~QGuvh# zocD9h#m}cgG9f7ErTqjPxOQ=jdx)3v_SW-Mbz?vHIwoe7}$qHXd6ckc3NszBf@}4SoFY)}g zxEB&=!IkVD`X{prAG>YZtGd_w&hSH7{UZF^F|87DP1@rKrXhrPfQV zc?-E^PNiBD#T@(l8-E#l&Vc}&HGhkz(W+Z>|L#t@v+gnH0<=-Qx#IrA4PgDOxZjWP zW0sjkci#O&6+K3dz!Bsq*+#aR zdOYXZ05$>djWCQd(PhNy@w{`l8|V$NrV-DEbpJJS*n>ek#s2GO%`Y0$u)h%fRqYR? z130mPhU@X(-fqDA_8ag9_PS}riyXWbPxqqCr!4oUm)wfu9k}j>=6Um#tcven!~Vnf zuK_Rn3Ef{-?Oz~&1HGSrhweW(KbCPPN#Gt%=Z|zlEx$GBKtj0xk~wJn?ySnb7n`OY zultWBjC2*f!ES-=)#D9Tq&hsg^NC%Dmmc!^u<4se!D$UPa+Q4;?>{)QvM$Pri-GL2 zyD0B3wEuN@?SCDfvT=V_k9Sy?O#Y1F3Oz)=faDN7pTAA?<`DckX3RSDQCRr#{z}F# z+#g&ogaa*gDgD#=71D?LtHOu+tHSI2q5d?4{3(j+w+_!b9BtYyGU_aeVHwuzM|`*j zTcQB%U)}yg`&Wn8{?*~x66LSMEC2fa#~Aa&;vTz}>!-YbBmWBeR%^Q3IXcs7x4Yd| zyVdUG&}wzNK=u3mnO=8hX1dew&Cbm9X8PU!O#j$Szt;v$r`_pxx?K{tx~)Day3^Aj zWNNxK-7~Eg8MZppv#8Ua?X*#`-RrQaE?9T)4>;QI0j2>n0%#D>?{!6-KH6XtUM41U zpz7`esGTqvO!GuA2Rn2- z<_icf4BI=sox#pvnB+(%x>&jTW+pvqA9AbavB3-J2P3@79u?*pnIB2iL)sE@SK{#k zjO1wnN?_gsLlEypv;RV7`&ThH!nLb*kQrZTPon&2l{~;Ix;1gi@jIm7dQ>eGkL?HCk=U!Z018gJgT)B3+mkb6;Z`{ooQ0v$s zm=g%tE4w89k+Syj7HnRIi#Yog3;3P+FF@}Sn*~P;I-0j0#H$3)Hv&Kl^C3O7t(NsgBP+$>^lj4`D-)%^XxKaW zXG;2e#9YSyTIcABdBHrVq>K;qU*zK>qm*D4MklA~kI-Y5GH{;qJUoDJ{!edVurN5c zb8`0-gYDU9eHs6srxv;ydN9WS6_A_sb8Z06c*20Mgs6SYKb$@Q<5xfMiv1TO^t?KV zmYsjXu!iWKPoDh#gdAyJu6T{pOiG^5t(n^h?+kP;v1s9NkX2l4+>1eVJ>98af2A_% zMGx`%+V0lO_L1K~L{Rd4It@6HE8}Ra)2!!f#f28n(+)G_v`jw?W%+{ zq}Mvnm>*>Nt3H1(o?@~7C+X>5EccST2pylRNb^33?}BHb6_GyHkMfssTEbnjR(gIL zPgjiJdgb%Au3XNCZQ@yB!3!QsY6%2(R0(IE!J;@By>@o|b+IT8QuoXh zLNkmi(3J0+_K)qK*)QVyjYvLS<15JWB3&5@edMStA#+amFZW95k=gO1UDy823}(jA46PLm*e~$W=LJxt8~vQL-e0P z>t|%8NJpOc$WDlJi5q$g@zWOX=h=RG!X_~uC#tloKAZNEz8%2+UWo81*0UF2xBS5N zKz|}#i0QMs1H>|p)Hn4=e-GCnuI1JCJ@4x#d@Q^g)bB53 z{?y}T{?y}T{?y}T{xsp)KLVdDd`pr~nG)D}`Y-GX?1MFgCAVaLBdg;3*RcQa{cFJc z{x#se{0(@||Iqyh=MVPYS>PT{=MTFf@9M0;dgCrk!uKK-$X!rp-}8KiYezkvT5ZD1 z`FB0N!IQa;p1e77b$B2$c+{=Ad2r&p&aY@;5VL(gGi3k3m2fG;(l!wORr`yu|JC@S z|JC@Sf7N&gnGF8NUOGycB40pq2%gU$gHa#iU&5#$_NiT5>-bZ<=dr@le$)A}9MQ}8 z)$cC~{pmA0wj_%AQ;je5SB)>`Pc^>KZylabK4WONFs_CVp#PW66R=;;#^)2zDXHrB zAJV^iysXmoc#*#zFZ}EFA3Cnj!3NOrlX;fr9p(L1LEnaxp?mCTYkIodYfaOOp#V2S zuh%^epT%syH#0lkne88&o$b%g^!l^2$5Dvdot_X()A`YD&60K+K8h|YN2SZ@kDqN@nBw;ph(+(URnAcmu` z6Henkd>`iDW$=F_M(6i+sW{8hN=Tv}T3@1b-Fcj@4H8?Fxtv{scf(|s=0z0=Qp!7I z709S4%Q^(`z~343=J&82Bt@ zG+xpwY>25IU+(h8piipFF?R@Zovh+OJM{W@6UaT^drCg^I2+YCb2@DYPWknV7F_kz%eE3k)9m!O~e@H4d=B4&ZDyY zJm2Q2-4J0Nsmn3B*A1oCQ06b%{Wbsg@JIc7#1R8$-O#PWep_>^ZUyfW*$8cL(s;rp zsD*$YmcCy=-4SGxpr`FIgER0jd1_o&-8p!%j+i4s71FcctGEZ*ztsT8juppBkx7b#yf@R#D!&yzd#vpIRtjr;OcV*M+xaQs9T#YkL?zvwTVqpWe) z_pORj=sCVaXsK5*KkjGzRQm1A^CVo0EAg}=$*T&eyRRX91oNN@Zliq3+i|z6&{(&) zMzRK5;9VR8wZgT*mgJ+SLBrVJ>5^N@$jPlLDED!I)z(>mtQE5O8a!C9mCAk`SqmmA zzs4b7%Cc!*#O&TRcMwL%hj1p-*xOk@%I_yg-M`0EmHMS`u?({Qp7+mTd0QZ?QRvQO zEhHft>C>=J&BW(w)kCA^7GluOuU>}Yv7Sjsi?vC$AjU$TV*zrA)g-5U#ob+9g59jXv!Vvu#W|g@+;WKJ- z)<^}}9dLiz3>r7dn6H@WzM-qaObY=4TrC zQ+9fg>gicS;Wb!aL)acWTA(pJT+d_QbQ?RXFPQI}$ILe~jLwg`{fEwvI=s%0dc4e! zI=qhmVfznS99R9yconJgI;VCo?N8dCw9lRP9kI^B!oG{`dzGRNud}co|8M5&Xr~@8 z&);f1rI)WItMPe9+`L;fkDJT(ntL=a3=`zU^^f)=zj{*8{?k6L+FyuGC-!p{Ui)81 zFZWn+8A_U-Kz}FSC z@D#v{(Cfojz>gw2vt9TjdiY?XKi!$`=m!#=&eU{gs>iP-rg>pGT@>(NbU+Fp2|l6d zO!wj4pzEOr*9MsO;Lh-HoN4cp==%>ZW;))X;rWr>EH54SFM{twd{L+9USle}Z)vSg4o z<2;TfMPO~0;S;}SdovblBFEE>*e^3tB`+v==S4oT7iVj8Hp0lcipVa#jAwUoI?ufU z11;eKxYoyKGpZS>BlN}jokc%GAf9Kt`u#z6wdIRy^s^;CK@<5Q+5fA*_* z12~pnc+$pZFGLR^f04iNUR3d?R`k8oGG2JufMuB0;;_u-b4Rg9p`9hHbNmMBs1}xD zYBknuQ9&t%OHt00^iRfz8sLo2!F7jogJh7r@z~nx+UoY|=$uKG=Ek9KQ+FraKjMVn z0djICw!F=IDUX>7!JmHn5yB`rdH*TIgWjQB1GvTXH#1t@9oYQ+AmK8Jw;_A^zL-4l zWjXgc5puQT{i^?WVf|0sQ5ld&ef^uO303yMCiDV#v*`#+Z_-alYH z@tkrEDAOmNZ<=wpKF%5qqL@EhT+XmUQ9M0(2ZvyNMr!HxFg)wItdh{I;@;QqFIGbG zNbV~BzB0bQxXwFYLPRf_diez}`jhd~o`-DW@e?^h{G|S-LNxj|40;lwd`6zqe1l=~ z`N`JOfI68Z2bBgshbMtPOxDof8z|Mte?6-1_oHat(>uUj?(GsWvoU|#5#y*9&&1S{ z+>9_h+to16Qwg5*0;21xtKefA{4`*5dV zRhiv_q1u6@boG);Xi zJB)%w?DwMQk;ZOj!ExUtzaO=Z{l&+!D&D*2qTPoJ`{(CJ1D^dm z*?{-*H{gXoHXwd?qxV8-f8%G5jv>d6vnd2V9~hp?Vx~fnQDm)Z`<`}<*x%K7@!{3e z%kNv(;}^X!b$D{8rBsK{dXj!{urj!~_n283tdxF#MQV_qnvwkjM^^2xqW>${xlQgb zivCyQi~d*Ri~d#P9ojTrGLeth5RyaiRjWWqzw0vv?=pYRt5eX2j&9k8(C;s<8F~8h z8bYYQs{KW%zbbsFzbbq&e*{~WFVt@py~xTr%yo_NBurs`@#_nIfAIp+HmE{dzyy6S z??0q}g>K4t?$Dd)MVs~X!oPn1AtPJAe-r){^!)v(?$JIx1JnNZqttuhe-H|p49M#4 zNe)+sDMWsVhdY2F>Wrxg(V zcZ@Loe7j%=@c?^bTq9>4_-qfnH9Fk6d)JLT{oW4bPItgRWjg?rBj@vI-%&0flisHPyr2(Hz@L$9Ktp==ng2 zzW*Td^}%F)JpsS%?K^LR-}ZWvtTSc;<EOq!&- zDe~#=E@P8|9x+O@{BFwp(57HSJj)Z5A>IWYII$npI$-Q}p#YY9K>htY0K_S(qg?1U z1|`c=^dKbx%N@9bUrKh!1MTHv%skoc`*Q2~v78hs`kz8>i*d)mlbQcV21OvScc2b) zkU@J2F1=~|9vi%kt?4Oz+{CY#2vaRM5Id5_mF3LgUtEm1J@K<{AQV9Lsg7paJ_Xij zDTAfa!DtETqsI@9!#iSFq>x<$^EQakLqICJXC~f;qj28z(Wqzi;snmPwr>;1Xw^kPC<`!3OQK!`Z-162O03KAp*7BUsBR;t0;lM0k@9?ALjo*E4 zxOshOHb1p-W8+hsu;_n&Ztl%Zv$65Yl~*=4%*HF9_{0X{D^Fj0aWotnv+?lh(+{Kk zS3kV*x!>F{O9E(S>q}_S42PR9eH`^KEI&+)dF2z}f;@OGgSC12x31xDh}T0_~2V#`ro$>P@cj61CZtfY5)KL diff --git a/frotz.6 b/frotz.6 new file mode 100644 index 0000000..f5dd8fb --- /dev/null +++ b/frotz.6 @@ -0,0 +1,131 @@ +.\" -*- nroff -*- +.TH FROTZ 6 2.32 +.SH NAME +frotz \- interpreter for all Infocom games +.SH SYNOPSIS +.B frotz +.RI [ options "] " file +.SH DESCRIPTION +.B Frotz +is a Z-machine interpreter. The Z-machine was a virtual machine designed +by Infocom to run all of their text adventures. It went through multiple +revisions during the lifetime of the company, and two further revisions +(V7 and V8) were created by Graham Nelson after the company's demise. +The specification is now quite well documented; this version of frotz +supports version 1.0. +.SH OPTIONS +.TP +.B \-a +Watch attribute setting. Setting and clearing of attributes on objects +will be noted in debugging messages. +.TP +.B \-A +Watch attribute testing. Every time the z-machine test an attribute value, +the test and the result will be reported. +.TP +.B \-b N +Sets the default background color. N corresponds to one of the Z-machine +colors, which are as follows: +.br +2 = black 3 = red 4 = green 5 = yellow +.br +6 = blue 7 = magenta 8 = cyan 9 = white +.br +If color support is disabled in the binary, or not +available on your terminal, this option does nothing. +.TP +.B \-c N +Sets the number of context lines used. By default, after a ``[MORE]'' +prompt, and assuming there is enough output pending, frotz will allow all +the currently visible lines to scroll off the screen before prompting +again. This switch specifies how many lines of text frotz will hold +over and display at the top of the next screen. +.TP +.B \-d +Disables color. If frotz discovers that your terminal has color support, +it will enable it by default. This switch overrides that behavior. +.TP +.B \-f N +Sets the default foreground color. N is a number corresponding to one of +the Z-machine colors, as listed above. If color support is disabled in +the binary, or not available on your terminal, this option does nothing. +.TP +.B \-h N +Manually sets the screen height. Though most curses libraries are intelligent +enough to determine the current width from the terminal, it may sometimes +be necessary to use this option to override the default. +.TP +.B \-i +Ignore runtime errors. Set this switch and Frotz no longer worries about +anything the game tries to do. This can help you to get around fatal errors. +.TP +.B \-l N +Sets the left margin, for those who might have specific formatting needs. +.TP +.B \-o +Watch object movement. This option enables debugging messages from the +interpreter which detail the moving of objects in the object tree. +.TP +.B \-O +Watch object location. These debugging messages detail the locations of +objects in the object tree. +.TP +.B \-p +Plain ASCII output only. This inhibits the output of accented letters +and other characters from the Latin-1 character set, replacing them with +reasonable alternatives. This may be necessary on devices lacking these +characters. +.TP +.B \-P +Alter the piracy opcode. The piracy opcode was never used by Infocom, and +this switch is only useful for those who like to toy around with Z-code. +.TP +.B \-r N +Sets the right margin. +.TP +.B \-s N +Set the random number seed value. The given seed value is used as the initial +seed value on every restart. This is helpful for testing games like +.B Curses +which make random decisions before the first input (such that the hot +key Alt\-S does not really help). +.TP +.B \-S N +Set the transcript width. By default your transscript files are formatted +to a width of 80 columns per line, regardless of the current screen width. +This switch allows you to change this setting. In particular, use \-S 0 +to deactivate automatic line splitting in transscript files. +.TP +.B \-t +Sets the z-machine's +.I Tandy bit, +which may affect the behavior of certain Infocom games. For example, +Zork I pretends not to have sequals, and Witness has it's language +toned down. +.TP +.B \-u N +Sets the number of slots available for frotz's multiple undo hotkey (see +below). This defaults to twenty, which should be sufficient for most +purposes. Setting too high a number here may be dangerous on machines +with limited memory. +.TP +.B \-w N +Manually sets the screen width. Again, this should not be necessary +except in special circumstances. +.TP +.B \-x +Expand the abbreviations "g","x", and "z" to "again", "examine", and "wait". +This switch was made for old Infocom games that lack the common +abbreviations introduced in later games. Use it with caution: A +few games might use "g", "x" or "z" for different purposes. +.SH ENVIRONMENT +If the INFOCOM_PATH environment variable is defined, frotz will search +those paths for game files. +.SH "SEE ALSO" +.SH CAVEATS +.SH BUGS +This program has no bugs. no bugs. no bugs. no *WHAP* thank you. +.SH AUTHOR +.B Frotz +was written by Stefan Jokisch in 1995-7. The unix port (and this man +page) were done by Galen Hazelwood. diff --git a/frotz.h b/frotz.h index 93a2c96..b62bc83 100644 --- a/frotz.h +++ b/frotz.h @@ -5,10 +5,16 @@ * */ +/* Unfortunately, frotz's bool definition conflicts with that of curses. + But since no os_* function uses it, it's safe to let the frotz core see + this definition, but have the unix port see the curses version. */ + +#ifndef __UNIX_PORT_FILE typedef int bool; #define TRUE 1 #define FALSE 0 +#endif typedef unsigned char zbyte; typedef unsigned short zword; diff --git a/ux_frotz.h b/ux_frotz.h new file mode 100644 index 0000000..dc23873 --- /dev/null +++ b/ux_frotz.h @@ -0,0 +1,10 @@ +/* + * ux_frotz.h + * + * Unix interface, declarations + * + */ + +extern int current_text_style; /* ux_init */ +extern char unix_plain_ascii; /* ux_init */ +extern int current_color; /* ux_text */ diff --git a/ux_init.c b/ux_init.c new file mode 100644 index 0000000..b2f528e --- /dev/null +++ b/ux_init.c @@ -0,0 +1,385 @@ +/* + * ux_init.c + * + * Unix interface, initialisation + * + */ + +#define __UNIX_PORT_FILE + +#include +#include +#include + +#include + +/* Prototypes for getopt */ +#ifdef USE_UNISTD_H +#include +#elif USE_GETOPT_H +#include +#else +#ifndef USE_NOTHING +extern int getopt(int, char **, char *); +extern int optind, opterr; +extern char *optarg; +#endif +#endif + +#ifdef USE_NCURSES_H +#include +#else +#include +#endif + +#include "frotz.h" +#include "ux_frotz.h" + +#define INFORMATION "\ +\n\ +FROTZ V2.32 - interpreter for all Infocom games. Complies with standard\n\ +1.0 of Graham Nelson's specification. Written by Stefan Jokisch in 1995-7\n\ +\n\ +Syntax: frotz [options] story-file\n\ +\n\ + -a watch attribute setting \t -l # left margin\n\ + -A watch attribute testing \t -o watch object movement\n\ + -b # background colour \t -O watch object locating\n\ + \t -p plain ASCII output only\n\ + \t -P alter piracy opcode\n\ + -c # context lines \t -r # right margin\n\ + -d disable color \t -s # random number seed value\n\ + \t -S # transscript width\n\ + -f # foreground colour \t -t set Tandy bit\n\ + \t -u # slots for multiple undo\n\ + -h # screen height \t -w # screen width\n\ + -i ignore runtime errors \t -x expand abbreviations g/x/z\n" + +static int user_disable_color = 0; +static int user_foreground_color = -1; +static int user_background_color = -1; +static int user_screen_width = -1; +static int user_screen_height = -1; +static int user_random_seed = -1; +static int user_tandy_bit = 0; + +static int curses_active = 0; /* true if os_init_screen has been run */ +int current_text_style = 0; /* Since I can't use attr_get, which + would make things easier, I need to + use the same hack the MS-DOS port + does...keep the current style in a + global variable. */ +char unix_plain_ascii = 0; /* true if user wants to disable latin-1 */ + +/* + * os_fatal + * + * Display error message and exit program. + * + */ + +void os_fatal (const char *s) +{ + + if (curses_active) { + os_display_string("\n\n"); + beep(); + os_set_text_style(BOLDFACE_STYLE); + os_display_string("Fatal error: "); + os_set_text_style(0); + os_display_string(s); + os_display_string("\n"); + os_reset_screen(); + exit(1); + } + + fputs ("\nFatal error: ", stderr); + fputs (s, stderr); + fputs ("\n\n", stderr); + + exit (1); + +}/* os_fatal */ + +extern char script_name[]; +extern char command_name[]; +extern char save_name[]; +extern char auxilary_name[]; + +/* + * os_process_arguments + * + * Handle command line switches. Some variables may be set to activate + * special features of Frotz: + * + * option_attribute_assignment + * option_attribute_testing + * option_context_lines + * option_object_locating + * option_object_movement + * option_left_margin + * option_right_margin + * option_ignore_errors + * option_piracy + * option_undo_slots + * option_expand_abbreviations + * option_script_cols + * + * The global pointer "story_name" is set to the story file name. + * + */ + +void os_process_arguments (int argc, char *argv[]) +{ + int c, i; + char stripped_story_name[MAX_FILE_NAME]; + char *p = NULL; + + /* Parse the options */ + + do { + + c = getopt(argc, argv, "aAb:c:df:h:il:oOpPr:s:S:tu:w:x"); + + switch(c) { + case 'a': option_attribute_assignment = 1; break; + case 'A': option_attribute_testing = 1; break; + case 'b': user_background_color = atoi(optarg); + if ((user_background_color < 2) || + (user_background_color > 9)) + user_background_color = -1; + break; + case 'c': option_context_lines = atoi(optarg); break; + case 'd': user_disable_color = 1; break; + case 'f': user_foreground_color = atoi(optarg); + if ((user_foreground_color < 2) || + (user_foreground_color > 9)) + user_foreground_color = -1; + break; + case 'h': user_screen_height = atoi(optarg); break; + case 'i': option_ignore_errors = 1; break; + case 'l': option_left_margin = atoi(optarg); break; + case 'o': option_object_movement = 1; break; + case 'O': option_object_locating = 1; break; + case 'p': unix_plain_ascii = 1; break; + case 'P': option_piracy = 1; break; + case 'r': option_right_margin = atoi(optarg); break; + case 's': user_random_seed = atoi(optarg); break; + case 'S': option_script_cols = atoi(optarg); break; + case 't': user_tandy_bit = 1; break; + case 'u': option_undo_slots = atoi(optarg); break; + case 'w': user_screen_width = atoi(optarg); break; + case 'x': option_expand_abbreviations = 1; break; + } + + } while (c != EOF); + + if (optind != argc - 1) { + puts (INFORMATION); + exit (1); + } + + /* Save the story file name */ + + story_name = argv[optind]; + + /* Strip path off the story file name */ + + p = story_name; + + for (i = 0; story_name[i] != 0; i++) + if (story_name[i] == '/') + p = story_name + i + 1; + + for (i = 0; p[i] != '\0' && p[i] != '.'; i++) + stripped_story_name[i] = p[i]; + stripped_story_name[i] = '\0'; + + /* Create nice default file names */ + + strcpy (script_name, stripped_story_name); + strcpy (command_name, stripped_story_name); + strcpy (save_name, stripped_story_name); + strcpy (auxilary_name, stripped_story_name); + + /* Don't forget the extensions */ + + strcat (script_name, ".scr"); + strcat (command_name, ".rec"); + strcat (save_name, ".sav"); + strcat (auxilary_name, ".aux"); + +}/* os_process_arguments */ + +/* + * os_init_screen + * + * Initialise the IO interface. Prepare the screen and other devices + * (mouse, sound board). Set various OS depending story file header + * entries: + * + * h_config (aka flags 1) + * h_flags (aka flags 2) + * h_screen_cols (aka screen width in characters) + * h_screen_rows (aka screen height in lines) + * h_screen_width + * h_screen_height + * h_font_height (defaults to 1) + * h_font_width (defaults to 1) + * h_default_foreground + * h_default_background + * h_interpreter_number + * h_interpreter_version + * h_user_name (optional; not used by any game) + * + * Finally, set reserve_mem to the amount of memory (in bytes) that + * should not be used for multiple undo and reserved for later use. + * + * (Unix has a non brain-damaged memory model which dosen't require such + * ugly hacks, neener neener neener. --GH :) + * + */ + +void os_init_screen (void) +{ + + /*trace(TRACE_CALLS);*/ + curses_active = 1; /* Let os_fatal know curses is running */ + initscr(); /* Set up curses */ + cbreak(); /* Raw input mode, no line processing */ + noecho(); /* No input echo */ + nonl(); /* No newline translation */ + intrflush(stdscr, TRUE); /* Flush output on interrupt */ + keypad(stdscr, TRUE); /* Enable the keypad and function keys */ + scrollok(stdscr, FALSE); /* No scrolling unless explicitly asked for */ + + if (h_version == V3 && user_tandy_bit != 0) + h_config |= CONFIG_TANDY; + + if (h_version == V3) + h_config |= CONFIG_SPLITSCREEN; + + if (h_version >= V4) + h_config |= CONFIG_BOLDFACE | CONFIG_EMPHASIS | CONFIG_FIXED | CONFIG_TIMEDINPUT; + +#ifndef SOUND_SUPPORT + if (h_version >= V5) + h_flags &= ~(GRAPHICS_FLAG | SOUND_FLAG | MOUSE_FLAG | MENU_FLAG); + + if (h_version == V3) + h_flags &= ~OLD_SOUND_FLAG; +#else + if (h_version >= V5) + h_flags &= ~(GRAPHICS_FLAG | MOUSE_FLAG | MENU_FLAG); + + if ((h_version >= 5) && (h_flags & SOUND_FLAG)) { + if (unix_init_sound()) + h_flags |= SOUND_FLAG; + else + h_flags &= ~SOUND_FLAG; + } + if ((h_version == 3) && (h_flags & OLD_SOUND_FLAG)) { + if (unix_init_sound()) + h_flags |= OLD_SOUND_FLAG; + else + h_flags &= ~OLD_SOUND_FLAG; + } +#endif + + if (h_version >= V5 && (h_flags & UNDO_FLAG)) + if (option_undo_slots == 0) + h_flags &= ~UNDO_FLAG; + + getmaxyx(stdscr, h_screen_rows, h_screen_cols); + + if (user_screen_height != -1) + h_screen_rows = user_screen_height; + if (user_screen_width != -1) + h_screen_cols = user_screen_width; + + h_screen_width = h_screen_cols; + h_screen_height = h_screen_rows; + + h_font_width = 1; + h_font_height = 1; + + h_interpreter_number = INTERP_DEC_20; /* We is a DECsystem-20 :) */ + h_interpreter_version = 'F'; + +#ifdef COLOR_SUPPORT + if (has_colors() && !user_disable_color) { + h_config |= CONFIG_COLOUR; + h_flags |= COLOUR_FLAG; /* FIXME: beyond zork handling? */ + start_color(); + if (user_foreground_color != -1) + h_default_foreground = user_foreground_color; + else + h_default_foreground = WHITE_COLOUR; + if (user_background_color != -1) + h_default_background = user_background_color; + else + h_default_background = BLUE_COLOUR; + os_set_colour(h_default_foreground, h_default_background); + bkgdset(current_color); + erase(); + /*os_erase_area(1, 1, h_screen_rows, h_screen_cols);*/ + } + else + if (h_flags & COLOUR_FLAG) h_flags &= ~COLOUR_FLAG; +#endif + + refresh(); + +}/* os_init_screen */ + +/* + * os_reset_screen + * + * Reset the screen before the program stops. + * + */ + +void os_reset_screen (void) +{ + + os_set_text_style(0); + os_display_string((zchar *) "[Hit any key to exit.]"); + os_read_key(0, FALSE); + scrollok(stdscr, TRUE); scroll(stdscr); + refresh(); endwin(); + +}/* os_reset_screen */ + +/* + * os_restart_game + * + * This routine allows the interface to interfere with the process of + * restarting a game at various stages: + * + * RESTART_BEGIN - restart has just begun + * RESTART_WPROP_SET - window properties have been initialised + * RESTART_END - restart is complete + * + */ + +void os_restart_game (int stage) +{ +} + +/* + * os_random_seed + * + * Return an appropriate random seed value in the range from 0 to + * 32767, possibly by using the current system time. + * + */ + +int os_random_seed (void) +{ + + if (user_random_seed == -1) + /* Use the epoch as seed value */ + return (time(0) & 0x7fff); + else return user_random_seed; + +}/* os_random_seed */ diff --git a/ux_input.c b/ux_input.c new file mode 100644 index 0000000..3676162 --- /dev/null +++ b/ux_input.c @@ -0,0 +1,489 @@ +/* + * ux_input.c + * + * Unix interface, input functions + * + */ + +#define __UNIX_PORT_FILE + +#include +#include +#include + +#include + +#ifdef USE_NCURSES_H +#include +#else +#include +#endif + +#include "frotz.h" +#include "ux_frotz.h" + +static struct timeval global_timeout; + +#define MAX_HISTORY 20 +static char *history_buffer[MAX_HISTORY]; +static short history_pointer = 0; /* Pointer to next available slot */ +static short history_frame = 0; /* Pointer to what the user's looking at */ + +extern bool is_terminator (zchar); +extern void read_string (int, zchar *); +extern int completion (const zchar *, zchar *); + +/* + * unix_set_global_timeout + * + * This sets up a time structure to determine when unix_read_char should + * return zero (representing input timeout). When current system time + * equals global_timeout, boom. + * + */ + +static void unix_set_global_timeout(int timeout) +{ + if (!timeout) global_timeout.tv_sec = 0; + else { + gettimeofday(&global_timeout, NULL); + global_timeout.tv_sec += (timeout/10); + global_timeout.tv_usec += ((timeout%10)*100000); + if (global_timeout.tv_usec > 999999) { + global_timeout.tv_sec++; + global_timeout.tv_usec -= 1000000; + } + } +} + +/* + * unix_read_char + * + * This uses the curses getch() routine to get the next character typed, + * and returns it unless the global timeout is reached. It returns values + * which the standard considers to be legal input, and also returns editing + * and frotz hot keys. If called with a non-zero flag, it will also return + * line-editing keys like INSERT, etc, + * + */ + +static int unix_read_char(int flag) +{ + int c; + struct timeval ctime; + + while(1) { + /* Timed keyboard input. Crude but functional. */ + if (global_timeout.tv_sec) { + nodelay(stdscr, TRUE); + do { + c = getch(); + if (c == ERR) { + gettimeofday(&ctime, NULL); + if ((ctime.tv_sec >= global_timeout.tv_sec) && + (ctime.tv_usec >= global_timeout.tv_usec)) { + nodelay(stdscr, FALSE); + return 0; + } + } + } while (c == ERR); + nodelay(stdscr, FALSE); + } + /* The easy way. */ + else c = getch(); + + /* Catch 98% of all input right here... */ + if ( ((c >= 32) && (c <= 126)) || (c == 13) || (c == 8)) + return c; + + /* ...and the other 2% makes up 98% of the code. :( */ + switch(c) { + /* Lucian P. Smith reports KEY_ENTER on Irix 5.3. 10 has never + been reported, but I'm leaving it in just in case. */ + case 10: case KEY_ENTER: return 13; + /* I've seen KEY_BACKSPACE returned on some terminals. */ + case KEY_BACKSPACE: return 8; + /* On seven-bit connections, "Alt-Foo" is returned as an escape + followed by the ASCII value of the letter. We have to decide + here whether to return a single escape or a frotz hot key. */ + case 27: nodelay(stdscr, TRUE); c = getch(); nodelay(stdscr, FALSE); + if (c == ERR) return 27; + switch(c) { + case 112: return ZC_HKEY_PLAYBACK; /* Alt-P */ + case 114: return ZC_HKEY_RECORD; /* Alt-R */ + case 115: return ZC_HKEY_SEED; /* Alt-S */ + case 117: return ZC_HKEY_UNDO; /* Alt-U */ + case 110: return ZC_HKEY_RESTART; /* Alt-N */ + case 120: return ZC_HKEY_QUIT; /* Alt-X */ + case 100: return ZC_HKEY_DEBUG; /* Alt-D */ + case 104: return ZC_HKEY_HELP; /* Alt-H */ + default: return 27; + } + break; + /* The standard function key block. */ + case KEY_UP: return 129; + case KEY_DOWN: return 130; + case KEY_LEFT: return 131; + case KEY_RIGHT: return 132; + case KEY_F(1): return 133; case KEY_F(2): return 134; + case KEY_F(3): return 135; case KEY_F(4): return 136; + case KEY_F(5): return 137; case KEY_F(6): return 138; + case KEY_F(7): return 139; case KEY_F(8): return 140; + case KEY_F(9): return 141; case KEY_F(10): return 142; + case KEY_F(11): return 143; case KEY_F(12): return 144; + /* Curses can't differentiate keypad numbers from cursor keys. Damn. */ + /* This will catch the alt-keys on 8-bit clean input streams... */ + case 240: return ZC_HKEY_PLAYBACK; /* Alt-P */ + case 242: return ZC_HKEY_RECORD; /* Alt-R */ + case 243: return ZC_HKEY_SEED; /* Alt-S */ + case 245: return ZC_HKEY_UNDO; /* Alt-U */ + case 238: return ZC_HKEY_RESTART; /* Alt-N */ + case 248: return ZC_HKEY_QUIT; /* Alt-X */ + case 228: return ZC_HKEY_DEBUG; /* Alt-D */ + case 232: return ZC_HKEY_HELP; /* Alt-H */ +#ifdef EMACS_EDITING + case 21: return 27; /* Ctrl-U, erase line */ + case 2: return 131; /* Ctrl-B, left arrow */ + case 6: return 132; /* Ctrl-F, right arrow */ + case 16: return 129; /* Ctrl-P, up arrow */ + case 14: return 130; /* Ctrl-N, down arrow */ + case 1: c = KEY_HOME; break; /* Ctrl-A */ + case 4: c = 127; break; /* Ctrl-D */ + case 5: c = KEY_END; break; /* Ctrl-E */ +#endif + default: break; /* Who knows? */ + } + + /* Finally, if we're in full line mode (os_read_line), we might return + codes which aren't legal Z-machine keys but are used by the editor. */ + if (flag) return c; + } +} + + +/* + * unix_add_to_history + * + * Add the given string to the next available history buffer slot. Commandeer + * that slot if necessary using realloc. + * + */ + +static void unix_add_to_history(zchar *str) +{ + + if (history_buffer[history_pointer] == NULL) + history_buffer[history_pointer] = (char *) malloc(strlen(str) + 1); + else + history_buffer[history_pointer] = + (char *) realloc(history_buffer[history_pointer], strlen(str) + 1); + strcpy(history_buffer[history_pointer], str); + history_pointer = ((history_pointer + 1) % MAX_HISTORY); + history_frame = history_pointer; /* Reset user frame after each line */ +} + +/* + * unix_history_back + * + * Copy last available string to str, if possible. Return 1 if successful. + * + */ + +static int unix_history_back(zchar *str) +{ + + history_frame--; if (history_frame==-1) history_frame = (MAX_HISTORY - 1); + if ((history_frame == history_pointer) || + (history_buffer[history_frame] == NULL)) { + beep(); history_frame = (history_frame + 1) % MAX_HISTORY; + return 0; + } + strcpy(str, history_buffer[history_frame]); + return 1; + +} + +/* + * unix_history_forward + * + * Opposite of unix_history_back, and works in the same way. + * + */ + +static int unix_history_forward(zchar *str) +{ + + history_frame = (history_frame + 1) % MAX_HISTORY; + if ((history_frame == history_pointer) || + (history_buffer[history_frame] == NULL)) { + beep(); history_frame--; if (history_frame == -1) history_frame = + (MAX_HISTORY - 1); + return 0; + } + strcpy(str, history_buffer[history_frame]); + return 1; + +} + +/* + * os_read_line + * + * Read a line of input from the keyboard into a buffer. The buffer + * may already be primed with some text. In this case, the "initial" + * text is already displayed on the screen. After the input action + * is complete, the function returns with the terminating key value. + * The length of the input should not exceed "max" characters plus + * an extra 0 terminator. + * + * Terminating keys are the return key (13) and all function keys + * (see the Specification of the Z-machine) which are accepted by + * the is_terminator function. Mouse clicks behave like function + * keys except that the mouse position is stored in global variables + * "mouse_x" and "mouse_y" (top left coordinates are (1,1)). + * + * Furthermore, Frotz introduces some special terminating keys: + * + * ZC_HKEY_KEY_PLAYBACK (Alt-P) + * ZC_HKEY_RECORD (Alt-R) + * ZC_HKEY_SEED (Alt-S) + * ZC_HKEY_UNDO (Alt-U) + * ZC_HKEY_RESTART (Alt-N, "new game") + * ZC_HKEY_QUIT (Alt-X, "exit game") + * ZC_HKEY_DEBUGGING (Alt-D) + * ZC_HKEY_HELP (Alt-H) + * + * If the timeout argument is not zero, the input gets interrupted + * after timeout/10 seconds (and the return value is 0). + * + * The complete input line including the cursor must fit in "width" + * screen units. + * + * The function may be called once again to continue after timeouts, + * misplaced mouse clicks or hot keys. In this case the "continued" + * flag will be set. This information can be useful if the interface + * implements input line history. + * + * The screen is not scrolled after the return key was pressed. The + * cursor is at the end of the input line when the function returns. + * + * Since Inform 2.2 the helper function "completion" can be called + * to implement word completion (similar to tcsh under Unix). + * + */ + +zchar os_read_line (int max, zchar *buf, int timeout, int width, int continued) +{ + int ch, scrpos, pos, y, x; + char insert_flag = 1; /* Insert mode is now default */ + + scrpos = pos = strlen((char *) buf); + + if (!continued) + history_frame = history_pointer; /* Reset user's history view */ + + unix_set_global_timeout(timeout); + + getyx(stdscr, y, x); + + do { + refresh(); /* Shouldn't be necessary, but is, to print spaces */ + + ch = unix_read_char(1); + + /* Backspace */ + if ((ch == 8) && (scrpos)) { + mvdelch(y, --x); + pos--; scrpos--; + if (scrpos != pos) + memmove(&(buf[scrpos]), &(buf[scrpos+1]), pos-scrpos); + } + + /* Delete */ + if (((ch == 127) || (ch == KEY_DC)) && (scrpos < pos)) { + delch(); pos--; + memmove(&(buf[scrpos]), &(buf[scrpos+1]), pos-scrpos); + } + + /* Left key */ + if ((ch == 131) && (scrpos)) { + scrpos--; + move(y, --x); + } + /* Right key */ + if ((ch == 132) && (scrpos < pos)) { + scrpos++; + move(y, ++x); + } + + /* Home */ + if (ch == KEY_HOME) { + x -= scrpos; scrpos = 0; + move(y, x); + } + /* End */ + if (ch == KEY_END) { + x += (pos - scrpos); scrpos = pos; + move(y,x); + } + + /* Insert */ + if (ch == KEY_IC) + insert_flag = (insert_flag ? 0 : 1); + + /* Up and down keys */ + if (ch == 129) { + if (unix_history_back(buf)) { + x -= scrpos; + move(y, x); + while (scrpos) {addch(' '); scrpos--;} + move(y, x); + addstr(buf); + scrpos = pos = strlen(buf); + x += scrpos; + } + } + if (ch == 130) { + if (unix_history_forward(buf)) { + x -= scrpos; + move(y, x); + while(scrpos) {addch(' '); scrpos--;} + move(y, x); + addstr(buf); + scrpos = pos = strlen(buf); + x += scrpos; + } + } + + /* Page up/down (passthrough as up/down arrows for beyond zork) */ + if (ch == KEY_PPAGE) ch = 129; + if (ch == KEY_NPAGE) ch = 130; + + /* Escape */ + if (ch == 27) { + /* Move cursor to end of buffer first */ + x += (pos - scrpos); scrpos = pos; move(y,x); + x -= scrpos; + move(y, x); + while (scrpos) {addch(' '); scrpos--;} + move(y, x); pos = 0; + } + + /* Tab */ + if ((ch == 9) && (scrpos == pos)) { + int status; + zchar extension[10]; + + status = completion(buf, extension); + if (status != 2) { + addstr(extension); + strcpy(&buf[pos], extension); + pos += strlen(extension); scrpos += strlen(extension); + } + if (status) beep(); + } + + /* ASCII printable */ + if ((ch >= 32) && (ch <= 126)) { + if (pos == scrpos) { + /* Append to end of buffer */ + if ((pos < max) && (pos < width)) { + buf[pos++] = (char) ch; + addch(ch); + scrpos++; x++; + } else beep(); + } + else { + /* Insert/overwrite in middle of buffer */ + if (insert_flag) { + memmove(&buf[scrpos+1], &buf[scrpos], pos-scrpos); + buf[scrpos++] = (char) ch; + insch(ch); + pos++; x++; move(y, x); + } else { + buf[scrpos++] = (char) ch; + addch(ch); + x++; + } + } + } + } while (!is_terminator(ch)); + + buf[pos] = '\0'; + if (ch == 13) unix_add_to_history(buf); + return ch; + +}/* os_read_line */ + +/* + * os_read_key + * + * Read a single character from the keyboard (or a mouse click) and + * return it. Input aborts after timeout/10 seconds. + * + */ + +zchar os_read_key (int timeout, int cursor) +{ + zchar c; + + refresh(); + if (!cursor) curs_set(0); + + unix_set_global_timeout(timeout); + c = (zchar) unix_read_char(0); + + if (!cursor) curs_set(1); + return c; + +}/* os_read_key */ + +/* + * os_read_file_name + * + * Return the name of a file. Flag can be one of: + * + * FILE_SAVE - Save game file + * FILE_RESTORE - Restore game file + * FILE_SCRIPT - Transscript file + * FILE_RECORD - Command file for recording + * FILE_PLAYBACK - Command file for playback + * FILE_SAVE_AUX - Save auxilary ("preferred settings") file + * FILE_LOAD_AUX - Load auxilary ("preferred settings") file + * + * The length of the file name is limited by MAX_FILE_NAME. Ideally + * an interpreter should open a file requester to ask for the file + * name. If it is unable to do that then this function should call + * print_string and read_string to ask for a file name. + * + */ + +int os_read_file_name (char *file_name, const char *default_name, int flag) +{ + + int saved_replay = istream_replay; + int saved_record = ostream_record; + + /* Turn off playback and recording temporarily */ + + istream_replay = 0; + ostream_record = 0; + + print_string ("Enter a file name.\nDefault is \""); + print_string (default_name); + print_string ("\": "); + + read_string (MAX_FILE_NAME, file_name); + + /* Use the default name if nothing was typed */ + + if (file_name[0] == 0) + strcpy (file_name, default_name); + + /* Restore state of playback and recording */ + + istream_replay = saved_replay; + ostream_record = saved_record; + + return 1; + +} /* os_read_file_name */ diff --git a/ux_pic.c b/ux_pic.c new file mode 100644 index 0000000..39e343b --- /dev/null +++ b/ux_pic.c @@ -0,0 +1,61 @@ +/* + * ux_pic.c + * + * Unix interface, stubs for picture functions + * + */ + +/* + * os_draw_picture + * + * Display a picture at the given coordinates. Top left is (1,1). + * + */ + +void os_draw_picture (int picture, int y, int x) +{ + + /* Not Implemented */ + +}/* os_draw_picture */ + +/* + * os_peek_colour + * + * Return the colour of the pixel below the cursor. This is used + * by V6 games to print text on top of pictures. The coulor need + * not be in the standard set of Z-machine colours. To handle + * this situation, Frotz extends the colour scheme: Values above + * 15 (and below 256) may be used by the interface to refer to + * non-standard colours. Of course, os_set_colour must be able to + * deal with these colours. Interfaces which refer to characters + * instead of pixels might return the current background colour + * instead. + * + */ + +int os_peek_colour (void) +{ + + /* Not Implemented */ + return 0; + +}/* os_peek_colour */ + +/* + * os_picture_data + * + * Return true if the given picture is available. If so, write the + * width and height of the picture into the appropriate variables. + * Only when picture 0 is asked for, write the number of available + * pictures and the release number instead. + * + */ + +int os_picture_data (int picture, int *height, int *width) +{ + + /* Not implemented */ + return 0; + +}/* os_picture_data */ diff --git a/ux_sample.c b/ux_sample.c new file mode 100644 index 0000000..1fa1871 --- /dev/null +++ b/ux_sample.c @@ -0,0 +1,107 @@ +/* + * ux_sample.c + * + * Unix interface, sound support + * + */ + +#define __UNIX_PORT_FILE + +#ifdef USE_NCURSES_H +#include +#else +#include +#endif + +#include "frotz.h" +#include "ux_frotz.h" + +/* + * os_beep + * + * Play a beep sound. Ideally, the sound should be high- (number == 1) + * or low-pitched (number == 2). + * + */ + +void os_beep (int number) +{ + + beep(); + +}/* os_beep */ + +/* + * os_prepare_sample + * + * Load the sample from the disk. + * + */ + +void os_prepare_sample (int number) +{ + + /* Not implemented */ + +}/* os_prepare_sample */ + +/* + * os_start_sample + * + * Play the given sample at the given volume (ranging from 1 to 8 and + * 255 meaning a default volume). The sound is played once or several + * times in the background (255 meaning forever). In Z-code 3 the + * repeats value is always 0 and the number of repeats is taken from + * the sound file itself. The end_of_sound function is called as soon + * as the sound finishes. + * + */ + +void os_start_sample (int number, int volume, int repeats) +{ + + /* Not implemented */ + +}/* os_start_sample */ + +/* + * os_stop_sample + * + * Turn off the current sample. + * + */ + +void os_stop_sample (void) +{ + + /* Not implemented */ + +}/* os_stop_sample */ + +/* + * os_finish_with_sample + * + * Remove the current sample from memory (if any). + * + */ + +void os_finish_with_sample (void) +{ + + /* Not implemented */ + +}/* os_finish_with_sample */ + +/* + * os_wait_sample + * + * Stop repeating the current sample and wait until it finishes. + * + */ + +void os_wait_sample (void) +{ + + /* Not implemented */ + +}/* os_wait_sample */ diff --git a/ux_screen.c b/ux_screen.c new file mode 100644 index 0000000..879cd28 --- /dev/null +++ b/ux_screen.c @@ -0,0 +1,101 @@ +/* + * ux_screen.c + * + * Unix interface, screen manipulation + * + */ + +#define __UNIX_PORT_FILE + +#include +#include +#include + +#ifdef USE_NCURSES_H +#include +#else +#include +#endif + +#include "frotz.h" +#include "ux_frotz.h" + +/* + * os_erase_area + * + * Fill a rectangular area of the screen with the current background + * colour. Top left coordinates are (1,1). The cursor does not move. + * + */ + +void os_erase_area (int top, int left, int bottom, int right) +{ + int y, x, i, j; + int saved_style; + + /* Catch the most common situation and do things the easy way */ + if ((top == 1) && (bottom == h_screen_rows) && + (left == 1) && (right == h_screen_cols)) + erase(); + else { + /* Sigh... */ + getyx(stdscr, y, x); + saved_style = current_text_style; + os_set_text_style(0); + top--; left--; bottom--; right--; + for (i = top; i <= bottom; i++) { + move(i, left); + for (j = left; j <= right; j++) + addch(' '); + } + + os_set_text_style(saved_style); + move(y, x); + } + + refresh(); + +}/* os_erase_area */ + +/* + * os_scroll_area + * + * Scroll a rectangular area of the screen up (units > 0) or down + * (units < 0) and fill the empty space with the current background + * colour. Top left coordinates are (1,1). The cursor stays put. + * + */ + +static int old_scroll_top = 0; +static int old_scroll_bottom = 0; + +void os_scroll_area (int top, int left, int bottom, int right, int units) +{ +#ifdef COLOR_SUPPORT + int y, x, i; + int saved_style; +#endif + + if (units != 1) os_fatal("Can't Happen (os_scroll_area)"); /* FIXME */ + + if (!((old_scroll_top == top) && (old_scroll_bottom == bottom))) { + old_scroll_top = top; old_scroll_bottom = bottom; + setscrreg(--top, --bottom); + } + scrollok(stdscr, TRUE); + scroll(stdscr); + scrollok(stdscr, FALSE); + +#ifdef COLOR_SUPPORT + if (h_flags & COLOUR_FLAG) { + getyx(stdscr, y, x); + move(old_scroll_bottom, 0); + saved_style = current_text_style; + os_set_text_style(0); + for (i = 0; i <= right; i++) addch(' '); + os_set_text_style(saved_style); + move(y, x); + } +#endif + +}/* os_scroll_area */ diff --git a/ux_text.c b/ux_text.c new file mode 100644 index 0000000..ccb933c --- /dev/null +++ b/ux_text.c @@ -0,0 +1,354 @@ +/* + * ux_text.c + * + * Unix interface, text functions + * + */ + +#define __UNIX_PORT_FILE + +#include +#include +#include + +#ifdef USE_NCURSES_H +#include +#else +#include +#endif + +#include "frotz.h" +#include "ux_frotz.h" + +#ifdef COLOR_SUPPORT +int current_color = 0; +#endif + +static char latin1_to_ascii[] = + " ! c L >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 */ -- 2.34.1