From e863c4ecfe3b60b89b80293bc4aa4a7369bb90a5 Mon Sep 17 00:00:00 2001 From: Alembic Petrofsky Date: Wed, 8 Jul 1998 04:17:14 +0000 Subject: [PATCH] Released dumb-frotz-2.32r1-std10.tar.gz --- Makefile | 73 ------ README.dumb | 279 ++++++++++++++++++++ readme.txt => README.frotz | 0 Readme.unix | 318 ---------------------- Todo | 12 - dumb-frotz.h | 37 +++ dumb-init.c | 160 +++++++++++ dumb-input.c | 422 +++++++++++++++++++++++++++++ dumb-output.c | 525 +++++++++++++++++++++++++++++++++++++ dumb-pic.c | 151 +++++++++++ fastmem.c | 22 +- frotz.6 | 131 --------- frotz.h | 6 - getopt.c | 69 ----- 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 ------------------------- 21 files changed, 1576 insertions(+), 2136 deletions(-) delete mode 100644 Makefile create mode 100644 README.dumb rename readme.txt => README.frotz (100%) delete mode 100644 Readme.unix delete mode 100644 Todo create mode 100644 dumb-frotz.h create mode 100644 dumb-init.c create mode 100644 dumb-input.c create mode 100644 dumb-output.c create mode 100644 dumb-pic.c delete mode 100644 frotz.6 delete mode 100644 getopt.c delete mode 100644 ux_frotz.h delete mode 100644 ux_init.c delete mode 100644 ux_input.c delete mode 100644 ux_pic.c delete mode 100644 ux_sample.c delete mode 100644 ux_screen.c delete mode 100644 ux_text.c diff --git a/Makefile b/Makefile deleted file mode 100644 index 21d055f..0000000 --- a/Makefile +++ /dev/null @@ -1,73 +0,0 @@ - -# 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.dumb b/README.dumb new file mode 100644 index 0000000..035aae9 --- /dev/null +++ b/README.dumb @@ -0,0 +1,279 @@ + +Dumb-Frotz, a frotz port for a standard C library and a dumb terminal. + +Port by Alembic Petrofsky . +Version 2.32r1, July 1998 + +============================== +HISTORY AND ALLEGED USEFULNESS +============================== + + In 1995 I quickly hacked zip to make it usable in an emacs shell-mode + buffer. This gave me unlimited scrollback and a gazillion + input-editing features. It also mixed in the status line with the + game text so that as I scrolled back I could easily see where and when + I had been at each input line. (This work eventually became the + dumbio.c file that was added to the jzip distribution in release + 2.02.) + + In 1997, I decided to do a similar job on frotz, partially so as to be + able to play v6 games, and partially as a silly exercise in unnatural + ways to support Z-machine I/O. I included some sort of support for + all the required z-machine features, including all the ones that are + impossible to do naturally with just the standard library: + cursor-addressable screen output, reverse video, pictures, + single-character input, timed input, and input editing. + + The result is potentially useful to/for: + - emacs junkies like myself + - character cell displays that are too dumb for curses. + - retro-freaks using a Teletype. + - speech synthesizers that work on a simple input stream. + - systems for which you have an ansi C library and no other port of frotz. + - collectors of z-machine curiosities + +======== +BUILDING +======== + + cc -o dumb-frotz *.c + +=========== +BASIC USAGE +=========== + + Invoke dumb-frotz like so: + + dumb-frotz [options] story-file [graphics-file] + + While playing, enter "\help" to see the list of special escape + characters and commands. It looks like this: + + DUMB-FROTZ runtime help: + General Commands: + \help Show this message. + \set Show the current values of runtime settings. + \s Show the current contents of the whole screen. + \d Discard the part of the input before the cursor. + \wN Advance clock N/10 seconds, possibly causing the current + and subsequent inputs to timeout. + \w Advance clock by the amount of real time since this input + started (times the current speed factor). + \t Advance clock just enough to timeout the current input + Reverse-Video Display Method Settings: + \rn none \rc CAPS \rd doublestrike \ru underline + \rbC show rv blanks as char C (orthogonal to above modes) + Output Compression Settings: + \cn none: show whole screen before every input. + \cm max: show only lines that have new nonblank characters. + \cs spans: like max, but emit a blank line between each span of + screen lines shown. + \chN Hide top N lines (orthogonal to above modes). + Misc Settings: + \sfX Set speed factor to X. (0 = never timeout automatically). + \mp Toggle use of MORE prompts + \ln Toggle display of line numbers. + \lt Toggle display of the line type identification chars. + \vb Toggle visual bell. + \pb Toggle display of picture outline boxes. + (Toggle commands can be followed by a 1 or 0 to set value ON or OFF.) + Character Escapes: + \\ backslash \# backspace \[ escape \_ return + \< \> \^ \. cursor motion \1 ..\0 f1..f10 + \D ..\X Standard Frotz hotkeys. Use \H (help) to see the list. + Line Type Identification Characters: + Input lines: + untimed timed + > T A regular line-oriented input + ) t A single-character input + } D A line input with some input before the cursor. + (Use \d to discard it.) + Output lines: + ] Output line that contains the cursor. + . A blank line emitted as part of span compression. + (blank) Any other output line. + + I won't attempt to fully explain all the features, but I will + discuss the implementation of each of the "impossible" ones. + +================================ +CURSOR-ADDRESSABLE SCREEN OUTPUT +================================ + + Dumb-frotz internally keeps an image of a rectangular screen that the + game can update in a random-access manner (at least in Z-machine + versions 4 and above it can). There are two basic approaches + supported for keeping the user informed as to the contents of the + screen: dump the whole thing to stdout every turn, or print just the + interesting parts. + + The first approach, selected by the \cn (compression: none) command, + is useful if you're really using a dumb terminal. You essentially get + get a really dumb version of curses that refreshes the display each + turn by redrawing the entire thing (with a mark to show you where the + cursor is) and then redraws the cursor line at the bottom, where you + type your input. For optimum visual effect, use on a large fast + terminal display, set height and width (-h and -w) to 1 less and 3 + less than what you've got, and blink each time you press return. + + In the compressed approach (\cm) we output only the lines that have + new information. In the default mode (\cs) we also add some blank + lines so that lines that are from different parts of the screen + aren't displayed right next to each other. + +============= +REVERSE VIDEO +============= + + Reverse video can minimally be indicated by using capitals and + underscores: "REVERSE_VIDEO". For the sake of printing terminals, + we also support (using backspaces) underlining and doublestriking. + +======== +PICTURES +======== + + Pictures are shown as outlines with the picture number in the lower + right-hand corner, like so: + + +--------+ + |::::::::| + |::::::37| + +--------+ + + Dumb-frotz reads pc picture files, which end in .cg1, .eg1, or .mg1. + It doesn't support pictures that are split into two or three files. + For the four infocom games, you can get the mg1 files from + ftp.gmd.de:/if-archive/infocom/missing-files. You actually only need + the first couple blocks of each file, which contain the dimensions + for all the pictures. + + Dumb-frotz scales the pictures according to the screen width and + height you are using (settable with the -h and -w command-line + options). All the infocom games deal pretty well with this. Here + is the opening screen for Zork Zero: + + +-------------------------------+---------+-------------------------------+ + |:::::::Banquet Hall ::::::|:::::::::|::::: Flatheadia:::::::| + |:::::::Moves:::0 :::::::::::|:::::::::|::++::::::::::Score: 0::::::5| + +-------------------------------|:::::::24|-------------------------------+ + +------+ +---------+ +-------+ + |::::::| |:::::::| + |::::::| +--------+ nother frantic day at the castle; Lord |:::::::| + |::::::| |::::::::| Dimwit Flathead the Excessive has invited a |:::::::| + |::::::| |:::::::2| few thousand friends over for dinner. Three |:::::::| + |::::::| +--------+ hundred dragons have been slaughtered for |:::::::| + |::::::| the occasion, and the kitchen is suffocated by the |:::::::| + |::::::| stench of their roasting flesh. |:::::::| + |::::::| |:::::::| + |::::::| Banquet Hall |:::::::| + |::::::| +---+ The hall is filled to capacity, and the thousands |:::::::| + |::::::| |216| of reveling guests are raising quite a din. The |:::::::| + |::::::| +---+ primary exits are to the west and south; smaller |:::::::| + |::::::| openings lead east and northeast. |:::::::| + |::::::| Dimwit is seated at the dais. His loud voice carries |:::::::| + |::::::| across the crowded hall. "Now that the statue is done, |:::::::| + |::::::| we must do something ceremonial. I have it! A |:::::::| + |::::::| dedication! We'll give everyone in the kingdom a year |:::::::| + |:::497| off and invite them to the Fublio Valley..." |::::498| + +------+ +-------+ + +====================== +SINGLE-CHARACTER INPUT +====================== + + We assume a normal line-buffered input environment, which means that + single character input is not really possible. When the game wants a + single character, you must type the character and a return (i.e. enter + a single-character line). If you just hit return (i.e. enter a blank + line) then the return is used as the character. If you enter a + multiple-character line, the extra characters are used one at a time + for subsequent single-character inputs, with no screen update in + between. This is useful for traversing menus. You can tell if the + game expects a single character or a full line by observing the + line-type character which is output in the first column of every line. + You can enter the non-printing characters (arrow keys, etc.) using + backslashed escape sequences. + +=========== +TIMED INPUT +=========== + + Standard getchar can not be made to timeout. However, we can and do + keep track of real time (to one second granularity) using time(). The + effect we produce is that the game is paused while reading input, but + when you finish entering a line, the game is first advanced by the + amount of real time that elapsed while you were typing the line, and + then the line is fed to the game. + + For example, if a game repeatedly does a read with a one second + timeout, like Border Zone, and the user takes five seconds to enter + the line "north", then the timeout routine is called five times, which + updates the game's clock, and then "north" is returned to the game + (unless the timeout routine returned "abort" one of those times, in + which case the "north" is discarded). If you've been sitting thinking + for a little while and want to check if anything has happened then + enter '\w'. This will trigger some number of timeouts to bring the + game up to the current time. + +============= +INPUT EDITING +============= + + This is the most blecherous requirement of the Z-machine: the game may + insert things into the input buffer, which the player must then be + able to edit. We minimally support this by showing the player the + game-provided input, and allowing him to type in something to be + appended to it, or to enter \d to discard it and enter something else. + +================ +TIPS FOR PLAYING +================ + + The escape sequences for the cursor keys are a pain to type, but you + hardly ever need them. For infocom hint menus, you can use N and P. + In Beyond Zork, use space for down; - and + for left and right. In + Journey, use space to switch menus; first letter of an item to select + it. You're only screwed when you want to choose [cancel]: you have to + use down several times and return. (You'd think one of '[', 'c', or + escape would work, but I guess that would be too easy.) With both of + these games, you need to use \rc to see menu highlighting. As far as + I know, these are the only two infocom titles for which reverse-video + is important. Other games show the current menu item with a '>', + and/or leave the cursor on it. + +======= +CAVEATS +======= + + Supposedly, this will work in any ansi C environment. Some things + that might prevent that: + + - non-ascii character set. I assumed this a couple places. Let me + know if you're actually using EBCDIC or a Teletype. I'll clean + things up and add some sort of transliteration. + + - lack of 8-bit char and 16-bit short. I didn't bother to think + much about this. If you're using a 36-bit Honeywell or + something, let me know. + + - Other bugs in my code. I'm sure there's plenty of 'em. + I've only tested it on a couple unix systems. + + - non-ansi compliance of your system. That's your problem. + Please don't bother sending me any "#ifdef MICROSHAFT ..." + patches. + +====== +CETERA +====== + + Comments, questions, suggestions, bug reports, bugfixes, donations, + insults, &c. are all welcome. + + If you want to take this thing to even more ridiculous extremes, here + are two ideas I had that I didn't implement: + + - Render images internally; have a command to dump screen to a ppm file. + - Do ascii rendering of images, a la pbmtoascii. With zoom and pan, the + images might actually be intelligible. diff --git a/readme.txt b/README.frotz similarity index 100% rename from readme.txt rename to README.frotz diff --git a/Readme.unix b/Readme.unix deleted file mode 100644 index 972b59e..0000000 --- a/Readme.unix +++ /dev/null @@ -1,318 +0,0 @@ -(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 deleted file mode 100644 index b189a4e..0000000 --- a/Todo +++ /dev/null @@ -1,12 +0,0 @@ -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/dumb-frotz.h b/dumb-frotz.h new file mode 100644 index 0000000..d92df12 --- /dev/null +++ b/dumb-frotz.h @@ -0,0 +1,37 @@ +/* dumb-frotz.h + * $Id: dumb-frotz.h,v 1.5 1998/07/08 03:45:40 al Exp $ + * Frotz os functions for a standard C library and a dumb terminal. + * Now you can finally play Zork Zero on your Teletype. + * + * Copyright 1997, 1998 Alembic Petrofsky . + * Any use permitted provided this notice stays intact. + */ +#include "frotz.h" +#include +#include +#include +#include +#include +#include + +/* From input.c. */ +bool is_terminator (zchar); + +/* dumb-input.c */ +bool dumb_handle_setting(const char *setting, bool show_cursor, bool startup); +void dumb_init_input(void); + +/* dumb-output.c */ +void dumb_init_output(void); +bool dumb_output_handle_setting(const char *setting, bool show_cursor, + bool startup); +void dumb_show_screen(bool show_cursor); +void dumb_show_prompt(bool show_cursor, char line_type); +void dumb_dump_screen(void); +void dumb_display_user_input(char *); +void dumb_discard_old_input(int num_chars); +void dumb_elide_more_prompt(void); +void dumb_set_picture_cell(int row, int col, char c); + +/* dumb-pic.c */ +void dumb_init_pictures(char *graphics_filename); diff --git a/dumb-init.c b/dumb-init.c new file mode 100644 index 0000000..336530a --- /dev/null +++ b/dumb-init.c @@ -0,0 +1,160 @@ +/* dumb-init.c + * $Id: dumb-init.c,v 1.4 1998/07/08 03:45:40 al Exp $ + * + * Copyright 1997,1998 Alva Petrofsky . + * Any use permitted provided this notice stays intact. + */ + +#include "dumb-frotz.h" + +static char usage[] = "\ +\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\ +DUMB-FROTZ V2.32R1 - port for all platforms. Somewhat complies with standard\n\ +9899 of ISO's specification. Written by Alembic Petrofsky in 1997-8.\n\ +\n\ +Syntax: frotz [options] story-file [graphics-file]\n\ +\n\ + -a watch attribute setting\n\ + -A watch attribute testing\n\ + -h # screen height\n\ + -i ignore runtime errors\n\ + -I # interpreter number to report to game\n\ + -o watch object movement\n\ + -O watch object locating\n\ + -p alter piracy opcode\n\ + -P transliterate latin1 to plain ASCII\n\ + -R xxx do runtime setting \\xxx before starting\n\ + (this option can be used multiple times)\n\ + -s # random number seed value\n\ + -S # transscript width\n\ + -t set Tandy bit\n\ + -u # slots for multiple undo\n\ + -w # screen width\n\ + -x expand abbreviations g/x/z\n\ +\n\ +While running, enter \"\\help\" to list the runtime escape sequences.\n\ +"; + +/* A unix-like getopt, but with the names changed to avoid any problems. */ +static int zoptind = 1; +static int zoptopt = 0; +static char *zoptarg = NULL; +static int zgetopt (int argc, char *argv[], const char *options) +{ + static pos = 1; + const char *p; + if (zoptind >= argc || argv[zoptind][0] != '-' || argv[zoptind][1] == 0) + return EOF; + zoptopt = argv[zoptind][pos++]; + zoptarg = NULL; + if (argv[zoptind][pos] == 0) + { pos = 1; zoptind++; } + p = strchr (options, zoptopt); + if (zoptopt == ':' || p == NULL) { + fputs ("illegal option -- ", stderr); + goto error; + } else if (p[1] == ':') + if (zoptind >= argc) { + fputs ("option requires an argument -- ", stderr); + goto error; + } else { + zoptarg = argv[zoptind]; + if (pos != 1) + zoptarg += pos; + pos = 1; zoptind++; + } + return zoptopt; +error: + fputc (zoptopt, stderr); + fputc ('\n', stderr); + return '?'; +}/* zgetopt */ + +static int user_screen_width = 75; +static int user_screen_height = 24; +static int user_interpreter_number = -1; +static int user_random_seed = -1; +static int user_tandy_bit = 0; +static char *graphics_filename = NULL; +static bool plain_ascii = FALSE; + +void os_process_arguments(int argc, char *argv[]) +{ + int c; + + /* Parse the options */ + do { + c = zgetopt(argc, argv, "aAh:iI:oOpPs:R:S:tu:w:x"); + switch(c) { + case 'a': option_attribute_assignment = 1; break; + case 'A': option_attribute_testing = 1; break; + case 'h': user_screen_height = atoi(zoptarg); break; + case 'i': option_ignore_errors = 1; break; + case 'I': user_interpreter_number = atoi(zoptarg); break; + case 'o': option_object_movement = 1; break; + case 'O': option_object_locating = 1; break; + case 'p': option_piracy = 1; break; + case 'P': plain_ascii = 1; break; + case 'R': dumb_handle_setting(zoptarg, FALSE, TRUE); break; + case 's': user_random_seed = atoi(zoptarg); break; + case 'S': option_script_cols = atoi(zoptarg); break; + case 't': user_tandy_bit = 1; break; + case 'u': option_undo_slots = atoi(zoptarg); break; + case 'w': user_screen_width = atoi(zoptarg); break; + case 'x': option_expand_abbreviations = 1; break; + } + } while (c != EOF); + + if (((argc - zoptind) != 1) && ((argc - zoptind) != 2)) { + puts(usage); + exit(1); + } + story_name = argv[zoptind++]; + if (zoptind < argc) + graphics_filename = argv[zoptind++]; +} + +void os_init_screen(void) +{ + if (h_version == V3 && user_tandy_bit) + h_config |= CONFIG_TANDY; + + if (h_version >= V5 && option_undo_slots == 0) + h_flags &= ~UNDO_FLAG; + + h_screen_rows = user_screen_height; + h_screen_cols = user_screen_width; + + if (user_interpreter_number > 0) + h_interpreter_number = user_interpreter_number; + else { + /* Use ms-dos for v6 (because that's what most people have the + * graphics files for), but don't use it for v5 (or Beyond Zork + * will try to use funky characters). */ + h_interpreter_number = h_version == 6 ? INTERP_MSDOS : INTERP_DEC_20; + } + h_interpreter_version = 'F'; + + dumb_init_input(); + dumb_init_output(); + dumb_init_pictures(graphics_filename); +} + +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; +} + +void os_restart_game (int stage) {} + +void os_fatal (const char *s) +{ + fprintf(stderr, "\nFatal error: %s\n", s); + exit(1); +} diff --git a/dumb-input.c b/dumb-input.c new file mode 100644 index 0000000..6a08ef9 --- /dev/null +++ b/dumb-input.c @@ -0,0 +1,422 @@ +/* dumb-input.c + * $Id: dumb-input.c,v 1.5 1998/07/08 03:45:40 al Exp $ + * Copyright 1997,1998 Alpine Petrofsky . + * Any use permitted provided this notice stays intact. + */ + +#include "dumb-frotz.h" + +static char runtime_usage[] = + "DUMB-FROTZ runtime help:\n" + " General Commands:\n" + " \\help Show this message.\n" + " \\set Show the current values of runtime settings.\n" + " \\s Show the current contents of the whole screen.\n" + " \\d Discard the part of the input before the cursor.\n" + " \\wN Advance clock N/10 seconds, possibly causing the current\n" + " and subsequent inputs to timeout.\n" + " \\w Advance clock by the amount of real time since this input\n" + " started (times the current speed factor).\n" + " \\t Advance clock just enough to timeout the current input\n" + " Reverse-Video Display Method Settings:\n" + " \\rn none \\rc CAPS \\rd doublestrike \\ru underline\n" + " \\rbC show rv blanks as char C (orthogonal to above modes)\n" + " Output Compression Settings:\n" + " \\cn none: show whole screen before every input.\n" + " \\cm max: show only lines that have new nonblank characters.\n" + " \\cs spans: like max, but emit a blank line between each span of\n" + " screen lines shown.\n" + " \\chN Hide top N lines (orthogonal to above modes).\n" + " Misc Settings:\n" + " \\sfX Set speed factor to X. (0 = never timeout automatically).\n" + " \\mp Toggle use of MORE prompts\n" + " \\ln Toggle display of line numbers.\n" + " \\lt Toggle display of the line type identification chars.\n" + " \\vb Toggle visual bell.\n" + " \\pb Toggle display of picture outline boxes.\n" + " (Toggle commands can be followed by a 1 or 0 to set value ON or OFF.)\n" + " Character Escapes:\n" + " \\\\ backslash \\# backspace \\[ escape \\_ return\n" + " \\< \\> \\^ \\. cursor motion \\1 ..\\0 f1..f10\n" + " \\D ..\\X Standard Frotz hotkeys. Use \\H (help) to see the list.\n" + " Line Type Identification Characters:\n" + " Input lines:\n" + " untimed timed\n" + " > T A regular line-oriented input\n" + " ) t A single-character input\n" + " } D A line input with some input before the cursor.\n" + " (Use \\d to discard it.)\n" + " Output lines:\n" + " ] Output line that contains the cursor.\n" + " . A blank line emitted as part of span compression.\n" + " (blank) Any other output line.\n" +; + +static float speed = 1; +static bool do_more_prompts = TRUE; + +enum input_type { + INPUT_CHAR, + INPUT_LINE, + INPUT_LINE_CONTINUED, +}; + +/* get a character. Exit with no fuss on EOF. */ +static int xgetchar(void) +{ + int c = getchar(); + if (c == EOF) { + if (feof(stdin)) { + fprintf(stderr, "\nEOT\n"); + exit(0); + } + os_fatal(strerror(errno)); + } + return c; +} + +/* Read one line, including the newline, into s. Safely avoids buffer + * overruns (but that's kind of pointless because there are several + * other places where I'm not so careful). */ +static void getline(char *s) +{ + int c; + char *p = s; + while (p < s + INPUT_BUFFER_SIZE - 1) + if ((*p++ = xgetchar()) == '\n') { + *p = '\0'; + return; + } + p[-1] = '\n'; + p[0] = '\0'; + while ((c = xgetchar()) != '\n') + ; + printf("Line too long, truncated to %s\n", s - INPUT_BUFFER_SIZE); +} + +/* Translate in place all the escape characters in s. */ +static void translate_special_chars(char *s) +{ + char *src = s, *dest = s; + while (*src) + switch(*src++) { + default: *dest++ = src[-1]; break; + case '\n': *dest++ = ZC_RETURN; break; + case '\\': + switch (*src++) { + case '\n': *dest++ = ZC_RETURN; break; + case '\\': *dest++ = '\\'; break; + case '?': *dest++ = ZC_BACKSPACE; break; + case '[': *dest++ = ZC_ESCAPE; break; + case '_': *dest++ = ZC_RETURN; break; + case '^': *dest++ = ZC_ARROW_UP; break; + case '.': *dest++ = ZC_ARROW_DOWN; break; + case '<': *dest++ = ZC_ARROW_LEFT; break; + case '>': *dest++ = ZC_ARROW_RIGHT; break; + case 'R': *dest++ = ZC_HKEY_RECORD; break; + case 'P': *dest++ = ZC_HKEY_PLAYBACK; break; + case 'S': *dest++ = ZC_HKEY_SEED; break; + case 'U': *dest++ = ZC_HKEY_UNDO; break; + case 'N': *dest++ = ZC_HKEY_RESTART; break; + case 'X': *dest++ = ZC_HKEY_QUIT; break; + case 'D': *dest++ = ZC_HKEY_DEBUG; break; + case 'H': *dest++ = ZC_HKEY_HELP; break; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + *dest++ = ZC_FKEY_MIN + src[-1] - '0' - 1; break; + case '0': *dest++ = ZC_FKEY_MIN + 9; break; + default: + fprintf(stderr, "DUMB-FROTZ: unknown escape char: %c\n", src[-1]); + fprintf(stderr, "Enter \\help to see the list\n"); + } + } + *dest = '\0'; +} + + +/* The time in tenths of seconds that the user is ahead of z time. */ +static int time_ahead = 0; + +/* Called from os_read_key and os_read_line if they have input from + * a previous call to dumb_read_line. + * Returns TRUE if we should timeout rather than use the read-ahead. + * (because the user is further ahead than the timeout). */ +static bool check_timeout(int timeout) +{ + if ((timeout == 0) || (timeout > time_ahead)) + time_ahead = 0; + else + time_ahead -= timeout; + return time_ahead != 0; +} + +/* If val is '0' or '1', set *var accordingly, otherwise toggle it. */ +static void toggle(bool *var, char val) +{ + *var = val == '1' || (val != '0' && !*var); +} + +/* Handle input-related user settings and call dumb_output_handle_setting. */ +bool dumb_handle_setting(const char *setting, bool show_cursor, bool startup) +{ + if (!strncmp(setting, "sf", 2)) { + speed = atof(&setting[2]); + printf("Speed Factor %g\n", speed); + } else if (!strncmp(setting, "mp", 2)) { + toggle(&do_more_prompts, setting[2]); + printf("More prompts %s\n", do_more_prompts ? "ON" : "OFF"); + } else { + if (!strcmp(setting, "set")) { + printf("Speed Factor %g\n", speed); + printf("More Prompts %s\n", do_more_prompts ? "ON" : "OFF"); + } + return dumb_output_handle_setting(setting, show_cursor, startup); + } + return TRUE; +} + +/* Read a line, processing commands (lines that start with a backslash + * (that isn't the start of a special character)), and write the + * first non-command to s. + * Return true if timed-out. */ +static bool dumb_read_line(char *s, char *prompt, bool show_cursor, + int timeout, enum input_type type, + zchar *continued_line_chars) +{ + time_t start_time; + + if (timeout) { + if (time_ahead >= timeout) { + time_ahead -= timeout; + return TRUE; + } + timeout -= time_ahead; + start_time = time(0); + } + time_ahead = 0; + + dumb_show_screen(show_cursor); + for (;;) { + char *command; + if (prompt) + fputs(prompt, stdout); + else + dumb_show_prompt(show_cursor, (timeout ? "tTD" : ")>}")[type]); + getline(s); + if ((s[0] != '\\') || ((s[1] != '\0') && !islower(s[1]))) { + /* Is not a command line. */ + translate_special_chars(s); + if (timeout) { + int elapsed = (time(0) - start_time) * 10 * speed; + if (elapsed > timeout) { + time_ahead = elapsed - timeout; + return TRUE; + } + } + return FALSE; + } + /* Commands. */ + + /* Remove the \ and the terminating newline. */ + command = s + 1; + command[strlen(command) - 1] = '\0'; + + if (!strcmp(command, "t")) { + if (timeout) { + time_ahead = 0; + s[0] = '\0'; + return TRUE; + } + } else if (*command == 'w') { + if (timeout) { + int elapsed = atoi(&command[1]); + time_t now = time(0); + if (elapsed == 0) + elapsed = (now - start_time) * 10 * speed; + if (elapsed >= timeout) { + time_ahead = elapsed - timeout; + s[0] = '\0'; + return TRUE; + } + timeout -= elapsed; + start_time = now; + } + } else if (!strcmp(command, "d")) { + if (type != INPUT_LINE_CONTINUED) + fprintf(stderr, "DUMB-FROTZ: No input to discard\n"); + else { + dumb_discard_old_input(strlen(continued_line_chars)); + continued_line_chars[0] = '\0'; + type = INPUT_LINE; + } + } else if (!strcmp(command, "help")) { + if (!do_more_prompts) + fputs(runtime_usage, stdout); + else { + char *current_page, *next_page; + current_page = next_page = runtime_usage; + for (;;) { + int i; + for (i = 0; (i < h_screen_rows - 2) && *next_page; i++) + next_page = strchr(next_page, '\n') + 1; + printf("%.*s", next_page - current_page, current_page); + current_page = next_page; + if (!*current_page) + break; + printf("HELP: Type for more, or q to stop: "); + getline(s); + if (!strcmp(s, "q\n")) + break; + } + } + } else if (!strcmp(command, "s")) { + dumb_dump_screen(); + } else if (!dumb_handle_setting(command, show_cursor, FALSE)) { + fprintf(stderr, "DUMB-FROTZ: unknown command: %s\n", s); + fprintf(stderr, "Enter \\help to see the list of commands\n"); + } + } +} + +/* Read a line that is not part of z-machine input (more prompts and + * filename requests). */ +static void dumb_read_misc_line(char *s, char *prompt) +{ + dumb_read_line(s, prompt, 0, 0, 0, 0); + /* Remove terminating newline */ + s[strlen(s) - 1] = '\0'; +} + +/* For allowing the user to input in a single line keys to be returned + * for several consecutive calls to read_char, with no screen update + * in between. Useful for traversing menus. */ +static char read_key_buffer[INPUT_BUFFER_SIZE]; + +/* Similar. Useful for using function key abbreviations. */ +static char read_line_buffer[INPUT_BUFFER_SIZE]; + +zchar os_read_key (int timeout, bool show_cursor) +{ + char c; + int timed_out; + + /* Discard any keys read for line input. */ + read_line_buffer[0] = '\0'; + + if (read_key_buffer[0] == '\0') { + timed_out = dumb_read_line(read_key_buffer, NULL, show_cursor, timeout, + INPUT_CHAR, NULL); + /* An empty input line is reported as a single CR. + * If there's anything else in the line, we report only the line's + * contents and not the terminating CR. */ + if (strlen(read_key_buffer) > 1) + read_key_buffer[strlen(read_key_buffer) - 1] = '\0'; + } else + timed_out = check_timeout(timeout); + + if (timed_out) + return ZC_TIME_OUT; + + c = read_key_buffer[0]; + memmove(read_key_buffer, read_key_buffer + 1, strlen(read_key_buffer)); + + /* TODO: error messages for invalid special chars. */ + + return c; +} + +zchar os_read_line (int max, zchar *buf, int timeout, int width, int continued) +{ + char *p; + int terminator; + static bool timed_out_last_time; + int timed_out; + + /* Discard any keys read for single key input. */ + read_key_buffer[0] = '\0'; + + /* After timing out, discard any further input unless we're continuing. */ + if (timed_out_last_time && !continued) + read_line_buffer[0] = '\0'; + + if (read_line_buffer[0] == '\0') + timed_out = dumb_read_line(read_line_buffer, NULL, TRUE, timeout, + buf[0] ? INPUT_LINE_CONTINUED : INPUT_LINE, + buf); + else + timed_out = check_timeout(timeout); + + if (timed_out) { + timed_out_last_time = TRUE; + return ZC_TIME_OUT; + } + + /* find the terminating character. */ + for (p = read_line_buffer;; p++) { + if (is_terminator(*p)) { + terminator = *p; + *p++ = '\0'; + break; + } + } + + /* TODO: Truncate to width and max. */ + + /* copy to screen */ + dumb_display_user_input(read_line_buffer); + + /* copy to the buffer and save the rest for next time. */ + strcat(buf, read_line_buffer); + p = read_line_buffer + strlen(read_line_buffer) + 1; + memmove(read_line_buffer, p, strlen(p) + 1); + + /* If there was just a newline after the terminating character, + * don't save it. */ + if ((read_line_buffer[0] == '\r') && (read_line_buffer[1] == '\0')) + read_line_buffer[0] = '\0'; + + timed_out_last_time = FALSE; + return terminator; +} + +int os_read_file_name (char *file_name, const char *default_name, int flag) +{ + char buf[INPUT_BUFFER_SIZE], prompt[INPUT_BUFFER_SIZE]; + FILE *fp; + + sprintf(prompt, "Please enter a filename [%s]: ", default_name); + dumb_read_misc_line(buf, prompt); + if (strlen(buf) > MAX_FILE_NAME) { + printf("Filename too long\n"); + return FALSE; + } + + strcpy (file_name, buf[0] ? buf : default_name); + + /* Warn if overwriting a file. */ + if ((flag == FILE_SAVE || flag == FILE_SAVE_AUX || flag == FILE_RECORD) + && ((fp = fopen(file_name, "rb")) != NULL)) { + fclose (fp); + dumb_read_misc_line(buf, "Overwrite existing file? "); + return(tolower(buf[0]) == 'y'); + } + return TRUE; +} + +void os_more_prompt (void) +{ + if (do_more_prompts) { + char buf[INPUT_BUFFER_SIZE]; + dumb_read_misc_line(buf, "***MORE***"); + } else + dumb_elide_more_prompt(); +} + +void dumb_init_input(void) +{ + if ((h_version >= V4) && (speed != 0)) + h_config |= CONFIG_TIMEDINPUT; + + if (h_version >= V5) + h_flags &= ~(MOUSE_FLAG | MENU_FLAG); +} diff --git a/dumb-output.c b/dumb-output.c new file mode 100644 index 0000000..6bf51d6 --- /dev/null +++ b/dumb-output.c @@ -0,0 +1,525 @@ +/* dumb-output.c + * $Id: dumb-output.c,v 1.5 1998/07/08 03:45:41 al Exp $ + * + * Copyright 1997,1998 Alfresco Petrofsky . + * Any use permitted provided this notice stays intact. + */ + +#include "dumb-frotz.h" + +static bool show_line_numbers = FALSE; +static bool show_line_types = -1; +static bool show_pictures = TRUE; +static bool visual_bell = TRUE; +static bool plain_ascii = FALSE; + +static char latin1_to_ascii[] = + " ! c L >o< Y | S '' C a << not - R _ " + "^0 +/- ^2 ^3 ' my P . , ^1 o >> 1/4 1/2 3/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 " +; + +/* h_screen_rows * h_screen_cols */ +static int screen_cells; + +/* The in-memory state of the screen. */ +/* Each cell contains a style in the upper byte and a char in the lower. */ +typedef unsigned short cell; +static cell *screen_data; + +static cell make_cell(int style, char c) {return (style << 8) | (0xff & c);} +static char cell_char(cell c) {return c & 0xff;} +static int cell_style(cell c) {return c >> 8;} + + +/* A cell's style is REVERSE_STYLE, normal (0), or PICTURE_STYLE. + * PICTURE_STYLE means the character is part of an ascii image outline + * box. (This just buys us the ability to turn box display on and off + * with immediate effect. No, not very useful, but I wanted to give + * the rv bit some company in that huge byte I allocated for it.) */ +#define PICTURE_STYLE 16 + +static int current_style = 0; + +/* Which cells have changed (1 byte per cell). */ +static char *screen_changes; + +static int cursor_row = 0, cursor_col = 0; + +/* Compression styles. */ +static enum { + COMPRESSION_NONE, COMPRESSION_SPANS, COMPRESSION_MAX, +} compression_mode = COMPRESSION_SPANS; +static char *compression_names[] = {"NONE", "SPANS", "MAX"}; +static int hide_lines = 0; + +/* Reverse-video display styles. */ +static enum { + RV_NONE, RV_DOUBLESTRIKE, RV_UNDERLINE, RV_CAPS, +} rv_mode = RV_NONE; +static char *rv_names[] = {"NONE", "DOUBLESTRIKE", "UNDERLINE", "CAPS"}; +static char rv_blank_char = ' '; + +static cell *dumb_row(int r) {return screen_data + r * h_screen_cols;} + +static char *dumb_changes_row(int r) +{ + return screen_changes + r * h_screen_cols; +} + +int os_char_width (zchar z) +{ + if (plain_ascii && z >= ZC_LATIN1_MIN && z <= ZC_LATIN1_MAX) { + char *p = latin1_to_ascii + 4 * (z - ZC_LATIN1_MIN); + return strchr(p, ' ') - p; + } + return 1; +} + +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++; + else + width += os_char_width(c); + + return width; +} + +void os_set_cursor(int row, int col) +{ + cursor_row = row - 1; cursor_col = col - 1; + if (cursor_row >= h_screen_rows) + cursor_row = h_screen_rows - 1; +} + +/* Set a cell and update screen_changes. */ +static void dumb_set_cell(int row, int col, cell c) +{ + dumb_changes_row(row)[col] = (c != dumb_row(row)[col]); + dumb_row(row)[col] = c; +} + +void dumb_set_picture_cell(int row, int col, char c) +{ + dumb_set_cell(row, col, make_cell(PICTURE_STYLE, c)); +} + +/* Copy a cell and copy its changedness state. + * This is used for scrolling. */ +static void dumb_copy_cell(int dest_row, int dest_col, + int src_row, int src_col) +{ + dumb_row(dest_row)[dest_col] = dumb_row(src_row)[src_col]; + dumb_changes_row(dest_row)[dest_col] = dumb_changes_row(src_row)[src_col]; +} + +void os_set_text_style(int x) +{ + current_style = x & REVERSE_STYLE; +} + +/* put a character in the cell at the cursor and advance the cursor. */ +static void dumb_display_char(char c) +{ + dumb_set_cell(cursor_row, cursor_col, make_cell(current_style, c)); + if (++cursor_col == h_screen_cols) + if (cursor_row == h_screen_rows - 1) + cursor_col--; + else { + cursor_row++; + cursor_col = 0; + } +} + +void dumb_display_user_input(char *s) +{ + /* copy to screen without marking it as a change. */ + while (*s) + dumb_row(cursor_row)[cursor_col++] = make_cell(0, *s++); +} + +void dumb_discard_old_input(int num_chars) +{ + /* Weird discard stuff. Grep spec for 'pain in my butt'. */ + /* The old characters should be on the screen just before the cursor. + * Erase them. */ + cursor_col -= num_chars; + if (cursor_col < 0) + cursor_col = 0; + os_erase_area(cursor_row + 1, cursor_col + 1, + cursor_row + 1, cursor_col + num_chars); +} + +void os_display_char (zchar c) +{ + if (c >= ZC_LATIN1_MIN && c <= ZC_LATIN1_MAX) { + if (plain_ascii) { + char *ptr = latin1_to_ascii + 4 * (c - ZC_LATIN1_MIN); + do + dumb_display_char(*ptr++); + while (*ptr != ' '); + } else + dumb_display_char(c); + } else if (c >= 32 && c <= 126) { + dumb_display_char(c); + } else if (c == ZC_GAP) { + dumb_display_char(' '); dumb_display_char(' '); + } else if (c == ZC_INDENT) { + dumb_display_char(' '); dumb_display_char(' '); dumb_display_char(' '); + } + return; +} + +void os_display_string (const zchar *s) +{ + zchar c; + while ((c = *s++) != 0) + if (c == ZC_NEW_FONT) + s++; + else if (c == ZC_NEW_STYLE) + os_set_text_style(*s++); + else + os_display_char (c); +} + +void os_erase_area (int top, int left, int bottom, int right) +{ + int row, col; + top--; left--; bottom--; right--; + for (row = top; row <= bottom; row++) + for (col = left; col <= right; col++) + dumb_set_cell(row, col, make_cell(current_style, ' ')); +} + +void os_scroll_area (int top, int left, int bottom, int right, int units) +{ + int row, col; + top--; left--; bottom--; right--; + if (units > 0) { + for (row = top; row <= bottom - units; row++) + for (col = left; col <= right; col++) + dumb_copy_cell(row, col, row + units, col); + os_erase_area(bottom - units + 2, left + 1, bottom + 1, right + 1); + } else if (units < 0) { + for (row = bottom; row >= top - units; row--) + for (col = left; col <= right; col++) + dumb_copy_cell(row, col, row + units, col); + os_erase_area(top + 1, left + 1, top - units, right + 1); + } +} + +int os_font_data(int font, int *height, int *width) +{ + if (font == TEXT_FONT) { + *height = 1; *width = 1; return 1; + } + return 0; +} + +void os_set_colour (int x, int y) {} +void os_set_font (int x) {} + +/* Print a cell to stdout. */ +static void show_cell(cell cel) +{ + char c = cell_char(cel); + switch (cell_style(cel)) { + case 0: + putchar(c); + break; + case PICTURE_STYLE: + putchar(show_pictures ? c : ' '); + break; + case REVERSE_STYLE: + if (c == ' ') + putchar(rv_blank_char); + else + switch (rv_mode) { + case RV_NONE: putchar(c); break; + case RV_CAPS: putchar(toupper(c)); break; + case RV_UNDERLINE: putchar('_'); putchar('\b'); putchar(c); break; + case RV_DOUBLESTRIKE: putchar(c); putchar('\b'); putchar(c); break; + } + break; + } +} + +static bool will_print_blank(cell c) +{ + return (((cell_style(c) == PICTURE_STYLE) && !show_pictures) + || ((cell_char(c) == ' ') + && ((cell_style(c) != REVERSE_STYLE) || (rv_blank_char == ' ')))); +} + +static void show_line_prefix(int row, char c) +{ + if (show_line_numbers) + printf((row == -1) ? ".." : "%02d", (row + 1) % 100); + if (show_line_types) + putchar(c); + /* Add a separator char (unless there's nothing to separate). */ + if (show_line_numbers || show_line_types) + putchar(' '); +} + +/* Print a row to stdout. */ +static void show_row(int r) +{ + if (r == -1) { + show_line_prefix(-1, '.'); + } else { + int c, last; + show_line_prefix(r, (r == cursor_row) ? ']' : ' '); + /* Don't print spaces at end of line. */ + /* (Saves bandwidth and printhead wear.) */ + /* TODO: compress spaces to tabs. */ + for (last = h_screen_cols - 1; last >= 0; last--) + if (!will_print_blank(dumb_row(r)[last])) + break; + for (c = 0; c <= last; c++) + show_cell(dumb_row(r)[c]); + } + putchar('\n'); +} + +/* Print the part of the cursor row before the cursor. */ +void dumb_show_prompt(bool show_cursor, char line_type) +{ + int i; + show_line_prefix(show_cursor ? cursor_row : -1, line_type); + if (show_cursor) + for (i = 0; i < cursor_col; i++) + show_cell(dumb_row(cursor_row)[i]); +} + +static void mark_all_unchanged(void) +{ + memset(screen_changes, 0, screen_cells); +} + +/* Check if a cell is a blank or will display as one. + * (Used to help decide if contents are worth printing.) */ +static bool is_blank(cell c) +{ + return ((cell_char(c) == ' ') + || ((cell_style(c) == PICTURE_STYLE) && !show_pictures)); +} + +/* Show the current screen contents, or what's changed since the last + * call. + * + * If compressing, and show_cursor is true, and the cursor is past the + * last nonblank character on the last line that would be shown, then + * don't show that line (because it will be redundant with the prompt + * line just below it). */ +void dumb_show_screen(bool show_cursor) +{ + int r, c, first, last; + char changed_rows[0x100]; + + /* Easy case */ + if (compression_mode == COMPRESSION_NONE) { + for (r = hide_lines; r < h_screen_rows; r++) + show_row(r); + mark_all_unchanged(); + return; + } + + /* Check which rows changed, and where the first and last change is. */ + first = last = -1; + memset(changed_rows, 0, h_screen_rows); + for (r = hide_lines; r < h_screen_rows; r++) { + for (c = 0; c < h_screen_cols; c++) + if (dumb_changes_row(r)[c] && !is_blank(dumb_row(r)[c])) + break; + changed_rows[r] = (c != h_screen_cols); + if (changed_rows[r]) { + first = (first != -1) ? first : r; + last = r; + } + } + + if (first == -1) + return; + + /* The show_cursor rule described above */ + if (show_cursor && (cursor_row == last)) { + for (c = cursor_col; c < h_screen_cols; c++) + if (!is_blank(dumb_row(last)[c])) + break; + if (c == h_screen_cols) + last--; + } + + /* Display the appropriate rows. */ + if (compression_mode == COMPRESSION_MAX) { + for (r = first; r <= last; r++) + if (changed_rows[r]) + show_row(r); + } else { + /* COMPRESSION_SPANS */ + for (r = first; r <= last; r++) { + if (changed_rows[r] || changed_rows[r + 1]) + show_row(r); + else { + while (!changed_rows[r + 1]) + r++; + show_row(-1); + } + } + if (show_cursor && (cursor_row > last + 1)) + show_row((cursor_row == last + 2) ? (last + 1) : -1); + } + + mark_all_unchanged(); +} + +/* Unconditionally show whole screen. For \s user command. */ +void dumb_dump_screen(void) +{ + int r; + for (r = 0; r < h_screen_height; r++) + show_row(r); +} + +/* Called when it's time for a more prompt but user has them turned off. */ +void dumb_elide_more_prompt(void) +{ + dumb_show_screen(FALSE); + if (compression_mode == COMPRESSION_SPANS && hide_lines == 0) { + show_row(-1); + } +} + +void os_reset_screen(void) +{ + dumb_show_screen(FALSE); +} + +void os_beep (int volume) +{ + if (visual_bell) + printf("[%s-PITCHED BEEP]\n", (volume == 1) ? "HIGH" : "LOW"); + else + putchar('\a'); /* so much for dumb. */ +} + +void os_prepare_sample (int x) {} +void os_finish_with_sample (void) {} +void os_start_sample (int x, int y, int z) {} +void os_stop_sample (void) {} + +/* if val is '0' or '1', set *var accordingly, else toggle it. */ +static void toggle(bool *var, char val) +{ + *var = val == '1' || (val != '0' && !*var); +} + +bool dumb_output_handle_setting(const char *setting, bool show_cursor, + bool startup) +{ + char *p; + int i; + + if (!strncmp(setting, "pb", 2)) { + toggle(&show_pictures, setting[2]); + printf("Picture outlines display %s\n", show_pictures ? "ON" : "OFF"); + if (startup) + return TRUE; + for (i = 0; i < screen_cells; i++) + screen_changes[i] = (cell_style(screen_data[i]) == PICTURE_STYLE); + dumb_show_screen(show_cursor); + + } else if (!strncmp(setting, "vb", 2)) { + toggle(&visual_bell, setting[2]); + printf("Visual bell %s\n", visual_bell ? "ON" : "OFF"); + os_beep(1); os_beep(2); + + } else if (!strncmp(setting, "ln", 2)) { + toggle(&show_line_numbers, setting[2]); + printf("Line numbering %s\n", show_line_numbers ? "ON" : "OFF"); + + } else if (!strncmp(setting, "lt", 2)) { + toggle(&show_line_types, setting[2]); + printf("Line-type display %s\n", show_line_types ? "ON" : "OFF"); + + } else if (*setting == 'c') { + switch (setting[1]) { + case 'm': compression_mode = COMPRESSION_MAX; break; + case 's': compression_mode = COMPRESSION_SPANS; break; + case 'n': compression_mode = COMPRESSION_NONE; break; + case 'h': hide_lines = atoi(&setting[2]); break; + default: return FALSE; + } + printf("Compression mode %s, hiding top %d lines\n", + compression_names[compression_mode], hide_lines); + + } else if (*setting == 'r') { + switch (setting[1]) { + case 'n': rv_mode = RV_NONE; break; + case 'o': rv_mode = RV_DOUBLESTRIKE; break; + case 'u': rv_mode = RV_UNDERLINE; break; + case 'c': rv_mode = RV_CAPS; break; + case 'b': rv_blank_char = setting[2] ? setting[2] : ' '; break; + default: return FALSE; + } + printf("Reverse-video mode %s, blanks reverse to '%c': ", + rv_names[rv_mode], rv_blank_char); + for (p = "sample reverse text"; *p; p++) + show_cell(make_cell(REVERSE_STYLE, *p)); + putchar('\n'); + for (i = 0; i < screen_cells; i++) + screen_changes[i] = (cell_style(screen_data[i]) == REVERSE_STYLE); + dumb_show_screen(show_cursor); + + } else if (!strcmp(setting, "set")) { + printf("Compression Mode %s, hiding top %d lines\n", + compression_names[compression_mode], hide_lines); + printf("Picture Boxes display %s\n", show_pictures ? "ON" : "OFF"); + printf("Visual Bell %s\n", visual_bell ? "ON" : "OFF"); + os_beep(1); os_beep(2); + printf("Line Numbering %s\n", show_line_numbers ? "ON" : "OFF"); + printf("Line-Type display %s\n", show_line_types ? "ON" : "OFF"); + printf("Reverse-Video mode %s, Blanks reverse to '%c': ", + rv_names[rv_mode], rv_blank_char); + for (p = "sample reverse text"; *p; p++) + show_cell(make_cell(REVERSE_STYLE, *p)); + putchar('\n'); + } else + return FALSE; + return TRUE; +} + +void dumb_init_output(void) +{ + if (h_version == V3) { + h_config |= CONFIG_SPLITSCREEN; + h_flags &= ~OLD_SOUND_FLAG; + } + + if (h_version >= V5) { + h_flags &= ~SOUND_FLAG; + } + + h_screen_height = h_screen_rows; + h_screen_width = h_screen_cols; + screen_cells = h_screen_rows * h_screen_cols; + + h_font_width = 1; h_font_height = 1; + + if (show_line_types == -1) + show_line_types = h_version > 3; + + screen_data = malloc(screen_cells * sizeof(cell)); + screen_changes = malloc(screen_cells); + os_erase_area(1, 1, h_screen_rows, h_screen_cols); + memset(screen_changes, 0, screen_cells); +} diff --git a/dumb-pic.c b/dumb-pic.c new file mode 100644 index 0000000..17f213b --- /dev/null +++ b/dumb-pic.c @@ -0,0 +1,151 @@ +/* dumb-pic.c + * $Id: dumb-pic.c,v 1.3 1998/07/08 03:45:41 al Exp $ + * + * Copyright 1997,1998 Alcibiades Petrofsky + * . + * Any use permitted provided this notice stays intact. + */ +#include "dumb-frotz.h" + +#define PIC_FILE_HEADER_FLAGS 1 +#define PIC_FILE_HEADER_NUM_IMAGES 4 +#define PIC_FILE_HEADER_ENTRY_SIZE 8 +#define PIC_FILE_HEADER_VERSION 14 + +#define PIC_HEADER_NUMBER 0 +#define PIC_HEADER_WIDTH 2 +#define PIC_HEADER_HEIGHT 4 + +static struct { + int z_num; + int width; + int height; + int orig_width; + int orig_height; +} *pict_info; +static int num_pictures = 0; + +static unsigned char lookupb(unsigned char *p, int n) {return p[n];} +static unsigned short lookupw(unsigned char *p, int n) +{ + return (p[n + 1] << 8) | p[n]; +} + +void dumb_init_pictures (char *filename) +{ + FILE *file = NULL; + int success = FALSE; + unsigned char gheader[16]; + unsigned char *raw_info = NULL; + int i, entry_size, flags; + float x_scaler, y_scaler; + + do { + if ((h_version != V6) + || !filename + || ((file = fopen (filename, "rb")) == NULL) + || (fread(&gheader, sizeof (gheader), 1, file) != 1)) + break; + + num_pictures = lookupw(gheader, PIC_FILE_HEADER_NUM_IMAGES); + entry_size = lookupb(gheader, PIC_FILE_HEADER_ENTRY_SIZE); + flags = lookupb(gheader, PIC_FILE_HEADER_FLAGS); + + raw_info = malloc(num_pictures * entry_size); + + if (fread(raw_info, num_pictures * entry_size, 1, file) != 1) + break; + + pict_info = malloc((num_pictures + 1) * sizeof(*pict_info)); + pict_info[0].z_num = 0; + pict_info[0].height = num_pictures; + pict_info[0].width = lookupw(gheader, PIC_FILE_HEADER_VERSION); + + y_scaler = h_screen_rows / 200.0; + x_scaler = h_screen_cols / ((flags & 0x08) ? 640.0 : 320.0); + + /* Copy and scale. */ + for (i = 1; i <= num_pictures; i++) { + unsigned char *p = raw_info + entry_size * (i - 1); + pict_info[i].z_num = lookupw(p, PIC_HEADER_NUMBER); + pict_info[i].orig_height = lookupw(p, PIC_HEADER_HEIGHT); + pict_info[i].orig_width = lookupw(p, PIC_HEADER_WIDTH); + pict_info[i].height = pict_info[i].orig_height * y_scaler + .5; + pict_info[i].width = pict_info[i].orig_width * x_scaler + .5; + } + success = TRUE; + } while (0); + if (file) + fclose(file); + if (raw_info) + free(raw_info); + if (success) + h_config |= CONFIG_PICTURES; + else + { + h_flags &= ~GRAPHICS_FLAG; + if (filename) + fprintf(stderr, "Warning: could not read graphics file %s\n", filename); + } +} + +/* Convert a Z picture number to an index into pict_info. */ +static int z_num_to_index(int n) +{ + int i; + for (i = 0; i <= num_pictures; i++) + if (pict_info[i].z_num == n) + return i; + return -1; +} + +bool os_picture_data(int num, int *height, int *width) +{ + int index; + + *height = 0; + *width = 0; + + if (!pict_info) + return FALSE; + + if ((index = z_num_to_index(num)) == -1) + return FALSE; + + *height = pict_info[index].height; + *width = pict_info[index].width; + + return TRUE; +} + +void os_draw_picture (int num, int row, int col) +{ + int width, height, r, c; + if (!os_picture_data(num, &height, &width) || !width || !height) + return; + col--, row--; + /* Draw corners */ + dumb_set_picture_cell(row, col, '+'); + dumb_set_picture_cell(row, col + width - 1, '+'); + dumb_set_picture_cell(row + height - 1, col, '+'); + dumb_set_picture_cell(row + height - 1, col + width - 1, '+'); + /* sides */ + for (c = col + 1; c < col + width - 1; c++) { + dumb_set_picture_cell(row, c, '-'); + dumb_set_picture_cell(row + height - 1, c, '-'); + } + for (r = row + 1; r < row + height - 1; r++) { + dumb_set_picture_cell(r, col, '|'); + dumb_set_picture_cell(r, col + width - 1, '|'); + } + /* body, but for last line */ + for (r = row + 1; r < row + height - 2; r++) + for (c = col + 1; c < col + width - 1; c++) + dumb_set_picture_cell(r, c, ':'); + /* Last line of body, including picture number. */ + if (height >= 3) + for (c = col + width - 2; c > col; c--, (num /= 10)) + dumb_set_picture_cell(row + height - 2, c, num ? (num % 10 + '0') : ':'); +} + +int os_peek_colour (void) {return BLACK_COLOUR; } diff --git a/fastmem.c b/fastmem.c index ea9b001..d121f1b 100644 --- a/fastmem.c +++ b/fastmem.c @@ -207,26 +207,8 @@ void init_memory (void) /* 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"); - } + if ((story_fp = fopen (story_name, "rb")) == NULL) + os_fatal ("Cannot open story file"); /* Allocate memory for story header */ diff --git a/frotz.6 b/frotz.6 deleted file mode 100644 index f5dd8fb..0000000 --- a/frotz.6 +++ /dev/null @@ -1,131 +0,0 @@ -.\" -*- 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 b62bc83..93a2c96 100644 --- a/frotz.h +++ b/frotz.h @@ -5,16 +5,10 @@ * */ -/* 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/getopt.c b/getopt.c deleted file mode 100644 index c1e40e1..0000000 --- a/getopt.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * getopt.c - * - * Replacement for a Unix style getopt function - * - */ - -#include -#include - -#ifndef __MSDOS__ -#define cdecl -#endif - -int optind = 1; -int optopt = 0; - -const char *optarg = NULL; - -int cdecl getopt (int argc, char *argv[], const char *options) -{ - static pos = 1; - - const char *p; - - if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == 0) - return EOF; - - optopt = argv[optind][pos++]; - optarg = NULL; - - if (argv[optind][pos] == 0) - { pos = 1; optind++; } - - p = strchr (options, optopt); - - if (optopt == ':' || p == NULL) { - - fputs ("illegal option -- ", stderr); - goto error; - - } else if (p[1] == ':') - - if (optind >= argc) { - - fputs ("option requires an argument -- ", stderr); - goto error; - - } else { - - optarg = argv[optind]; - - if (pos != 1) - optarg += pos; - - pos = 1; optind++; - - } - - return optopt; - -error: - - fputc (optopt, stderr); - fputc ('\n', stderr); - - return '?'; - -}/* getopt */ diff --git a/ux_frotz.h b/ux_frotz.h deleted file mode 100644 index dc23873..0000000 --- a/ux_frotz.h +++ /dev/null @@ -1,10 +0,0 @@ -/* - * 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 deleted file mode 100644 index b2f528e..0000000 --- a/ux_init.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - * 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 deleted file mode 100644 index 3676162..0000000 --- a/ux_input.c +++ /dev/null @@ -1,489 +0,0 @@ -/* - * 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 deleted file mode 100644 index 39e343b..0000000 --- a/ux_pic.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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 deleted file mode 100644 index 1fa1871..0000000 --- a/ux_sample.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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 deleted file mode 100644 index 879cd28..0000000 --- a/ux_screen.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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 deleted file mode 100644 index ccb933c..0000000 --- a/ux_text.c +++ /dev/null @@ -1,354 +0,0 @@ -/* - * 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