New plugin: frotz, a Z-machine interpreter, for playing interactive fiction.
The interpreter more or less passes all the tests in the z-machine test suite. It should build for every target except Archos (for which it is disabled). git-svn-id: svn://svn.rockbox.org/rockbox/trunk@24267 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
563f2602f4
commit
7f28c94eda
34 changed files with 10936 additions and 0 deletions
|
@ -28,6 +28,7 @@ fire,demos
|
|||
fireworks,demos
|
||||
firmware_flash,apps
|
||||
flipit,games
|
||||
frotz,viewers
|
||||
goban,games
|
||||
greyscale,demos
|
||||
helloworld,demos
|
||||
|
|
|
@ -25,6 +25,10 @@ jpeg
|
|||
sudoku
|
||||
reversi
|
||||
goban
|
||||
/* setjmp/longjmp are not implemented on sh */
|
||||
#if (CONFIG_CPU != SH7034)
|
||||
frotz
|
||||
#endif
|
||||
#ifdef HAVE_LCD_COLOR
|
||||
png
|
||||
#endif
|
||||
|
|
22
apps/plugins/frotz/SOURCES
Normal file
22
apps/plugins/frotz/SOURCES
Normal file
|
@ -0,0 +1,22 @@
|
|||
frotz.c
|
||||
buffer.c
|
||||
err.c
|
||||
fastmem.c
|
||||
files.c
|
||||
hotkey.c
|
||||
input.c
|
||||
main.c
|
||||
math.c
|
||||
object.c
|
||||
process.c
|
||||
quetzal.c
|
||||
random.c
|
||||
redirect.c
|
||||
screen.c
|
||||
sound.c
|
||||
stream.c
|
||||
table.c
|
||||
text.c
|
||||
variable.c
|
||||
dumb_init.c
|
||||
dumb_output.c
|
45
apps/plugins/frotz/STATUS
Normal file
45
apps/plugins/frotz/STATUS
Normal file
|
@ -0,0 +1,45 @@
|
|||
frotz is quite portable and is divided into 'common' and os-specific files.
|
||||
The common files are included here with minimal modifications. For the
|
||||
os-specific files I have started with dumbfrotz, the port intended for a plain
|
||||
C stdio system - it has its own screen buffering which is needed for rockbox.
|
||||
|
||||
Things that work
|
||||
----------------
|
||||
|
||||
Games, mostly! If the game is too large to fit in the plugin buffer it will
|
||||
stop playback and steal the audio buffer.
|
||||
|
||||
Saving and restoring (/path/to/story.sav, no filename selection).
|
||||
|
||||
Transcripts, command records and replays (likewise).
|
||||
|
||||
Undo, up to the limit of available memory (the rest of the plugin buffer if
|
||||
the game fit there, or the rest of the audio buffer if not).
|
||||
|
||||
Timed input, though it resets the timer when you enter the menu and only
|
||||
counts until you enter the keyboard.
|
||||
|
||||
Input line preloading, though the actual displayed line after editing looks
|
||||
wrong.
|
||||
|
||||
Things that don't work because I've not implemented it
|
||||
------------------------------------------------------
|
||||
|
||||
Reading buttons that don't appear on the rockbox keyboard.
|
||||
|
||||
Audible beeps (just a splash for now).
|
||||
|
||||
Setting the random seed.
|
||||
|
||||
Things which don't work in the original frotz anyway
|
||||
----------------------------------------------------
|
||||
|
||||
Mouse and menus.
|
||||
|
||||
Pictures.
|
||||
|
||||
Non-beep sound samples.
|
||||
|
||||
Unicode.
|
||||
|
||||
Colours.
|
152
apps/plugins/frotz/buffer.c
Normal file
152
apps/plugins/frotz/buffer.c
Normal file
|
@ -0,0 +1,152 @@
|
|||
/* buffer.c - Text buffering and word wrapping
|
||||
* Copyright (c) 1995-1997 Stefan Jokisch
|
||||
*
|
||||
* This file is part of Frotz.
|
||||
*
|
||||
* Frotz is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Frotz is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include "frotz.h"
|
||||
|
||||
extern void stream_char (zchar);
|
||||
extern void stream_word (const zchar *);
|
||||
extern void stream_new_line (void);
|
||||
|
||||
static zchar buffer[TEXT_BUFFER_SIZE];
|
||||
static int bufpos = 0;
|
||||
|
||||
static zchar prev_c = 0;
|
||||
|
||||
/*
|
||||
* flush_buffer
|
||||
*
|
||||
* Copy the contents of the text buffer to the output streams.
|
||||
*
|
||||
*/
|
||||
|
||||
void flush_buffer (void)
|
||||
{
|
||||
static bool locked = FALSE;
|
||||
|
||||
/* Make sure we stop when flush_buffer is called from flush_buffer.
|
||||
Note that this is difficult to avoid as we might print a newline
|
||||
during flush_buffer, which might cause a newline interrupt, that
|
||||
might execute any arbitrary opcode, which might flush the buffer. */
|
||||
|
||||
if (locked || bufpos == 0)
|
||||
return;
|
||||
|
||||
/* Send the buffer to the output streams */
|
||||
|
||||
buffer[bufpos] = 0;
|
||||
|
||||
|
||||
locked = TRUE;
|
||||
|
||||
stream_word (buffer);
|
||||
|
||||
#ifdef SPEECH_OUTPUT
|
||||
os_speech_output(buffer);
|
||||
#endif
|
||||
|
||||
locked = FALSE;
|
||||
|
||||
/* Reset the buffer */
|
||||
|
||||
bufpos = 0;
|
||||
prev_c = 0;
|
||||
|
||||
}/* flush_buffer */
|
||||
|
||||
/*
|
||||
* print_char
|
||||
*
|
||||
* High level output function.
|
||||
*
|
||||
*/
|
||||
|
||||
void print_char (zchar c)
|
||||
{
|
||||
static bool flag = FALSE;
|
||||
|
||||
if (message || ostream_memory || enable_buffering) {
|
||||
|
||||
if (!flag) {
|
||||
|
||||
/* Characters 0 and ZC_RETURN are special cases */
|
||||
|
||||
if (c == ZC_RETURN)
|
||||
{ new_line (); return; }
|
||||
if (c == 0)
|
||||
return;
|
||||
|
||||
/* Flush the buffer before a whitespace or after a hyphen */
|
||||
|
||||
if (c == ' ' || c == ZC_INDENT || c == ZC_GAP || (prev_c == '-' && c != '-'))
|
||||
|
||||
|
||||
flush_buffer ();
|
||||
|
||||
/* Set the flag if this is part one of a style or font change */
|
||||
|
||||
if (c == ZC_NEW_FONT || c == ZC_NEW_STYLE)
|
||||
flag = TRUE;
|
||||
|
||||
/* Remember the current character code */
|
||||
|
||||
prev_c = c;
|
||||
|
||||
} else flag = FALSE;
|
||||
|
||||
/* Insert the character into the buffer */
|
||||
|
||||
buffer[bufpos++] = c;
|
||||
|
||||
if (bufpos == TEXT_BUFFER_SIZE)
|
||||
runtime_error (ERR_TEXT_BUF_OVF);
|
||||
|
||||
} else stream_char (c);
|
||||
|
||||
}/* print_char */
|
||||
|
||||
/*
|
||||
* new_line
|
||||
*
|
||||
* High level newline function.
|
||||
*
|
||||
*/
|
||||
|
||||
void new_line (void)
|
||||
{
|
||||
|
||||
flush_buffer (); stream_new_line ();
|
||||
|
||||
}/* new_line */
|
||||
|
||||
|
||||
/*
|
||||
* init_buffer
|
||||
*
|
||||
* Initialize buffer variables.
|
||||
*
|
||||
*/
|
||||
|
||||
void init_buffer(void)
|
||||
{
|
||||
memset(buffer, 0, sizeof (zchar) * TEXT_BUFFER_SIZE);
|
||||
bufpos = 0;
|
||||
prev_c = 0;
|
||||
}
|
||||
|
19
apps/plugins/frotz/dumb_frotz.h
Normal file
19
apps/plugins/frotz/dumb_frotz.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
/* dumb-frotz.h
|
||||
* $Id: dumb-frotz.h,v 1.1.1.1 2002/03/26 22:38:34 feedle 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 <alembic@petrofsky.berkeley.ca.us>.
|
||||
* Any use permitted provided this notice stays intact.
|
||||
*
|
||||
* Changes for Rockbox copyright 2009 Torne Wuff
|
||||
*/
|
||||
#include "frotz.h"
|
||||
|
||||
/* from ../common/setup.h */
|
||||
extern f_setup_t f_setup;
|
||||
|
||||
/* dumb-output.c */
|
||||
void dumb_init_output(void);
|
||||
void dumb_show_screen(bool show_cursor);
|
||||
void dumb_dump_screen(void);
|
86
apps/plugins/frotz/dumb_init.c
Normal file
86
apps/plugins/frotz/dumb_init.c
Normal file
|
@ -0,0 +1,86 @@
|
|||
/* dumb-init.c
|
||||
* $Id: dumb-init.c,v 1.1.1.1 2002/03/26 22:38:34 feedle Exp $
|
||||
*
|
||||
* Copyright 1997,1998 Alva Petrofsky <alva@petrofsky.berkeley.ca.us>.
|
||||
* Any use permitted provided this notice stays intact.
|
||||
*
|
||||
* Changes for Rockbox copyright 2009 Torne Wuff
|
||||
*/
|
||||
|
||||
#include "dumb_frotz.h"
|
||||
#include "lib/pluginlib_exit.h"
|
||||
|
||||
static int user_screen_width = LCD_WIDTH / SYSFONT_WIDTH;
|
||||
static int user_screen_height = LCD_HEIGHT / SYSFONT_HEIGHT;
|
||||
static int user_interpreter_number = -1;
|
||||
static int user_random_seed = -1;
|
||||
static int user_tandy_bit = 0;
|
||||
|
||||
|
||||
void os_init_screen(void)
|
||||
{
|
||||
if (h_version == V3 && user_tandy_bit)
|
||||
h_config |= CONFIG_TANDY;
|
||||
|
||||
if (h_version >= V5 && f_setup.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';
|
||||
|
||||
if (h_version >= V4)
|
||||
h_config |= CONFIG_TIMEDINPUT;
|
||||
|
||||
if (h_version >= V5)
|
||||
h_flags &= ~(MOUSE_FLAG | MENU_FLAG);
|
||||
|
||||
dumb_init_output();
|
||||
|
||||
h_flags &= ~GRAPHICS_FLAG;
|
||||
}
|
||||
|
||||
int os_random_seed (void)
|
||||
{
|
||||
if (user_random_seed == -1)
|
||||
/* Use the rockbox tick as seed value */
|
||||
return ((int)rb->current_tick) & 0x7fff;
|
||||
else return user_random_seed;
|
||||
}
|
||||
|
||||
void os_restart_game (int stage) { (void)stage; }
|
||||
|
||||
void os_fatal (const char *s)
|
||||
{
|
||||
rb->splash(HZ*10, s);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void os_init_setup(void)
|
||||
{
|
||||
f_setup.attribute_assignment = 0;
|
||||
f_setup.attribute_testing = 0;
|
||||
f_setup.context_lines = 0;
|
||||
f_setup.object_locating = 0;
|
||||
f_setup.object_movement = 0;
|
||||
f_setup.left_margin = 0;
|
||||
f_setup.right_margin = 0;
|
||||
f_setup.ignore_errors = 0;
|
||||
f_setup.piracy = 0;
|
||||
f_setup.undo_slots = MAX_UNDO_SLOTS;
|
||||
f_setup.expand_abbreviations = 0;
|
||||
f_setup.script_cols = 80;
|
||||
f_setup.save_quetzal = 1;
|
||||
f_setup.sound = 1;
|
||||
f_setup.err_report_mode = ERR_DEFAULT_REPORT_MODE;
|
||||
|
||||
}
|
256
apps/plugins/frotz/dumb_output.c
Normal file
256
apps/plugins/frotz/dumb_output.c
Normal file
|
@ -0,0 +1,256 @@
|
|||
/* dumb-output.c
|
||||
* $Id: dumb-output.c,v 1.2 2002/03/26 22:52:31 feedle Exp $
|
||||
*
|
||||
* Copyright 1997,1998 Alfresco Petrofsky <alfresco@petrofsky.berkeley.edu>.
|
||||
* Any use permitted provided this notice stays intact.
|
||||
*
|
||||
* Changes for Rockbox copyright 2009 Torne Wuff
|
||||
*
|
||||
* Rockbox is not really a dumb terminal (it supports printing text wherever
|
||||
* you like) but it doesn't implement a terminal type buffer, so this is
|
||||
* close enough to be a good starting point. Keeping a copy of the graphical
|
||||
* framebuffer would be too expensive, text+attributes is much smaller.
|
||||
*/
|
||||
|
||||
#include "dumb_frotz.h"
|
||||
|
||||
/* 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[(LCD_WIDTH/SYSFONT_WIDTH) * (LCD_HEIGHT/SYSFONT_HEIGHT)];
|
||||
|
||||
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;}
|
||||
|
||||
static int current_style = 0;
|
||||
static int cursor_row = 0, cursor_col = 0;
|
||||
|
||||
static cell *dumb_row(int r) {return screen_data + r * h_screen_cols;}
|
||||
|
||||
int os_char_width (zchar z)
|
||||
{
|
||||
(void)z;
|
||||
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 */
|
||||
static void dumb_set_cell(int row, int col, cell c)
|
||||
{
|
||||
dumb_row(row)[col] = c;
|
||||
}
|
||||
|
||||
void os_set_text_style(int x)
|
||||
{
|
||||
current_style = x & REVERSE_STYLE;
|
||||
}
|
||||
|
||||
static void dumb_display_cell(int row, int col)
|
||||
{
|
||||
cell cel = dumb_row(row)[col];
|
||||
char c = cell_char(cel);
|
||||
if (!c)
|
||||
c = ' ';
|
||||
char style = cell_style(cel);
|
||||
char s[5];
|
||||
char *end = rb->utf8encode(c, s);
|
||||
*end = 0;
|
||||
if (style & REVERSE_STYLE)
|
||||
rb->lcd_set_drawmode(DRMODE_INVERSEVID);
|
||||
rb->lcd_putsxy(col * SYSFONT_WIDTH, row * SYSFONT_HEIGHT, s);
|
||||
rb->lcd_set_drawmode(DRMODE_SOLID);
|
||||
}
|
||||
|
||||
/* 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 os_display_char (zchar c)
|
||||
{
|
||||
if (c >= ZC_LATIN1_MIN /*&& c <= ZC_LATIN1_MAX*/) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/* Haxor your boxor? */
|
||||
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;
|
||||
top--; left--; bottom--; right--;
|
||||
if (left == 0 && right == h_screen_cols - 1)
|
||||
rb->memset(dumb_row(top), 0, (bottom - top + 1) * h_screen_cols * sizeof(cell));
|
||||
else
|
||||
for (row = top; row <= bottom; row++)
|
||||
rb->memset(dumb_row(row) + left, 0, (right - left + 1) * sizeof(cell));
|
||||
}
|
||||
|
||||
void os_scroll_area (int top, int left, int bottom, int right, int units)
|
||||
{
|
||||
int row;
|
||||
top--; left--; bottom--; right--;
|
||||
if (units > 0) {
|
||||
for (row = top; row <= bottom - units; row++)
|
||||
rb->memcpy(dumb_row(row) + left,
|
||||
dumb_row(row + units) + left,
|
||||
(right - left + 1) * sizeof(cell));
|
||||
os_erase_area(bottom - units + 2, left + 1, bottom + 1, right + 1);
|
||||
} else if (units < 0) {
|
||||
for (row = bottom; row >= top - units; row--)
|
||||
rb->memcpy(dumb_row(row) + left,
|
||||
dumb_row(row + units) + left,
|
||||
(right - left + 1) * sizeof(cell));
|
||||
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)x; (void)y; }
|
||||
void os_set_font (int x) { (void)x; }
|
||||
|
||||
/* Unconditionally show whole screen. */
|
||||
void dumb_dump_screen(void)
|
||||
{
|
||||
int r, c;
|
||||
rb->lcd_clear_display();
|
||||
for (r = 0; r < h_screen_height; r++)
|
||||
for (c = 0; c < h_screen_width; c++)
|
||||
dumb_display_cell(r, c);
|
||||
rb->lcd_update();
|
||||
}
|
||||
|
||||
/* Show the current screen contents. */
|
||||
void dumb_show_screen(bool show_cursor)
|
||||
{
|
||||
(void)show_cursor;
|
||||
dumb_dump_screen();
|
||||
}
|
||||
|
||||
void os_more_prompt(void)
|
||||
{
|
||||
int old_row = cursor_row;
|
||||
int old_col = cursor_col;
|
||||
int old_style = current_style;
|
||||
|
||||
current_style = REVERSE_STYLE;
|
||||
os_display_string("[MORE]");
|
||||
wait_for_key();
|
||||
|
||||
cursor_row = old_row;
|
||||
cursor_col = old_col;
|
||||
current_style = old_style;
|
||||
os_erase_area(cursor_row+1, cursor_col+1, cursor_row+1, cursor_col+7);
|
||||
}
|
||||
|
||||
void os_reset_screen(void)
|
||||
{
|
||||
current_style = REVERSE_STYLE;
|
||||
os_display_string("[Press key to exit]");
|
||||
wait_for_key();
|
||||
}
|
||||
|
||||
|
||||
/* To make the common code happy */
|
||||
|
||||
void os_prepare_sample (int a) { (void)a; }
|
||||
void os_finish_with_sample (int a) { (void)a; }
|
||||
void os_start_sample (int a, int b, int c, zword d)
|
||||
{
|
||||
(void)a; (void)b; (void)c; (void)d;
|
||||
}
|
||||
void os_stop_sample (int a) { (void)a; }
|
||||
|
||||
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;
|
||||
|
||||
h_font_width = 1; h_font_height = 1;
|
||||
|
||||
os_erase_area(1, 1, h_screen_rows, h_screen_cols);
|
||||
}
|
||||
|
||||
bool os_picture_data(int num, int *height, int *width)
|
||||
{
|
||||
(void)num;
|
||||
*height = 0;
|
||||
*width = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void os_draw_picture (int num, int row, int col)
|
||||
{
|
||||
(void)num;
|
||||
(void)row;
|
||||
(void)col;
|
||||
}
|
||||
|
||||
int os_peek_colour (void) {return BLACK_COLOUR; }
|
154
apps/plugins/frotz/err.c
Normal file
154
apps/plugins/frotz/err.c
Normal file
|
@ -0,0 +1,154 @@
|
|||
/* err.c - Runtime error reporting functions
|
||||
* Written by Jim Dunleavy <jim.dunleavy@erha.ie>
|
||||
*
|
||||
* This file is part of Frotz.
|
||||
*
|
||||
* Frotz is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Frotz is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include "frotz.h"
|
||||
|
||||
/* Define stuff for stricter Z-code error checking, for the generic
|
||||
Unix/DOS/etc terminal-window interface. Feel free to change the way
|
||||
player prefs are specified, or replace report_zstrict_error()
|
||||
completely if you want to change the way errors are reported. */
|
||||
|
||||
/* int err_report_mode = ERR_DEFAULT_REPORT_MODE; */
|
||||
|
||||
static int error_count[ERR_NUM_ERRORS];
|
||||
|
||||
static char *err_messages[] = {
|
||||
"Text buffer overflow",
|
||||
"Store out of dynamic memory",
|
||||
"Division by zero",
|
||||
"Illegal object",
|
||||
"Illegal attribute",
|
||||
"No such property",
|
||||
"Stack overflow",
|
||||
"Call to illegal address",
|
||||
"Call to non-routine",
|
||||
"Stack underflow",
|
||||
"Illegal opcode",
|
||||
"Bad stack frame",
|
||||
"Jump to illegal address",
|
||||
"Can't save while in interrupt",
|
||||
"Nesting stream #3 too deep",
|
||||
"Illegal window",
|
||||
"Illegal window property",
|
||||
"Print at illegal address",
|
||||
"@jin called with object 0",
|
||||
"@get_child called with object 0",
|
||||
"@get_parent called with object 0",
|
||||
"@get_sibling called with object 0",
|
||||
"@get_prop_addr called with object 0",
|
||||
"@get_prop called with object 0",
|
||||
"@put_prop called with object 0",
|
||||
"@clear_attr called with object 0",
|
||||
"@set_attr called with object 0",
|
||||
"@test_attr called with object 0",
|
||||
"@move_object called moving object 0",
|
||||
"@move_object called moving into object 0",
|
||||
"@remove_object called with object 0",
|
||||
"@get_next_prop called with object 0"
|
||||
};
|
||||
|
||||
static void print_long (unsigned long value, int base);
|
||||
|
||||
/*
|
||||
* init_err
|
||||
*
|
||||
* Initialise error reporting.
|
||||
*
|
||||
*/
|
||||
|
||||
void init_err (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Initialize the counters. */
|
||||
|
||||
for (i = 0; i < ERR_NUM_ERRORS; i++)
|
||||
error_count[i] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* runtime_error
|
||||
*
|
||||
* An error has occurred. Ignore it, pass it to os_fatal or report
|
||||
* it according to err_report_mode.
|
||||
*
|
||||
* errnum : Numeric code for error (1 to ERR_NUM_ERRORS)
|
||||
*
|
||||
*/
|
||||
|
||||
void runtime_error (int errnum)
|
||||
{
|
||||
int wasfirst;
|
||||
|
||||
if (errnum <= 0 || errnum > ERR_NUM_ERRORS)
|
||||
return;
|
||||
|
||||
if (f_setup.err_report_mode == ERR_REPORT_FATAL
|
||||
|| (!f_setup.ignore_errors && errnum <= ERR_MAX_FATAL)) {
|
||||
flush_buffer ();
|
||||
os_fatal (err_messages[errnum - 1]);
|
||||
return;
|
||||
}
|
||||
|
||||
wasfirst = (error_count[errnum - 1] == 0);
|
||||
error_count[errnum - 1]++;
|
||||
|
||||
if ((f_setup.err_report_mode == ERR_REPORT_ALWAYS)
|
||||
|| (f_setup.err_report_mode == ERR_REPORT_ONCE && wasfirst)) {
|
||||
long pc;
|
||||
|
||||
GET_PC (pc);
|
||||
print_string ("Warning: ");
|
||||
print_string (err_messages[errnum - 1]);
|
||||
print_string (" (PC = ");
|
||||
print_long (pc, 16);
|
||||
print_char (')');
|
||||
|
||||
if (f_setup.err_report_mode == ERR_REPORT_ONCE) {
|
||||
print_string (" (will ignore further occurrences)");
|
||||
} else {
|
||||
print_string (" (occurence ");
|
||||
print_long (error_count[errnum - 1], 10);
|
||||
print_char (')');
|
||||
}
|
||||
new_line ();
|
||||
}
|
||||
|
||||
} /* report_error */
|
||||
|
||||
/*
|
||||
* print_long
|
||||
*
|
||||
* Print an unsigned 32bit number in decimal or hex.
|
||||
*
|
||||
*/
|
||||
|
||||
static void print_long (unsigned long value, int base)
|
||||
{
|
||||
unsigned long i;
|
||||
char c;
|
||||
|
||||
for (i = (base == 10 ? 1000000000 : 0x10000000); i != 0; i /= base)
|
||||
if (value >= i || i == 1) {
|
||||
c = (value / i) % base;
|
||||
print_char (c + (c <= 9 ? '0' : 'a' - 10));
|
||||
}
|
||||
|
||||
}/* print_long */
|
1013
apps/plugins/frotz/fastmem.c
Normal file
1013
apps/plugins/frotz/fastmem.c
Normal file
File diff suppressed because it is too large
Load diff
563
apps/plugins/frotz/files.c
Normal file
563
apps/plugins/frotz/files.c
Normal file
|
@ -0,0 +1,563 @@
|
|||
/* files.c - Transscription, recording and playback
|
||||
* Copyright (c) 1995-1997 Stefan Jokisch
|
||||
*
|
||||
* Changes for Rockbox copyright 2009 Torne Wuff
|
||||
*
|
||||
* This file is part of Frotz.
|
||||
*
|
||||
* Frotz is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Frotz is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include "frotz.h"
|
||||
|
||||
extern void set_more_prompts (bool);
|
||||
|
||||
extern bool is_terminator (zchar);
|
||||
|
||||
extern bool read_yes_or_no (const char *);
|
||||
|
||||
char script_name[MAX_PATH];
|
||||
char command_name[MAX_PATH];
|
||||
|
||||
#ifdef __MSDOS__
|
||||
extern char latin1_to_ibm[];
|
||||
#endif
|
||||
|
||||
static int script_width = 0;
|
||||
|
||||
int sfp = -1;
|
||||
int rfp = -1;
|
||||
int pfp = -1;
|
||||
|
||||
/*
|
||||
* script_open
|
||||
*
|
||||
* Open the transscript file. 'AMFV' makes this more complicated as it
|
||||
* turns transscription on/off several times to exclude some text from
|
||||
* the transscription file. This wasn't a problem for the original V4
|
||||
* interpreters which always sent transscription to the printer, but it
|
||||
* means a problem to modern interpreters that offer to open a new file
|
||||
* every time transscription is turned on. Our solution is to append to
|
||||
* the old transscription file in V1 to V4, and to ask for a new file
|
||||
* name in V5+.
|
||||
*
|
||||
*/
|
||||
|
||||
void script_open (void)
|
||||
{
|
||||
static bool script_valid = FALSE;
|
||||
|
||||
char new_name[MAX_PATH];
|
||||
|
||||
h_flags &= ~SCRIPTING_FLAG;
|
||||
|
||||
if (h_version >= V5 || !script_valid) {
|
||||
|
||||
if (!os_read_file_name (new_name, script_name, FILE_SCRIPT))
|
||||
goto done;
|
||||
|
||||
strcpy (script_name, new_name);
|
||||
|
||||
}
|
||||
|
||||
/* Opening in "at" mode doesn't work for script_erase_input... */
|
||||
|
||||
if ((sfp = rb->open (script_name, O_RDWR|O_CREAT)) != -1) {
|
||||
|
||||
fseek (sfp, 0, SEEK_END);
|
||||
|
||||
h_flags |= SCRIPTING_FLAG;
|
||||
|
||||
script_valid = TRUE;
|
||||
ostream_script = TRUE;
|
||||
|
||||
script_width = 0;
|
||||
|
||||
} else print_string ("Cannot open file\n");
|
||||
|
||||
done:
|
||||
|
||||
SET_WORD (H_FLAGS, h_flags)
|
||||
|
||||
}/* script_open */
|
||||
|
||||
/*
|
||||
* script_close
|
||||
*
|
||||
* Stop transscription.
|
||||
*
|
||||
*/
|
||||
|
||||
void script_close (void)
|
||||
{
|
||||
|
||||
h_flags &= ~SCRIPTING_FLAG;
|
||||
SET_WORD (H_FLAGS, h_flags)
|
||||
|
||||
fclose (sfp); ostream_script = FALSE;
|
||||
sfp = -1;
|
||||
|
||||
}/* script_close */
|
||||
|
||||
/*
|
||||
* script_new_line
|
||||
*
|
||||
* Write a newline to the transscript file.
|
||||
*
|
||||
*/
|
||||
|
||||
void script_new_line (void)
|
||||
{
|
||||
|
||||
if (fputc ('\n', sfp) == EOF)
|
||||
script_close ();
|
||||
|
||||
script_width = 0;
|
||||
|
||||
}/* script_new_line */
|
||||
|
||||
/*
|
||||
* script_char
|
||||
*
|
||||
* Write a single character to the transscript file.
|
||||
*
|
||||
*/
|
||||
|
||||
void script_char (zchar c)
|
||||
{
|
||||
|
||||
if (c == ZC_INDENT && script_width != 0)
|
||||
c = ' ';
|
||||
|
||||
if (c == ZC_INDENT)
|
||||
{ script_char (' '); script_char (' '); script_char (' '); return; }
|
||||
if (c == ZC_GAP)
|
||||
{ script_char (' '); script_char (' '); return; }
|
||||
|
||||
#ifdef __MSDOS__
|
||||
if (c >= ZC_LATIN1_MIN)
|
||||
c = latin1_to_ibm[c - ZC_LATIN1_MIN];
|
||||
#endif
|
||||
|
||||
fputc (c, sfp); script_width++;
|
||||
|
||||
}/* script_char */
|
||||
|
||||
/*
|
||||
* script_word
|
||||
*
|
||||
* Write a string to the transscript file.
|
||||
*
|
||||
*/
|
||||
|
||||
void script_word (const zchar *s)
|
||||
{
|
||||
int width;
|
||||
int i;
|
||||
|
||||
if (*s == ZC_INDENT && script_width != 0)
|
||||
script_char (*s++);
|
||||
|
||||
for (i = 0, width = 0; s[i] != 0; i++)
|
||||
|
||||
if (s[i] == ZC_NEW_STYLE || s[i] == ZC_NEW_FONT)
|
||||
i++;
|
||||
else if (s[i] == ZC_GAP)
|
||||
width += 3;
|
||||
else if (s[i] == ZC_INDENT)
|
||||
width += 2;
|
||||
else
|
||||
width += 1;
|
||||
|
||||
if (f_setup.script_cols != 0 && script_width + width > f_setup.script_cols) {
|
||||
|
||||
if (*s == ' ' || *s == ZC_INDENT || *s == ZC_GAP)
|
||||
s++;
|
||||
|
||||
script_new_line ();
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; s[i] != 0; i++)
|
||||
|
||||
if (s[i] == ZC_NEW_FONT || s[i] == ZC_NEW_STYLE)
|
||||
i++;
|
||||
else
|
||||
script_char (s[i]);
|
||||
|
||||
}/* script_word */
|
||||
|
||||
/*
|
||||
* script_write_input
|
||||
*
|
||||
* Send an input line to the transscript file.
|
||||
*
|
||||
*/
|
||||
|
||||
void script_write_input (const zchar *buf, zchar key)
|
||||
{
|
||||
int width;
|
||||
int i;
|
||||
|
||||
for (i = 0, width = 0; buf[i] != 0; i++)
|
||||
width++;
|
||||
|
||||
if (f_setup.script_cols != 0 && script_width + width > f_setup.script_cols)
|
||||
script_new_line ();
|
||||
|
||||
for (i = 0; buf[i] != 0; i++)
|
||||
script_char (buf[i]);
|
||||
|
||||
if (key == ZC_RETURN)
|
||||
script_new_line ();
|
||||
|
||||
}/* script_write_input */
|
||||
|
||||
/*
|
||||
* script_erase_input
|
||||
*
|
||||
* Remove an input line from the transscript file.
|
||||
*
|
||||
*/
|
||||
|
||||
void script_erase_input (const zchar *buf)
|
||||
{
|
||||
int width;
|
||||
int i;
|
||||
|
||||
for (i = 0, width = 0; buf[i] != 0; i++)
|
||||
width++;
|
||||
|
||||
fseek (sfp, -width, SEEK_CUR); script_width -= width;
|
||||
|
||||
}/* script_erase_input */
|
||||
|
||||
/*
|
||||
* script_mssg_on
|
||||
*
|
||||
* Start sending a "debugging" message to the transscript file.
|
||||
*
|
||||
*/
|
||||
|
||||
void script_mssg_on (void)
|
||||
{
|
||||
|
||||
if (script_width != 0)
|
||||
script_new_line ();
|
||||
|
||||
script_char (ZC_INDENT);
|
||||
|
||||
}/* script_mssg_on */
|
||||
|
||||
/*
|
||||
* script_mssg_off
|
||||
*
|
||||
* Stop writing a "debugging" message.
|
||||
*
|
||||
*/
|
||||
|
||||
void script_mssg_off (void)
|
||||
{
|
||||
|
||||
script_new_line ();
|
||||
|
||||
}/* script_mssg_off */
|
||||
|
||||
/*
|
||||
* record_open
|
||||
*
|
||||
* Open a file to record the player's input.
|
||||
*
|
||||
*/
|
||||
|
||||
void record_open (void)
|
||||
{
|
||||
char new_name[MAX_PATH];
|
||||
|
||||
if (os_read_file_name (new_name, command_name, FILE_RECORD)) {
|
||||
|
||||
strcpy (command_name, new_name);
|
||||
|
||||
if ((rfp = rb->open (new_name, O_WRONLY|O_CREAT|O_TRUNC)) != -1)
|
||||
ostream_record = TRUE;
|
||||
else
|
||||
print_string ("Cannot open file\n");
|
||||
|
||||
}
|
||||
|
||||
}/* record_open */
|
||||
|
||||
/*
|
||||
* record_close
|
||||
*
|
||||
* Stop recording the player's input.
|
||||
*
|
||||
*/
|
||||
|
||||
void record_close (void)
|
||||
{
|
||||
|
||||
fclose (rfp); ostream_record = FALSE;
|
||||
rfp = -1;
|
||||
|
||||
}/* record_close */
|
||||
|
||||
/*
|
||||
* record_code
|
||||
*
|
||||
* Helper function for record_char.
|
||||
*
|
||||
*/
|
||||
|
||||
static void record_code (int c, bool force_encoding)
|
||||
{
|
||||
|
||||
if (force_encoding || c == '[' || c < 0x20 || c > 0x7e) {
|
||||
|
||||
int i;
|
||||
|
||||
fputc ('[', rfp);
|
||||
|
||||
for (i = 10000; i != 0; i /= 10)
|
||||
if (c >= i || i == 1)
|
||||
fputc ('0' + (c / i) % 10, rfp);
|
||||
|
||||
fputc (']', rfp);
|
||||
|
||||
} else fputc (c, rfp);
|
||||
|
||||
}/* record_code */
|
||||
|
||||
/*
|
||||
* record_char
|
||||
*
|
||||
* Write a character to the command file.
|
||||
*
|
||||
*/
|
||||
|
||||
static void record_char (zchar c)
|
||||
{
|
||||
|
||||
if (c != ZC_RETURN) {
|
||||
if (c < ZC_HKEY_MIN || c > ZC_HKEY_MAX) {
|
||||
record_code (translate_to_zscii (c), FALSE);
|
||||
if (c == ZC_SINGLE_CLICK || c == ZC_DOUBLE_CLICK) {
|
||||
record_code (mouse_x, TRUE);
|
||||
record_code (mouse_y, TRUE);
|
||||
}
|
||||
} else record_code (1000 + c - ZC_HKEY_MIN, TRUE);
|
||||
}
|
||||
|
||||
}/* record_char */
|
||||
|
||||
/*
|
||||
* record_write_key
|
||||
*
|
||||
* Copy a keystroke to the command file.
|
||||
*
|
||||
*/
|
||||
|
||||
void record_write_key (zchar key)
|
||||
{
|
||||
|
||||
record_char (key);
|
||||
|
||||
if (fputc ('\n', rfp) == EOF)
|
||||
record_close ();
|
||||
|
||||
}/* record_write_key */
|
||||
|
||||
/*
|
||||
* record_write_input
|
||||
*
|
||||
* Copy a line of input to a command file.
|
||||
*
|
||||
*/
|
||||
|
||||
void record_write_input (const zchar *buf, zchar key)
|
||||
{
|
||||
zchar c;
|
||||
|
||||
while ((c = *buf++) != 0)
|
||||
record_char (c);
|
||||
|
||||
record_char (key);
|
||||
|
||||
if (fputc ('\n', rfp) == EOF)
|
||||
record_close ();
|
||||
|
||||
}/* record_write_input */
|
||||
|
||||
/*
|
||||
* replay_open
|
||||
*
|
||||
* Open a file of commands for playback.
|
||||
*
|
||||
*/
|
||||
|
||||
void replay_open (void)
|
||||
{
|
||||
char new_name[MAX_PATH];
|
||||
|
||||
if (os_read_file_name (new_name, command_name, FILE_PLAYBACK)) {
|
||||
|
||||
strcpy (command_name, new_name);
|
||||
|
||||
if ((pfp = rb->open (new_name, O_RDONLY)) != -1) {
|
||||
|
||||
set_more_prompts (read_yes_or_no ("Do you want MORE prompts"));
|
||||
|
||||
istream_replay = TRUE;
|
||||
|
||||
} else print_string ("Cannot open file\n");
|
||||
|
||||
}
|
||||
|
||||
}/* replay_open */
|
||||
|
||||
/*
|
||||
* replay_close
|
||||
*
|
||||
* Stop playback of commands.
|
||||
*
|
||||
*/
|
||||
|
||||
void replay_close (void)
|
||||
{
|
||||
|
||||
set_more_prompts (TRUE);
|
||||
|
||||
fclose (pfp); istream_replay = FALSE;
|
||||
pfp = -1;
|
||||
|
||||
}/* replay_close */
|
||||
|
||||
/*
|
||||
* replay_code
|
||||
*
|
||||
* Helper function for replay_key and replay_line.
|
||||
*
|
||||
*/
|
||||
|
||||
static int replay_code (void)
|
||||
{
|
||||
int c;
|
||||
|
||||
if ((c = fgetc (pfp)) == '[') {
|
||||
|
||||
int c2;
|
||||
|
||||
c = 0;
|
||||
|
||||
while ((c2 = fgetc (pfp)) != EOF && c2 >= '0' && c2 <= '9')
|
||||
c = 10 * c + c2 - '0';
|
||||
|
||||
return (c2 == ']') ? c : EOF;
|
||||
|
||||
} else return c;
|
||||
|
||||
}/* replay_code */
|
||||
|
||||
/*
|
||||
* replay_char
|
||||
*
|
||||
* Read a character from the command file.
|
||||
*
|
||||
*/
|
||||
|
||||
static zchar replay_char (void)
|
||||
{
|
||||
int c;
|
||||
|
||||
if ((c = replay_code ()) != EOF) {
|
||||
|
||||
if (c != '\n') {
|
||||
|
||||
if (c < 1000) {
|
||||
|
||||
c = translate_from_zscii (c);
|
||||
|
||||
if (c == ZC_SINGLE_CLICK || c == ZC_DOUBLE_CLICK) {
|
||||
mouse_x = replay_code ();
|
||||
mouse_y = replay_code ();
|
||||
}
|
||||
|
||||
return c;
|
||||
|
||||
} else return ZC_HKEY_MIN + c - 1000;
|
||||
}
|
||||
|
||||
ungetc ('\n', pfp);
|
||||
|
||||
return ZC_RETURN;
|
||||
|
||||
} else return ZC_BAD;
|
||||
|
||||
}/* replay_char */
|
||||
|
||||
/*
|
||||
* replay_read_key
|
||||
*
|
||||
* Read a keystroke from a command file.
|
||||
*
|
||||
*/
|
||||
|
||||
zchar replay_read_key (void)
|
||||
{
|
||||
zchar key;
|
||||
|
||||
key = replay_char ();
|
||||
|
||||
if (fgetc (pfp) != '\n') {
|
||||
|
||||
replay_close ();
|
||||
return ZC_BAD;
|
||||
|
||||
} else return key;
|
||||
|
||||
}/* replay_read_key */
|
||||
|
||||
/*
|
||||
* replay_read_input
|
||||
*
|
||||
* Read a line of input from a command file.
|
||||
*
|
||||
*/
|
||||
|
||||
zchar replay_read_input (zchar *buf)
|
||||
{
|
||||
zchar c;
|
||||
|
||||
for (;;) {
|
||||
|
||||
c = replay_char ();
|
||||
|
||||
if (c == ZC_BAD || is_terminator (c))
|
||||
break;
|
||||
|
||||
*buf++ = c;
|
||||
|
||||
}
|
||||
|
||||
*buf = 0;
|
||||
|
||||
if (fgetc (pfp) != '\n') {
|
||||
|
||||
replay_close ();
|
||||
return ZC_BAD;
|
||||
|
||||
} else return c;
|
||||
|
||||
}/* replay_read_input */
|
314
apps/plugins/frotz/frotz.c
Normal file
314
apps/plugins/frotz/frotz.c
Normal file
|
@ -0,0 +1,314 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2009 Torne Wuff
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include "plugin.h"
|
||||
#include "dumb_frotz.h"
|
||||
#include "lib/pluginlib_exit.h"
|
||||
#include "lib/pluginlib_actions.h"
|
||||
|
||||
PLUGIN_HEADER
|
||||
|
||||
extern int frotz_main(void);
|
||||
extern bool hot_key_quit(void);
|
||||
|
||||
f_setup_t f_setup;
|
||||
extern char save_name[], auxilary_name[], script_name[], command_name[];
|
||||
extern int story_fp, sfp, rfp, pfp;
|
||||
|
||||
static struct viewport vp[NB_SCREENS];
|
||||
|
||||
static void atexit_cleanup(void);
|
||||
|
||||
enum plugin_status plugin_start(const void* parameter)
|
||||
{
|
||||
int i;
|
||||
char* ext;
|
||||
|
||||
PLUGINLIB_EXIT_INIT_ATEXIT(atexit_cleanup);
|
||||
|
||||
if (!parameter)
|
||||
return PLUGIN_ERROR;
|
||||
|
||||
rb->lcd_setfont(FONT_SYSFIXED);
|
||||
#if LCD_DEPTH > 1
|
||||
rb->lcd_set_backdrop(NULL);
|
||||
#endif
|
||||
rb->lcd_clear_display();
|
||||
|
||||
FOR_NB_SCREENS(i)
|
||||
rb->viewport_set_defaults(&vp[i], i);
|
||||
|
||||
story_name = parameter;
|
||||
strcpy(save_name, story_name);
|
||||
ext = rb->strrchr(save_name, '.');
|
||||
if (ext)
|
||||
*ext = '\0';
|
||||
strcpy(auxilary_name, save_name);
|
||||
strcpy(script_name, save_name);
|
||||
strcpy(command_name, save_name);
|
||||
rb->strlcat(save_name, ".sav", MAX_PATH);
|
||||
rb->strlcat(auxilary_name, ".aux", MAX_PATH);
|
||||
rb->strlcat(script_name, ".scr", MAX_PATH);
|
||||
rb->strlcat(command_name, ".rec", MAX_PATH);
|
||||
|
||||
frotz_main();
|
||||
|
||||
return PLUGIN_OK;
|
||||
}
|
||||
|
||||
void atexit_cleanup()
|
||||
{
|
||||
if (story_fp != -1)
|
||||
fclose(story_fp);
|
||||
if (sfp != -1)
|
||||
fclose(sfp);
|
||||
if (rfp != -1)
|
||||
fclose(rfp);
|
||||
if (pfp != -1)
|
||||
fclose(pfp);
|
||||
}
|
||||
|
||||
MENUITEM_STRINGLIST(ingame_menu, "Frotz", NULL, "Resume", "Undo", "Restart",
|
||||
"Toggle input recording", "Play back input",
|
||||
"Debug options", "Exit");
|
||||
|
||||
zchar menu(void)
|
||||
{
|
||||
switch (rb->do_menu(&ingame_menu, NULL, vp, true))
|
||||
{
|
||||
case 0:
|
||||
default:
|
||||
dumb_dump_screen();
|
||||
return ZC_BAD;
|
||||
case 1:
|
||||
return ZC_HKEY_UNDO;
|
||||
case 2:
|
||||
return ZC_HKEY_RESTART;
|
||||
case 3:
|
||||
return ZC_HKEY_RECORD;
|
||||
case 4:
|
||||
return ZC_HKEY_PLAYBACK;
|
||||
case 5:
|
||||
return ZC_HKEY_DEBUG;
|
||||
case 6:
|
||||
return ZC_HKEY_QUIT;
|
||||
}
|
||||
}
|
||||
|
||||
const struct button_mapping* plugin_contexts[]={generic_actions};
|
||||
|
||||
void wait_for_key()
|
||||
{
|
||||
int action;
|
||||
|
||||
dumb_show_screen(false);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
action = pluginlib_getaction(TIMEOUT_BLOCK,
|
||||
plugin_contexts, 1);
|
||||
switch (action)
|
||||
{
|
||||
case PLA_QUIT:
|
||||
hot_key_quit();
|
||||
break;
|
||||
|
||||
case PLA_FIRE:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
zchar do_input(int timeout, bool show_cursor)
|
||||
{
|
||||
int action;
|
||||
long timeout_at;
|
||||
zchar menu_ret;
|
||||
|
||||
dumb_show_screen(show_cursor);
|
||||
|
||||
/* Convert timeout (tenths of a second) to ticks */
|
||||
if (timeout > 0)
|
||||
timeout = (timeout * HZ) / 10;
|
||||
else
|
||||
timeout = TIMEOUT_BLOCK;
|
||||
|
||||
timeout_at = *rb->current_tick + timeout;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
action = pluginlib_getaction(timeout,
|
||||
plugin_contexts, 1);
|
||||
switch (action)
|
||||
{
|
||||
case PLA_QUIT:
|
||||
return ZC_HKEY_QUIT;
|
||||
|
||||
case PLA_MENU:
|
||||
menu_ret = menu();
|
||||
if (menu_ret != ZC_BAD)
|
||||
return menu_ret;
|
||||
timeout_at = *rb->current_tick + timeout;
|
||||
break;
|
||||
|
||||
case PLA_FIRE:
|
||||
return ZC_RETURN;
|
||||
|
||||
case PLA_START:
|
||||
return ZC_BAD;
|
||||
|
||||
default:
|
||||
if (timeout != TIMEOUT_BLOCK &&
|
||||
!TIME_BEFORE(*rb->current_tick, timeout_at))
|
||||
return ZC_TIME_OUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
zchar os_read_key(int timeout, bool show_cursor)
|
||||
{
|
||||
int r;
|
||||
char inputbuf[5];
|
||||
short key;
|
||||
zchar zkey;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
zkey = do_input(timeout, show_cursor);
|
||||
if (zkey != ZC_BAD)
|
||||
return zkey;
|
||||
|
||||
inputbuf[0] = '\0';
|
||||
r = rb->kbd_input(inputbuf, 5);
|
||||
rb->lcd_setfont(FONT_SYSFIXED);
|
||||
dumb_dump_screen();
|
||||
if (!r)
|
||||
{
|
||||
rb->utf8decode(inputbuf, &key);
|
||||
if (key > 0 && key < 256)
|
||||
return (zchar)key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
zchar os_read_line(int max, zchar *buf, int timeout, int width, int continued)
|
||||
{
|
||||
(void)continued;
|
||||
int r;
|
||||
char inputbuf[256];
|
||||
const char *in;
|
||||
char *out;
|
||||
short key;
|
||||
zchar zkey;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
zkey = do_input(timeout, true);
|
||||
if (zkey != ZC_BAD)
|
||||
return zkey;
|
||||
|
||||
if (max > width)
|
||||
max = width;
|
||||
strcpy(inputbuf, buf);
|
||||
r = rb->kbd_input(inputbuf, 256);
|
||||
rb->lcd_setfont(FONT_SYSFIXED);
|
||||
dumb_dump_screen();
|
||||
if (!r)
|
||||
{
|
||||
in = inputbuf;
|
||||
out = buf;
|
||||
while (*in && max)
|
||||
{
|
||||
in = rb->utf8decode(in, &key);
|
||||
if (key > 0 && key < 256)
|
||||
{
|
||||
*out++ = key;
|
||||
max--;
|
||||
}
|
||||
}
|
||||
*out = '\0';
|
||||
os_display_string(buf);
|
||||
return ZC_RETURN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool read_yes_or_no(const char *s)
|
||||
{
|
||||
char message_line[50];
|
||||
const char *message_lines[] = {message_line};
|
||||
const struct text_message message = {message_lines, 1};
|
||||
|
||||
rb->strlcpy(message_line, s, 49);
|
||||
rb->strcat(message_line, "?");
|
||||
|
||||
if (rb->gui_syncyesno_run(&message, NULL, NULL) == YESNO_YES)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
zchar os_read_mouse(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int os_read_file_name(char *file_name, const char *default_name, int flag)
|
||||
{
|
||||
(void)flag;
|
||||
strcpy(file_name, default_name);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void os_beep(int volume)
|
||||
{
|
||||
rb->splashf(HZ/2, "[%s-PITCHED BEEP]", (volume==1) ? "HIGH" : "LOW");
|
||||
}
|
||||
|
||||
static unsigned char unget_buf;
|
||||
static int unget_file;
|
||||
|
||||
int ungetc(int c, int f)
|
||||
{
|
||||
unget_file = f;
|
||||
unget_buf = c;
|
||||
return c;
|
||||
}
|
||||
|
||||
int fgetc(int f)
|
||||
{
|
||||
unsigned char cb;
|
||||
if (unget_file == f)
|
||||
{
|
||||
unget_file = -1;
|
||||
return unget_buf;
|
||||
}
|
||||
if (rb->read(f, &cb, 1) != 1)
|
||||
return EOF;
|
||||
return cb;
|
||||
}
|
||||
|
||||
int fputc(int c, int f)
|
||||
{
|
||||
unsigned char cb = c;
|
||||
if (rb->write(f, &cb, 1) != 1)
|
||||
return EOF;
|
||||
return cb;
|
||||
}
|
583
apps/plugins/frotz/frotz.h
Normal file
583
apps/plugins/frotz/frotz.h
Normal file
|
@ -0,0 +1,583 @@
|
|||
/*
|
||||
* frotz.h
|
||||
*
|
||||
* Global declarations and definitions
|
||||
*
|
||||
*/
|
||||
|
||||
#include "frotzplugin.h"
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
typedef unsigned char zbyte;
|
||||
typedef unsigned short zword;
|
||||
|
||||
enum story {
|
||||
BEYOND_ZORK,
|
||||
SHERLOCK,
|
||||
ZORK_ZERO,
|
||||
SHOGUN,
|
||||
ARTHUR,
|
||||
JOURNEY,
|
||||
LURKING_HORROR,
|
||||
UNKNOWN
|
||||
};
|
||||
|
||||
typedef unsigned char zchar;
|
||||
|
||||
/*** Constants that may be set at compile time ***/
|
||||
|
||||
#ifndef MAX_UNDO_SLOTS
|
||||
#define MAX_UNDO_SLOTS 500
|
||||
#endif
|
||||
#ifndef TEXT_BUFFER_SIZE
|
||||
#define TEXT_BUFFER_SIZE 200
|
||||
#endif
|
||||
#ifndef INPUT_BUFFER_SIZE
|
||||
#define INPUT_BUFFER_SIZE 200
|
||||
#endif
|
||||
#ifndef STACK_SIZE
|
||||
#define STACK_SIZE 1024
|
||||
#endif
|
||||
|
||||
/*** Story file header format ***/
|
||||
|
||||
#define H_VERSION 0
|
||||
#define H_CONFIG 1
|
||||
#define H_RELEASE 2
|
||||
#define H_RESIDENT_SIZE 4
|
||||
#define H_START_PC 6
|
||||
#define H_DICTIONARY 8
|
||||
#define H_OBJECTS 10
|
||||
#define H_GLOBALS 12
|
||||
#define H_DYNAMIC_SIZE 14
|
||||
#define H_FLAGS 16
|
||||
#define H_SERIAL 18
|
||||
#define H_ABBREVIATIONS 24
|
||||
#define H_FILE_SIZE 26
|
||||
#define H_CHECKSUM 28
|
||||
#define H_INTERPRETER_NUMBER 30
|
||||
#define H_INTERPRETER_VERSION 31
|
||||
#define H_SCREEN_ROWS 32
|
||||
#define H_SCREEN_COLS 33
|
||||
#define H_SCREEN_WIDTH 34
|
||||
#define H_SCREEN_HEIGHT 36
|
||||
#define H_FONT_HEIGHT 38 /* this is the font width in V5 */
|
||||
#define H_FONT_WIDTH 39 /* this is the font height in V5 */
|
||||
#define H_FUNCTIONS_OFFSET 40
|
||||
#define H_STRINGS_OFFSET 42
|
||||
#define H_DEFAULT_BACKGROUND 44
|
||||
#define H_DEFAULT_FOREGROUND 45
|
||||
#define H_TERMINATING_KEYS 46
|
||||
#define H_LINE_WIDTH 48
|
||||
#define H_STANDARD_HIGH 50
|
||||
#define H_STANDARD_LOW 51
|
||||
#define H_ALPHABET 52
|
||||
#define H_EXTENSION_TABLE 54
|
||||
#define H_USER_NAME 56
|
||||
|
||||
#define HX_TABLE_SIZE 0
|
||||
#define HX_MOUSE_X 1
|
||||
#define HX_MOUSE_Y 2
|
||||
#define HX_UNICODE_TABLE 3
|
||||
|
||||
/*** Various Z-machine constants ***/
|
||||
|
||||
#define V1 1
|
||||
#define V2 2
|
||||
#define V3 3
|
||||
#define V4 4
|
||||
#define V5 5
|
||||
#define V6 6
|
||||
#define V7 7
|
||||
#define V8 8
|
||||
|
||||
#define CONFIG_BYTE_SWAPPED 0x01 /* Story file is byte swapped - V3 */
|
||||
#define CONFIG_TIME 0x02 /* Status line displays time - V3 */
|
||||
#define CONFIG_TWODISKS 0x04 /* Story file occupied two disks - V3 */
|
||||
#define CONFIG_TANDY 0x08 /* Tandy licensed game - V3 */
|
||||
#define CONFIG_NOSTATUSLINE 0x10 /* Interpr can't support status lines - V3 */
|
||||
#define CONFIG_SPLITSCREEN 0x20 /* Interpr supports split screen mode - V3 */
|
||||
#define CONFIG_PROPORTIONAL 0x40 /* Interpr uses proportional font - V3 */
|
||||
|
||||
#define CONFIG_COLOUR 0x01 /* Interpr supports colour - V5+ */
|
||||
#define CONFIG_PICTURES 0x02 /* Interpr supports pictures - V6 */
|
||||
#define CONFIG_BOLDFACE 0x04 /* Interpr supports boldface style - V4+ */
|
||||
#define CONFIG_EMPHASIS 0x08 /* Interpr supports emphasis style - V4+ */
|
||||
#define CONFIG_FIXED 0x10 /* Interpr supports fixed width style - V4+ */
|
||||
#define CONFIG_SOUND 0x20 /* Interpr supports sound - V6 */
|
||||
|
||||
#define CONFIG_TIMEDINPUT 0x80 /* Interpr supports timed input - V4+ */
|
||||
|
||||
#define SCRIPTING_FLAG 0x0001 /* Outputting to transscription file - V1+ */
|
||||
#define FIXED_FONT_FLAG 0x0002 /* Use fixed width font - V3+ */
|
||||
#define REFRESH_FLAG 0x0004 /* Refresh the screen - V6 */
|
||||
#define GRAPHICS_FLAG 0x0008 /* Game wants to use graphics - V5+ */
|
||||
#define OLD_SOUND_FLAG 0x0010 /* Game wants to use sound effects - V3 */
|
||||
#define UNDO_FLAG 0x0010 /* Game wants to use UNDO feature - V5+ */
|
||||
#define MOUSE_FLAG 0x0020 /* Game wants to use a mouse - V5+ */
|
||||
#define COLOUR_FLAG 0x0040 /* Game wants to use colours - V5+ */
|
||||
#define SOUND_FLAG 0x0080 /* Game wants to use sound effects - V5+ */
|
||||
#define MENU_FLAG 0x0100 /* Game wants to use menus - V6 */
|
||||
|
||||
#define INTERP_DEFAULT 0
|
||||
#define INTERP_DEC_20 1
|
||||
#define INTERP_APPLE_IIE 2
|
||||
#define INTERP_MACINTOSH 3
|
||||
#define INTERP_AMIGA 4
|
||||
#define INTERP_ATARI_ST 5
|
||||
#define INTERP_MSDOS 6
|
||||
#define INTERP_CBM_128 7
|
||||
#define INTERP_CBM_64 8
|
||||
#define INTERP_APPLE_IIC 9
|
||||
#define INTERP_APPLE_IIGS 10
|
||||
#define INTERP_TANDY 11
|
||||
|
||||
#define BLACK_COLOUR 2
|
||||
#define RED_COLOUR 3
|
||||
#define GREEN_COLOUR 4
|
||||
#define YELLOW_COLOUR 5
|
||||
#define BLUE_COLOUR 6
|
||||
#define MAGENTA_COLOUR 7
|
||||
#define CYAN_COLOUR 8
|
||||
#define WHITE_COLOUR 9
|
||||
#define GREY_COLOUR 10 /* INTERP_MSDOS only */
|
||||
#define LIGHTGREY_COLOUR 10 /* INTERP_AMIGA only */
|
||||
#define MEDIUMGREY_COLOUR 11 /* INTERP_AMIGA only */
|
||||
#define DARKGREY_COLOUR 12 /* INTERP_AMIGA only */
|
||||
|
||||
#define REVERSE_STYLE 1
|
||||
#define BOLDFACE_STYLE 2
|
||||
#define EMPHASIS_STYLE 4
|
||||
#define FIXED_WIDTH_STYLE 8
|
||||
|
||||
#define TEXT_FONT 1
|
||||
#define PICTURE_FONT 2
|
||||
#define GRAPHICS_FONT 3
|
||||
#define FIXED_WIDTH_FONT 4
|
||||
|
||||
#define BEEP_HIGH 1
|
||||
#define BEEP_LOW 2
|
||||
|
||||
/*** Constants for os_restart_game */
|
||||
|
||||
#define RESTART_BEGIN 0
|
||||
#define RESTART_WPROP_SET 1
|
||||
#define RESTART_END 2
|
||||
|
||||
/*** Character codes ***/
|
||||
|
||||
#define ZC_TIME_OUT 0x00
|
||||
#define ZC_NEW_STYLE 0x01
|
||||
#define ZC_NEW_FONT 0x02
|
||||
#define ZC_BACKSPACE 0x08
|
||||
#define ZC_INDENT 0x09
|
||||
#define ZC_GAP 0x0b
|
||||
#define ZC_RETURN 0x0d
|
||||
#define ZC_HKEY_MIN 0x0e
|
||||
#define ZC_HKEY_RECORD 0x0e
|
||||
#define ZC_HKEY_PLAYBACK 0x0f
|
||||
#define ZC_HKEY_SEED 0x10
|
||||
#define ZC_HKEY_UNDO 0x11
|
||||
#define ZC_HKEY_RESTART 0x12
|
||||
#define ZC_HKEY_QUIT 0x13
|
||||
#define ZC_HKEY_DEBUG 0x14
|
||||
#define ZC_HKEY_HELP 0x15
|
||||
#define ZC_HKEY_MAX 0x15
|
||||
#define ZC_ESCAPE 0x1b
|
||||
#define ZC_ASCII_MIN 0x20
|
||||
#define ZC_ASCII_MAX 0x7e
|
||||
#define ZC_BAD 0x7f
|
||||
#define ZC_ARROW_MIN 0x81
|
||||
#define ZC_ARROW_UP 0x81
|
||||
#define ZC_ARROW_DOWN 0x82
|
||||
#define ZC_ARROW_LEFT 0x83
|
||||
#define ZC_ARROW_RIGHT 0x84
|
||||
#define ZC_ARROW_MAX 0x84
|
||||
#define ZC_FKEY_MIN 0x85
|
||||
#define ZC_FKEY_MAX 0x90
|
||||
#define ZC_NUMPAD_MIN 0x91
|
||||
#define ZC_NUMPAD_MAX 0x9a
|
||||
#define ZC_SINGLE_CLICK 0x9b
|
||||
#define ZC_DOUBLE_CLICK 0x9c
|
||||
#define ZC_MENU_CLICK 0x9d
|
||||
#define ZC_LATIN1_MIN 0xa0
|
||||
#define ZC_LATIN1_MAX 0xff
|
||||
|
||||
/*** File types ***/
|
||||
|
||||
#define FILE_RESTORE 0
|
||||
#define FILE_SAVE 1
|
||||
#define FILE_SCRIPT 2
|
||||
#define FILE_PLAYBACK 3
|
||||
#define FILE_RECORD 4
|
||||
#define FILE_LOAD_AUX 5
|
||||
#define FILE_SAVE_AUX 6
|
||||
|
||||
/*** Data access macros ***/
|
||||
|
||||
#define SET_BYTE(addr,v) { zmp[addr] = v; }
|
||||
#define LOW_BYTE(addr,v) { v = zmp[addr]; }
|
||||
#define CODE_BYTE(v) { v = *pcp++; }
|
||||
|
||||
#if defined (AMIGA)
|
||||
|
||||
extern zbyte *pcp;
|
||||
extern zbyte *zmp;
|
||||
|
||||
#define lo(v) ((zbyte *)&v)[1]
|
||||
#define hi(v) ((zbyte *)&v)[0]
|
||||
|
||||
#define SET_WORD(addr,v) { zmp[addr] = hi(v); zmp[addr+1] = lo(v); }
|
||||
#define LOW_WORD(addr,v) { hi(v) = zmp[addr]; lo(v) = zmp[addr+1]; }
|
||||
#define HIGH_WORD(addr,v) { hi(v) = zmp[addr]; lo(v) = zmp[addr+1]; }
|
||||
#define CODE_WORD(v) { hi(v) = *pcp++; lo(v) = *pcp++; }
|
||||
#define GET_PC(v) { v = pcp - zmp; }
|
||||
#define SET_PC(v) { pcp = zmp + v; }
|
||||
|
||||
#endif
|
||||
|
||||
/* A bunch of x86 assembly code previously appeared here. */
|
||||
|
||||
#if !defined (AMIGA) && !defined (MSDOS_16BIT)
|
||||
|
||||
extern zbyte *pcp;
|
||||
extern zbyte *zmp;
|
||||
|
||||
#define lo(v) (v & 0xff)
|
||||
#define hi(v) (v >> 8)
|
||||
|
||||
#define SET_WORD(addr,v) { zmp[addr] = hi(v); zmp[addr+1] = lo(v); }
|
||||
#define LOW_WORD(addr,v) { v = ((zword) zmp[addr] << 8) | zmp[addr+1]; }
|
||||
#define HIGH_WORD(addr,v) { v = ((zword) zmp[addr] << 8) | zmp[addr+1]; }
|
||||
#define CODE_WORD(v) { v = ((zword) pcp[0] << 8) | pcp[1]; pcp += 2; }
|
||||
#define GET_PC(v) { v = pcp - zmp; }
|
||||
#define SET_PC(v) { pcp = zmp + v; }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*** Story file header data ***/
|
||||
|
||||
extern zbyte h_version;
|
||||
extern zbyte h_config;
|
||||
extern zword h_release;
|
||||
extern zword h_resident_size;
|
||||
extern zword h_start_pc;
|
||||
extern zword h_dictionary;
|
||||
extern zword h_objects;
|
||||
extern zword h_globals;
|
||||
extern zword h_dynamic_size;
|
||||
extern zword h_flags;
|
||||
extern zbyte h_serial[6];
|
||||
extern zword h_abbreviations;
|
||||
extern zword h_file_size;
|
||||
extern zword h_checksum;
|
||||
extern zbyte h_interpreter_number;
|
||||
extern zbyte h_interpreter_version;
|
||||
extern zbyte h_screen_rows;
|
||||
extern zbyte h_screen_cols;
|
||||
extern zword h_screen_width;
|
||||
extern zword h_screen_height;
|
||||
extern zbyte h_font_height;
|
||||
extern zbyte h_font_width;
|
||||
extern zword h_functions_offset;
|
||||
extern zword h_strings_offset;
|
||||
extern zbyte h_default_background;
|
||||
extern zbyte h_default_foreground;
|
||||
extern zword h_terminating_keys;
|
||||
extern zword h_line_width;
|
||||
extern zbyte h_standard_high;
|
||||
extern zbyte h_standard_low;
|
||||
extern zword h_alphabet;
|
||||
extern zword h_extension_table;
|
||||
extern zbyte h_user_name[8];
|
||||
|
||||
extern zword hx_table_size;
|
||||
extern zword hx_mouse_x;
|
||||
extern zword hx_mouse_y;
|
||||
extern zword hx_unicode_table;
|
||||
|
||||
/*** Various data ***/
|
||||
|
||||
extern const char *story_name;
|
||||
|
||||
extern enum story story_id;
|
||||
extern long story_size;
|
||||
|
||||
extern zword stack[STACK_SIZE];
|
||||
extern zword *sp;
|
||||
extern zword *fp;
|
||||
extern zword frame_count;
|
||||
|
||||
extern zword zargs[8];
|
||||
extern int zargc;
|
||||
|
||||
extern bool ostream_screen;
|
||||
extern bool ostream_script;
|
||||
extern bool ostream_memory;
|
||||
extern bool ostream_record;
|
||||
extern bool istream_replay;
|
||||
extern bool message;
|
||||
|
||||
extern int cwin;
|
||||
extern int mwin;
|
||||
|
||||
extern int mouse_x;
|
||||
extern int mouse_y;
|
||||
|
||||
extern bool enable_wrapping;
|
||||
extern bool enable_scripting;
|
||||
extern bool enable_scrolling;
|
||||
extern bool enable_buffering;
|
||||
|
||||
|
||||
extern char *option_zcode_path; /* dg */
|
||||
|
||||
|
||||
/*** Blorb stuff ***/
|
||||
/*
|
||||
bb_err_t blorb_err;
|
||||
bb_map_t *blorb_map;
|
||||
*/
|
||||
|
||||
/*** Z-machine opcodes ***/
|
||||
|
||||
void z_add (void);
|
||||
void z_and (void);
|
||||
void z_art_shift (void);
|
||||
void z_buffer_mode (void);
|
||||
void z_call_n (void);
|
||||
void z_call_s (void);
|
||||
void z_catch (void);
|
||||
void z_check_arg_count (void);
|
||||
void z_check_unicode (void);
|
||||
void z_clear_attr (void);
|
||||
void z_copy_table (void);
|
||||
void z_dec (void);
|
||||
void z_dec_chk (void);
|
||||
void z_div (void);
|
||||
void z_draw_picture (void);
|
||||
void z_encode_text (void);
|
||||
void z_erase_line (void);
|
||||
void z_erase_picture (void);
|
||||
void z_erase_window (void);
|
||||
void z_get_child (void);
|
||||
void z_get_cursor (void);
|
||||
void z_get_next_prop (void);
|
||||
void z_get_parent (void);
|
||||
void z_get_prop (void);
|
||||
void z_get_prop_addr (void);
|
||||
void z_get_prop_len (void);
|
||||
void z_get_sibling (void);
|
||||
void z_get_wind_prop (void);
|
||||
void z_inc (void);
|
||||
void z_inc_chk (void);
|
||||
void z_input_stream (void);
|
||||
void z_insert_obj (void);
|
||||
void z_je (void);
|
||||
void z_jg (void);
|
||||
void z_jin (void);
|
||||
void z_jl (void);
|
||||
void z_jump (void);
|
||||
void z_jz (void);
|
||||
void z_load (void);
|
||||
void z_loadb (void);
|
||||
void z_loadw (void);
|
||||
void z_log_shift (void);
|
||||
void z_make_menu (void);
|
||||
void z_mod (void);
|
||||
void z_mouse_window (void);
|
||||
void z_move_window (void);
|
||||
void z_mul (void);
|
||||
void z_new_line (void);
|
||||
void z_nop (void);
|
||||
void z_not (void);
|
||||
void z_or (void);
|
||||
void z_output_stream (void);
|
||||
void z_picture_data (void);
|
||||
void z_picture_table (void);
|
||||
void z_piracy (void);
|
||||
void z_pop (void);
|
||||
void z_pop_stack (void);
|
||||
void z_print (void);
|
||||
void z_print_addr (void);
|
||||
void z_print_char (void);
|
||||
void z_print_form (void);
|
||||
void z_print_num (void);
|
||||
void z_print_obj (void);
|
||||
void z_print_paddr (void);
|
||||
void z_print_ret (void);
|
||||
void z_print_table (void);
|
||||
void z_print_unicode (void);
|
||||
void z_pull (void);
|
||||
void z_push (void);
|
||||
void z_push_stack (void);
|
||||
void z_put_prop (void);
|
||||
void z_put_wind_prop (void);
|
||||
void z_quit (void);
|
||||
void z_random (void);
|
||||
void z_read (void);
|
||||
void z_read_char (void);
|
||||
void z_read_mouse (void);
|
||||
void z_remove_obj (void);
|
||||
void z_restart (void);
|
||||
void z_restore (void);
|
||||
void z_restore_undo (void);
|
||||
void z_ret (void);
|
||||
void z_ret_popped (void);
|
||||
void z_rfalse (void);
|
||||
void z_rtrue (void);
|
||||
void z_save (void);
|
||||
void z_save_undo (void);
|
||||
void z_scan_table (void);
|
||||
void z_scroll_window (void);
|
||||
void z_set_attr (void);
|
||||
void z_set_font (void);
|
||||
void z_set_colour (void);
|
||||
void z_set_cursor (void);
|
||||
void z_set_margins (void);
|
||||
void z_set_window (void);
|
||||
void z_set_text_style (void);
|
||||
void z_show_status (void);
|
||||
void z_sound_effect (void);
|
||||
void z_split_window (void);
|
||||
void z_store (void);
|
||||
void z_storeb (void);
|
||||
void z_storew (void);
|
||||
void z_sub (void);
|
||||
void z_test (void);
|
||||
void z_test_attr (void);
|
||||
void z_throw (void);
|
||||
void z_tokenise (void);
|
||||
void z_verify (void);
|
||||
void z_window_size (void);
|
||||
void z_window_style (void);
|
||||
|
||||
/* Definitions for error handling functions and error codes. */
|
||||
|
||||
/* extern int err_report_mode; */
|
||||
|
||||
void init_err (void);
|
||||
void runtime_error (int);
|
||||
|
||||
/* Error codes */
|
||||
#define ERR_TEXT_BUF_OVF 1 /* Text buffer overflow */
|
||||
#define ERR_STORE_RANGE 2 /* Store out of dynamic memory */
|
||||
#define ERR_DIV_ZERO 3 /* Division by zero */
|
||||
#define ERR_ILL_OBJ 4 /* Illegal object */
|
||||
#define ERR_ILL_ATTR 5 /* Illegal attribute */
|
||||
#define ERR_NO_PROP 6 /* No such property */
|
||||
#define ERR_STK_OVF 7 /* Stack overflow */
|
||||
#define ERR_ILL_CALL_ADDR 8 /* Call to illegal address */
|
||||
#define ERR_CALL_NON_RTN 9 /* Call to non-routine */
|
||||
#define ERR_STK_UNDF 10 /* Stack underflow */
|
||||
#define ERR_ILL_OPCODE 11 /* Illegal opcode */
|
||||
#define ERR_BAD_FRAME 12 /* Bad stack frame */
|
||||
#define ERR_ILL_JUMP_ADDR 13 /* Jump to illegal address */
|
||||
#define ERR_SAVE_IN_INTER 14 /* Can't save while in interrupt */
|
||||
#define ERR_STR3_NESTING 15 /* Nesting stream #3 too deep */
|
||||
#define ERR_ILL_WIN 16 /* Illegal window */
|
||||
#define ERR_ILL_WIN_PROP 17 /* Illegal window property */
|
||||
#define ERR_ILL_PRINT_ADDR 18 /* Print at illegal address */
|
||||
#define ERR_MAX_FATAL 18
|
||||
|
||||
/* Less serious errors */
|
||||
#define ERR_JIN_0 19 /* @jin called with object 0 */
|
||||
#define ERR_GET_CHILD_0 20 /* @get_child called with object 0 */
|
||||
#define ERR_GET_PARENT_0 21 /* @get_parent called with object 0 */
|
||||
#define ERR_GET_SIBLING_0 22 /* @get_sibling called with object 0 */
|
||||
#define ERR_GET_PROP_ADDR_0 23 /* @get_prop_addr called with object 0 */
|
||||
#define ERR_GET_PROP_0 24 /* @get_prop called with object 0 */
|
||||
#define ERR_PUT_PROP_0 25 /* @put_prop called with object 0 */
|
||||
#define ERR_CLEAR_ATTR_0 26 /* @clear_attr called with object 0 */
|
||||
#define ERR_SET_ATTR_0 27 /* @set_attr called with object 0 */
|
||||
#define ERR_TEST_ATTR_0 28 /* @test_attr called with object 0 */
|
||||
#define ERR_MOVE_OBJECT_0 29 /* @move_object called moving object 0 */
|
||||
#define ERR_MOVE_OBJECT_TO_0 30 /* @move_object called moving into object 0 */
|
||||
#define ERR_REMOVE_OBJECT_0 31 /* @remove_object called with object 0 */
|
||||
#define ERR_GET_NEXT_PROP_0 32 /* @get_next_prop called with object 0 */
|
||||
#define ERR_NUM_ERRORS (32)
|
||||
|
||||
/* There are four error reporting modes: never report errors;
|
||||
report only the first time a given error type occurs; report
|
||||
every time an error occurs; or treat all errors as fatal
|
||||
errors, killing the interpreter. I strongly recommend
|
||||
"report once" as the default. But you can compile in a
|
||||
different default by changing the definition of
|
||||
ERR_DEFAULT_REPORT_MODE. In any case, the player can
|
||||
specify a report mode on the command line by typing "-Z 0"
|
||||
through "-Z 3". */
|
||||
|
||||
#define ERR_REPORT_NEVER (0)
|
||||
#define ERR_REPORT_ONCE (1)
|
||||
#define ERR_REPORT_ALWAYS (2)
|
||||
#define ERR_REPORT_FATAL (3)
|
||||
|
||||
#define ERR_DEFAULT_REPORT_MODE ERR_REPORT_ONCE
|
||||
|
||||
|
||||
/*** Various global functions ***/
|
||||
|
||||
zchar translate_from_zscii (zbyte);
|
||||
zbyte translate_to_zscii (zchar);
|
||||
|
||||
void flush_buffer (void);
|
||||
void new_line (void);
|
||||
void print_char (zchar);
|
||||
void print_num (zword);
|
||||
void print_object (zword);
|
||||
void print_string (const char *);
|
||||
|
||||
void stream_mssg_on (void);
|
||||
void stream_mssg_off (void);
|
||||
|
||||
void ret (zword);
|
||||
void store (zword);
|
||||
void branch (bool);
|
||||
|
||||
void storeb (zword, zbyte);
|
||||
void storew (zword, zword);
|
||||
|
||||
/*** Interface functions ***/
|
||||
|
||||
void os_beep (int);
|
||||
int os_char_width (zchar);
|
||||
void os_display_char (zchar);
|
||||
void os_display_string (const zchar *);
|
||||
void os_draw_picture (int, int, int);
|
||||
void os_erase_area (int, int, int, int);
|
||||
void os_fatal (const char *) __attribute__((noreturn));
|
||||
void os_finish_with_sample (int);
|
||||
int os_font_data (int, int *, int *);
|
||||
void os_init_screen (void);
|
||||
void os_more_prompt (void);
|
||||
int os_peek_colour (void);
|
||||
bool os_picture_data (int, int *, int *);
|
||||
void os_prepare_sample (int);
|
||||
void os_process_arguments (int, char *[]);
|
||||
int os_random_seed (void);
|
||||
int os_read_file_name (char *, const char *, int);
|
||||
zchar os_read_key (int, bool);
|
||||
zchar os_read_line (int, zchar *, int, int, int);
|
||||
zchar os_read_mouse (void);
|
||||
void os_reset_screen (void);
|
||||
void os_restart_game (int);
|
||||
void os_scroll_area (int, int, int, int, int);
|
||||
void os_set_colour (int, int);
|
||||
void os_set_cursor (int, int);
|
||||
void os_set_font (int);
|
||||
void os_set_text_style (int);
|
||||
void os_start_sample (int, int, int, zword);
|
||||
void os_stop_sample (int);
|
||||
int os_string_width (const zchar *);
|
||||
void os_init_setup (void);
|
||||
int os_speech_output(const zchar *);
|
||||
|
||||
#include "setup.h"
|
21
apps/plugins/frotz/frotz.make
Normal file
21
apps/plugins/frotz/frotz.make
Normal file
|
@ -0,0 +1,21 @@
|
|||
# __________ __ ___.
|
||||
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
# \/ \/ \/ \/ \/
|
||||
# $Id$
|
||||
#
|
||||
|
||||
FROTZSRCDIR := $(APPSDIR)/plugins/frotz
|
||||
FROTZBUILDDIR := $(BUILDDIR)/apps/plugins/frotz
|
||||
|
||||
ROCKS += $(FROTZBUILDDIR)/frotz.rock
|
||||
|
||||
FROTZ_SRC := $(call preprocess, $(FROTZSRCDIR)/SOURCES)
|
||||
FROTZ_OBJ := $(call c2obj, $(FROTZ_SRC))
|
||||
|
||||
# add source files to OTHER_SRC to get automatic dependencies
|
||||
OTHER_SRC += $(FROTZ_SRC)
|
||||
|
||||
$(FROTZBUILDDIR)/frotz.rock: $(FROTZ_OBJ)
|
56
apps/plugins/frotz/frotzplugin.h
Normal file
56
apps/plugins/frotz/frotzplugin.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2009 Torne Wuff
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef _FROTZPLUGIN_H_
|
||||
#define _FROTZPLUGIN_H_
|
||||
|
||||
#include "plugin.h"
|
||||
|
||||
/*
|
||||
* pretend stdio.h is implemented. references to FILE * still have to be
|
||||
* changed to int, and references to NULL into -1, but there are less of those
|
||||
*/
|
||||
#define fread(ptr, size, nmemb, stream) rb->read(stream, ptr, size*nmemb)
|
||||
#define fwrite(ptr, size, nmemb, stream) rb->write(stream, ptr, size*nmemb)
|
||||
#define fclose(stream) rb->close(stream)
|
||||
#define fseek(stream, offset, whence) rb->lseek(stream, offset, whence)
|
||||
#define ftell(stream) rb->lseek(stream, 0, SEEK_CUR)
|
||||
#define ferror(stream) 0
|
||||
|
||||
/*
|
||||
* we need functions for character io
|
||||
*/
|
||||
extern int ungetc(int c, int f);
|
||||
extern int fgetc(int f);
|
||||
extern int fputc(int c, int f);
|
||||
|
||||
/*
|
||||
* this is used instead of os_read_key for more prompts and the like
|
||||
* since the menu can't be used there.
|
||||
*/
|
||||
extern void wait_for_key(void);
|
||||
|
||||
/*
|
||||
* wrappers
|
||||
*/
|
||||
#define strchr(s, c) rb->strchr(s, c)
|
||||
#define strcpy(dest, src) rb->strcpy(dest, src)
|
||||
|
||||
#endif /* _FROTZPLUGIN_H_ */
|
221
apps/plugins/frotz/hotkey.c
Normal file
221
apps/plugins/frotz/hotkey.c
Normal file
|
@ -0,0 +1,221 @@
|
|||
/* hotkey.c - Hot key functions
|
||||
* Copyright (c) 1995-1997 Stefan Jokisch
|
||||
*
|
||||
* Changes for Rockbox copyright 2009 Torne Wuff
|
||||
*
|
||||
* This file is part of Frotz.
|
||||
*
|
||||
* Frotz is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Frotz is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include "frotz.h"
|
||||
#include "lib/pluginlib_exit.h"
|
||||
|
||||
extern int restore_undo (void);
|
||||
|
||||
extern int read_number (void);
|
||||
|
||||
extern bool read_yes_or_no (const char *);
|
||||
|
||||
extern void replay_open (void);
|
||||
extern void replay_close (void);
|
||||
extern void record_open (void);
|
||||
extern void record_close (void);
|
||||
|
||||
extern void seed_random (int);
|
||||
|
||||
/*
|
||||
* hot_key_debugging
|
||||
*
|
||||
* ...allows user to toggle cheating options on/off.
|
||||
*
|
||||
*/
|
||||
|
||||
static bool hot_key_debugging (void)
|
||||
{
|
||||
|
||||
f_setup.attribute_assignment = read_yes_or_no ("Watch attribute assignment");
|
||||
f_setup.attribute_testing = read_yes_or_no ("Watch attribute testing");
|
||||
|
||||
f_setup.object_movement = read_yes_or_no ("Watch object movement");
|
||||
f_setup.object_locating = read_yes_or_no ("Watch object locating");
|
||||
|
||||
return FALSE;
|
||||
|
||||
}/* hot_key_debugging */
|
||||
|
||||
/*
|
||||
* hot_key_playback
|
||||
*
|
||||
* ...allows user to turn playback on.
|
||||
*
|
||||
*/
|
||||
|
||||
static bool hot_key_playback (void)
|
||||
{
|
||||
|
||||
rb->splash(HZ, "Playback on");
|
||||
|
||||
if (!istream_replay)
|
||||
replay_open ();
|
||||
|
||||
return FALSE;
|
||||
|
||||
}/* hot_key_playback */
|
||||
|
||||
/*
|
||||
* hot_key_recording
|
||||
*
|
||||
* ...allows user to turn recording on/off.
|
||||
*
|
||||
*/
|
||||
|
||||
static bool hot_key_recording (void)
|
||||
{
|
||||
|
||||
if (istream_replay) {
|
||||
rb->splash(HZ, "Playback off");
|
||||
replay_close ();
|
||||
} else if (ostream_record) {
|
||||
rb->splash(HZ, "Recording off");
|
||||
record_close ();
|
||||
} else {
|
||||
rb->splash(HZ, "Recording on");
|
||||
record_open ();
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
}/* hot_key_recording */
|
||||
|
||||
/*
|
||||
* hot_key_seed
|
||||
*
|
||||
* ...allows user to seed the random number seed.
|
||||
*
|
||||
*/
|
||||
|
||||
static bool hot_key_seed (void)
|
||||
{
|
||||
|
||||
print_string ("Enter seed value (or return to randomize): ");
|
||||
seed_random (read_number ());
|
||||
|
||||
return FALSE;
|
||||
|
||||
}/* hot_key_seed */
|
||||
|
||||
/*
|
||||
* hot_key_undo
|
||||
*
|
||||
* ...allows user to undo the previous turn.
|
||||
*
|
||||
*/
|
||||
|
||||
static bool hot_key_undo (void)
|
||||
{
|
||||
|
||||
if (restore_undo ()) {
|
||||
|
||||
print_string ("undo\n");
|
||||
|
||||
if (h_version >= V5) { /* for V5+ games we must */
|
||||
store (2); /* store 2 (for success) */
|
||||
return TRUE; /* and abort the input */
|
||||
}
|
||||
|
||||
if (h_version <= V3) { /* for V3- games we must */
|
||||
z_show_status (); /* draw the status line */
|
||||
return FALSE; /* and continue input */
|
||||
}
|
||||
|
||||
} else rb->splash(HZ, "No undo information available.");
|
||||
|
||||
return FALSE;
|
||||
|
||||
}/* hot_key_undo */
|
||||
|
||||
/*
|
||||
* hot_key_restart
|
||||
*
|
||||
* ...allows user to start a new game.
|
||||
*
|
||||
*/
|
||||
|
||||
static bool hot_key_restart (void)
|
||||
{
|
||||
|
||||
if (read_yes_or_no ("Do you wish to restart")) {
|
||||
|
||||
z_restart ();
|
||||
return TRUE;
|
||||
|
||||
} else return FALSE;
|
||||
|
||||
}/* hot_key_restart */
|
||||
|
||||
/*
|
||||
* hot_key_quit
|
||||
*
|
||||
* ...allows user to exit the game.
|
||||
*
|
||||
*/
|
||||
|
||||
bool hot_key_quit (void)
|
||||
{
|
||||
|
||||
if (read_yes_or_no ("Do you wish to quit")) {
|
||||
|
||||
exit(0);
|
||||
|
||||
} else return FALSE;
|
||||
|
||||
}/* hot_key_quit */
|
||||
|
||||
/*
|
||||
* handle_hot_key
|
||||
*
|
||||
* Perform the action associated with a so-called hot key. Return
|
||||
* true to abort the current input action.
|
||||
*
|
||||
*/
|
||||
|
||||
bool handle_hot_key (zchar key)
|
||||
{
|
||||
|
||||
if (cwin == 0) {
|
||||
|
||||
bool aborting;
|
||||
|
||||
aborting = FALSE;
|
||||
|
||||
switch (key) {
|
||||
case ZC_HKEY_RECORD: aborting = hot_key_recording (); break;
|
||||
case ZC_HKEY_PLAYBACK: aborting = hot_key_playback (); break;
|
||||
case ZC_HKEY_SEED: aborting = hot_key_seed (); break;
|
||||
case ZC_HKEY_UNDO: aborting = hot_key_undo (); break;
|
||||
case ZC_HKEY_RESTART: aborting = hot_key_restart (); break;
|
||||
case ZC_HKEY_QUIT: aborting = hot_key_quit (); break;
|
||||
case ZC_HKEY_DEBUG: aborting = hot_key_debugging (); break;
|
||||
}
|
||||
|
||||
if (aborting)
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
}/* handle_hot_key */
|
301
apps/plugins/frotz/input.c
Normal file
301
apps/plugins/frotz/input.c
Normal file
|
@ -0,0 +1,301 @@
|
|||
/* input.c - High level input functions
|
||||
* Copyright (c) 1995-1997 Stefan Jokisch
|
||||
*
|
||||
* Changes for Rockbox copyright 2009 Torne Wuff
|
||||
*
|
||||
* This file is part of Frotz.
|
||||
*
|
||||
* Frotz is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Frotz is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include "frotz.h"
|
||||
|
||||
extern int save_undo (void);
|
||||
|
||||
extern zchar stream_read_key (zword, zword, bool);
|
||||
extern zchar stream_read_input (int, zchar *, zword, zword, bool, bool);
|
||||
|
||||
extern void tokenise_line (zword, zword, zword, bool);
|
||||
|
||||
/*
|
||||
* is_terminator
|
||||
*
|
||||
* Check if the given key is an input terminator.
|
||||
*
|
||||
*/
|
||||
|
||||
bool is_terminator (zchar key)
|
||||
{
|
||||
|
||||
if (key == ZC_TIME_OUT)
|
||||
return TRUE;
|
||||
if (key == ZC_RETURN)
|
||||
return TRUE;
|
||||
if (key >= ZC_HKEY_MIN && key <= ZC_HKEY_MAX)
|
||||
return TRUE;
|
||||
|
||||
if (h_terminating_keys != 0)
|
||||
|
||||
if (key >= ZC_ARROW_MIN && key <= ZC_MENU_CLICK) {
|
||||
|
||||
zword addr = h_terminating_keys;
|
||||
zbyte c;
|
||||
|
||||
do {
|
||||
LOW_BYTE (addr, c)
|
||||
if (c == 255 || key == translate_from_zscii (c))
|
||||
return TRUE;
|
||||
addr++;
|
||||
} while (c != 0);
|
||||
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
}/* is_terminator */
|
||||
|
||||
/*
|
||||
* z_make_menu, add or remove a menu and branch if successful.
|
||||
*
|
||||
* zargs[0] = number of menu
|
||||
* zargs[1] = table of menu entries or 0 to remove menu
|
||||
*
|
||||
*/
|
||||
|
||||
void z_make_menu (void)
|
||||
{
|
||||
|
||||
/* This opcode was only used for the Macintosh version of Journey.
|
||||
It controls menus with numbers greater than 2 (menus 0, 1 and 2
|
||||
are system menus). Frotz doesn't implement menus yet. */
|
||||
|
||||
branch (FALSE);
|
||||
|
||||
}/* z_make_menu */
|
||||
|
||||
extern bool read_yes_or_no (const char *s);
|
||||
|
||||
/*
|
||||
* read_string
|
||||
*
|
||||
* Read a string from the current input stream.
|
||||
*
|
||||
*/
|
||||
|
||||
void read_string (int max, zchar *buffer)
|
||||
{
|
||||
zchar key;
|
||||
|
||||
buffer[0] = 0;
|
||||
|
||||
do {
|
||||
|
||||
key = stream_read_input (max, buffer, 0, 0, FALSE, FALSE);
|
||||
|
||||
} while (key != ZC_RETURN);
|
||||
|
||||
}/* read_string */
|
||||
|
||||
/*
|
||||
* read_number
|
||||
*
|
||||
* Ask the user to type in a number and return it.
|
||||
*
|
||||
*/
|
||||
|
||||
int read_number (void)
|
||||
{
|
||||
zchar buffer[6];
|
||||
int value = 0;
|
||||
int i;
|
||||
|
||||
read_string (5, buffer);
|
||||
|
||||
for (i = 0; buffer[i] != 0; i++)
|
||||
if (buffer[i] >= '0' && buffer[i] <= '9')
|
||||
value = 10 * value + buffer[i] - '0';
|
||||
|
||||
return value;
|
||||
|
||||
}/* read_number */
|
||||
|
||||
/*
|
||||
* z_read, read a line of input and (in V5+) store the terminating key.
|
||||
*
|
||||
* zargs[0] = address of text buffer
|
||||
* zargs[1] = address of token buffer
|
||||
* zargs[2] = timeout in tenths of a second (optional)
|
||||
* zargs[3] = packed address of routine to be called on timeout
|
||||
*
|
||||
*/
|
||||
|
||||
void z_read (void)
|
||||
{
|
||||
zchar buffer[INPUT_BUFFER_SIZE];
|
||||
zword addr;
|
||||
zchar key;
|
||||
zbyte max, size;
|
||||
zbyte c;
|
||||
int i;
|
||||
|
||||
/* Supply default arguments */
|
||||
|
||||
if (zargc < 3)
|
||||
zargs[2] = 0;
|
||||
|
||||
/* Get maximum input size */
|
||||
|
||||
addr = zargs[0];
|
||||
|
||||
LOW_BYTE (addr, max)
|
||||
|
||||
if (h_version <= V4)
|
||||
max--;
|
||||
|
||||
if (max >= INPUT_BUFFER_SIZE)
|
||||
max = INPUT_BUFFER_SIZE - 1;
|
||||
|
||||
/* Get initial input size */
|
||||
|
||||
if (h_version >= V5) {
|
||||
addr++;
|
||||
LOW_BYTE (addr, size)
|
||||
} else size = 0;
|
||||
|
||||
/* Copy initial input to local buffer */
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
addr++;
|
||||
LOW_BYTE (addr, c)
|
||||
buffer[i] = translate_from_zscii (c);
|
||||
}
|
||||
|
||||
buffer[i] = 0;
|
||||
|
||||
/* Draw status line for V1 to V3 games */
|
||||
|
||||
if (h_version <= V3)
|
||||
z_show_status ();
|
||||
|
||||
/* Read input from current input stream */
|
||||
|
||||
key = stream_read_input (
|
||||
max, buffer, /* buffer and size */
|
||||
zargs[2], /* timeout value */
|
||||
zargs[3], /* timeout routine */
|
||||
TRUE, /* enable hot keys */
|
||||
h_version == V6); /* no script in V6 */
|
||||
|
||||
if (key == ZC_BAD)
|
||||
return;
|
||||
|
||||
/* Perform save_undo for V1 to V4 games */
|
||||
|
||||
if (h_version <= V4)
|
||||
save_undo ();
|
||||
|
||||
/* Copy local buffer back to dynamic memory */
|
||||
|
||||
for (i = 0; buffer[i] != 0; i++) {
|
||||
|
||||
if (key == ZC_RETURN) {
|
||||
|
||||
if (buffer[i] >= 'A' && buffer[i] <= 'Z')
|
||||
buffer[i] += 'a' - 'A';
|
||||
if (buffer[i] >= 0xc0 && buffer[i] <= 0xde && buffer[i] != 0xd7)
|
||||
buffer[i] += 0x20;
|
||||
|
||||
}
|
||||
|
||||
storeb ((zword) (zargs[0] + ((h_version <= V4) ? 1 : 2) + i), translate_to_zscii (buffer[i]));
|
||||
|
||||
}
|
||||
|
||||
/* Add null character (V1-V4) or write input length into 2nd byte */
|
||||
|
||||
if (h_version <= V4)
|
||||
storeb ((zword) (zargs[0] + 1 + i), 0);
|
||||
else
|
||||
storeb ((zword) (zargs[0] + 1), i);
|
||||
|
||||
/* Tokenise line if a token buffer is present */
|
||||
|
||||
if (key == ZC_RETURN && zargs[1] != 0)
|
||||
tokenise_line (zargs[0], zargs[1], 0, FALSE);
|
||||
|
||||
/* Store key */
|
||||
|
||||
if (h_version >= V5)
|
||||
store (translate_to_zscii (key));
|
||||
|
||||
}/* z_read */
|
||||
|
||||
/*
|
||||
* z_read_char, read and store a key.
|
||||
*
|
||||
* zargs[0] = input device (must be 1)
|
||||
* zargs[1] = timeout in tenths of a second (optional)
|
||||
* zargs[2] = packed address of routine to be called on timeout
|
||||
*
|
||||
*/
|
||||
|
||||
void z_read_char (void)
|
||||
{
|
||||
zchar key;
|
||||
|
||||
/* Supply default arguments */
|
||||
|
||||
if (zargc < 2)
|
||||
zargs[1] = 0;
|
||||
|
||||
/* Read input from the current input stream */
|
||||
|
||||
key = stream_read_key (
|
||||
zargs[1], /* timeout value */
|
||||
zargs[2], /* timeout routine */
|
||||
TRUE); /* enable hot keys */
|
||||
|
||||
if (key == ZC_BAD)
|
||||
return;
|
||||
|
||||
/* Store key */
|
||||
|
||||
store (translate_to_zscii (key));
|
||||
|
||||
}/* z_read_char */
|
||||
|
||||
/*
|
||||
* z_read_mouse, write the current mouse status into a table.
|
||||
*
|
||||
* zargs[0] = address of table
|
||||
*
|
||||
*/
|
||||
|
||||
void z_read_mouse (void)
|
||||
{
|
||||
zword btn;
|
||||
|
||||
/* Read the mouse position and which buttons are down */
|
||||
|
||||
btn = os_read_mouse ();
|
||||
hx_mouse_y = mouse_y;
|
||||
hx_mouse_x = mouse_x;
|
||||
|
||||
storew ((zword) (zargs[0] + 0), hx_mouse_y);
|
||||
storew ((zword) (zargs[0] + 2), hx_mouse_x);
|
||||
storew ((zword) (zargs[0] + 4), btn); /* mouse button bits */
|
||||
storew ((zword) (zargs[0] + 6), 0); /* menu selection */
|
||||
|
||||
}/* z_read_mouse */
|
205
apps/plugins/frotz/main.c
Normal file
205
apps/plugins/frotz/main.c
Normal file
|
@ -0,0 +1,205 @@
|
|||
/* main.c - Frotz V2.40 main function
|
||||
* Copyright (c) 1995-1997 Stefan Jokisch
|
||||
*
|
||||
* Changes for Rockbox copyright 2009 Torne Wuff
|
||||
*
|
||||
* This file is part of Frotz.
|
||||
*
|
||||
* Frotz is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Frotz is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is an interpreter for Infocom V1 to V6 games. It also supports
|
||||
* the recently defined V7 and V8 games. Please report bugs to
|
||||
*
|
||||
* s.jokisch@avu.de
|
||||
*
|
||||
*/
|
||||
|
||||
#include "frotz.h"
|
||||
|
||||
#ifndef MSDOS_16BIT
|
||||
#define cdecl
|
||||
#endif
|
||||
|
||||
extern void interpret (void);
|
||||
extern void init_memory (void);
|
||||
extern void init_undo (void);
|
||||
extern void reset_memory (void);
|
||||
extern void init_buffer (void);
|
||||
extern void init_sound (void);
|
||||
extern void init_process (void);
|
||||
extern void script_close (void);
|
||||
extern void record_close (void);
|
||||
extern void replay_close (void);
|
||||
|
||||
/* Story file name, id number and size */
|
||||
|
||||
const char *story_name = 0;
|
||||
|
||||
enum story story_id = UNKNOWN;
|
||||
long story_size = 0;
|
||||
|
||||
/* Story file header data */
|
||||
|
||||
zbyte h_version = 0;
|
||||
zbyte h_config = 0;
|
||||
zword h_release = 0;
|
||||
zword h_resident_size = 0;
|
||||
zword h_start_pc = 0;
|
||||
zword h_dictionary = 0;
|
||||
zword h_objects = 0;
|
||||
zword h_globals = 0;
|
||||
zword h_dynamic_size = 0;
|
||||
zword h_flags = 0;
|
||||
zbyte h_serial[6] = { 0, 0, 0, 0, 0, 0 };
|
||||
zword h_abbreviations = 0;
|
||||
zword h_file_size = 0;
|
||||
zword h_checksum = 0;
|
||||
zbyte h_interpreter_number = 0;
|
||||
zbyte h_interpreter_version = 0;
|
||||
zbyte h_screen_rows = 0;
|
||||
zbyte h_screen_cols = 0;
|
||||
zword h_screen_width = 0;
|
||||
zword h_screen_height = 0;
|
||||
zbyte h_font_height = 1;
|
||||
zbyte h_font_width = 1;
|
||||
zword h_functions_offset = 0;
|
||||
zword h_strings_offset = 0;
|
||||
zbyte h_default_background = 0;
|
||||
zbyte h_default_foreground = 0;
|
||||
zword h_terminating_keys = 0;
|
||||
zword h_line_width = 0;
|
||||
zbyte h_standard_high = 1;
|
||||
zbyte h_standard_low = 0;
|
||||
zword h_alphabet = 0;
|
||||
zword h_extension_table = 0;
|
||||
zbyte h_user_name[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
zword hx_table_size = 0;
|
||||
zword hx_mouse_x = 0;
|
||||
zword hx_mouse_y = 0;
|
||||
zword hx_unicode_table = 0;
|
||||
|
||||
/* Stack data */
|
||||
|
||||
zword stack[STACK_SIZE];
|
||||
zword *sp = 0;
|
||||
zword *fp = 0;
|
||||
zword frame_count = 0;
|
||||
|
||||
/* IO streams */
|
||||
|
||||
bool ostream_screen = TRUE;
|
||||
bool ostream_script = FALSE;
|
||||
bool ostream_memory = FALSE;
|
||||
bool ostream_record = FALSE;
|
||||
bool istream_replay = FALSE;
|
||||
bool message = FALSE;
|
||||
|
||||
/* Current window and mouse data */
|
||||
|
||||
int cwin = 0;
|
||||
int mwin = 0;
|
||||
|
||||
int mouse_y = 0;
|
||||
int mouse_x = 0;
|
||||
|
||||
/* Window attributes */
|
||||
|
||||
bool enable_wrapping = FALSE;
|
||||
bool enable_scripting = FALSE;
|
||||
bool enable_scrolling = FALSE;
|
||||
bool enable_buffering = FALSE;
|
||||
|
||||
/* User options */
|
||||
|
||||
/*
|
||||
int option_attribute_assignment = 0;
|
||||
int option_attribute_testing = 0;
|
||||
int option_context_lines = 0;
|
||||
int option_object_locating = 0;
|
||||
int option_object_movement = 0;
|
||||
int option_left_margin = 0;
|
||||
int option_right_margin = 0;
|
||||
int option_ignore_errors = 0;
|
||||
int option_piracy = 0;
|
||||
int option_undo_slots = MAX_UNDO_SLOTS;
|
||||
int option_expand_abbreviations = 0;
|
||||
int option_script_cols = 80;
|
||||
int option_save_quetzal = 1;
|
||||
*/
|
||||
|
||||
int option_sound = 1;
|
||||
char *option_zcode_path;
|
||||
|
||||
|
||||
/*
|
||||
* z_piracy, branch if the story file is a legal copy.
|
||||
*
|
||||
* no zargs used
|
||||
*
|
||||
*/
|
||||
|
||||
void z_piracy (void)
|
||||
{
|
||||
|
||||
branch (!f_setup.piracy);
|
||||
|
||||
}/* z_piracy */
|
||||
|
||||
/*
|
||||
* main
|
||||
*
|
||||
* Prepare and run the game.
|
||||
*
|
||||
*/
|
||||
|
||||
int cdecl frotz_main (void)
|
||||
{
|
||||
|
||||
os_init_setup ();
|
||||
|
||||
init_buffer ();
|
||||
|
||||
init_err ();
|
||||
|
||||
init_memory ();
|
||||
|
||||
init_process ();
|
||||
|
||||
init_sound ();
|
||||
|
||||
os_init_screen ();
|
||||
|
||||
init_undo ();
|
||||
|
||||
z_restart ();
|
||||
|
||||
interpret ();
|
||||
|
||||
script_close ();
|
||||
|
||||
record_close ();
|
||||
|
||||
replay_close ();
|
||||
|
||||
reset_memory ();
|
||||
|
||||
os_reset_screen ();
|
||||
|
||||
return 0;
|
||||
|
||||
}/* main */
|
261
apps/plugins/frotz/math.c
Normal file
261
apps/plugins/frotz/math.c
Normal file
|
@ -0,0 +1,261 @@
|
|||
/* math.c - Arithmetic, compare and logical opcodes
|
||||
* Copyright (c) 1995-1997 Stefan Jokisch
|
||||
*
|
||||
* This file is part of Frotz.
|
||||
*
|
||||
* Frotz is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Frotz is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include "frotz.h"
|
||||
|
||||
/*
|
||||
* z_add, 16bit addition.
|
||||
*
|
||||
* zargs[0] = first value
|
||||
* zargs[1] = second value
|
||||
*
|
||||
*/
|
||||
|
||||
void z_add (void)
|
||||
{
|
||||
|
||||
store ((zword) ((short) zargs[0] + (short) zargs[1]));
|
||||
|
||||
}/* z_add */
|
||||
|
||||
/*
|
||||
* z_and, bitwise AND operation.
|
||||
*
|
||||
* zargs[0] = first value
|
||||
* zargs[1] = second value
|
||||
*
|
||||
*/
|
||||
|
||||
void z_and (void)
|
||||
{
|
||||
|
||||
store ((zword) (zargs[0] & zargs[1]));
|
||||
|
||||
}/* z_and */
|
||||
|
||||
/*
|
||||
* z_art_shift, arithmetic SHIFT operation.
|
||||
*
|
||||
* zargs[0] = value
|
||||
* zargs[1] = #positions to shift left (positive) or right
|
||||
*
|
||||
*/
|
||||
|
||||
void z_art_shift (void)
|
||||
{
|
||||
|
||||
if ((short) zargs[1] > 0)
|
||||
store ((zword) ((short) zargs[0] << (short) zargs[1]));
|
||||
else
|
||||
store ((zword) ((short) zargs[0] >> - (short) zargs[1]));
|
||||
|
||||
}/* z_art_shift */
|
||||
|
||||
/*
|
||||
* z_div, signed 16bit division.
|
||||
*
|
||||
* zargs[0] = first value
|
||||
* zargs[1] = second value
|
||||
*
|
||||
*/
|
||||
|
||||
void z_div (void)
|
||||
{
|
||||
|
||||
if (zargs[1] == 0)
|
||||
runtime_error (ERR_DIV_ZERO);
|
||||
|
||||
store ((zword) ((short) zargs[0] / (short) zargs[1]));
|
||||
|
||||
}/* z_div */
|
||||
|
||||
/*
|
||||
* z_je, branch if the first value equals any of the following.
|
||||
*
|
||||
* zargs[0] = first value
|
||||
* zargs[1] = second value (optional)
|
||||
* ...
|
||||
* zargs[3] = fourth value (optional)
|
||||
*
|
||||
*/
|
||||
|
||||
void z_je (void)
|
||||
{
|
||||
|
||||
branch (
|
||||
zargc > 1 && (zargs[0] == zargs[1] || (
|
||||
zargc > 2 && (zargs[0] == zargs[2] || (
|
||||
zargc > 3 && (zargs[0] == zargs[3]))))));
|
||||
|
||||
}/* z_je */
|
||||
|
||||
/*
|
||||
* z_jg, branch if the first value is greater than the second.
|
||||
*
|
||||
* zargs[0] = first value
|
||||
* zargs[1] = second value
|
||||
*
|
||||
*/
|
||||
|
||||
void z_jg (void)
|
||||
{
|
||||
|
||||
branch ((short) zargs[0] > (short) zargs[1]);
|
||||
|
||||
}/* z_jg */
|
||||
|
||||
/*
|
||||
* z_jl, branch if the first value is less than the second.
|
||||
*
|
||||
* zargs[0] = first value
|
||||
* zargs[1] = second value
|
||||
*
|
||||
*/
|
||||
|
||||
void z_jl (void)
|
||||
{
|
||||
|
||||
branch ((short) zargs[0] < (short) zargs[1]);
|
||||
|
||||
}/* z_jl */
|
||||
|
||||
/*
|
||||
* z_jz, branch if value is zero.
|
||||
*
|
||||
* zargs[0] = value
|
||||
*
|
||||
*/
|
||||
|
||||
void z_jz (void)
|
||||
{
|
||||
|
||||
branch ((short) zargs[0] == 0);
|
||||
|
||||
}/* z_jz */
|
||||
|
||||
/*
|
||||
* z_log_shift, logical SHIFT operation.
|
||||
*
|
||||
* zargs[0] = value
|
||||
* zargs[1] = #positions to shift left (positive) or right (negative)
|
||||
*
|
||||
*/
|
||||
|
||||
void z_log_shift (void)
|
||||
{
|
||||
|
||||
if ((short) zargs[1] > 0)
|
||||
store ((zword) (zargs[0] << (short) zargs[1]));
|
||||
else
|
||||
store ((zword) (zargs[0] >> - (short) zargs[1]));
|
||||
|
||||
}/* z_log_shift */
|
||||
|
||||
/*
|
||||
* z_mod, remainder after signed 16bit division.
|
||||
*
|
||||
* zargs[0] = first value
|
||||
* zargs[1] = second value
|
||||
*
|
||||
*/
|
||||
|
||||
void z_mod (void)
|
||||
{
|
||||
|
||||
if (zargs[1] == 0)
|
||||
runtime_error (ERR_DIV_ZERO);
|
||||
|
||||
store ((zword) ((short) zargs[0] % (short) zargs[1]));
|
||||
|
||||
}/* z_mod */
|
||||
|
||||
/*
|
||||
* z_mul, 16bit multiplication.
|
||||
*
|
||||
* zargs[0] = first value
|
||||
* zargs[1] = second value
|
||||
*
|
||||
*/
|
||||
|
||||
void z_mul (void)
|
||||
{
|
||||
|
||||
store ((zword) ((short) zargs[0] * (short) zargs[1]));
|
||||
|
||||
}/* z_mul */
|
||||
|
||||
/*
|
||||
* z_not, bitwise NOT operation.
|
||||
*
|
||||
* zargs[0] = value
|
||||
*
|
||||
*/
|
||||
|
||||
void z_not (void)
|
||||
{
|
||||
|
||||
store ((zword) ~zargs[0]);
|
||||
|
||||
}/* z_not */
|
||||
|
||||
/*
|
||||
* z_or, bitwise OR operation.
|
||||
*
|
||||
* zargs[0] = first value
|
||||
* zargs[1] = second value
|
||||
*
|
||||
*/
|
||||
|
||||
void z_or (void)
|
||||
{
|
||||
|
||||
store ((zword) (zargs[0] | zargs[1]));
|
||||
|
||||
}/* z_or */
|
||||
|
||||
/*
|
||||
* z_sub, 16bit substraction.
|
||||
*
|
||||
* zargs[0] = first value
|
||||
* zargs[1] = second value
|
||||
*
|
||||
*/
|
||||
|
||||
void z_sub (void)
|
||||
{
|
||||
|
||||
store ((zword) ((short) zargs[0] - (short) zargs[1]));
|
||||
|
||||
}/* z_sub */
|
||||
|
||||
/*
|
||||
* z_test, branch if all the flags of a bit mask are set in a value.
|
||||
*
|
||||
* zargs[0] = value to be examined
|
||||
* zargs[1] = bit mask
|
||||
*
|
||||
*/
|
||||
|
||||
void z_test (void)
|
||||
{
|
||||
|
||||
branch ((zargs[0] & zargs[1]) == zargs[1]);
|
||||
|
||||
}/* z_test */
|
1003
apps/plugins/frotz/object.c
Normal file
1003
apps/plugins/frotz/object.c
Normal file
File diff suppressed because it is too large
Load diff
798
apps/plugins/frotz/process.c
Normal file
798
apps/plugins/frotz/process.c
Normal file
|
@ -0,0 +1,798 @@
|
|||
/* process.c - Interpreter loop and program control
|
||||
* Copyright (c) 1995-1997 Stefan Jokisch
|
||||
*
|
||||
* This file is part of Frotz.
|
||||
*
|
||||
* Frotz is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Frotz is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include "frotz.h"
|
||||
|
||||
#ifdef DJGPP
|
||||
#include "djfrotz.h"
|
||||
#endif
|
||||
|
||||
|
||||
zword zargs[8];
|
||||
int zargc;
|
||||
|
||||
static int finished = 0;
|
||||
|
||||
static void __extended__ (void);
|
||||
static void __illegal__ (void);
|
||||
|
||||
void (*op0_opcodes[0x10]) (void) = {
|
||||
z_rtrue,
|
||||
z_rfalse,
|
||||
z_print,
|
||||
z_print_ret,
|
||||
z_nop,
|
||||
z_save,
|
||||
z_restore,
|
||||
z_restart,
|
||||
z_ret_popped,
|
||||
z_catch,
|
||||
z_quit,
|
||||
z_new_line,
|
||||
z_show_status,
|
||||
z_verify,
|
||||
__extended__,
|
||||
z_piracy
|
||||
};
|
||||
|
||||
void (*op1_opcodes[0x10]) (void) = {
|
||||
z_jz,
|
||||
z_get_sibling,
|
||||
z_get_child,
|
||||
z_get_parent,
|
||||
z_get_prop_len,
|
||||
z_inc,
|
||||
z_dec,
|
||||
z_print_addr,
|
||||
z_call_s,
|
||||
z_remove_obj,
|
||||
z_print_obj,
|
||||
z_ret,
|
||||
z_jump,
|
||||
z_print_paddr,
|
||||
z_load,
|
||||
z_call_n
|
||||
};
|
||||
|
||||
void (*var_opcodes[0x40]) (void) = {
|
||||
__illegal__,
|
||||
z_je,
|
||||
z_jl,
|
||||
z_jg,
|
||||
z_dec_chk,
|
||||
z_inc_chk,
|
||||
z_jin,
|
||||
z_test,
|
||||
z_or,
|
||||
z_and,
|
||||
z_test_attr,
|
||||
z_set_attr,
|
||||
z_clear_attr,
|
||||
z_store,
|
||||
z_insert_obj,
|
||||
z_loadw,
|
||||
z_loadb,
|
||||
z_get_prop,
|
||||
z_get_prop_addr,
|
||||
z_get_next_prop,
|
||||
z_add,
|
||||
z_sub,
|
||||
z_mul,
|
||||
z_div,
|
||||
z_mod,
|
||||
z_call_s,
|
||||
z_call_n,
|
||||
z_set_colour,
|
||||
z_throw,
|
||||
__illegal__,
|
||||
__illegal__,
|
||||
__illegal__,
|
||||
z_call_s,
|
||||
z_storew,
|
||||
z_storeb,
|
||||
z_put_prop,
|
||||
z_read,
|
||||
z_print_char,
|
||||
z_print_num,
|
||||
z_random,
|
||||
z_push,
|
||||
z_pull,
|
||||
z_split_window,
|
||||
z_set_window,
|
||||
z_call_s,
|
||||
z_erase_window,
|
||||
z_erase_line,
|
||||
z_set_cursor,
|
||||
z_get_cursor,
|
||||
z_set_text_style,
|
||||
z_buffer_mode,
|
||||
z_output_stream,
|
||||
z_input_stream,
|
||||
z_sound_effect,
|
||||
z_read_char,
|
||||
z_scan_table,
|
||||
z_not,
|
||||
z_call_n,
|
||||
z_call_n,
|
||||
z_tokenise,
|
||||
z_encode_text,
|
||||
z_copy_table,
|
||||
z_print_table,
|
||||
z_check_arg_count
|
||||
};
|
||||
|
||||
void (*ext_opcodes[0x1d]) (void) = {
|
||||
z_save,
|
||||
z_restore,
|
||||
z_log_shift,
|
||||
z_art_shift,
|
||||
z_set_font,
|
||||
z_draw_picture,
|
||||
z_picture_data,
|
||||
z_erase_picture,
|
||||
z_set_margins,
|
||||
z_save_undo,
|
||||
z_restore_undo,
|
||||
z_print_unicode,
|
||||
z_check_unicode,
|
||||
__illegal__,
|
||||
__illegal__,
|
||||
__illegal__,
|
||||
z_move_window,
|
||||
z_window_size,
|
||||
z_window_style,
|
||||
z_get_wind_prop,
|
||||
z_scroll_window,
|
||||
z_pop_stack,
|
||||
z_read_mouse,
|
||||
z_mouse_window,
|
||||
z_push_stack,
|
||||
z_put_wind_prop,
|
||||
z_print_form,
|
||||
z_make_menu,
|
||||
z_picture_table
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* init_process
|
||||
*
|
||||
* Initialize process variables.
|
||||
*
|
||||
*/
|
||||
|
||||
void init_process (void)
|
||||
{
|
||||
finished = 0;
|
||||
} /* init_process */
|
||||
|
||||
|
||||
/*
|
||||
* load_operand
|
||||
*
|
||||
* Load an operand, either a variable or a constant.
|
||||
*
|
||||
*/
|
||||
|
||||
static void load_operand (zbyte type)
|
||||
{
|
||||
zword value;
|
||||
|
||||
if (type & 2) { /* variable */
|
||||
|
||||
zbyte variable;
|
||||
|
||||
CODE_BYTE (variable)
|
||||
|
||||
if (variable == 0)
|
||||
value = *sp++;
|
||||
else if (variable < 16)
|
||||
value = *(fp - variable);
|
||||
else {
|
||||
zword addr = h_globals + 2 * (variable - 16);
|
||||
LOW_WORD (addr, value)
|
||||
}
|
||||
|
||||
} else if (type & 1) { /* small constant */
|
||||
|
||||
zbyte bvalue;
|
||||
|
||||
CODE_BYTE (bvalue)
|
||||
value = bvalue;
|
||||
|
||||
} else CODE_WORD (value) /* large constant */
|
||||
|
||||
zargs[zargc++] = value;
|
||||
|
||||
}/* load_operand */
|
||||
|
||||
/*
|
||||
* load_all_operands
|
||||
*
|
||||
* Given the operand specifier byte, load all (up to four) operands
|
||||
* for a VAR or EXT opcode.
|
||||
*
|
||||
*/
|
||||
|
||||
static void load_all_operands (zbyte specifier)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 6; i >= 0; i -= 2) {
|
||||
|
||||
zbyte type = (specifier >> i) & 0x03;
|
||||
|
||||
if (type == 3)
|
||||
break;
|
||||
|
||||
load_operand (type);
|
||||
|
||||
}
|
||||
|
||||
}/* load_all_operands */
|
||||
|
||||
/*
|
||||
* interpret
|
||||
*
|
||||
* Z-code interpreter main loop
|
||||
*
|
||||
*/
|
||||
|
||||
void interpret (void)
|
||||
{
|
||||
|
||||
do {
|
||||
|
||||
zbyte opcode;
|
||||
|
||||
CODE_BYTE (opcode)
|
||||
|
||||
zargc = 0;
|
||||
|
||||
if (opcode < 0x80) { /* 2OP opcodes */
|
||||
|
||||
load_operand ((zbyte) (opcode & 0x40) ? 2 : 1);
|
||||
load_operand ((zbyte) (opcode & 0x20) ? 2 : 1);
|
||||
|
||||
var_opcodes[opcode & 0x1f] ();
|
||||
|
||||
} else if (opcode < 0xb0) { /* 1OP opcodes */
|
||||
|
||||
load_operand ((zbyte) (opcode >> 4));
|
||||
|
||||
op1_opcodes[opcode & 0x0f] ();
|
||||
|
||||
} else if (opcode < 0xc0) { /* 0OP opcodes */
|
||||
|
||||
op0_opcodes[opcode - 0xb0] ();
|
||||
|
||||
} else { /* VAR opcodes */
|
||||
|
||||
zbyte specifier1;
|
||||
zbyte specifier2;
|
||||
|
||||
if (opcode == 0xec || opcode == 0xfa) { /* opcodes 0xec */
|
||||
CODE_BYTE (specifier1) /* and 0xfa are */
|
||||
CODE_BYTE (specifier2) /* call opcodes */
|
||||
load_all_operands (specifier1); /* with up to 8 */
|
||||
load_all_operands (specifier2); /* arguments */
|
||||
} else {
|
||||
CODE_BYTE (specifier1)
|
||||
load_all_operands (specifier1);
|
||||
}
|
||||
|
||||
var_opcodes[opcode - 0xc0] ();
|
||||
|
||||
}
|
||||
|
||||
#if defined(DJGPP) && defined(SOUND_SUPPORT)
|
||||
if (end_of_sound_flag)
|
||||
end_of_sound ();
|
||||
#endif
|
||||
|
||||
} while (finished == 0);
|
||||
|
||||
finished--;
|
||||
|
||||
}/* interpret */
|
||||
|
||||
/*
|
||||
* call
|
||||
*
|
||||
* Call a subroutine. Save PC and FP then load new PC and initialise
|
||||
* new stack frame. Note that the caller may legally provide less or
|
||||
* more arguments than the function actually has. The call type "ct"
|
||||
* can be 0 (z_call_s), 1 (z_call_n) or 2 (direct call).
|
||||
*
|
||||
*/
|
||||
|
||||
void call (zword routine, int argc, zword *args, int ct)
|
||||
{
|
||||
long pc;
|
||||
zword value;
|
||||
zbyte count;
|
||||
int i;
|
||||
|
||||
if (sp - stack < 4)
|
||||
runtime_error (ERR_STK_OVF);
|
||||
|
||||
GET_PC (pc)
|
||||
|
||||
*--sp = (zword) (pc >> 9);
|
||||
*--sp = (zword) (pc & 0x1ff);
|
||||
*--sp = (zword) (fp - stack - 1);
|
||||
*--sp = (zword) (argc | (ct << (f_setup.save_quetzal ? 12 : 8)));
|
||||
|
||||
fp = sp;
|
||||
frame_count++;
|
||||
|
||||
/* Calculate byte address of routine */
|
||||
|
||||
if (h_version <= V3)
|
||||
pc = (long) routine << 1;
|
||||
else if (h_version <= V5)
|
||||
pc = (long) routine << 2;
|
||||
else if (h_version <= V7)
|
||||
pc = ((long) routine << 2) + ((long) h_functions_offset << 3);
|
||||
else /* h_version == V8 */
|
||||
pc = (long) routine << 3;
|
||||
|
||||
if (pc >= story_size)
|
||||
runtime_error (ERR_ILL_CALL_ADDR);
|
||||
|
||||
SET_PC (pc)
|
||||
|
||||
/* Initialise local variables */
|
||||
|
||||
CODE_BYTE (count)
|
||||
|
||||
if (count > 15)
|
||||
runtime_error (ERR_CALL_NON_RTN);
|
||||
if (sp - stack < count)
|
||||
runtime_error (ERR_STK_OVF);
|
||||
|
||||
if (f_setup.save_quetzal)
|
||||
fp[0] |= (zword) count << 8; /* Save local var count for Quetzal. */
|
||||
|
||||
value = 0;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
|
||||
if (h_version <= V4) /* V1 to V4 games provide default */
|
||||
CODE_WORD (value) /* values for all local variables */
|
||||
|
||||
*--sp = (zword) ((argc-- > 0) ? args[i] : value);
|
||||
|
||||
}
|
||||
|
||||
/* Start main loop for direct calls */
|
||||
|
||||
if (ct == 2)
|
||||
interpret ();
|
||||
|
||||
}/* call */
|
||||
|
||||
/*
|
||||
* ret
|
||||
*
|
||||
* Return from the current subroutine and restore the previous stack
|
||||
* frame. The result may be stored (0), thrown away (1) or pushed on
|
||||
* the stack (2). In the latter case a direct call has been finished
|
||||
* and we must exit the interpreter loop.
|
||||
*
|
||||
*/
|
||||
|
||||
void ret (zword value)
|
||||
{
|
||||
long pc;
|
||||
int ct;
|
||||
|
||||
if (sp > fp)
|
||||
runtime_error (ERR_STK_UNDF);
|
||||
|
||||
sp = fp;
|
||||
|
||||
ct = *sp++ >> (f_setup.save_quetzal ? 12 : 8);
|
||||
frame_count--;
|
||||
fp = stack + 1 + *sp++;
|
||||
pc = *sp++;
|
||||
pc = ((long) *sp++ << 9) | pc;
|
||||
|
||||
SET_PC (pc)
|
||||
|
||||
/* Handle resulting value */
|
||||
|
||||
if (ct == 0)
|
||||
store (value);
|
||||
if (ct == 2)
|
||||
*--sp = value;
|
||||
|
||||
/* Stop main loop for direct calls */
|
||||
|
||||
if (ct == 2)
|
||||
finished++;
|
||||
|
||||
}/* ret */
|
||||
|
||||
/*
|
||||
* branch
|
||||
*
|
||||
* Take a jump after an instruction based on the flag, either true or
|
||||
* false. The branch can be short or long; it is encoded in one or two
|
||||
* bytes respectively. When bit 7 of the first byte is set, the jump
|
||||
* takes place if the flag is true; otherwise it is taken if the flag
|
||||
* is false. When bit 6 of the first byte is set, the branch is short;
|
||||
* otherwise it is long. The offset occupies the bottom 6 bits of the
|
||||
* first byte plus all the bits in the second byte for long branches.
|
||||
* Uniquely, an offset of 0 means return false, and an offset of 1 is
|
||||
* return true.
|
||||
*
|
||||
*/
|
||||
|
||||
void branch (bool flag)
|
||||
{
|
||||
long pc;
|
||||
zword offset;
|
||||
zbyte specifier;
|
||||
zbyte off1;
|
||||
zbyte off2;
|
||||
|
||||
CODE_BYTE (specifier)
|
||||
|
||||
off1 = specifier & 0x3f;
|
||||
|
||||
if (!flag)
|
||||
specifier ^= 0x80;
|
||||
|
||||
if (!(specifier & 0x40)) { /* it's a long branch */
|
||||
|
||||
if (off1 & 0x20) /* propagate sign bit */
|
||||
off1 |= 0xc0;
|
||||
|
||||
CODE_BYTE (off2)
|
||||
|
||||
offset = (off1 << 8) | off2;
|
||||
|
||||
} else offset = off1; /* it's a short branch */
|
||||
|
||||
if (specifier & 0x80) {
|
||||
|
||||
if (offset > 1) { /* normal branch */
|
||||
|
||||
GET_PC (pc)
|
||||
pc += (short) offset - 2;
|
||||
SET_PC (pc)
|
||||
|
||||
} else ret (offset); /* special case, return 0 or 1 */
|
||||
}
|
||||
|
||||
}/* branch */
|
||||
|
||||
/*
|
||||
* store
|
||||
*
|
||||
* Store an operand, either as a variable or pushed on the stack.
|
||||
*
|
||||
*/
|
||||
|
||||
void store (zword value)
|
||||
{
|
||||
zbyte variable;
|
||||
|
||||
CODE_BYTE (variable)
|
||||
|
||||
if (variable == 0)
|
||||
*--sp = value;
|
||||
else if (variable < 16)
|
||||
*(fp - variable) = value;
|
||||
else {
|
||||
zword addr = h_globals + 2 * (variable - 16);
|
||||
SET_WORD (addr, value)
|
||||
}
|
||||
|
||||
}/* store */
|
||||
|
||||
/*
|
||||
* direct_call
|
||||
*
|
||||
* Call the interpreter loop directly. This is necessary when
|
||||
*
|
||||
* - a sound effect has been finished
|
||||
* - a read instruction has timed out
|
||||
* - a newline countdown has hit zero
|
||||
*
|
||||
* The interpreter returns the result value on the stack.
|
||||
*
|
||||
*/
|
||||
|
||||
int direct_call (zword addr)
|
||||
{
|
||||
zword saved_zargs[8];
|
||||
int saved_zargc;
|
||||
int i;
|
||||
|
||||
/* Calls to address 0 return false */
|
||||
|
||||
if (addr == 0)
|
||||
return 0;
|
||||
|
||||
/* Save operands and operand count */
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
saved_zargs[i] = zargs[i];
|
||||
|
||||
saved_zargc = zargc;
|
||||
|
||||
/* Call routine directly */
|
||||
|
||||
call (addr, 0, 0, 2);
|
||||
|
||||
/* Restore operands and operand count */
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
zargs[i] = saved_zargs[i];
|
||||
|
||||
zargc = saved_zargc;
|
||||
|
||||
/* Resulting value lies on top of the stack */
|
||||
|
||||
return (short) *sp++;
|
||||
|
||||
}/* direct_call */
|
||||
|
||||
/*
|
||||
* __extended__
|
||||
*
|
||||
* Load and execute an extended opcode.
|
||||
*
|
||||
*/
|
||||
|
||||
static void __extended__ (void)
|
||||
{
|
||||
zbyte opcode;
|
||||
zbyte specifier;
|
||||
|
||||
CODE_BYTE (opcode)
|
||||
CODE_BYTE (specifier)
|
||||
|
||||
load_all_operands (specifier);
|
||||
|
||||
if (opcode < 0x1d) /* extended opcodes from 0x1d on */
|
||||
ext_opcodes[opcode] (); /* are reserved for future spec' */
|
||||
|
||||
}/* __extended__ */
|
||||
|
||||
/*
|
||||
* __illegal__
|
||||
*
|
||||
* Exit game because an unknown opcode has been hit.
|
||||
*
|
||||
*/
|
||||
|
||||
static void __illegal__ (void)
|
||||
{
|
||||
|
||||
runtime_error (ERR_ILL_OPCODE);
|
||||
|
||||
}/* __illegal__ */
|
||||
|
||||
/*
|
||||
* z_catch, store the current stack frame for later use with z_throw.
|
||||
*
|
||||
* no zargs used
|
||||
*
|
||||
*/
|
||||
|
||||
void z_catch (void)
|
||||
{
|
||||
|
||||
store (f_setup.save_quetzal ? frame_count : (zword) (fp - stack));
|
||||
|
||||
}/* z_catch */
|
||||
|
||||
/*
|
||||
* z_throw, go back to the given stack frame and return the given value.
|
||||
*
|
||||
* zargs[0] = value to return
|
||||
* zargs[1] = stack frame
|
||||
*
|
||||
*/
|
||||
|
||||
void z_throw (void)
|
||||
{
|
||||
|
||||
if (f_setup.save_quetzal) {
|
||||
if (zargs[1] > frame_count)
|
||||
runtime_error (ERR_BAD_FRAME);
|
||||
|
||||
/* Unwind the stack a frame at a time. */
|
||||
for (; frame_count > zargs[1]; --frame_count)
|
||||
fp = stack + 1 + fp[1];
|
||||
} else {
|
||||
if (zargs[1] > STACK_SIZE)
|
||||
runtime_error (ERR_BAD_FRAME);
|
||||
|
||||
fp = stack + zargs[1];
|
||||
}
|
||||
|
||||
ret (zargs[0]);
|
||||
|
||||
}/* z_throw */
|
||||
|
||||
/*
|
||||
* z_call_n, call a subroutine and discard its result.
|
||||
*
|
||||
* zargs[0] = packed address of subroutine
|
||||
* zargs[1] = first argument (optional)
|
||||
* ...
|
||||
* zargs[7] = seventh argument (optional)
|
||||
*
|
||||
*/
|
||||
|
||||
void z_call_n (void)
|
||||
{
|
||||
|
||||
if (zargs[0] != 0)
|
||||
call (zargs[0], zargc - 1, zargs + 1, 1);
|
||||
|
||||
}/* z_call_n */
|
||||
|
||||
/*
|
||||
* z_call_s, call a subroutine and store its result.
|
||||
*
|
||||
* zargs[0] = packed address of subroutine
|
||||
* zargs[1] = first argument (optional)
|
||||
* ...
|
||||
* zargs[7] = seventh argument (optional)
|
||||
*
|
||||
*/
|
||||
|
||||
void z_call_s (void)
|
||||
{
|
||||
|
||||
if (zargs[0] != 0)
|
||||
call (zargs[0], zargc - 1, zargs + 1, 0);
|
||||
else
|
||||
store (0);
|
||||
|
||||
}/* z_call_s */
|
||||
|
||||
/*
|
||||
* z_check_arg_count, branch if subroutine was called with >= n arg's.
|
||||
*
|
||||
* zargs[0] = number of arguments
|
||||
*
|
||||
*/
|
||||
|
||||
void z_check_arg_count (void)
|
||||
{
|
||||
|
||||
if (fp == stack + STACK_SIZE)
|
||||
branch (zargs[0] == 0);
|
||||
else
|
||||
branch (zargs[0] <= (*fp & 0xff));
|
||||
|
||||
}/* z_check_arg_count */
|
||||
|
||||
/*
|
||||
* z_jump, jump unconditionally to the given address.
|
||||
*
|
||||
* zargs[0] = PC relative address
|
||||
*
|
||||
*/
|
||||
|
||||
void z_jump (void)
|
||||
{
|
||||
long pc;
|
||||
|
||||
GET_PC (pc)
|
||||
|
||||
pc += (short) zargs[0] - 2;
|
||||
|
||||
if (pc >= story_size)
|
||||
runtime_error (ERR_ILL_JUMP_ADDR);
|
||||
|
||||
SET_PC (pc)
|
||||
|
||||
}/* z_jump */
|
||||
|
||||
/*
|
||||
* z_nop, no operation.
|
||||
*
|
||||
* no zargs used
|
||||
*
|
||||
*/
|
||||
|
||||
void z_nop (void)
|
||||
{
|
||||
|
||||
/* Do nothing */
|
||||
|
||||
}/* z_nop */
|
||||
|
||||
/*
|
||||
* z_quit, stop game and exit interpreter.
|
||||
*
|
||||
* no zargs used
|
||||
*
|
||||
*/
|
||||
|
||||
void z_quit (void)
|
||||
{
|
||||
|
||||
finished = 9999;
|
||||
|
||||
}/* z_quit */
|
||||
|
||||
/*
|
||||
* z_ret, return from a subroutine with the given value.
|
||||
*
|
||||
* zargs[0] = value to return
|
||||
*
|
||||
*/
|
||||
|
||||
void z_ret (void)
|
||||
{
|
||||
|
||||
ret (zargs[0]);
|
||||
|
||||
}/* z_ret */
|
||||
|
||||
/*
|
||||
* z_ret_popped, return from a subroutine with a value popped off the stack.
|
||||
*
|
||||
* no zargs used
|
||||
*
|
||||
*/
|
||||
|
||||
void z_ret_popped (void)
|
||||
{
|
||||
|
||||
ret (*sp++);
|
||||
|
||||
}/* z_ret_popped */
|
||||
|
||||
/*
|
||||
* z_rfalse, return from a subroutine with false (0).
|
||||
*
|
||||
* no zargs used
|
||||
*
|
||||
*/
|
||||
|
||||
void z_rfalse (void)
|
||||
{
|
||||
|
||||
ret (0);
|
||||
|
||||
}/* z_rfalse */
|
||||
|
||||
/*
|
||||
* z_rtrue, return from a subroutine with true (1).
|
||||
*
|
||||
* no zargs used
|
||||
*
|
||||
*/
|
||||
|
||||
void z_rtrue (void)
|
||||
{
|
||||
|
||||
ret (1);
|
||||
|
||||
}/* z_rtrue */
|
541
apps/plugins/frotz/quetzal.c
Normal file
541
apps/plugins/frotz/quetzal.c
Normal file
|
@ -0,0 +1,541 @@
|
|||
/* quetzal.c - Saving and restoring of Quetzal files.
|
||||
* Written by Martin Frost <mdf@doc.ic.ac.uk>
|
||||
*
|
||||
* Changes for Rockbox copyright 2009 Torne Wuff
|
||||
*
|
||||
* This file is part of Frotz.
|
||||
*
|
||||
* Frotz is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Frotz is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include "frotz.h"
|
||||
|
||||
#define far
|
||||
|
||||
#define get_c fgetc
|
||||
#define put_c fputc
|
||||
|
||||
typedef unsigned long zlong;
|
||||
|
||||
/*
|
||||
* This is used only by save_quetzal. It probably should be allocated
|
||||
* dynamically rather than statically.
|
||||
*/
|
||||
|
||||
static zword frames[STACK_SIZE/4+1];
|
||||
|
||||
/*
|
||||
* ID types.
|
||||
*/
|
||||
|
||||
#define makeid(a,b,c,d) ((zlong) (((a)<<24) | ((b)<<16) | ((c)<<8) | (d)))
|
||||
|
||||
#define ID_FORM makeid ('F','O','R','M')
|
||||
#define ID_IFZS makeid ('I','F','Z','S')
|
||||
#define ID_IFhd makeid ('I','F','h','d')
|
||||
#define ID_UMem makeid ('U','M','e','m')
|
||||
#define ID_CMem makeid ('C','M','e','m')
|
||||
#define ID_Stks makeid ('S','t','k','s')
|
||||
#define ID_ANNO makeid ('A','N','N','O')
|
||||
|
||||
/*
|
||||
* Various parsing states within restoration.
|
||||
*/
|
||||
|
||||
#define GOT_HEADER 0x01
|
||||
#define GOT_STACK 0x02
|
||||
#define GOT_MEMORY 0x04
|
||||
#define GOT_NONE 0x00
|
||||
#define GOT_ALL 0x07
|
||||
#define GOT_ERROR 0x80
|
||||
|
||||
/*
|
||||
* Macros used to write the files.
|
||||
*/
|
||||
|
||||
#define write_byte(fp,b) (put_c (b, fp) != EOF)
|
||||
#define write_bytx(fp,b) write_byte (fp, (b) & 0xFF)
|
||||
#define write_word(fp,w) \
|
||||
(write_bytx (fp, (w) >> 8) && write_bytx (fp, (w)))
|
||||
#define write_long(fp,l) \
|
||||
(write_bytx (fp, (l) >> 24) && write_bytx (fp, (l) >> 16) && \
|
||||
write_bytx (fp, (l) >> 8) && write_bytx (fp, (l)))
|
||||
#define write_chnk(fp,id,len) \
|
||||
(write_long (fp, (id)) && write_long (fp, (len)))
|
||||
#define write_run(fp,run) \
|
||||
(write_byte (fp, 0) && write_byte (fp, (run)))
|
||||
|
||||
/* Read one word from file; return TRUE if OK. */
|
||||
static bool read_word (int f, zword *result)
|
||||
{
|
||||
int a, b;
|
||||
|
||||
if ((a = get_c (f)) == EOF) return FALSE;
|
||||
if ((b = get_c (f)) == EOF) return FALSE;
|
||||
|
||||
*result = ((zword) a << 8) | (zword) b;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Read one long from file; return TRUE if OK. */
|
||||
static bool read_long (int f, zlong *result)
|
||||
{
|
||||
int a, b, c, d;
|
||||
|
||||
if ((a = get_c (f)) == EOF) return FALSE;
|
||||
if ((b = get_c (f)) == EOF) return FALSE;
|
||||
if ((c = get_c (f)) == EOF) return FALSE;
|
||||
if ((d = get_c (f)) == EOF) return FALSE;
|
||||
|
||||
*result = ((zlong) a << 24) | ((zlong) b << 16) |
|
||||
((zlong) c << 8) | (zlong) d;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore a saved game using Quetzal format. Return 2 if OK, 0 if an error
|
||||
* occurred before any damage was done, -1 on a fatal error.
|
||||
*/
|
||||
|
||||
zword restore_quetzal (int svf, int stf)
|
||||
{
|
||||
zlong ifzslen, currlen, tmpl;
|
||||
zlong pc;
|
||||
zword i, tmpw;
|
||||
zword fatal = 0; /* Set to -1 when errors must be fatal. */
|
||||
zbyte skip, progress = GOT_NONE;
|
||||
int x, y;
|
||||
|
||||
/* Check it's really an `IFZS' file. */
|
||||
if (!read_long (svf, &tmpl)
|
||||
|| !read_long (svf, &ifzslen)
|
||||
|| !read_long (svf, &currlen)) return 0;
|
||||
if (tmpl != ID_FORM || currlen != ID_IFZS)
|
||||
{
|
||||
print_string ("This is not a saved game file!\n");
|
||||
return 0;
|
||||
}
|
||||
if ((ifzslen & 1) || ifzslen<4) /* Sanity checks. */ return 0;
|
||||
ifzslen -= 4;
|
||||
|
||||
/* Read each chunk and process it. */
|
||||
while (ifzslen > 0)
|
||||
{
|
||||
/* Read chunk header. */
|
||||
if (ifzslen < 8) /* Couldn't contain a chunk. */ return 0;
|
||||
if (!read_long (svf, &tmpl)
|
||||
|| !read_long (svf, &currlen)) return 0;
|
||||
ifzslen -= 8; /* Reduce remaining by size of header. */
|
||||
|
||||
/* Handle chunk body. */
|
||||
if (ifzslen < currlen) /* Chunk goes past EOF?! */ return 0;
|
||||
skip = currlen & 1;
|
||||
ifzslen -= currlen + (zlong) skip;
|
||||
|
||||
switch (tmpl)
|
||||
{
|
||||
/* `IFhd' header chunk; must be first in file. */
|
||||
case ID_IFhd:
|
||||
if (progress & GOT_HEADER)
|
||||
{
|
||||
print_string ("Save file has two IFZS chunks!\n");
|
||||
return fatal;
|
||||
}
|
||||
progress |= GOT_HEADER;
|
||||
if (currlen < 13
|
||||
|| !read_word (svf, &tmpw)) return fatal;
|
||||
if (tmpw != h_release)
|
||||
progress = GOT_ERROR;
|
||||
|
||||
for (i=H_SERIAL; i<H_SERIAL+6; ++i)
|
||||
{
|
||||
if ((x = get_c (svf)) == EOF) return fatal;
|
||||
if (x != zmp[i])
|
||||
progress = GOT_ERROR;
|
||||
}
|
||||
|
||||
if (!read_word (svf, &tmpw)) return fatal;
|
||||
if (tmpw != h_checksum)
|
||||
progress = GOT_ERROR;
|
||||
|
||||
if (progress & GOT_ERROR)
|
||||
{
|
||||
print_string ("File was not saved from this story!\n");
|
||||
return fatal;
|
||||
}
|
||||
if ((x = get_c (svf)) == EOF) return fatal;
|
||||
pc = (zlong) x << 16;
|
||||
if ((x = get_c (svf)) == EOF) return fatal;
|
||||
pc |= (zlong) x << 8;
|
||||
if ((x = get_c (svf)) == EOF) return fatal;
|
||||
pc |= (zlong) x;
|
||||
fatal = -1; /* Setting PC means errors must be fatal. */
|
||||
SET_PC (pc);
|
||||
|
||||
for (i=13; i<currlen; ++i)
|
||||
(void) get_c (svf); /* Skip rest of chunk. */
|
||||
break;
|
||||
/* `Stks' stacks chunk; restoring this is quite complex. ;) */
|
||||
case ID_Stks:
|
||||
if (progress & GOT_STACK)
|
||||
{
|
||||
print_string ("File contains two stack chunks!\n");
|
||||
break;
|
||||
}
|
||||
progress |= GOT_STACK;
|
||||
|
||||
fatal = -1; /* Setting SP means errors must be fatal. */
|
||||
sp = stack + STACK_SIZE;
|
||||
|
||||
/*
|
||||
* All versions other than V6 may use evaluation stack outside
|
||||
* any function context. As a result a faked function context
|
||||
* will be present in the file here. We skip this context, but
|
||||
* load the associated stack onto the stack proper...
|
||||
*/
|
||||
if (h_version != V6)
|
||||
{
|
||||
if (currlen < 8) return fatal;
|
||||
for (i=0; i<6; ++i)
|
||||
if (get_c (svf) != 0) return fatal;
|
||||
if (!read_word (svf, &tmpw)) return fatal;
|
||||
if (tmpw > STACK_SIZE)
|
||||
{
|
||||
print_string ("Save-file has too much stack (and I can't cope).\n");
|
||||
return fatal;
|
||||
}
|
||||
currlen -= 8;
|
||||
if ((signed)currlen < tmpw*2) return fatal;
|
||||
for (i=0; i<tmpw; ++i)
|
||||
if (!read_word (svf, --sp)) return fatal;
|
||||
currlen -= tmpw*2;
|
||||
}
|
||||
|
||||
/* We now proceed to load the main block of stack frames. */
|
||||
for (fp = stack+STACK_SIZE, frame_count = 0;
|
||||
currlen > 0;
|
||||
currlen -= 8, ++frame_count)
|
||||
{
|
||||
if (currlen < 8) return fatal;
|
||||
if (sp - stack < 4) /* No space for frame. */
|
||||
{
|
||||
print_string ("Save-file has too much stack (and I can't cope).\n");
|
||||
return fatal;
|
||||
}
|
||||
|
||||
/* Read PC, procedure flag and formal param count. */
|
||||
if (!read_long (svf, &tmpl)) return fatal;
|
||||
y = (int) (tmpl & 0x0F); /* Number of formals. */
|
||||
tmpw = y << 8;
|
||||
|
||||
/* Read result variable. */
|
||||
if ((x = get_c (svf)) == EOF) return fatal;
|
||||
|
||||
/* Check the procedure flag... */
|
||||
if (tmpl & 0x10)
|
||||
{
|
||||
tmpw |= 0x1000; /* It's a procedure. */
|
||||
tmpl >>= 8; /* Shift to get PC value. */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Functions have type 0, so no need to or anything. */
|
||||
tmpl >>= 8; /* Shift to get PC value. */
|
||||
--tmpl; /* Point at result byte. */
|
||||
/* Sanity check on result variable... */
|
||||
if (zmp[tmpl] != (zbyte) x)
|
||||
{
|
||||
print_string ("Save-file has wrong variable number on stack (possibly wrong game version?)\n");
|
||||
return fatal;
|
||||
}
|
||||
}
|
||||
*--sp = (zword) (tmpl >> 9); /* High part of PC */
|
||||
*--sp = (zword) (tmpl & 0x1FF); /* Low part of PC */
|
||||
*--sp = (zword) (fp - stack - 1); /* FP */
|
||||
|
||||
/* Read and process argument mask. */
|
||||
if ((x = get_c (svf)) == EOF) return fatal;
|
||||
++x; /* Should now be a power of 2 */
|
||||
for (i=0; i<8; ++i)
|
||||
if (x & (1<<i))
|
||||
break;
|
||||
if (x ^ (1<<i)) /* Not a power of 2 */
|
||||
{
|
||||
print_string ("Save-file uses incomplete argument lists (which I can't handle)\n");
|
||||
return fatal;
|
||||
}
|
||||
*--sp = tmpw | i;
|
||||
fp = sp; /* FP for next frame. */
|
||||
|
||||
/* Read amount of eval stack used. */
|
||||
if (!read_word (svf, &tmpw)) return fatal;
|
||||
|
||||
tmpw += y; /* Amount of stack + number of locals. */
|
||||
if (sp - stack <= tmpw)
|
||||
{
|
||||
print_string ("Save-file has too much stack (and I can't cope).\n");
|
||||
return fatal;
|
||||
}
|
||||
if ((signed)currlen < tmpw*2) return fatal;
|
||||
for (i=0; i<tmpw; ++i)
|
||||
if (!read_word (svf, --sp)) return fatal;
|
||||
currlen -= tmpw*2;
|
||||
}
|
||||
/* End of `Stks' processing... */
|
||||
break;
|
||||
/* Any more special chunk types must go in HERE or ABOVE. */
|
||||
/* `CMem' compressed memory chunk; uncompress it. */
|
||||
case ID_CMem:
|
||||
if (!(progress & GOT_MEMORY)) /* Don't complain if two. */
|
||||
{
|
||||
(void) fseek (stf, 0, SEEK_SET);
|
||||
i=0; /* Bytes written to data area. */
|
||||
for (; currlen > 0; --currlen)
|
||||
{
|
||||
if ((x = get_c (svf)) == EOF) return fatal;
|
||||
if (x == 0) /* Start run. */
|
||||
{
|
||||
/* Check for bogus run. */
|
||||
if (currlen < 2)
|
||||
{
|
||||
print_string ("File contains bogus `CMem' chunk.\n");
|
||||
for (; currlen > 0; --currlen)
|
||||
(void) get_c (svf); /* Skip rest. */
|
||||
currlen = 1;
|
||||
i = 0xFFFF;
|
||||
break; /* Keep going; may be a `UMem' too. */
|
||||
}
|
||||
/* Copy story file to memory during the run. */
|
||||
--currlen;
|
||||
if ((x = get_c (svf)) == EOF) return fatal;
|
||||
for (; x >= 0 && i<h_dynamic_size; --x, ++i)
|
||||
if ((y = get_c (stf)) == EOF) return fatal;
|
||||
else
|
||||
zmp[i] = (zbyte) y;
|
||||
}
|
||||
else /* Not a run. */
|
||||
{
|
||||
if ((y = get_c (stf)) == EOF) return fatal;
|
||||
zmp[i] = (zbyte) (x ^ y);
|
||||
++i;
|
||||
}
|
||||
/* Make sure we don't load too much. */
|
||||
if (i > h_dynamic_size)
|
||||
{
|
||||
print_string ("warning: `CMem' chunk too long!\n");
|
||||
for (; currlen > 1; --currlen)
|
||||
(void) get_c (svf); /* Skip rest. */
|
||||
break; /* Keep going; there may be a `UMem' too. */
|
||||
}
|
||||
}
|
||||
/* If chunk is short, assume a run. */
|
||||
for (; i<h_dynamic_size; ++i)
|
||||
if ((y = get_c (stf)) == EOF) return fatal;
|
||||
else
|
||||
zmp[i] = (zbyte) y;
|
||||
if (currlen == 0)
|
||||
progress |= GOT_MEMORY; /* Only if succeeded. */
|
||||
break;
|
||||
}
|
||||
/* Fall right thru (to default) if already GOT_MEMORY */
|
||||
/* `UMem' uncompressed memory chunk; load it. */
|
||||
case ID_UMem:
|
||||
if (!(progress & GOT_MEMORY)) /* Don't complain if two. */
|
||||
{
|
||||
/* Must be exactly the right size. */
|
||||
if (currlen == h_dynamic_size)
|
||||
{
|
||||
if (fread (zmp, currlen, 1, svf) == 1)
|
||||
{
|
||||
progress |= GOT_MEMORY; /* Only on success. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
print_string ("`UMem' chunk wrong size!\n");
|
||||
/* Fall into default action (skip chunk) on errors. */
|
||||
}
|
||||
/* Fall thru (to default) if already GOT_MEMORY */
|
||||
/* Unrecognised chunk type; skip it. */
|
||||
default:
|
||||
(void) fseek (svf, currlen, SEEK_CUR); /* Skip chunk. */
|
||||
break;
|
||||
}
|
||||
if (skip)
|
||||
(void) get_c (svf); /* Skip pad byte. */
|
||||
}
|
||||
|
||||
/*
|
||||
* We've reached the end of the file. For the restoration to have been a
|
||||
* success, we must have had one of each of the required chunks.
|
||||
*/
|
||||
if (!(progress & GOT_HEADER))
|
||||
print_string ("error: no valid header (`IFhd') chunk in file.\n");
|
||||
if (!(progress & GOT_STACK))
|
||||
print_string ("error: no valid stack (`Stks') chunk in file.\n");
|
||||
if (!(progress & GOT_MEMORY))
|
||||
print_string ("error: no valid memory (`CMem' or `UMem') chunk in file.\n");
|
||||
|
||||
return (progress == GOT_ALL ? 2 : fatal);
|
||||
}
|
||||
|
||||
/*
|
||||
* Save a game using Quetzal format. Return 1 if OK, 0 if failed.
|
||||
*/
|
||||
|
||||
zword save_quetzal (int svf, int stf)
|
||||
{
|
||||
zlong ifzslen = 0, cmemlen = 0, stkslen = 0;
|
||||
zlong pc;
|
||||
zword i, j, n;
|
||||
zword nvars, nargs, nstk, *p;
|
||||
zbyte var;
|
||||
long cmempos, stkspos;
|
||||
int c;
|
||||
|
||||
/* Write `IFZS' header. */
|
||||
if (!write_chnk (svf, ID_FORM, 0)) return 0;
|
||||
if (!write_long (svf, ID_IFZS)) return 0;
|
||||
|
||||
/* Write `IFhd' chunk. */
|
||||
GET_PC (pc);
|
||||
if (!write_chnk (svf, ID_IFhd, 13)) return 0;
|
||||
if (!write_word (svf, h_release)) return 0;
|
||||
for (i=H_SERIAL; i<H_SERIAL+6; ++i)
|
||||
if (!write_byte (svf, zmp[i])) return 0;
|
||||
if (!write_word (svf, h_checksum)) return 0;
|
||||
if (!write_long (svf, pc << 8)) /* Includes pad. */ return 0;
|
||||
|
||||
/* Write `CMem' chunk. */
|
||||
if ((cmempos = ftell (svf)) < 0) return 0;
|
||||
if (!write_chnk (svf, ID_CMem, 0)) return 0;
|
||||
(void) fseek (stf, 0, SEEK_SET);
|
||||
/* j holds current run length. */
|
||||
for (i=0, j=0, cmemlen=0; i < h_dynamic_size; ++i)
|
||||
{
|
||||
if ((c = get_c (stf)) == EOF) return 0;
|
||||
c ^= (int) zmp[i];
|
||||
if (c == 0)
|
||||
++j; /* It's a run of equal bytes. */
|
||||
else
|
||||
{
|
||||
/* Write out any run there may be. */
|
||||
if (j > 0)
|
||||
{
|
||||
for (; j > 0x100; j -= 0x100)
|
||||
{
|
||||
if (!write_run (svf, 0xFF)) return 0;
|
||||
cmemlen += 2;
|
||||
}
|
||||
if (!write_run (svf, j-1)) return 0;
|
||||
cmemlen += 2;
|
||||
j = 0;
|
||||
}
|
||||
/* Any runs are now written. Write this (nonzero) byte. */
|
||||
if (!write_byte (svf, (zbyte) c)) return 0;
|
||||
++cmemlen;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Reached end of dynamic memory. We ignore any unwritten run there may be
|
||||
* at this point.
|
||||
*/
|
||||
if (cmemlen & 1) /* Chunk length must be even. */
|
||||
if (!write_byte (svf, 0)) return 0;
|
||||
|
||||
/* Write `Stks' chunk. You are not expected to understand this. ;) */
|
||||
if ((stkspos = ftell (svf)) < 0) return 0;
|
||||
if (!write_chnk (svf, ID_Stks, 0)) return 0;
|
||||
|
||||
/*
|
||||
* We construct a list of frame indices, most recent first, in `frames'.
|
||||
* These indices are the offsets into the `stack' array of the word before
|
||||
* the first word pushed in each frame.
|
||||
*/
|
||||
frames[0] = sp - stack; /* The frame we'd get by doing a call now. */
|
||||
for (i = fp - stack + 4, n=0; i < STACK_SIZE+4; i = stack[i-3] + 5)
|
||||
frames[++n] = i;
|
||||
|
||||
/*
|
||||
* All versions other than V6 can use evaluation stack outside a function
|
||||
* context. We write a faked stack frame (most fields zero) to cater for
|
||||
* this.
|
||||
*/
|
||||
if (h_version != V6)
|
||||
{
|
||||
for (i=0; i<6; ++i)
|
||||
if (!write_byte (svf, 0)) return 0;
|
||||
nstk = STACK_SIZE - frames[n];
|
||||
if (!write_word (svf, nstk)) return 0;
|
||||
for (j=STACK_SIZE-1; j >= frames[n]; --j)
|
||||
if (!write_word (svf, stack[j])) return 0;
|
||||
stkslen = 8 + 2*nstk;
|
||||
}
|
||||
|
||||
/* Write out the rest of the stack frames. */
|
||||
for (i=n; i>0; --i)
|
||||
{
|
||||
p = stack + frames[i] - 4; /* Points to call frame. */
|
||||
nvars = (p[0] & 0x0F00) >> 8;
|
||||
nargs = p[0] & 0x00FF;
|
||||
nstk = frames[i] - frames[i-1] - nvars - 4;
|
||||
pc = ((zlong) p[3] << 9) | p[2];
|
||||
|
||||
switch (p[0] & 0xF000) /* Check type of call. */
|
||||
{
|
||||
case 0x0000: /* Function. */
|
||||
var = zmp[pc];
|
||||
pc = ((pc + 1) << 8) | nvars;
|
||||
break;
|
||||
case 0x1000: /* Procedure. */
|
||||
var = 0;
|
||||
pc = (pc << 8) | 0x10 | nvars; /* Set procedure flag. */
|
||||
break;
|
||||
/* case 0x2000: */
|
||||
default:
|
||||
runtime_error (ERR_SAVE_IN_INTER);
|
||||
return 0;
|
||||
}
|
||||
if (nargs != 0)
|
||||
nargs = (1 << nargs) - 1; /* Make args into bitmap. */
|
||||
|
||||
/* Write the main part of the frame... */
|
||||
if (!write_long (svf, pc)
|
||||
|| !write_byte (svf, var)
|
||||
|| !write_byte (svf, nargs)
|
||||
|| !write_word (svf, nstk)) return 0;
|
||||
|
||||
/* Write the variables and eval stack. */
|
||||
for (j=0, ++p; j<nvars+nstk; ++j, --p)
|
||||
if (!write_word (svf, *p)) return 0;
|
||||
|
||||
/* Calculate length written thus far. */
|
||||
stkslen += 8 + 2 * (nvars + nstk);
|
||||
}
|
||||
|
||||
/* Fill in variable chunk lengths. */
|
||||
ifzslen = 3*8 + 4 + 14 + cmemlen + stkslen;
|
||||
if (cmemlen & 1)
|
||||
++ifzslen;
|
||||
(void) fseek (svf, 4, SEEK_SET);
|
||||
if (!write_long (svf, ifzslen)) return 0;
|
||||
(void) fseek (svf, cmempos+4, SEEK_SET);
|
||||
if (!write_long (svf, cmemlen)) return 0;
|
||||
(void) fseek (svf, stkspos+4, SEEK_SET);
|
||||
if (!write_long (svf, stkslen)) return 0;
|
||||
|
||||
/* After all that, still nothing went wrong! */
|
||||
return 1;
|
||||
}
|
82
apps/plugins/frotz/random.c
Normal file
82
apps/plugins/frotz/random.c
Normal file
|
@ -0,0 +1,82 @@
|
|||
/* random.c - Z-machine random number generator
|
||||
* Copyright (c) 1995-1997 Stefan Jokisch
|
||||
*
|
||||
* This file is part of Frotz.
|
||||
*
|
||||
* Frotz is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Frotz is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include "frotz.h"
|
||||
|
||||
static long A = 1;
|
||||
|
||||
static int interval = 0;
|
||||
static int counter = 0;
|
||||
|
||||
/*
|
||||
* seed_random
|
||||
*
|
||||
* Set the seed value for the random number generator.
|
||||
*
|
||||
*/
|
||||
|
||||
void seed_random (int value)
|
||||
{
|
||||
|
||||
if (value == 0) { /* ask interface for seed value */
|
||||
A = os_random_seed ();
|
||||
interval = 0;
|
||||
} else if (value < 1000) { /* special seed value */
|
||||
counter = 0;
|
||||
interval = value;
|
||||
} else { /* standard seed value */
|
||||
A = value;
|
||||
interval = 0;
|
||||
}
|
||||
|
||||
}/* seed_random */
|
||||
|
||||
/*
|
||||
* z_random, store a random number or set the random number seed.
|
||||
*
|
||||
* zargs[0] = range (positive) or seed value (negative)
|
||||
*
|
||||
*/
|
||||
|
||||
void z_random ()
|
||||
{
|
||||
|
||||
if ((short) zargs[0] <= 0) { /* set random seed */
|
||||
|
||||
seed_random (- (short) zargs[0]);
|
||||
store (0);
|
||||
|
||||
} else { /* generate random number */
|
||||
|
||||
zword result;
|
||||
|
||||
if (interval != 0) { /* ...in special mode */
|
||||
result = counter++;
|
||||
if (counter == interval) counter = 0;
|
||||
} else { /* ...in standard mode */
|
||||
A = 0x015a4e35L * A + 1;
|
||||
result = (A >> 16) & 0x7fff;
|
||||
}
|
||||
|
||||
store ((zword) (result % zargs[0] + 1));
|
||||
|
||||
}
|
||||
|
||||
}/* z_random */
|
172
apps/plugins/frotz/redirect.c
Normal file
172
apps/plugins/frotz/redirect.c
Normal file
|
@ -0,0 +1,172 @@
|
|||
/* redirect.c - Output redirection to Z-machine memory
|
||||
* Copyright (c) 1995-1997 Stefan Jokisch
|
||||
*
|
||||
* This file is part of Frotz.
|
||||
*
|
||||
* Frotz is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Frotz is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include "frotz.h"
|
||||
|
||||
#define MAX_NESTING 16
|
||||
|
||||
extern zword get_max_width (zword);
|
||||
|
||||
static int depth = -1;
|
||||
|
||||
static struct {
|
||||
zword xsize;
|
||||
zword table;
|
||||
zword width;
|
||||
zword total;
|
||||
} redirect[MAX_NESTING];
|
||||
|
||||
/*
|
||||
* memory_open
|
||||
*
|
||||
* Begin output redirection to the memory of the Z-machine.
|
||||
*
|
||||
*/
|
||||
|
||||
void memory_open (zword table, zword xsize, bool buffering)
|
||||
{
|
||||
|
||||
if (++depth < MAX_NESTING) {
|
||||
|
||||
if (!buffering)
|
||||
xsize = 0xffff;
|
||||
if (buffering && (short) xsize <= 0)
|
||||
xsize = get_max_width ((zword) (- (short) xsize));
|
||||
|
||||
storew (table, 0);
|
||||
|
||||
redirect[depth].table = table;
|
||||
redirect[depth].width = 0;
|
||||
redirect[depth].total = 0;
|
||||
redirect[depth].xsize = xsize;
|
||||
|
||||
ostream_memory = TRUE;
|
||||
|
||||
} else runtime_error (ERR_STR3_NESTING);
|
||||
|
||||
}/* memory_open */
|
||||
|
||||
/*
|
||||
* memory_new_line
|
||||
*
|
||||
* Redirect a newline to the memory of the Z-machine.
|
||||
*
|
||||
*/
|
||||
|
||||
void memory_new_line (void)
|
||||
{
|
||||
zword size;
|
||||
zword addr;
|
||||
|
||||
redirect[depth].total += redirect[depth].width;
|
||||
redirect[depth].width = 0;
|
||||
|
||||
addr = redirect[depth].table;
|
||||
|
||||
LOW_WORD (addr, size)
|
||||
addr += 2;
|
||||
|
||||
if (redirect[depth].xsize != 0xffff) {
|
||||
|
||||
redirect[depth].table = addr + size;
|
||||
size = 0;
|
||||
|
||||
} else storeb ((zword) (addr + (size++)), 13);
|
||||
|
||||
storew (redirect[depth].table, size);
|
||||
|
||||
}/* memory_new_line */
|
||||
|
||||
/*
|
||||
* memory_word
|
||||
*
|
||||
* Redirect a string of characters to the memory of the Z-machine.
|
||||
*
|
||||
*/
|
||||
|
||||
void memory_word (const zchar *s)
|
||||
{
|
||||
zword size;
|
||||
zword addr;
|
||||
zchar c;
|
||||
|
||||
if (h_version == V6) {
|
||||
|
||||
int width = os_string_width (s);
|
||||
|
||||
if (redirect[depth].xsize != 0xffff)
|
||||
|
||||
if (redirect[depth].width + width > redirect[depth].xsize) {
|
||||
|
||||
if (*s == ' ' || *s == ZC_INDENT || *s == ZC_GAP)
|
||||
width = os_string_width (++s);
|
||||
|
||||
memory_new_line ();
|
||||
|
||||
}
|
||||
|
||||
redirect[depth].width += width;
|
||||
|
||||
}
|
||||
|
||||
addr = redirect[depth].table;
|
||||
|
||||
LOW_WORD (addr, size)
|
||||
addr += 2;
|
||||
|
||||
while ((c = *s++) != 0)
|
||||
storeb ((zword) (addr + (size++)), translate_to_zscii (c));
|
||||
|
||||
storew (redirect[depth].table, size);
|
||||
|
||||
}/* memory_word */
|
||||
|
||||
/*
|
||||
* memory_close
|
||||
*
|
||||
* End of output redirection.
|
||||
*
|
||||
*/
|
||||
|
||||
void memory_close (void)
|
||||
{
|
||||
|
||||
if (depth >= 0) {
|
||||
|
||||
if (redirect[depth].xsize != 0xffff)
|
||||
memory_new_line ();
|
||||
|
||||
if (h_version == V6) {
|
||||
|
||||
h_line_width = (redirect[depth].xsize != 0xffff) ?
|
||||
redirect[depth].total : redirect[depth].width;
|
||||
|
||||
SET_WORD (H_LINE_WIDTH, h_line_width)
|
||||
|
||||
}
|
||||
|
||||
if (depth == 0)
|
||||
ostream_memory = FALSE;
|
||||
|
||||
depth--;
|
||||
|
||||
}
|
||||
|
||||
}/* memory_close */
|
1743
apps/plugins/frotz/screen.c
Normal file
1743
apps/plugins/frotz/screen.c
Normal file
File diff suppressed because it is too large
Load diff
67
apps/plugins/frotz/setup.h
Normal file
67
apps/plugins/frotz/setup.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Various status thingies for the interpreter and interface.
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct frotz_setup_struct {
|
||||
int attribute_assignment; /* done */
|
||||
int attribute_testing; /* done */
|
||||
int context_lines; /* done */
|
||||
int object_locating; /* done */
|
||||
int object_movement; /* done */
|
||||
int left_margin; /* done */
|
||||
int right_margin; /* done */
|
||||
int ignore_errors; /* done */
|
||||
int interpreter_number; /* Just dumb frotz now */
|
||||
int piracy; /* done */
|
||||
int undo_slots; /* done */
|
||||
int expand_abbreviations; /* done */
|
||||
int script_cols; /* done */
|
||||
int save_quetzal; /* done */
|
||||
int sound; /* done */
|
||||
int err_report_mode; /* done */
|
||||
} f_setup_t;
|
||||
|
||||
extern f_setup_t f_setup;
|
||||
|
||||
|
||||
typedef struct zcode_header_struct {
|
||||
zbyte h_version;
|
||||
zbyte h_config;
|
||||
zword h_release;
|
||||
zword h_resident_size;
|
||||
zword h_start_pc;
|
||||
zword h_dictionary;
|
||||
zword h_objects;
|
||||
zword h_globals;
|
||||
zword h_dynamic_size;
|
||||
zword h_flags;
|
||||
zbyte h_serial[6];
|
||||
zword h_abbreviations;
|
||||
zword h_file_size;
|
||||
zword h_checksum;
|
||||
zbyte h_interpreter_number;
|
||||
zbyte h_interpreter_version;
|
||||
zbyte h_screen_rows;
|
||||
zbyte h_screen_cols;
|
||||
zword h_screen_width;
|
||||
zword h_screen_height;
|
||||
zbyte h_font_height;
|
||||
zbyte h_font_width;
|
||||
zword h_functions_offset;
|
||||
zword h_strings_offset;
|
||||
zbyte h_default_background;
|
||||
zbyte h_default_foreground;
|
||||
zword h_terminating_keys;
|
||||
zword h_line_width;
|
||||
zbyte h_standard_high;
|
||||
zbyte h_standard_low;
|
||||
zword h_alphabet;
|
||||
zword h_extension_table;
|
||||
zbyte h_user_name[8];
|
||||
|
||||
zword hx_table_size;
|
||||
zword hx_mouse_x;
|
||||
zword hx_mouse_y;
|
||||
zword hx_unicode_table;
|
||||
} z_header_t;
|
204
apps/plugins/frotz/sound.c
Normal file
204
apps/plugins/frotz/sound.c
Normal file
|
@ -0,0 +1,204 @@
|
|||
/* sound.c - Sound effect function
|
||||
* Copyright (c) 1995-1997 Stefan Jokisch
|
||||
*
|
||||
* This file is part of Frotz.
|
||||
*
|
||||
* Frotz is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Frotz is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include "frotz.h"
|
||||
|
||||
#ifdef DJGPP
|
||||
#include "djfrotz.h"
|
||||
#endif
|
||||
|
||||
#define EFFECT_PREPARE 1
|
||||
#define EFFECT_PLAY 2
|
||||
#define EFFECT_STOP 3
|
||||
#define EFFECT_FINISH_WITH 4
|
||||
|
||||
extern int direct_call (zword);
|
||||
|
||||
static zword routine = 0;
|
||||
|
||||
static int next_sample = 0;
|
||||
static int next_volume = 0;
|
||||
|
||||
static bool locked = FALSE;
|
||||
static bool playing = FALSE;
|
||||
|
||||
/*
|
||||
* init_sound
|
||||
*
|
||||
* Initialize sound variables.
|
||||
*
|
||||
*/
|
||||
|
||||
void init_sound (void)
|
||||
{
|
||||
locked = FALSE;
|
||||
playing = FALSE;
|
||||
} /* init_sound */
|
||||
|
||||
|
||||
/*
|
||||
* start_sample
|
||||
*
|
||||
* Call the IO interface to play a sample.
|
||||
*
|
||||
*/
|
||||
|
||||
static void start_sample (int number, int volume, int repeats, zword eos)
|
||||
{
|
||||
|
||||
static zbyte lh_repeats[] = {
|
||||
0x00, 0x00, 0x00, 0x01, 0xff,
|
||||
0x00, 0x01, 0x01, 0x01, 0x01,
|
||||
0xff, 0x01, 0x01, 0xff, 0x00,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
|
||||
if (story_id == LURKING_HORROR)
|
||||
repeats = lh_repeats[number];
|
||||
|
||||
os_start_sample (number, volume, repeats, eos);
|
||||
|
||||
routine = eos;
|
||||
playing = TRUE;
|
||||
|
||||
}/* start_sample */
|
||||
|
||||
/*
|
||||
* start_next_sample
|
||||
*
|
||||
* Play a sample that has been delayed until the previous sound effect has
|
||||
* finished. This is necessary for two samples in The Lurking Horror that
|
||||
* immediately follow other samples.
|
||||
*
|
||||
*/
|
||||
|
||||
static void start_next_sample (void)
|
||||
{
|
||||
|
||||
if (next_sample != 0)
|
||||
start_sample (next_sample, next_volume, 0, 0);
|
||||
|
||||
next_sample = 0;
|
||||
next_volume = 0;
|
||||
|
||||
}/* start_next_sample */
|
||||
|
||||
/*
|
||||
* end_of_sound
|
||||
*
|
||||
* Call the Z-code routine which was given as the last parameter of
|
||||
* a sound_effect call. This function may be called from a hardware
|
||||
* interrupt (which requires extremely careful programming).
|
||||
*
|
||||
*/
|
||||
|
||||
void end_of_sound (void)
|
||||
{
|
||||
|
||||
#if defined(DJGPP) && defined(SOUND_SUPPORT)
|
||||
end_of_sound_flag = 0;
|
||||
#endif
|
||||
|
||||
playing = FALSE;
|
||||
|
||||
if (!locked) {
|
||||
|
||||
if (story_id == LURKING_HORROR)
|
||||
start_next_sample ();
|
||||
|
||||
direct_call (routine);
|
||||
|
||||
}
|
||||
|
||||
}/* end_of_sound */
|
||||
|
||||
/*
|
||||
* z_sound_effect, load / play / stop / discard a sound effect.
|
||||
*
|
||||
* zargs[0] = number of bleep (1 or 2) or sample
|
||||
* zargs[1] = operation to perform (samples only)
|
||||
* zargs[2] = repeats and volume (play sample only)
|
||||
* zargs[3] = end-of-sound routine (play sample only, optional)
|
||||
*
|
||||
* Note: Volumes range from 1 to 8, volume 255 is the default volume.
|
||||
* Repeats are stored in the high byte, 255 is infinite loop.
|
||||
*
|
||||
*/
|
||||
|
||||
void z_sound_effect (void)
|
||||
{
|
||||
zword number = zargs[0];
|
||||
zword effect = zargs[1];
|
||||
zword volume = zargs[2];
|
||||
|
||||
/* By default play sound 1 at volume 8 */
|
||||
if (zargc < 1)
|
||||
number = 1;
|
||||
if (zargc < 2)
|
||||
effect = EFFECT_PLAY;
|
||||
if (zargc < 3)
|
||||
volume = 8;
|
||||
|
||||
if (number >= 3 || number == 0) {
|
||||
|
||||
locked = TRUE;
|
||||
|
||||
if (story_id == LURKING_HORROR && (number == 9 || number == 16)) {
|
||||
|
||||
if (effect == EFFECT_PLAY) {
|
||||
|
||||
next_sample = number;
|
||||
next_volume = volume;
|
||||
|
||||
locked = FALSE;
|
||||
|
||||
if (!playing)
|
||||
start_next_sample ();
|
||||
|
||||
} else locked = FALSE;
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
playing = FALSE;
|
||||
|
||||
switch (effect) {
|
||||
|
||||
case EFFECT_PREPARE:
|
||||
os_prepare_sample (number);
|
||||
break;
|
||||
case EFFECT_PLAY:
|
||||
start_sample (number, lo (volume), hi (volume), (zargc == 4) ? zargs[3] : 0);
|
||||
break;
|
||||
case EFFECT_STOP:
|
||||
os_stop_sample (number);
|
||||
break;
|
||||
case EFFECT_FINISH_WITH:
|
||||
os_finish_with_sample (number);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
locked = FALSE;
|
||||
|
||||
} else os_beep (number);
|
||||
|
||||
}/* z_sound_effect */
|
365
apps/plugins/frotz/stream.c
Normal file
365
apps/plugins/frotz/stream.c
Normal file
|
@ -0,0 +1,365 @@
|
|||
/* stream.c - IO stream implementation
|
||||
* Copyright (c) 1995-1997 Stefan Jokisch
|
||||
*
|
||||
* This file is part of Frotz.
|
||||
*
|
||||
* Frotz is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Frotz is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include "frotz.h"
|
||||
|
||||
extern bool handle_hot_key (zchar);
|
||||
|
||||
extern bool validate_click (void);
|
||||
|
||||
extern void replay_open (void);
|
||||
extern void replay_close (void);
|
||||
extern void memory_open (zword, zword, bool);
|
||||
extern void memory_close (void);
|
||||
extern void record_open (void);
|
||||
extern void record_close (void);
|
||||
extern void script_open (void);
|
||||
extern void script_close (void);
|
||||
|
||||
extern void memory_word (const zchar *);
|
||||
extern void memory_new_line (void);
|
||||
extern void record_write_key (zchar);
|
||||
extern void record_write_input (const zchar *, zchar);
|
||||
extern void script_char (zchar);
|
||||
extern void script_word (const zchar *);
|
||||
extern void script_new_line (void);
|
||||
extern void script_write_input (const zchar *, zchar);
|
||||
extern void script_erase_input (const zchar *);
|
||||
extern void script_mssg_on (void);
|
||||
extern void script_mssg_off (void);
|
||||
extern void screen_char (zchar);
|
||||
extern void screen_word (const zchar *);
|
||||
extern void screen_new_line (void);
|
||||
extern void screen_write_input (const zchar *, zchar);
|
||||
extern void screen_erase_input (const zchar *);
|
||||
extern void screen_mssg_on (void);
|
||||
extern void screen_mssg_off (void);
|
||||
|
||||
extern zchar replay_read_key (void);
|
||||
extern zchar replay_read_input (zchar *);
|
||||
extern zchar console_read_key (zword);
|
||||
extern zchar console_read_input (int, zchar *, zword, bool);
|
||||
|
||||
extern int direct_call (zword);
|
||||
|
||||
/*
|
||||
* stream_mssg_on
|
||||
*
|
||||
* Start printing a "debugging" message.
|
||||
*
|
||||
*/
|
||||
|
||||
void stream_mssg_on (void)
|
||||
{
|
||||
|
||||
flush_buffer ();
|
||||
|
||||
if (ostream_screen)
|
||||
screen_mssg_on ();
|
||||
if (ostream_script && enable_scripting)
|
||||
script_mssg_on ();
|
||||
|
||||
message = TRUE;
|
||||
|
||||
}/* stream_mssg_on */
|
||||
|
||||
/*
|
||||
* stream_mssg_off
|
||||
*
|
||||
* Stop printing a "debugging" message.
|
||||
*
|
||||
*/
|
||||
|
||||
void stream_mssg_off (void)
|
||||
{
|
||||
|
||||
flush_buffer ();
|
||||
|
||||
if (ostream_screen)
|
||||
screen_mssg_off ();
|
||||
if (ostream_script && enable_scripting)
|
||||
script_mssg_off ();
|
||||
|
||||
message = FALSE;
|
||||
|
||||
}/* stream_mssg_off */
|
||||
|
||||
/*
|
||||
* z_output_stream, open or close an output stream.
|
||||
*
|
||||
* zargs[0] = stream to open (positive) or close (negative)
|
||||
* zargs[1] = address to redirect output to (stream 3 only)
|
||||
* zargs[2] = width of redirected output (stream 3 only, optional)
|
||||
*
|
||||
*/
|
||||
|
||||
void z_output_stream (void)
|
||||
{
|
||||
|
||||
flush_buffer ();
|
||||
|
||||
switch ((short) zargs[0]) {
|
||||
|
||||
case 1: ostream_screen = TRUE;
|
||||
break;
|
||||
case -1: ostream_screen = FALSE;
|
||||
break;
|
||||
case 2: if (!ostream_script) script_open ();
|
||||
break;
|
||||
case -2: if (ostream_script) script_close ();
|
||||
break;
|
||||
case 3: memory_open (zargs[1], zargs[2], zargc >= 3);
|
||||
break;
|
||||
case -3: memory_close ();
|
||||
break;
|
||||
case 4: if (!ostream_record) record_open ();
|
||||
break;
|
||||
case -4: if (ostream_record) record_close ();
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}/* z_output_stream */
|
||||
|
||||
/*
|
||||
* stream_char
|
||||
*
|
||||
* Send a single character to the output stream.
|
||||
*
|
||||
*/
|
||||
|
||||
void stream_char (zchar c)
|
||||
{
|
||||
|
||||
if (ostream_screen)
|
||||
screen_char (c);
|
||||
if (ostream_script && enable_scripting)
|
||||
script_char (c);
|
||||
|
||||
}/* stream_char */
|
||||
|
||||
/*
|
||||
* stream_word
|
||||
*
|
||||
* Send a string of characters to the output streams.
|
||||
*
|
||||
*/
|
||||
|
||||
void stream_word (const zchar *s)
|
||||
{
|
||||
|
||||
if (ostream_memory && !message)
|
||||
|
||||
memory_word (s);
|
||||
|
||||
else {
|
||||
|
||||
if (ostream_screen)
|
||||
screen_word (s);
|
||||
if (ostream_script && enable_scripting)
|
||||
script_word (s);
|
||||
|
||||
}
|
||||
|
||||
}/* stream_word */
|
||||
|
||||
/*
|
||||
* stream_new_line
|
||||
*
|
||||
* Send a newline to the output streams.
|
||||
*
|
||||
*/
|
||||
|
||||
void stream_new_line (void)
|
||||
{
|
||||
|
||||
if (ostream_memory && !message)
|
||||
|
||||
memory_new_line ();
|
||||
|
||||
else {
|
||||
|
||||
if (ostream_screen)
|
||||
screen_new_line ();
|
||||
if (ostream_script && enable_scripting)
|
||||
script_new_line ();
|
||||
|
||||
}
|
||||
|
||||
}/* stream_new_line */
|
||||
|
||||
/*
|
||||
* z_input_stream, select an input stream.
|
||||
*
|
||||
* zargs[0] = input stream to be selected
|
||||
*
|
||||
*/
|
||||
|
||||
void z_input_stream (void)
|
||||
{
|
||||
|
||||
flush_buffer ();
|
||||
|
||||
if (zargs[0] == 0 && istream_replay)
|
||||
replay_close ();
|
||||
if (zargs[0] == 1 && !istream_replay)
|
||||
replay_open ();
|
||||
|
||||
}/* z_input_stream */
|
||||
|
||||
/*
|
||||
* stream_read_key
|
||||
*
|
||||
* Read a single keystroke from the current input stream.
|
||||
*
|
||||
*/
|
||||
|
||||
zchar stream_read_key ( zword timeout, zword routine,
|
||||
bool hot_keys )
|
||||
{
|
||||
zchar key = ZC_BAD;
|
||||
|
||||
flush_buffer ();
|
||||
|
||||
/* Read key from current input stream */
|
||||
|
||||
continue_input:
|
||||
|
||||
do {
|
||||
|
||||
if (istream_replay)
|
||||
key = replay_read_key ();
|
||||
else
|
||||
key = console_read_key (timeout);
|
||||
|
||||
} while (key == ZC_BAD);
|
||||
|
||||
/* Verify mouse clicks */
|
||||
|
||||
if (key == ZC_SINGLE_CLICK || key == ZC_DOUBLE_CLICK)
|
||||
if (!validate_click ())
|
||||
goto continue_input;
|
||||
|
||||
/* Copy key to the command file */
|
||||
|
||||
if (ostream_record && !istream_replay)
|
||||
record_write_key (key);
|
||||
|
||||
/* Handle timeouts */
|
||||
|
||||
if (key == ZC_TIME_OUT)
|
||||
if (direct_call (routine) == 0)
|
||||
goto continue_input;
|
||||
|
||||
/* Handle hot keys */
|
||||
|
||||
if (hot_keys && key >= ZC_HKEY_MIN && key <= ZC_HKEY_MAX) {
|
||||
|
||||
if (h_version == V4 && key == ZC_HKEY_UNDO)
|
||||
goto continue_input;
|
||||
if (!handle_hot_key (key))
|
||||
goto continue_input;
|
||||
|
||||
return ZC_BAD;
|
||||
|
||||
}
|
||||
|
||||
/* Return key */
|
||||
|
||||
return key;
|
||||
|
||||
}/* stream_read_key */
|
||||
|
||||
/*
|
||||
* stream_read_input
|
||||
*
|
||||
* Read a line of input from the current input stream.
|
||||
*
|
||||
*/
|
||||
|
||||
zchar stream_read_input ( int max, zchar *buf,
|
||||
zword timeout, zword routine,
|
||||
bool hot_keys,
|
||||
bool no_scripting )
|
||||
{
|
||||
zchar key = ZC_BAD;
|
||||
|
||||
flush_buffer ();
|
||||
|
||||
/* Remove initial input from the transscript file or from the screen */
|
||||
|
||||
if (ostream_script && enable_scripting && !no_scripting)
|
||||
script_erase_input (buf);
|
||||
if (istream_replay)
|
||||
screen_erase_input (buf);
|
||||
|
||||
/* Read input line from current input stream */
|
||||
|
||||
continue_input:
|
||||
|
||||
do {
|
||||
|
||||
if (istream_replay)
|
||||
key = replay_read_input (buf);
|
||||
else
|
||||
key = console_read_input (max, buf, timeout, key != ZC_BAD);
|
||||
|
||||
} while (key == ZC_BAD);
|
||||
|
||||
/* Verify mouse clicks */
|
||||
|
||||
if (key == ZC_SINGLE_CLICK || key == ZC_DOUBLE_CLICK)
|
||||
if (!validate_click ())
|
||||
goto continue_input;
|
||||
|
||||
/* Copy input line to the command file */
|
||||
|
||||
if (ostream_record && !istream_replay)
|
||||
record_write_input (buf, key);
|
||||
|
||||
/* Handle timeouts */
|
||||
|
||||
if (key == ZC_TIME_OUT)
|
||||
if (direct_call (routine) == 0)
|
||||
goto continue_input;
|
||||
|
||||
/* Handle hot keys */
|
||||
|
||||
if (hot_keys && key >= ZC_HKEY_MIN && key <= ZC_HKEY_MAX) {
|
||||
|
||||
if (!handle_hot_key (key))
|
||||
goto continue_input;
|
||||
|
||||
return ZC_BAD;
|
||||
|
||||
}
|
||||
|
||||
/* Copy input line to transscript file or to the screen */
|
||||
|
||||
if (ostream_script && enable_scripting && !no_scripting)
|
||||
script_write_input (buf, key);
|
||||
if (istream_replay)
|
||||
screen_write_input (buf, key);
|
||||
|
||||
/* Return terminating key */
|
||||
|
||||
return key;
|
||||
|
||||
}/* stream_read_input */
|
193
apps/plugins/frotz/table.c
Normal file
193
apps/plugins/frotz/table.c
Normal file
|
@ -0,0 +1,193 @@
|
|||
/* table.c - Table handling opcodes
|
||||
* Copyright (c) 1995-1997 Stefan Jokisch
|
||||
*
|
||||
* This file is part of Frotz.
|
||||
*
|
||||
* Frotz is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Frotz is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include "frotz.h"
|
||||
|
||||
/*
|
||||
* z_copy_table, copy a table or fill it with zeroes.
|
||||
*
|
||||
* zargs[0] = address of table
|
||||
* zargs[1] = destination address or 0 for fill
|
||||
* zargs[2] = size of table
|
||||
*
|
||||
* Note: Copying is safe even when source and destination overlap; but
|
||||
* if zargs[1] is negative the table _must_ be copied forwards.
|
||||
*
|
||||
*/
|
||||
|
||||
void z_copy_table (void)
|
||||
{
|
||||
zword addr;
|
||||
zword size = zargs[2];
|
||||
zbyte value;
|
||||
int i;
|
||||
|
||||
if (zargs[1] == 0) /* zero table */
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
storeb ((zword) (zargs[0] + i), 0);
|
||||
|
||||
else if ((short) size < 0 || zargs[0] > zargs[1]) /* copy forwards */
|
||||
|
||||
for (i = 0; i < (((short) size < 0) ? - (short) size : size); i++) {
|
||||
addr = zargs[0] + i;
|
||||
LOW_BYTE (addr, value)
|
||||
storeb ((zword) (zargs[1] + i), value);
|
||||
}
|
||||
|
||||
else /* copy backwards */
|
||||
|
||||
for (i = size - 1; i >= 0; i--) {
|
||||
addr = zargs[0] + i;
|
||||
LOW_BYTE (addr, value)
|
||||
storeb ((zword) (zargs[1] + i), value);
|
||||
}
|
||||
|
||||
}/* z_copy_table */
|
||||
|
||||
/*
|
||||
* z_loadb, store a value from a table of bytes.
|
||||
*
|
||||
* zargs[0] = address of table
|
||||
* zargs[1] = index of table entry to store
|
||||
*
|
||||
*/
|
||||
|
||||
void z_loadb (void)
|
||||
{
|
||||
zword addr = zargs[0] + zargs[1];
|
||||
zbyte value;
|
||||
|
||||
LOW_BYTE (addr, value)
|
||||
|
||||
store (value);
|
||||
|
||||
}/* z_loadb */
|
||||
|
||||
/*
|
||||
* z_loadw, store a value from a table of words.
|
||||
*
|
||||
* zargs[0] = address of table
|
||||
* zargs[1] = index of table entry to store
|
||||
*
|
||||
*/
|
||||
|
||||
void z_loadw (void)
|
||||
{
|
||||
zword addr = zargs[0] + 2 * zargs[1];
|
||||
zword value;
|
||||
|
||||
LOW_WORD (addr, value)
|
||||
|
||||
store (value);
|
||||
|
||||
}/* z_loadw */
|
||||
|
||||
/*
|
||||
* z_scan_table, find and store the address of a target within a table.
|
||||
*
|
||||
* zargs[0] = target value to be searched for
|
||||
* zargs[1] = address of table
|
||||
* zargs[2] = number of table entries to check value against
|
||||
* zargs[3] = type of table (optional, defaults to 0x82)
|
||||
*
|
||||
* Note: The table is a word array if bit 7 of zargs[3] is set; otherwise
|
||||
* it's a byte array. The lower bits hold the address step.
|
||||
*
|
||||
*/
|
||||
|
||||
void z_scan_table (void)
|
||||
{
|
||||
zword addr = zargs[1];
|
||||
int i;
|
||||
|
||||
/* Supply default arguments */
|
||||
|
||||
if (zargc < 4)
|
||||
zargs[3] = 0x82;
|
||||
|
||||
/* Scan byte or word array */
|
||||
|
||||
for (i = 0; i < zargs[2]; i++) {
|
||||
|
||||
if (zargs[3] & 0x80) { /* scan word array */
|
||||
|
||||
zword wvalue;
|
||||
|
||||
LOW_WORD (addr, wvalue)
|
||||
|
||||
if (wvalue == zargs[0])
|
||||
goto finished;
|
||||
|
||||
} else { /* scan byte array */
|
||||
|
||||
zbyte bvalue;
|
||||
|
||||
LOW_BYTE (addr, bvalue)
|
||||
|
||||
if (bvalue == zargs[0])
|
||||
goto finished;
|
||||
|
||||
}
|
||||
|
||||
addr += zargs[3] & 0x7f;
|
||||
|
||||
}
|
||||
|
||||
addr = 0;
|
||||
|
||||
finished:
|
||||
|
||||
store (addr);
|
||||
branch (addr);
|
||||
|
||||
}/* z_scan_table */
|
||||
|
||||
/*
|
||||
* z_storeb, write a byte into a table of bytes.
|
||||
*
|
||||
* zargs[0] = address of table
|
||||
* zargs[1] = index of table entry
|
||||
* zargs[2] = value to be written
|
||||
*
|
||||
*/
|
||||
|
||||
void z_storeb (void)
|
||||
{
|
||||
|
||||
storeb ((zword) (zargs[0] + zargs[1]), zargs[2]);
|
||||
|
||||
}/* z_storeb */
|
||||
|
||||
/*
|
||||
* z_storew, write a word into a table of words.
|
||||
*
|
||||
* zargs[0] = address of table
|
||||
* zargs[1] = index of table entry
|
||||
* zargs[2] = value to be written
|
||||
*
|
||||
*/
|
||||
|
||||
void z_storew (void)
|
||||
{
|
||||
|
||||
storew ((zword) (zargs[0] + 2 * zargs[1]), zargs[2]);
|
||||
|
||||
}/* z_storew */
|
1109
apps/plugins/frotz/text.c
Normal file
1109
apps/plugins/frotz/text.c
Normal file
File diff suppressed because it is too large
Load diff
304
apps/plugins/frotz/variable.c
Normal file
304
apps/plugins/frotz/variable.c
Normal file
|
@ -0,0 +1,304 @@
|
|||
/* variable.c - Variable and stack related opcodes
|
||||
* Copyright (c) 1995-1997 Stefan Jokisch
|
||||
*
|
||||
* This file is part of Frotz.
|
||||
*
|
||||
* Frotz is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Frotz is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include "frotz.h"
|
||||
|
||||
/*
|
||||
* z_dec, decrement a variable.
|
||||
*
|
||||
* zargs[0] = variable to decrement
|
||||
*
|
||||
*/
|
||||
|
||||
void z_dec (void)
|
||||
{
|
||||
zword value;
|
||||
|
||||
if (zargs[0] == 0)
|
||||
(*sp)--;
|
||||
else if (zargs[0] < 16)
|
||||
(*(fp - zargs[0]))--;
|
||||
else {
|
||||
zword addr = h_globals + 2 * (zargs[0] - 16);
|
||||
LOW_WORD (addr, value)
|
||||
value--;
|
||||
SET_WORD (addr, value)
|
||||
}
|
||||
|
||||
}/* z_dec */
|
||||
|
||||
/*
|
||||
* z_dec_chk, decrement a variable and branch if now less than value.
|
||||
*
|
||||
* zargs[0] = variable to decrement
|
||||
* zargs[1] = value to check variable against
|
||||
*
|
||||
*/
|
||||
|
||||
void z_dec_chk (void)
|
||||
{
|
||||
zword value;
|
||||
|
||||
if (zargs[0] == 0)
|
||||
value = --(*sp);
|
||||
else if (zargs[0] < 16)
|
||||
value = --(*(fp - zargs[0]));
|
||||
else {
|
||||
zword addr = h_globals + 2 * (zargs[0] - 16);
|
||||
LOW_WORD (addr, value)
|
||||
value--;
|
||||
SET_WORD (addr, value)
|
||||
}
|
||||
|
||||
branch ((short) value < (short) zargs[1]);
|
||||
|
||||
}/* z_dec_chk */
|
||||
|
||||
/*
|
||||
* z_inc, increment a variable.
|
||||
*
|
||||
* zargs[0] = variable to increment
|
||||
*
|
||||
*/
|
||||
|
||||
void z_inc (void)
|
||||
{
|
||||
zword value;
|
||||
|
||||
if (zargs[0] == 0)
|
||||
(*sp)++;
|
||||
else if (zargs[0] < 16)
|
||||
(*(fp - zargs[0]))++;
|
||||
else {
|
||||
zword addr = h_globals + 2 * (zargs[0] - 16);
|
||||
LOW_WORD (addr, value)
|
||||
value++;
|
||||
SET_WORD (addr, value)
|
||||
}
|
||||
|
||||
}/* z_inc */
|
||||
|
||||
/*
|
||||
* z_inc_chk, increment a variable and branch if now greater than value.
|
||||
*
|
||||
* zargs[0] = variable to increment
|
||||
* zargs[1] = value to check variable against
|
||||
*
|
||||
*/
|
||||
|
||||
void z_inc_chk (void)
|
||||
{
|
||||
zword value;
|
||||
|
||||
if (zargs[0] == 0)
|
||||
value = ++(*sp);
|
||||
else if (zargs[0] < 16)
|
||||
value = ++(*(fp - zargs[0]));
|
||||
else {
|
||||
zword addr = h_globals + 2 * (zargs[0] - 16);
|
||||
LOW_WORD (addr, value)
|
||||
value++;
|
||||
SET_WORD (addr, value)
|
||||
}
|
||||
|
||||
branch ((short) value > (short) zargs[1]);
|
||||
|
||||
}/* z_inc_chk */
|
||||
|
||||
/*
|
||||
* z_load, store the value of a variable.
|
||||
*
|
||||
* zargs[0] = variable to store
|
||||
*
|
||||
*/
|
||||
|
||||
void z_load (void)
|
||||
{
|
||||
zword value;
|
||||
|
||||
if (zargs[0] == 0)
|
||||
value = *sp;
|
||||
else if (zargs[0] < 16)
|
||||
value = *(fp - zargs[0]);
|
||||
else {
|
||||
zword addr = h_globals + 2 * (zargs[0] - 16);
|
||||
LOW_WORD (addr, value)
|
||||
}
|
||||
|
||||
store (value);
|
||||
|
||||
}/* z_load */
|
||||
|
||||
/*
|
||||
* z_pop, pop a value off the game stack and discard it.
|
||||
*
|
||||
* no zargs used
|
||||
*
|
||||
*/
|
||||
|
||||
void z_pop (void)
|
||||
{
|
||||
|
||||
sp++;
|
||||
|
||||
}/* z_pop */
|
||||
|
||||
/*
|
||||
* z_pop_stack, pop n values off the game or user stack and discard them.
|
||||
*
|
||||
* zargs[0] = number of values to discard
|
||||
* zargs[1] = address of user stack (optional)
|
||||
*
|
||||
*/
|
||||
|
||||
void z_pop_stack (void)
|
||||
{
|
||||
|
||||
if (zargc == 2) { /* it's a user stack */
|
||||
|
||||
zword size;
|
||||
zword addr = zargs[1];
|
||||
|
||||
LOW_WORD (addr, size)
|
||||
|
||||
size += zargs[0];
|
||||
storew (addr, size);
|
||||
|
||||
} else sp += zargs[0]; /* it's the game stack */
|
||||
|
||||
}/* z_pop_stack */
|
||||
|
||||
/*
|
||||
* z_pull, pop a value off...
|
||||
*
|
||||
* a) ...the game or a user stack and store it (V6)
|
||||
*
|
||||
* zargs[0] = address of user stack (optional)
|
||||
*
|
||||
* b) ...the game stack and write it to a variable (other than V6)
|
||||
*
|
||||
* zargs[0] = variable to write value to
|
||||
*
|
||||
*/
|
||||
|
||||
void z_pull (void)
|
||||
{
|
||||
zword value;
|
||||
|
||||
if (h_version != V6) { /* not a V6 game, pop stack and write */
|
||||
|
||||
value = *sp++;
|
||||
|
||||
if (zargs[0] == 0)
|
||||
*sp = value;
|
||||
else if (zargs[0] < 16)
|
||||
*(fp - zargs[0]) = value;
|
||||
else {
|
||||
zword addr = h_globals + 2 * (zargs[0] - 16);
|
||||
SET_WORD (addr, value)
|
||||
}
|
||||
|
||||
} else { /* it's V6, but is there a user stack? */
|
||||
|
||||
if (zargc == 1) { /* it's a user stack */
|
||||
|
||||
zword size;
|
||||
zword addr = zargs[0];
|
||||
|
||||
LOW_WORD (addr, size)
|
||||
|
||||
size++;
|
||||
storew (addr, size);
|
||||
|
||||
addr += 2 * size;
|
||||
LOW_WORD (addr, value)
|
||||
|
||||
} else value = *sp++; /* it's the game stack */
|
||||
|
||||
store (value);
|
||||
|
||||
}
|
||||
|
||||
}/* z_pull */
|
||||
|
||||
/*
|
||||
* z_push, push a value onto the game stack.
|
||||
*
|
||||
* zargs[0] = value to push onto the stack
|
||||
*
|
||||
*/
|
||||
|
||||
void z_push (void)
|
||||
{
|
||||
|
||||
*--sp = zargs[0];
|
||||
|
||||
}/* z_push */
|
||||
|
||||
/*
|
||||
* z_push_stack, push a value onto a user stack then branch if successful.
|
||||
*
|
||||
* zargs[0] = value to push onto the stack
|
||||
* zargs[1] = address of user stack
|
||||
*
|
||||
*/
|
||||
|
||||
void z_push_stack (void)
|
||||
{
|
||||
zword size;
|
||||
zword addr = zargs[1];
|
||||
|
||||
LOW_WORD (addr, size)
|
||||
|
||||
if (size != 0) {
|
||||
|
||||
storew ((zword) (addr + 2 * size), zargs[0]);
|
||||
|
||||
size--;
|
||||
storew (addr, size);
|
||||
|
||||
}
|
||||
|
||||
branch (size);
|
||||
|
||||
}/* z_push_stack */
|
||||
|
||||
/*
|
||||
* z_store, write a value to a variable.
|
||||
*
|
||||
* zargs[0] = variable to be written to
|
||||
* zargs[1] = value to write
|
||||
*
|
||||
*/
|
||||
|
||||
void z_store (void)
|
||||
{
|
||||
zword value = zargs[1];
|
||||
|
||||
if (zargs[0] == 0)
|
||||
*sp = value;
|
||||
else if (zargs[0] < 16)
|
||||
*(fp - zargs[0]) = value;
|
||||
else {
|
||||
zword addr = h_globals + 2 * (zargs[0] - 16);
|
||||
SET_WORD (addr, value)
|
||||
}
|
||||
|
||||
}/* z_store */
|
|
@ -61,3 +61,11 @@ link,viewers/shortcuts_view,-
|
|||
lua,viewers/lua,-
|
||||
ipod,viewers/crypt_firmware,-
|
||||
ipodx,viewers/crypt_firmware,-
|
||||
z1,viewers/frotz,-
|
||||
z2,viewers/frotz,-
|
||||
z3,viewers/frotz,-
|
||||
z4,viewers/frotz,-
|
||||
z5,viewers/frotz,-
|
||||
z6,viewers/frotz,-
|
||||
z7,viewers/frotz,-
|
||||
z8,viewers/frotz,-
|
||||
|
|
67
manual/plugins/frotz.tex
Normal file
67
manual/plugins/frotz.tex
Normal file
|
@ -0,0 +1,67 @@
|
|||
% $Id$ %
|
||||
\subsection{Frotz}
|
||||
Frotz is a Z-Machine interpreter for playing Infocom's interactive fiction
|
||||
games, and newer games using the same format. To start a game open a
|
||||
\fname{.z1 - .z8} file in the \setting{File Browser}. Most modern games are
|
||||
in the \fname{.z5} or \fname{.z8} format but the older formats used by
|
||||
Infocom are supported.
|
||||
|
||||
Z-Machine games are text based and most depend heavily on typed commands.
|
||||
The virtual keyboard is used for text entry, both for typing entire lines
|
||||
and for typing single characters when the game requires single character
|
||||
input.
|
||||
|
||||
Sounds, pictures, colour and Unicode are not currently supported, but
|
||||
the interpreter informs the game of this and almost all games will
|
||||
adapt so that they are still playable. This port of Frotz attempts to be
|
||||
compliant with the Z-Machine Specification version 1.0.
|
||||
|
||||
Some places where you can find Z-Machine games, and information about
|
||||
interactive fiction:
|
||||
\begin{itemize}
|
||||
\item The Interactive Fiction Archive, where many free modern works
|
||||
can be downloaded:
|
||||
\url{http://www.ifarchive.org/}
|
||||
\item The specific folder on the if-archive containing Z-Machine games:
|
||||
\url{http://www.ifarchive.org/indexes/if-archiveXgamesXzcode.html}
|
||||
\item The Infocom homepage, with information about how to get the
|
||||
classic commercial Infocom games:
|
||||
\url{http://www.csd.uwo.ca/Infocom/}
|
||||
\item The Frotz homepage (for the original Unix port):
|
||||
\url{http://frotz.sourceforge.net/}
|
||||
\item A Beginner's Guide to Playing Interactive Fiction:
|
||||
\url{http://www.microheaven.com/IFGuide/}
|
||||
\end{itemize}
|
||||
|
||||
\begin{table}
|
||||
\begin{btnmap}{}{}
|
||||
\opt{RECORDER_PAD,IRIVER_H100_PAD,IRIVER_H300_PAD}{\ButtonOn}
|
||||
\opt{IPOD_4G_PAD,IPOD_3G_PAD,IRIVER_H10_PAD,GIGABEAT_S_PAD}{\ButtonPlay}
|
||||
\opt{ONDIO_PAD}{\ButtonMenu}
|
||||
\opt{IAUDIO_X5_PAD,MROBE100_PAD}{\ButtonPower}
|
||||
\opt{SANSA_E200_PAD,SANSA_C200_PAD}{\ButtonUp}
|
||||
\opt{GIGABEAT_PAD}{\ButtonA}
|
||||
\opt{HAVEREMOTEKEYMAP}{&
|
||||
\opt{IRIVER_RC_H100_PAD}{\ButtonRCOn}
|
||||
}
|
||||
& Display keyboard to enter text\\
|
||||
\opt{IRIVER_H100_PAD,IRIVER_H300_PAD,IAUDIO_X5_PAD,IPOD_4G_PAD,IPOD_3G_PAD%
|
||||
,SANSA_E200_PAD,SANSA_C200_PAD,GIGABEAT_PAD,GIGABEAT_S_PAD,MROBE100_PAD}{\ButtonSelect}
|
||||
\opt{RECORDER_PAD}{\ButtonPlay}
|
||||
\opt{ONDIO_PAD}{\ButtonUp}
|
||||
\opt{IRIVER_H10_PAD}{\ButtonRew}
|
||||
\opt{COWON_D2_PAD}{\ButtonMenu{}, \TouchCenter{} or \TouchBottomMiddle}
|
||||
\opt{HAVEREMOTEKEYMAP}{& }
|
||||
& Press enter\\
|
||||
\opt{RECORDER_PAD,ONDIO_PAD,IRIVER_H100_PAD,IRIVER_H300_PAD}{\ButtonOff}
|
||||
\opt{IPOD_4G_PAD,IPOD_3G_PAD}{\ButtonMenu}
|
||||
\opt{IAUDIO_X5_PAD,IRIVER_H10_PAD,SANSA_E200_PAD,SANSA_C200_PAD,GIGABEAT_PAD%
|
||||
,MROBE100_PAD}{\ButtonPower}
|
||||
\opt{GIGABEAT_S_PAD}{\ButtonBack}
|
||||
\opt{COWON_D2_PAD}{\ButtonPower{} or \TouchBottomRight}
|
||||
\opt{HAVEREMOTEKEYMAP}{&
|
||||
\opt{IRIVER_RC_H100_PAD}{\ButtonRCStop}
|
||||
}
|
||||
& Open Frotz menu (not available at MORE prompts)\\
|
||||
\end{btnmap}
|
||||
\end{table}
|
|
@ -135,6 +135,7 @@ option from the \setting{Context Menu} (see \reference{ref:Contextmenu}).}
|
|||
{}{}
|
||||
Shortcuts & \fname{.link} & \\
|
||||
Chip-8 Emulator & \fname{.ch8} & \\
|
||||
Frotz & \fname{.z1 - .z8} & \\
|
||||
JPEG Viewer & \fname{.jpg, .jpeg} & \\
|
||||
Lua scripting language& \fname{.lua} & \\
|
||||
Midiplay & \fname{.mid, .midi} & \\
|
||||
|
@ -160,6 +161,8 @@ option from the \setting{Context Menu} (see \reference{ref:Contextmenu}).}
|
|||
|
||||
\opt{lcd_bitmap}{\input{plugins/chip8emulator.tex}}
|
||||
|
||||
\opt{lcd_bitmap}{\input{plugins/frotz.tex}}
|
||||
|
||||
\opt{lcd_bitmap}{\input{plugins/jpegviewer.tex}}
|
||||
|
||||
\opt{large_plugin_buffer}{\input{plugins/lua.tex}}
|
||||
|
|
Loading…
Reference in a new issue