aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Gilbert2019-06-18 19:56:25 -0700
committerPaul Gilbert2019-06-22 14:40:49 -0700
commited21388e11a928fc965714a035d2c18887ec7f62 (patch)
treebb41c7bf99f482c2e8964403929a779f976fe21a
parent08bc570308b0698090ce668dc7dca4c0c76dd3df (diff)
downloadscummvm-rg350-ed21388e11a928fc965714a035d2c18887ec7f62.tar.gz
scummvm-rg350-ed21388e11a928fc965714a035d2c18887ec7f62.tar.bz2
scummvm-rg350-ed21388e11a928fc965714a035d2c18887ec7f62.zip
GLK: ALAN2: Added missing main code file, hooked up to Alan2 engine skeleton
-rw-r--r--engines/glk/alan2/acode.cpp81
-rw-r--r--engines/glk/alan2/acode.h98
-rw-r--r--engines/glk/alan2/alan2.cpp12
-rw-r--r--engines/glk/alan2/args.cpp2
-rw-r--r--engines/glk/alan2/glkio.cpp3
-rw-r--r--engines/glk/alan2/glkio.h4
-rw-r--r--engines/glk/alan2/main.cpp1926
-rw-r--r--engines/glk/alan2/main.h4
-rw-r--r--engines/glk/alan2/sysdep.cpp11
-rw-r--r--engines/glk/alan2/sysdep.h3
-rw-r--r--engines/glk/module.mk2
11 files changed, 2098 insertions, 48 deletions
diff --git a/engines/glk/alan2/acode.cpp b/engines/glk/alan2/acode.cpp
new file mode 100644
index 0000000000..b842c81ff2
--- /dev/null
+++ b/engines/glk/alan2/acode.cpp
@@ -0,0 +1,81 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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 program 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "glk/alan2/acode.h"
+
+namespace Glk {
+namespace Alan2 {
+
+AcdHdr::AcdHdr() : size(0), pack(0), paglen(0), pagwidth(0), debug(0), dict(0), oatrs(0),
+ latrs(0), aatrs(0), acts(0), objs(0), locs(0), stxs(0), vrbs(0), evts(0),
+ cnts(0), ruls(0), init(0), start(0), msgs(0), objmin(0), objmax(0), actmin(0),
+ actmax(0), cntmin(0), cntmax(0), locmin(0), locmax(0), dirmin(0), dirmax(0),
+ evtmin(0), evtmax(0), rulmin(0), rulmax(0), maxscore(0), scores(0),
+ freq(0), acdcrc(0), txtcrc(0) {
+ vers[0] = vers[1] = vers[2] = vers[3] = 0;
+}
+
+void AcdHdr::load(Common::SeekableReadStream &s) {
+ s.read(vers, 4);
+ size = s.readUint32LE();
+ pack = s.readUint32LE();
+ paglen = s.readUint32LE();
+ pagwidth = s.readUint32LE();
+ debug = s.readUint32LE();
+ dict = s.readUint32LE();
+ oatrs = s.readUint32LE();
+ latrs = s.readUint32LE();
+ aatrs = s.readUint32LE();
+ acts = s.readUint32LE();
+ objs = s.readUint32LE();
+ locs = s.readUint32LE();
+ stxs = s.readUint32LE();
+ vrbs = s.readUint32LE();
+ evts = s.readUint32LE();
+ cnts = s.readUint32LE();
+ ruls = s.readUint32LE();
+ init = s.readUint32LE();
+ start = s.readUint32LE();
+ msgs = s.readUint32LE();
+ objmin = s.readUint32LE();
+ objmax = s.readUint32LE();
+ actmin = s.readUint32LE();
+ actmax = s.readUint32LE();
+ cntmin = s.readUint32LE();
+ cntmax = s.readUint32LE();
+ locmin = s.readUint32LE();
+ locmax = s.readUint32LE();
+ dirmin = s.readUint32LE();
+ dirmax = s.readUint32LE();
+ evtmin = s.readUint32LE();
+ evtmax = s.readUint32LE();
+ rulmin = s.readUint32LE();
+ rulmax = s.readUint32LE();
+ maxscore = s.readUint32LE();
+ scores = s.readUint32LE();
+ freq = s.readUint32LE();
+ acdcrc = s.readUint32LE();
+ txtcrc = s.readUint32LE();
+}
+
+} // End of namespace Alan2
+} // End of namespace Glk
diff --git a/engines/glk/alan2/acode.h b/engines/glk/alan2/acode.h
index 5fee277c6c..fff5144298 100644
--- a/engines/glk/alan2/acode.h
+++ b/engines/glk/alan2/acode.h
@@ -23,15 +23,17 @@
#ifndef GLK_ALAN2_ACODE
#define GLK_ALAN2_ACODE
+#include "common/stream.h"
+
namespace Glk {
namespace Alan2 {
typedef size_t Aptr; /* Type for an ACODE memory address */
-typedef unsigned int Aword; /* Type for an ACODE word */
-typedef unsigned int Aaddr; /* Type for an ACODE address */
-typedef unsigned int Abool; /* Type for an ACODE Boolean value */
-typedef signed int Aint; /* Type for an ACODE Integer value */
+typedef uint32 Aword; /* Type for an ACODE word */
+typedef uint32 Aaddr; /* Type for an ACODE address */
+typedef uint32 Abool; /* Type for an ACODE Boolean value */
+typedef int32 Aint; /* Type for an ACODE Integer value */
typedef int CodeValue; /* Definition for the packing process */
#ifdef UNUSED
@@ -208,45 +210,55 @@ typedef enum VarClass {
#define I_OP(x) ((x&0x8000000)?(x)|0x0f0000000:(x)&0x0fffffff)
-typedef struct AcdHdr {
-/* Important info */
- char vers[4]; /* 01 - Version of compiler */
- Aword size; /* 02 - Size of ACD-file in Awords */
-/* Options */
- Abool pack; /* 03 - Is the text packed ? */
- Aword paglen; /* 04 - Length of a page */
- Aword pagwidth; /* 05 - and width */
- Aword debug; /* 06 - Option debug */
-/* Data structures */
- Aaddr dict; /* 07 - Dictionary */
- Aaddr oatrs; /* 08 - Object default attributes */
- Aaddr latrs; /* 09 - Location default attributes */
- Aaddr aatrs; /* 0a - Actor default attributes */
- Aaddr acts; /* 0b - Actor table */
- Aaddr objs; /* 0c - Object table */
- Aaddr locs; /* 0d - Location table */
- Aaddr stxs; /* 0e - Syntax table */
- Aaddr vrbs; /* 0f - Verb table */
- Aaddr evts; /* 10 - Event table */
- Aaddr cnts; /* 11 - Container table */
- Aaddr ruls; /* 12 - Rule table */
- Aaddr init; /* 13 - String init table */
- Aaddr start; /* 14 - Start code */
- Aword msgs; /* 15 - Messages table */
-/* Miscellaneous */
- Aword objmin, objmax; /* 16 - Interval for object codes */
- Aword actmin, actmax; /* 18 - Interval for actor codes */
- Aword cntmin, cntmax; /* 1a - Interval for container codes */
- Aword locmin, locmax; /* 1c - Interval for location codes */
- Aword dirmin, dirmax; /* 1e - Interval for direction codes */
- Aword evtmin, evtmax; /* 20 - Interval for event codes */
- Aword rulmin, rulmax; /* 22 - Interval for rule codes */
- Aword maxscore; /* 24 - Maximum score */
- Aaddr scores; /* 25 - Score table */
- Aaddr freq; /* 26 - Address to Char freq's for coding */
- Aword acdcrc; /* 27 - Checksum for acd code (excl. hdr) */
- Aword txtcrc; /* 28 - Checksum for text data file */
-} AcdHdr;
+struct AcdHdr {
+ /* Important info */
+ char vers[4]; /* 01 - Version of compiler */
+ Aword size; /* 02 - Size of ACD-file in Awords */
+ /* Options */
+ Abool pack; /* 03 - Is the text packed ? */
+ Aword paglen; /* 04 - Length of a page */
+ Aword pagwidth; /* 05 - and width */
+ Aword debug; /* 06 - Option debug */
+ /* Data structures */
+ Aaddr dict; /* 07 - Dictionary */
+ Aaddr oatrs; /* 08 - Object default attributes */
+ Aaddr latrs; /* 09 - Location default attributes */
+ Aaddr aatrs; /* 0a - Actor default attributes */
+ Aaddr acts; /* 0b - Actor table */
+ Aaddr objs; /* 0c - Object table */
+ Aaddr locs; /* 0d - Location table */
+ Aaddr stxs; /* 0e - Syntax table */
+ Aaddr vrbs; /* 0f - Verb table */
+ Aaddr evts; /* 10 - Event table */
+ Aaddr cnts; /* 11 - Container table */
+ Aaddr ruls; /* 12 - Rule table */
+ Aaddr init; /* 13 - String init table */
+ Aaddr start; /* 14 - Start code */
+ Aword msgs; /* 15 - Messages table */
+ /* Miscellaneous */
+ Aword objmin, objmax; /* 16 - Interval for object codes */
+ Aword actmin, actmax; /* 18 - Interval for actor codes */
+ Aword cntmin, cntmax; /* 1a - Interval for container codes */
+ Aword locmin, locmax; /* 1c - Interval for location codes */
+ Aword dirmin, dirmax; /* 1e - Interval for direction codes */
+ Aword evtmin, evtmax; /* 20 - Interval for event codes */
+ Aword rulmin, rulmax; /* 22 - Interval for rule codes */
+ Aword maxscore; /* 24 - Maximum score */
+ Aaddr scores; /* 25 - Score table */
+ Aaddr freq; /* 26 - Address to Char freq's for coding */
+ Aword acdcrc; /* 27 - Checksum for acd code (excl. hdr) */
+ Aword txtcrc; /* 28 - Checksum for text data file */
+
+ /**
+ * Constructor
+ */
+ AcdHdr();
+
+ /**
+ * Loads the header from the passed stream
+ */
+ void load(Common::SeekableReadStream &s);
+};
/* Error message numbers */
typedef enum MsgKind {
diff --git a/engines/glk/alan2/alan2.cpp b/engines/glk/alan2/alan2.cpp
index 1889c696cd..fec1c62a40 100644
--- a/engines/glk/alan2/alan2.cpp
+++ b/engines/glk/alan2/alan2.cpp
@@ -21,6 +21,7 @@
*/
#include "glk/alan2/alan2.h"
+#include "glk/alan2/main.h"
#include "common/config-manager.h"
#include "common/translation.h"
#include "common/error.h"
@@ -45,7 +46,16 @@ void Alan2::runGame() {
if (!is_gamefile_valid())
return;
- // TODO
+ Common::String filename = getFilename();
+ while (filename.contains('.'))
+ filename.deleteLastChar();
+ advnam = filename.c_str();
+
+ codfil = &_gameFile;
+ strncpy(codfnm, getFilename().c_str(), 255);
+ codfnm[255] = '\0';
+
+ run();
}
Common::Error Alan2::readSaveData(Common::SeekableReadStream *rs) {
diff --git a/engines/glk/alan2/args.cpp b/engines/glk/alan2/args.cpp
index aceb00b67a..19462393a3 100644
--- a/engines/glk/alan2/args.cpp
+++ b/engines/glk/alan2/args.cpp
@@ -65,6 +65,7 @@ static void switches(argc, argv)
char *argv[];
#endif
{
+#ifndef GLK
uint i;
advnam = "";
@@ -111,6 +112,7 @@ static void switches(argc, argv)
advnam[strlen(advnam)-4] = '\0';
}
}
+#endif
}
diff --git a/engines/glk/alan2/glkio.cpp b/engines/glk/alan2/glkio.cpp
index 346413170c..47dbbf2ff0 100644
--- a/engines/glk/alan2/glkio.cpp
+++ b/engines/glk/alan2/glkio.cpp
@@ -27,6 +27,9 @@
namespace Glk {
namespace Alan2 {
+winid_t glkMainWin;
+winid_t glkStatusWin;
+
void glkio_printf(char *fmt, ...) {
va_list argp;
va_start(argp, fmt);
diff --git a/engines/glk/alan2/glkio.h b/engines/glk/alan2/glkio.h
index 7dca2cab87..151bb7a3b5 100644
--- a/engines/glk/alan2/glkio.h
+++ b/engines/glk/alan2/glkio.h
@@ -31,8 +31,8 @@
namespace Glk {
namespace Alan2 {
-winid_t glkMainWin;
-winid_t glkStatusWin;
+extern winid_t glkMainWin;
+extern winid_t glkStatusWin;
/* NB: this header must be included in any file which calls print() */
diff --git a/engines/glk/alan2/main.cpp b/engines/glk/alan2/main.cpp
new file mode 100644
index 0000000000..d2e8323e2c
--- /dev/null
+++ b/engines/glk/alan2/main.cpp
@@ -0,0 +1,1926 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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 program 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#define V27COMPATIBLE
+
+#include "glk/alan2/sysdep.h"
+
+#include "glk/alan2/types.h"
+#include "glk/alan2/main.h"
+
+//#include <time.h>
+#ifdef USE_READLINE
+#include "glk/alan2/readline.h"
+#endif
+
+#ifdef HAVE_SHORT_FILENAMES
+#include "glk/alan2/av.h"
+#else
+#include "glk/alan2/alan_version.h"
+#endif
+
+#include "glk/alan2/args.h"
+#include "glk/alan2/parse.h"
+#include "glk/alan2/inter.h"
+#include "glk/alan2/rules.h"
+#ifdef REVERSED
+#include "glk/alan2/reverse.h"
+#endif
+#include "glk/alan2/debug.h"
+#include "glk/alan2/stack.h"
+#include "glk/alan2/exe.h"
+#include "glk/alan2/term.h"
+
+#ifdef GLK
+#include "common/file.h"
+#include "glk/alan2/alan2.h"
+#include "glk/alan2/glkio.h"
+#endif
+
+namespace Glk {
+namespace Alan2 {
+
+/* PUBLIC DATA */
+
+/* The Amachine memory */
+Aword *memory;
+//static AcdHdr dummyHeader; /* Dummy to use until memory allocated */
+AcdHdr *header;
+
+int memTop = 0; /* Top of load memory */
+
+int conjWord; /* First conjunction in dictonary, for ',' */
+
+
+/* Amachine variables */
+CurVars cur;
+
+/* Amachine structures */
+WrdElem *dict; /* Dictionary pointer */
+ActElem *acts; /* Actor table pointer */
+LocElem *locs; /* Location table pointer */
+VrbElem *vrbs; /* Verb table pointer */
+StxElem *stxs; /* Syntax table pointer */
+ObjElem *objs; /* Object table pointer */
+CntElem *cnts; /* Container table pointer */
+RulElem *ruls; /* Rule table pointer */
+EvtElem *evts; /* Event table pointer */
+MsgElem *msgs; /* Message table pointer */
+Aword *scores; /* Score table pointer */
+Aword *freq; /* Cumulative character frequencies */
+
+int dictsize;
+
+Boolean verbose = FALSE;
+Boolean errflg = TRUE;
+Boolean trcflg = FALSE;
+Boolean dbgflg = FALSE;
+Boolean stpflg = FALSE;
+Boolean logflg = FALSE;
+Boolean statusflg = TRUE;
+Boolean fail = FALSE;
+Boolean anyOutput = FALSE;
+
+
+/* The files and filenames */
+const char *advnam;
+Common::File *txtfil;
+Common::WriteStream *logfil;
+
+
+/* Screen formatting info */
+int col, lin;
+int paglen, pagwidth;
+
+Boolean needsp = FALSE;
+Boolean skipsp = FALSE;
+
+/* Restart jump buffer */
+//jmp_buf restart_label;
+
+
+/* PRIVATE DATA */
+//static jmp_buf jmpbuf; /* Error return long jump buffer */
+
+
+
+/*======================================================================
+
+ terminate()
+
+ Terminate the execution of the adventure, e.g. close windows,
+ return buffers...
+
+ */
+#ifdef _PROTOTYPES_
+void terminate(int code)
+#else
+void terminate(code)
+ int code;
+#endif
+{
+#ifdef __amiga__
+#ifdef AZTEC_C
+#include <fcntl.h>
+ extern struct _dev *_devtab;
+ char buf[85];
+
+ if (con) { /* Running from WB, created a console so kill it */
+ /* Running from WB, so we created a console and
+ hacked the Aztec C device table to use it for all I/O
+ so now we need to make it close it (once!) */
+ _devtab[1].fd = _devtab[2].fd = 0;
+ } else
+#else
+ /* Geek Gadgets GCC */
+#include <workbench/startup.h>
+#include <clib/dos_protos.h>
+#include <clib/intuition_protos.h>
+
+ if (_WBenchMsg != NULL) {
+ Close(window);
+ if (_WBenchMsg->sm_ArgList != NULL)
+ UnLock(CurrentDir(cd));
+ } else
+#endif
+#endif
+ newline();
+ free(memory);
+ if (logflg)
+ fclose(logfil);
+
+#ifdef __MWERKS__
+ printf("Command-Q to close window.");
+#endif
+
+#ifdef GLK
+ g_vm->glk_exit();
+#else
+ exit(code);
+#endif
+}
+
+/*======================================================================
+
+ usage()
+
+ */
+#ifdef _PROTOTYPES_
+void usage(void)
+#else
+void usage()
+#endif
+{
+ printf("Usage:\n\n");
+ printf(" %s [<switches>] <adventure>\n\n", PROGNAME);
+ printf("where the possible optional switches are:\n");
+#ifdef GLK
+ g_vm->glk_set_style(style_Preformatted);
+#endif
+ printf(" -v verbose mode\n");
+ printf(" -l log player commands and game output to a file\n");
+ printf(" -i ignore version and checksum errors\n");
+ printf(" -n no Status Line\n");
+ printf(" -d enter debug mode\n");
+ printf(" -t trace game execution\n");
+ printf(" -s single instruction trace\n");
+#ifdef GLK
+ g_vm->glk_set_style(style_Normal);
+#endif
+}
+
+
+/*======================================================================
+
+ syserr()
+
+ Print a little text blaming the user for the system error.
+
+ */
+#ifdef _PROTOTYPES_
+void syserr(char *str)
+#else
+void syserr(str)
+ char *str;
+#endif
+{
+ output("$n$nAs you enter the twilight zone of Adventures, you stumble \
+and fall to your knees. In front of you, you can vaguely see the outlines \
+of an Adventure that never was.$n$nSYSTEM ERROR: ");
+ output(str);
+ output("$n$n");
+
+ if (logflg)
+ fclose(logfil);
+ newline();
+
+#ifdef __amiga__
+#ifdef AZTEC_C
+ {
+ char buf[80];
+
+ if (con) { /* Running from WB, wait for user ack. */
+ printf("press RETURN to quit");
+ gets(buf);
+ }
+ }
+#endif
+#endif
+
+ terminate(0);
+}
+
+
+/*======================================================================
+
+ error()
+
+ Print an error message, force new player input and abort.
+
+ */
+#ifdef _PROTOTYPES_
+void error(MsgKind msgno) /* IN - The error message number */
+#else
+void error(msgno)
+ MsgKind msgno; /* IN - The error message number */
+#endif
+{
+ if (msgno != MSGMAX)
+ prmsg(msgno);
+ wrds[wrdidx] = EOF; /* Force new player input */
+ dscrstkp = 0; /* Reset describe stack */
+
+ //longjmp(jmpbuf,TRUE);
+ ::error("Error occurred");
+}
+
+
+/*======================================================================
+
+ statusline()
+
+ Print the the status line on the top of the screen.
+
+ */
+void statusline(void)
+{
+#ifdef GLK
+ uint glkWidth;
+ char line[100];
+ int pcol = col;
+ uint i;
+
+ if (NULL == glkStatusWin)
+ return;
+
+ g_vm->glk_set_window(glkStatusWin);
+ g_vm->glk_window_clear(glkStatusWin);
+ g_vm->glk_window_get_size(glkStatusWin, &glkWidth, NULL);
+
+ g_vm->glk_set_style(style_User1);
+ for (i = 0; i < glkWidth; i++)
+ g_vm->glk_put_char(' ');
+
+ col = 1;
+ g_vm->glk_window_move_cursor(glkStatusWin, 1, 0);
+needsp = FALSE;
+ say(where(HERO));
+ if (header->maxscore > 0)
+ sprintf(line, "Score %d(%d)/%d moves", cur.score, (int)header->maxscore, cur.tick);
+ else
+ sprintf(line, "%d moves", cur.tick);
+ g_vm->glk_window_move_cursor(glkStatusWin, glkWidth - col - strlen(line), 0);
+ printf(line);
+ needsp = FALSE;
+
+ col = pcol;
+
+ g_vm->glk_set_window(glkMainWin);
+#else
+#ifdef HAVE_ANSI
+ char line[100];
+ int i;
+ int pcol = col;
+
+ if (!statusflg) return;
+ /* ansi_position(1,1); ansi_bold_on(); */
+ printf("\x1b[1;1H");
+ printf("\x1b[7m");
+ col = 1;
+ say(where(HERO));
+ if (header->maxscore > 0)
+ sprintf(line, "Score %ld(%ld)/%ld moves", cur.score, (int)header->maxscore, cur.tick);
+ else
+ sprintf(line, "%ld moves", cur.tick);
+ for (i=0; i < pagwidth - col - strlen(line); i++) putchar(' ');
+ printf(line);
+ printf("\x1b[m");
+ printf("\x1b[%d;1H", paglen);
+ needsp = FALSE;
+
+ col = pcol;
+#endif
+#endif
+}
+
+
+/*======================================================================
+
+ logprint()
+
+ Print some text and log it if logging is on.
+
+ */
+void logprint(char str[])
+{
+ printf(str);
+ if (logflg)
+ fprintf(logfil, "%s", str);
+}
+
+
+
+/*======================================================================
+
+ newline()
+
+ Make a newline, but check for screen full.
+
+ */
+#ifdef _PROTOTYPES_
+void newline(void)
+#else
+void newline()
+#endif
+{
+#ifdef GLK
+ g_vm->glk_put_char('\n');
+#else
+ char buf[256];
+
+ col = 1;
+ if (lin >= paglen - 1) {
+ logprint("\n");
+ needsp = FALSE;
+ prmsg(M_MORE);
+#ifdef USE_READLINE
+ (void) readline(buf);
+#else
+ fgets(buf, 256, stdin);
+#endif
+ getPageSize();
+ lin = 0;
+ } else
+ logprint("\n");
+
+ lin++;
+ needsp = FALSE;
+#endif
+}
+
+
+/*======================================================================
+
+ para()
+
+ Make a new paragraph, i.e one empty line (one or two newlines).
+
+ */
+#ifdef _PROTOTYPES_
+void para(void)
+#else
+void para()
+#endif
+{
+ if (col != 1)
+ newline();
+ newline();
+}
+
+
+/*======================================================================
+
+ clear()
+
+ Clear the screen.
+
+ */
+#ifdef _PROTOTYPES_
+void clear(void)
+#else
+void clear()
+#endif
+{
+#ifdef GLK
+ g_vm->glk_window_clear(glkMainWin);
+#else
+#ifdef HAVE_ANSI
+ if (!statusflg) return;
+ printf("\x1b[2J");
+ printf("\x1b[%d;1H", paglen);
+#endif
+#endif
+}
+
+
+/*======================================================================
+
+ allocate()
+
+ Safely allocate new memory.
+
+*/
+#ifdef _PROTOTYPES_
+void *allocate(unsigned long len) /* IN - Length to allocate */
+#else
+void *allocate(len)
+ unsigned long len; /* IN - Length to allocate */
+#endif
+{
+ void *p = (void *)malloc((size_t)len);
+
+ if (p == NULL)
+ syserr("Out of memory.");
+
+ return p;
+}
+
+
+/*----------------------------------------------------------------------
+
+ just()
+
+ Justify a string so that it wraps at end of screen.
+
+ */
+#ifdef _PROTOTYPES_
+static void just(char str[])
+#else
+static void just(str)
+ char str[];
+#endif
+{
+#ifdef GLK
+ logprint(str);
+#else
+ int i;
+ char ch;
+
+ if (col >= pagwidth && !skipsp)
+ newline();
+
+ while (strlen(str) > pagwidth - col) {
+ i = pagwidth - col - 1;
+ while (!isSpace(str[i]) && i > 0) /* First find wrap point */
+ i--;
+ if (i == 0 && col == 1) /* If it doesn't fit at all */
+ /* Wrap immediately after this word */
+ while (!isSpace(str[i]) && str[i] != '\0')
+ i++;
+ if (i > 0) { /* If it fits ... */
+ ch = str[i]; /* Save space or NULL */
+ str[i] = '\0'; /* Terminate string */
+ logprint(str); /* and print it */
+ skipsp = FALSE; /* If skipping, now we're done */
+ str[i] = ch; /* Restore character */
+ /* Skip white after printed portion */
+ for (str = &str[i]; isSpace(str[0]) && str[0] != '\0'; str++);
+ }
+ newline(); /* Then start a new line */
+ }
+ logprint(str); /* Print tail */
+ col = col + strlen(str); /* Update column */
+#endif
+}
+
+
+/*----------------------------------------------------------------------
+
+ space()
+
+ Output a space if needed.
+
+ */
+#ifdef _PROTOTYPES_
+static void space(void)
+#else
+static void space()
+#endif
+{
+ if (skipsp)
+ skipsp = FALSE;
+ else {
+ if (needsp) {
+ logprint(" ");
+ col++;
+ }
+ }
+ needsp = FALSE;
+}
+
+
+
+/*----------------------------------------------------------------------
+
+ sayparam()
+
+ A parameter needs to be said, check for words the player used and use
+ them if possible.
+
+*/
+#ifdef _PROTOTYPES_
+static void sayparam(int p)
+#else
+static void sayparam(p)
+ int p;
+#endif
+{
+ int i;
+
+ for (i = 0; i <= p; i++)
+ if (params[i].code == EOF)
+ syserr("Nonexistent parameter referenced.");
+
+ if (params[p].firstWord == EOF) /* Any words he used? */
+ say(params[p].code);
+ else /* Yes, so use them... */
+ for (i = params[p].firstWord; i <= params[p].lastWord; i++) {
+ just((char *)addrTo(dict[wrds[i]].wrd));
+ if (i < params[p].lastWord)
+ just(" ");
+ }
+}
+
+
+/*----------------------------------------------------------------------
+
+ prsym()
+
+ Print an expanded symbolic reference.
+
+ N = newline
+ I = indent on a new line
+ P = new paragraph
+ L = current location name
+ O = current object -> first parameter!
+ V = current verb
+ A = current actor
+ T = tabulation
+ $ = no space needed after this
+ */
+#ifdef _PROTOTYPES_
+static void prsym(
+ char *str /* IN - The string starting with '$' */
+)
+#else
+static void prsym(str)
+ char *str; /* IN - The string starting with '$' */
+#endif
+{
+ switch (toLower(str[1])) {
+ case 'n':
+ newline();
+ needsp = FALSE;
+ break;
+ case 'i':
+ newline();
+ logprint(" ");
+ col = 5;
+ needsp = FALSE;
+ break;
+ case 'o':
+ sayparam(0);
+ needsp = TRUE; /* We did print something non-white */
+ break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ sayparam(str[1]-'1');
+ needsp = TRUE; /* We did print something non-white */
+ break;
+ case 'l':
+ say(cur.loc);
+ needsp = TRUE; /* We did print something non-white */
+ break;
+ case 'a':
+ say(cur.act);
+ needsp = TRUE; /* We did print something non-white */
+ break;
+ case 'v':
+ just((char *)addrTo(dict[vrbwrd].wrd));
+ needsp = TRUE; /* We did print something non-white */
+ break;
+ case 'p':
+ para();
+ needsp = FALSE;
+ break;
+ case 't': {
+ int i;
+ int spaces = 4-(col-1)%4;
+
+ for (i = 0; i<spaces; i++) logprint(" ");
+ col = col + spaces;
+ needsp = FALSE;
+ break;
+ }
+ case '$':
+ skipsp = TRUE;
+ break;
+ default:
+ logprint("$");
+ break;
+ }
+}
+
+
+
+/*======================================================================
+
+ output()
+
+ Output a string to suit the screen. Any symbolic inserts ('$') are
+ recogniced and performed.
+
+ */
+#ifdef _PROTOTYPES_
+void output(char original[])
+#else
+void output(original)
+ char original[];
+#endif
+{
+ char ch;
+ char *str, *copy;
+ char *symptr;
+
+ copy = strdup(original);
+ str = copy;
+
+ if (str[0] != '$' || str[1] != '$')
+ space(); /* Output space if needed (& not inhibited) */
+
+ while ((symptr = strchr(str, '$')) != (char *) NULL) {
+ ch = *symptr; /* Terminate before symbol */
+ *symptr = '\0';
+ if (strlen(str) > 0) {
+ just(str); /* Output part before '$' */
+ if (str[strlen(str)-1] == ' ')
+ needsp = FALSE;
+ }
+ *symptr = ch; /* restore '$' */
+ prsym(symptr); /* Print the symbolic reference */
+ str = &symptr[2]; /* Advance to after symbol and continue */
+ }
+ if (str[0] != 0) {
+ just(str); /* Output trailing part */
+ skipsp = FALSE;
+ if (str[strlen(str)-1] != ' ')
+ needsp = TRUE;
+ }
+ anyOutput = TRUE;
+ free(copy);
+}
+
+
+/*======================================================================
+
+ prmsg()
+
+ Print a message from the message table.
+
+ */
+#ifdef _PROTOTYPES_
+void prmsg(MsgKind msg) /* IN - message number */
+#else
+void prmsg(msg)
+ MsgKind msg; /* IN - message number */
+#endif
+{
+ interpret(msgs[msg].stms);
+}
+
+
+/*----------------------------------------------------------------------*\
+
+ Various check functions
+
+ endOfTable()
+ isObj, isLoc, isAct, IsCnt & isNum
+
+\*----------------------------------------------------------------------*/
+
+/* How to know we are at end of a table */
+#ifdef _PROTOTYPES_
+Boolean eot(Aword *adr)
+#else
+Boolean eot(adr)
+ Aword *adr;
+#endif
+{
+ return *adr == EOF;
+}
+
+
+#ifdef _PROTOTYPES_
+Boolean isObj(Aword x)
+#else
+Boolean isObj(x)
+ Aword x;
+#endif
+{
+ return x >= OBJMIN && x <= OBJMAX;
+}
+
+#ifdef _PROTOTYPES_
+Boolean isCnt(Aword x)
+#else
+Boolean isCnt(x)
+ Aword x;
+#endif
+{
+ return (x >= CNTMIN && x <= CNTMAX) ||
+ (isObj(x) && objs[x-OBJMIN].cont != 0) ||
+ (isAct(x) && acts[x-ACTMIN].cont != 0);
+}
+
+#ifdef _PROTOTYPES_
+Boolean isAct(Aword x)
+#else
+Boolean isAct(x)
+ Aword x;
+#endif
+{
+ return x >= ACTMIN && x <= ACTMAX;
+}
+
+#ifdef _PROTOTYPES_
+Boolean isLoc(Aword x)
+#else
+Boolean isLoc(x)
+ Aword x;
+#endif
+{
+ return x >= LOCMIN && x <= LOCMAX;
+}
+
+#ifdef _PROTOTYPES_
+Boolean isNum(Aword x)
+#else
+Boolean isNum(x)
+ Aword x;
+#endif
+{
+ return x >= LITMIN && x <= LITMAX && litValues[x-LITMIN].type == TYPNUM;
+}
+
+#ifdef _PROTOTYPES_
+Boolean isStr(Aword x)
+#else
+Boolean isStr(x)
+ Aword x;
+#endif
+{
+ return x >= LITMIN && x <= LITMAX && litValues[x-LITMIN].type == TYPSTR;
+}
+
+#ifdef _PROTOTYPES_
+Boolean isLit(Aword x)
+#else
+Boolean isLit(x)
+ Aword x;
+#endif
+{
+ return x >= LITMIN && x <= LITMAX;
+}
+
+
+
+/*======================================================================
+
+ exitto()
+
+ Is there an exit from one location to another?
+
+ */
+#ifdef _PROTOTYPES_
+Boolean exitto(int to, int from)
+#else
+Boolean exitto(to, from)
+ int to, from;
+#endif
+{
+ ExtElem *ext;
+
+ if (locs[from-LOCMIN].exts == 0)
+ return(FALSE); /* No exits */
+
+ for (ext = (ExtElem *) addrTo(locs[from-LOCMIN].exts); !endOfTable(ext); ext++)
+ if (ext->next == to)
+ return(TRUE);
+
+ return(FALSE);
+}
+
+
+
+#ifdef CHECKOBJ
+/*======================================================================
+
+ checkobj()
+
+ Check that the object given is valid, else print an error message
+ or find out what he wanted.
+
+ This routine is not used any longer, kept for sentimental reasons ;-)
+
+ */
+void checkobj(obj)
+ Aword *obj;
+{
+ Aword oldobj;
+
+ if (*obj != EOF)
+ return;
+
+ oldobj = EOF;
+ for (cur.obj = OBJMIN; cur.obj <= OBJMAX; cur.obj++) {
+ /* If an object is present and it is possible to perform his action */
+ if (isHere(cur.obj) && possible())
+ if (oldobj == EOF)
+ oldobj = cur.obj;
+ else
+ error(WANT); /* And we didn't find multiple objects */
+ }
+
+ if (oldobj == EOF)
+ error(WANT); /* But we found ONE */
+
+ *obj = cur.obj = oldobj;
+ output("($o)"); /* Then he surely meant this object */
+}
+#endif
+
+
+
+
+/*----------------------------------------------------------------------
+ count()
+
+ Count the number of items in a container.
+
+ */
+#ifdef _PROTOTYPES_
+static int count(int cnt) /* IN - the container to count */
+#else
+static int count(cnt)
+ int cnt; /* IN - the container to count */
+#endif
+{
+ int i, j = 0;
+
+ for (i = OBJMIN; i <= OBJMAX; i++)
+ if (in(i, cnt))
+ /* Then it's in this container also */
+ j++;
+ return(j);
+}
+
+
+
+/*----------------------------------------------------------------------
+ sumatr()
+
+ Sum the values of one attribute in a container. Recursively.
+
+ */
+#ifdef _PROTOTYPES_
+static int sumatr(
+ Aword atr, /* IN - the attribute to sum over */
+ Aword cnt /* IN - the container to sum */
+)
+#else
+static int sumatr(atr, cnt)
+ Aword atr; /* IN - the attribute to sum over */
+ Aword cnt; /* IN - the container to sum */
+#endif
+{
+ int i;
+ int sum = 0;
+
+ for (i = OBJMIN; i <= OBJMAX; i++)
+ if (objs[i-OBJMIN].loc == cnt) { /* Then it's in this container */
+ if (objs[i-OBJMIN].cont != 0) /* This is also a container! */
+ sum = sum + sumatr(atr, i);
+ sum = sum + attribute(i, atr);
+ }
+ return(sum);
+}
+
+
+
+
+/*======================================================================
+ checklim()
+
+ Checks if a limit for a container is exceeded.
+
+ */
+#ifdef _PROTOTYPES_
+Boolean checklim(
+ Aword cnt, /* IN - Container code */
+ Aword obj /* IN - The object to add */
+)
+#else
+Boolean checklim(cnt, obj)
+ Aword cnt; /* IN - Container code */
+ Aword obj; /* IN - The object to add */
+#endif
+{
+ LimElem *lim;
+ Aword props;
+
+ fail = TRUE;
+ if (!isCnt(cnt))
+ syserr("Checking limits for a non-container.");
+
+ /* Find the container properties */
+ if (isObj(cnt))
+ props = objs[cnt-OBJMIN].cont;
+ else if (isAct(cnt))
+ props = acts[cnt-ACTMIN].cont;
+ else
+ props = cnt;
+
+ if (cnts[props-CNTMIN].lims != 0) { /* Any limits at all? */
+ for (lim = (LimElem *) addrTo(cnts[props-CNTMIN].lims); !endOfTable(lim); lim++)
+ if (lim->atr == 0) {
+ if (count(cnt) >= lim->val) {
+ interpret(lim->stms);
+ return(TRUE); /* Limit check failed */
+ }
+ } else {
+ if (sumatr(lim->atr, cnt) + attribute(obj, lim->atr) > lim->val) {
+ interpret(lim->stms);
+ return(TRUE);
+ }
+ }
+ }
+ fail = FALSE;
+ return(FALSE);
+}
+
+
+
+
+
+/*----------------------------------------------------------------------*\
+
+ Action routines
+
+\*----------------------------------------------------------------------*/
+
+
+
+/*----------------------------------------------------------------------
+ trycheck()
+
+ Tries a check, returns TRUE if it passed, FALSE else.
+
+ */
+#ifdef _PROTOTYPES_
+static Boolean trycheck(
+ Aaddr adr, /* IN - ACODE address to check table */
+ Boolean act /* IN - Act if it fails ? */
+)
+#else
+static Boolean trycheck(adr, act)
+ Aaddr adr; /* IN - ACODE address to check table */
+ Boolean act; /* IN - Act if it fails ? */
+#endif
+{
+ ChkElem *chk;
+
+ chk = (ChkElem *) addrTo(adr);
+ if (chk->exp == 0) {
+ interpret(chk->stms);
+ return(FALSE);
+ } else {
+ while (!endOfTable(chk)) {
+ interpret(chk->exp);
+ if (!(Abool)pop()) {
+ if (act)
+ interpret(chk->stms);
+ return(FALSE);
+ }
+ chk++;
+ }
+ return(TRUE);
+ }
+}
+
+
+/*======================================================================
+ go()
+
+ Move hero in a direction.
+
+ */
+#ifdef _PROTOTYPES_
+void go(int dir)
+#else
+void go(dir)
+ int dir;
+#endif
+{
+ ExtElem *ext;
+ Boolean ok;
+ Aword oldloc;
+
+ ext = (ExtElem *) addrTo(locs[cur.loc-LOCMIN].exts);
+ if (locs[cur.loc-LOCMIN].exts != 0)
+ while (!endOfTable(ext)) {
+ if (ext->code == dir) {
+ ok = TRUE;
+ if (ext->checks != 0) {
+ if (trcflg) {
+ printf("\n<EXIT %d (%s) from %d (", dir,
+ (char *)addrTo(dict[wrds[wrdidx-1]].wrd), cur.loc);
+ debugsay(cur.loc);
+ printf("), Checking:>\n");
+ }
+ ok = trycheck(ext->checks, TRUE);
+ }
+ if (ok) {
+ oldloc = cur.loc;
+ if (ext->action != 0) {
+ if (trcflg) {
+ printf("\n<EXIT %d (%s) from %d (", dir,
+ (char *)addrTo(dict[wrds[wrdidx-1]].wrd), cur.loc);
+ debugsay(cur.loc);
+ printf("), Executing:>\n");
+ }
+ interpret(ext->action);
+ }
+ /* Still at the same place? */
+ if (where(HERO) == oldloc) {
+ if (trcflg) {
+ printf("\n<EXIT %d (%s) from %d (", dir,
+ (char *)addrTo(dict[wrds[wrdidx-1]].wrd), cur.loc);
+ debugsay(cur.loc);
+ printf("), Moving:>\n");
+ }
+ locate(HERO, ext->next);
+ }
+ }
+ return;
+ }
+ ext++;
+ }
+ error(M_NO_WAY);
+}
+
+
+
+/*----------------------------------------------------------------------
+
+ findalt()
+
+ Find the verb alternative wanted in a verb list and return
+ the address to it.
+
+ */
+#ifdef _PROTOTYPES_
+static AltElem *findalt(
+ Aword vrbsadr, /* IN - Address to start of list */
+ Aword param /* IN - Which parameter to match */
+)
+#else
+static AltElem *findalt(vrbsadr, param)
+ Aword vrbsadr; /* IN - Address to start of list */
+ Aword param; /* IN - Which parameter to match */
+#endif
+{
+ VrbElem *vrb;
+ AltElem *alt;
+
+ if (vrbsadr == 0)
+ return(NULL);
+
+ for (vrb = (VrbElem *) addrTo(vrbsadr); !endOfTable(vrb); vrb++)
+ if (vrb->code == cur.vrb) {
+ for (alt = (AltElem *) addrTo(vrb->alts); !endOfTable(alt); alt++)
+ if (alt->param == param || alt->param == 0)
+ return alt;
+ return NULL;
+ }
+ return NULL;
+}
+
+
+
+
+/*======================================================================
+
+ possible()
+
+ Check if current action is possible according to the CHECKs.
+
+ */
+#ifdef _PROTOTYPES_
+Boolean possible(void)
+#else
+Boolean possible()
+#endif
+{
+ AltElem *alt[MAXPARAMS+2]; /* List of alt-pointers, one for each param */
+ int i; /* Parameter index */
+
+ fail = FALSE;
+ alt[0] = findalt(header->vrbs, 0);
+ /* Perform global checks */
+ if (alt[0] != 0 && alt[0]->checks != 0) {
+ if (!trycheck(alt[0]->checks, FALSE)) return FALSE;
+ if (fail) return FALSE;
+ }
+
+ /* Now CHECKs in this location */
+ alt[1] = findalt(locs[cur.loc-LOCMIN].vrbs, 0);
+ if (alt[1] != 0 && alt[1]->checks != 0)
+ if (!trycheck(alt[1]->checks, FALSE))
+ return FALSE;
+
+ for (i = 0; params[i].code != EOF; i++) {
+ alt[i+2] = findalt(objs[params[i].code-OBJMIN].vrbs, i+1);
+ /* CHECKs in a possible parameter */
+ if (alt[i+2] != 0 && alt[i+2]->checks != 0)
+ if (!trycheck(alt[i+2]->checks, FALSE))
+ return FALSE;
+ }
+
+ for (i = 0; i < 2 || params[i-2].code != EOF; i++)
+ if (alt[i] != 0 && alt[i]->action != 0)
+ break;
+ if (i >= 2 && params[i-2].code == EOF)
+ /* Didn't find any code for this verb/object combination */
+ return FALSE;
+ else
+ return TRUE;
+}
+
+
+
+/*----------------------------------------------------------------------
+
+ do_it()
+
+ Execute the action commanded by hero.
+
+ */
+#ifdef _PROTOTYPES_
+static void do_it(void)
+#else
+static void do_it()
+#endif
+{
+ AltElem *alt[MAXPARAMS+2]; /* List of alt-pointers, one for each param */
+ Boolean done[MAXPARAMS+2]; /* Is it done */
+ int i; /* Parameter index */
+ char trace[80]; /* Trace string buffer */
+
+ fail = FALSE;
+ alt[0] = findalt(header->vrbs, 0);
+ /* Perform global checks */
+ if (alt[0] != 0 && alt[0]->checks != 0) {
+ if (trcflg)
+ printf("\n<VERB %d, CHECK, GLOBAL:>\n", cur.vrb);
+ if (!trycheck(alt[0]->checks, TRUE)) return;
+ if (fail) return;
+ }
+
+ /* Now CHECKs in this location */
+ alt[1] = findalt(locs[cur.loc-LOCMIN].vrbs, 0);
+ if (alt[1] != 0 && alt[1]->checks != 0) {
+ if (trcflg)
+ printf("\n<VERB %d, CHECK, in LOCATION:>\n", cur.vrb);
+ if (!trycheck(alt[1]->checks, TRUE)) return;
+ if (fail) return;
+ }
+
+ for (i = 0; params[i].code != EOF; i++) {
+ if (isLit(params[i].code))
+ alt[i+2] = 0;
+ else {
+ if (isObj(params[i].code))
+ alt[i+2] = findalt(objs[params[i].code-OBJMIN].vrbs, i+1);
+ else if (isAct(params[i].code))
+ alt[i+2] = findalt(acts[params[i].code-ACTMIN].vrbs, i+1);
+ else
+ syserr("Illegal parameter type.");
+ /* CHECKs in the parameters */
+ if (alt[i+2] != 0 && alt[i+2]->checks != 0) {
+ if (trcflg)
+ printf("\n<VERB %d, CHECK, in Parameter #%d:>\n", cur.vrb, i);
+ if (!trycheck(alt[i+2]->checks, TRUE)) return;
+ if (fail) return;
+ }
+ }
+ }
+
+ /* Check for anything to execute... */
+ for (i = 0; i < 2 || params[i-2].code != EOF; i++)
+ if (alt[i] != 0 && alt[i]->action != 0)
+ break;
+ if (i >= 2 && params[i-2].code == EOF)
+ /* Didn't find any code for this verb/object combination */
+ error(M_CANT0);
+
+ /* Perform actions! */
+
+ /* First try any BEFORE or ONLY from outside in */
+ done[0] = FALSE;
+ done[1] = FALSE;
+ for (i = 2; params[i-2].code != EOF; i++)
+ done[i] = FALSE;
+ i--;
+ while (i >= 0) {
+ if (alt[i] != 0)
+ if (alt[i]->qual == (Aword)Q_BEFORE || alt[i]->qual == (Aword)Q_ONLY) {
+ if (alt[i]->action != 0) {
+ if (trcflg) {
+ if (i == 0)
+ strcpy(trace, "GLOBAL");
+ else if (i == 1)
+ strcpy(trace, "in LOCATION");
+ else
+ sprintf(trace, "in PARAMETER %d", i-1);
+ if (alt[i]->qual == (Aword)Q_BEFORE)
+ printf("\n<VERB %d, %s (BEFORE), Body:>\n", cur.vrb, trace);
+ else
+ printf("\n<VERB %d, %s (ONLY), Body:>\n", cur.vrb, trace);
+ }
+ interpret(alt[i]->action);
+ if (fail) return;
+ if (alt[i]->qual == (Aword)Q_ONLY) return;
+ }
+ done[i] = TRUE;
+ }
+ i--;
+ }
+
+ /* Then execute any not declared as AFTER, i.e. the default */
+ for (i = 0; i < 2 || params[i-2].code != EOF; i++) {
+ if (alt[i] != 0)
+ if (alt[i]->qual != (Aword)Q_AFTER) {
+ if (!done[i] && alt[i]->action != 0) {
+ if (trcflg) {
+ if (i == 0)
+ strcpy(trace, "GLOBAL");
+ else if (i == 1)
+ strcpy(trace, "in LOCATION");
+ else
+ sprintf(trace, "in PARAMETER %d", i-1);
+ printf("\n<VERB %d, %s, Body:>\n", cur.vrb, trace);
+ }
+ interpret(alt[i]->action);
+ if (fail) return;
+ }
+ done[i] = TRUE;
+ }
+ }
+
+ /* Finally, the ones declared as after */
+ i--;
+ while (i >= 0) {
+ if (alt[i] != 0)
+ if (!done[i] && alt[i]->action != 0) {
+ if (trcflg) {
+ if (i == 0)
+ strcpy(trace, "GLOBAL");
+ else if (i == 1)
+ strcpy(trace, "in LOCATION");
+ else
+ sprintf(trace, "in PARAMETER %d", i-1);
+ printf("\n<VERB %d, %s (AFTER), Body:>\n", cur.vrb, trace);
+ }
+ interpret(alt[i]->action);
+ if (fail) return;
+ }
+ i--;
+ }
+}
+
+
+
+/*======================================================================
+
+ action()
+
+ Execute all activities commanded. Handles possible multiple actions
+ such as THEM or lists of objects.
+
+ */
+#ifdef _PROTOTYPES_
+void action(
+ ParamElem plst[] /* IN - Plural parameter list */
+)
+#else
+void action(plst)
+ ParamElem plst[];
+#endif
+{
+ int i, mpos;
+ char marker[10];
+
+ if (plural) {
+ /*
+ The code == 0 means this is a multiple position. We must loop
+ over this position (and replace it by each present in the plst)
+ */
+ for (mpos = 0; params[mpos].code != 0; mpos++); /* Find multiple position */
+ sprintf(marker, "($%d)", mpos+1); /* Prepare a printout with $1/2/3 */
+ for (i = 0; plst[i].code != EOF; i++) {
+ params[mpos] = plst[i];
+ output(marker);
+ do_it();
+ if (plst[i+1].code != EOF)
+ para();
+ }
+ params[mpos].code = 0;
+ } else
+ do_it();
+}
+
+
+
+/*----------------------------------------------------------------------*\
+
+ Event Handling
+
+ eventchk()
+
+\*----------------------------------------------------------------------*/
+
+
+/*----------------------------------------------------------------------
+ eventchk()
+
+ Check if any events are pending. If so execute them.
+ */
+#ifdef _PROTOTYPES_
+static void eventchk(void)
+#else
+static void eventchk()
+#endif
+{
+ while (etop != 0 && eventq[etop-1].time == cur.tick) {
+ etop--;
+ if (isLoc(eventq[etop].where))
+ cur.loc = eventq[etop].where;
+ else
+ cur.loc = where(eventq[etop].where);
+ if (trcflg) {
+ printf("\n<EVENT %d (at ", eventq[etop].event);
+ debugsay(cur.loc);
+ printf("):>\n");
+ }
+ interpret(evts[eventq[etop].event-EVTMIN].code);
+ }
+}
+
+
+
+
+
+/*----------------------------------------------------------------------*\
+
+ Main program and initialisation
+
+ codfil
+ filenames
+
+ checkvers()
+ load()
+ checkdebug()
+ initheader()
+ initstrings()
+ start()
+ init()
+ main()
+
+\*----------------------------------------------------------------------*/
+
+
+Common::SeekableReadStream *codfil;
+char codfnm[256];
+static char txtfnm[256];
+static char logfnm[256];
+
+
+/*----------------------------------------------------------------------
+
+ checkvers()
+
+ */
+#ifdef _PROTOTYPES_
+static void checkvers(AcdHdr *header)
+#else
+static void checkvers(header)
+ AcdHdr *header;
+#endif
+{
+ char vers[4];
+ char state[2];
+
+ /* Construct our own version */
+ vers[0] = alan.version.version;
+ vers[1] = alan.version.revision;
+
+ /* Check version of .ACD file */
+ if (dbgflg) {
+ state[0] = header->vers[3];
+ state[1] = '\0';
+ printf("<Version of '%s' is %d.%d(%d)%s>",
+ advnam,
+ (int)(header->vers[0]),
+ (int)(header->vers[1]),
+ (int)(header->vers[2]),
+ (header->vers[3])==0? "": state);
+ newline();
+ }
+
+ /* Compatible if version and revision match... */
+ if (strncmp(header->vers, vers, 2) != 0) {
+#ifdef V25COMPATIBLE
+ if (header->vers[0] == 2 && header->vers[1] == 5) /* Check for 2.5 version */
+ /* This we can convert later if needed... */;
+ else
+#endif
+#ifdef V27COMPATIBLE
+ if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
+ /* This we can convert later if needed... */;
+ else
+#endif
+ if (errflg) {
+ char str[80];
+ sprintf(str, "Incompatible version of ACODE program. Game is %ld.%ld, interpreter %ld.%ld.",
+ (long) (header->vers[0]),
+ (long) (header->vers[1]),
+ (long) alan.version.version,
+ (long) alan.version.revision);
+ syserr(str);
+ } else
+ output("<WARNING! Incompatible version of ACODE program.>\n");
+ }
+}
+
+
+/*----------------------------------------------------------------------
+
+ load()
+
+ */
+#ifdef _PROTOTYPES_
+static void load(void)
+#else
+static void load()
+#endif
+{
+ AcdHdr tmphdr;
+ Aword crc = 0;
+ int i;
+ char err[100];
+
+ codfil->seek(0);
+ tmphdr.load(*codfil);
+ checkvers(&tmphdr);
+
+ /* Allocate and load memory */
+
+#ifdef REVERSED
+ reverseHdr(&tmphdr);
+#endif
+
+ /* No memory allocated yet? */
+ if (memory == NULL) {
+#ifdef V25COMPATIBLE
+ if (tmphdr.vers[0] == 2 && tmphdr.vers[1] == 5)
+ /* We need some more memory to expand 2.5 format*/
+ memory = allocate((tmphdr.size+tmphdr.objmax-tmphdr.objmin+1+2)*sizeof(Aword));
+ else
+#endif
+ memory = (Aword *)allocate(tmphdr.size * sizeof(Aword));
+ }
+ header = (AcdHdr *) addrTo(0);
+
+ if ((tmphdr.size * sizeof(Aword)) > codfil->size())
+ ::error("Header size is greater than filesize");
+
+ codfil->seek(0);
+ Aword *ptr = addrTo(0);
+ for (int idx = 0; idx < tmphdr.size; ++idx, ++ptr)
+ *ptr = codfil->readUint32LE();
+
+ /* Calculate checksum */
+ for (i = sizeof(tmphdr)/sizeof(Aword); i < memTop; i++) {
+ crc += memory[i]&0xff;
+ crc += (memory[i]>>8)&0xff;
+ crc += (memory[i]>>16)&0xff;
+ crc += (memory[i]>>24)&0xff;
+#ifdef CRCLOG
+ printf("%6x\t%6lx\t%6lx\n", i, crc, memory[i]);
+#endif
+ }
+ if (crc != tmphdr.acdcrc) {
+ sprintf(err, "Checksum error in .ACD file (0x%lx instead of 0x%lx).",
+ (unsigned long) crc, (unsigned long) tmphdr.acdcrc);
+ if (errflg)
+ syserr(err);
+ else {
+ output("<WARNING! $$");
+ output(err);
+ output("$$ Ignored, proceed at your own risk.>$n");
+ }
+ }
+
+#ifdef REVERSED
+ if (dbgflg||trcflg||stpflg)
+ output("<Hmm, this is a little-endian machine, fixing byte ordering....");
+ reverseACD(tmphdr.vers[0] == 2 && tmphdr.vers[1] == 5); /* Reverse all words in the ACD file */
+ if (dbgflg||trcflg||stpflg)
+ output("OK.>$n");
+#endif
+
+#ifdef V25COMPATIBLE
+ /* Check for 2.5 version */
+ if (tmphdr.vers[0] == 2 && tmphdr.vers[1] == 5) {
+ if (dbgflg||trcflg||stpflg)
+ output("<Hmm, this is a v2.5 game, please wait while I convert it...");
+ c25to26ACD();
+ if (dbgflg||trcflg||stpflg)
+ output("OK.>$n");
+ }
+#endif
+
+}
+
+
+/*----------------------------------------------------------------------
+
+ checkdebug()
+
+ */
+#ifdef _PROTOTYPES_
+static void checkdebug(void)
+#else
+static void checkdebug()
+#endif
+{
+ /* Make sure he can't debug if not allowed! */
+ if (!header->debug) {
+ if (dbgflg|trcflg|stpflg)
+ printf("<Sorry, '%s' is not compiled for debug!>\n", advnam);
+ para();
+ dbgflg = FALSE;
+ trcflg = FALSE;
+ stpflg = FALSE;
+ }
+
+#ifndef GLK
+ if (dbgflg) /* If debugging */
+ srand(0); /* use no randomization */
+ else
+ srand(time(0)); /* seed random generator */
+#endif
+}
+
+
+/*----------------------------------------------------------------------
+
+ initheader()
+
+ */
+#ifdef _PROTOTYPES_
+static void initheader(void)
+#else
+static void initheader()
+#endif
+{
+ dict = (WrdElem *) addrTo(header->dict);
+ /* Find out number of entries in dictionary */
+ for (dictsize = 0; !endOfTable(&dict[dictsize]); dictsize++);
+ vrbs = (VrbElem *) addrTo(header->vrbs);
+ stxs = (StxElem *) addrTo(header->stxs);
+ locs = (LocElem *) addrTo(header->locs);
+ acts = (ActElem *) addrTo(header->acts);
+ objs = (ObjElem *) addrTo(header->objs);
+ evts = (EvtElem *) addrTo(header->evts);
+ cnts = (CntElem *) addrTo(header->cnts);
+ ruls = (RulElem *) addrTo(header->ruls);
+ msgs = (MsgElem *) addrTo(header->msgs);
+ scores = (Aword *) addrTo(header->scores);
+
+ if (header->pack)
+ freq = (Aword *) addrTo(header->freq);
+}
+
+
+/*----------------------------------------------------------------------
+
+ initstrings()
+
+ */
+#ifdef _PROTOTYPES_
+static void initstrings(void)
+#else
+static void initstrings()
+#endif
+{
+ IniElem *init;
+
+ for (init = (IniElem *) addrTo(header->init); !endOfTable(init); init++) {
+ getstr(init->fpos, init->len);
+ memory[init->adr] = pop();
+ }
+}
+
+
+/*----------------------------------------------------------------------
+
+ start()
+
+ */
+#ifdef _PROTOTYPES_
+static void start(void)
+#else
+static void start()
+#endif
+{
+ int startloc;
+
+ cur.tick = -1;
+ cur.loc = startloc = where(HERO);
+ cur.act = HERO;
+ cur.score = 0;
+ if (trcflg)
+ printf("\n<START:>\n");
+ interpret(header->start);
+ para();
+
+ acts[HERO-ACTMIN].loc = 0;
+ locate(HERO, startloc);
+}
+
+
+
+/*----------------------------------------------------------------------
+ init()
+
+ Initialization, program load etc.
+
+ */
+#ifdef _PROTOTYPES_
+static void init(void)
+#else
+static void init()
+#endif
+{
+ int i;
+
+ /* Initialise some status */
+ etop = 0; /* No pending events */
+ looking = FALSE; /* Not looking now */
+ dscrstkp = 0; /* No describe in progress */
+
+ load();
+
+ initheader();
+ checkdebug();
+
+ /* Initialise string attributes */
+ initstrings();
+
+ getPageSize();
+
+ /* Find first conjunction and use that for ',' handling */
+ for (i = 0; i < dictsize; i++)
+ if (isConj(i)) {
+ conjWord = i;
+ break;
+ }
+
+ /* Start the adventure */
+ clear();
+ start();
+}
+
+
+
+/*----------------------------------------------------------------------
+ movactor()
+
+ Let the current actor move. If player, ask him.
+
+ */
+#ifdef _PROTOTYPES_
+static void movactor(void)
+#else
+static void movactor()
+#endif
+{
+ ScrElem *scr;
+ StepElem *step;
+ ActElem *act = (ActElem *) &acts[cur.act-ACTMIN];
+
+ cur.loc = where(cur.act);
+ if (cur.act == HERO) {
+ parse();
+ fail = FALSE; /* fail only aborts one actor */
+ rules();
+ } else if (act->script != 0) {
+ for (scr = (ScrElem *) addrTo(act->scradr); !endOfTable(scr); scr++)
+ if (scr->code == act->script) {
+ /* Find correct step in the list by indexing */
+ step = (StepElem *) addrTo(scr->steps);
+ step = (StepElem *) &step[act->step];
+ /* Now execute it, maybe. First check wait count */
+ if (step->after > act->count) {
+ /* Wait some more */
+ if (trcflg) {
+ printf("\n<ACTOR %d, ", cur.act);
+ debugsay(cur.act);
+ printf(" (at ");
+ debugsay(cur.loc);
+ printf("), SCRIPT %ld, STEP %ld, Waiting %ld more>\n",
+ act->script, act->step+1, step->after-act->count);
+ }
+ act->count++;
+ rules();
+ return;
+ } else
+ act->count = 0;
+ /* Then check possible expression */
+ if (step->exp != 0) {
+ if (trcflg) {
+ printf("\n<ACTOR %d, ", cur.act);
+ debugsay(cur.act);
+ printf(" (at ");
+ debugsay(cur.loc);
+ printf("), SCRIPT %ld, STEP %ld, Evaluating:>\n",
+ act->script, act->step+1);
+ }
+ interpret(step->exp);
+ if (!(Abool)pop()) {
+ rules();
+ return; /* Hadn't happened yet */
+ }
+ }
+ /* OK, so finally let him do his thing */
+ act->step++; /* Increment step number before executing... */
+ if (trcflg) {
+ printf("\n<ACTOR %d, ", cur.act);
+ debugsay(cur.act);
+ printf(" (at ");
+ debugsay(cur.loc);
+ printf("), SCRIPT %ld, STEP %ld, Executing:>\n",
+ act->script, act->step);
+ }
+ interpret(step->stm);
+ step++;
+ /* ... so that we can see if he is USEing another script now */
+ if (act->step != 0 && endOfTable(step))
+ /* No more steps in this script, so stop him */
+ act->script = 0;
+ fail = FALSE; /* fail only aborts one actor */
+ rules();
+ return;
+ }
+ syserr("Unknown actor script.");
+ } else if (trcflg) {
+ printf("\n<ACTOR %d, ", cur.act);
+ debugsay(cur.act);
+ printf(" (at ");
+ debugsay(cur.loc);
+ printf("), Idle>\n");
+ rules();
+ return;
+ }
+}
+
+/*----------------------------------------------------------------------
+
+ openFiles()
+
+ Open the necessary files.
+
+ */
+#ifdef _PROTOTYPES_
+static void openFiles(void)
+#else
+static void openFiles()
+#endif
+{
+ char str[256];
+ char *usr = "";
+ time_t tick;
+
+#ifndef GLK
+ /* Open Acode file */
+ strcpy(codfnm, advnam);
+ strcat(codfnm, ".acd");
+
+ if ((codfil = fopen(codfnm, READ_MODE)) == NULL) {
+ strcpy(str, "Can't open adventure code file '");
+ strcat(str, codfnm);
+ strcat(str, "'.");
+ syserr(str);
+ }
+#endif
+
+#ifdef GARGLK
+ {
+ char *s = strrchr(codfnm, '\\');
+ if (!s) s = strrchr(codfnm, '/');
+ g_vm->garglk_set_story_name(s ? s + 1 : codfnm);
+ }
+#endif
+
+ /* Open Text file */
+ strcpy(txtfnm, advnam);
+ strcat(txtfnm, ".dat");
+
+ Common::File *f = new Common::File();
+ if (!f->open(txtfnm)) {
+ delete f;
+ Common::String s = Common::String::format("Can't open adventure text data file '%s'.", txtfnm);
+ ::error(s.c_str());
+ }
+
+ // If logging open log file
+ if (logflg) {
+ sprintf(logfnm, "%s.log", advnam);
+ logfil = g_system->getSavefileManager()->openForSaving(logfnm);
+
+ logflg = logfil != nullptr;
+ }
+}
+
+
+/*======================================================================
+
+ run()
+
+ Run the adventure
+
+ */
+void run(void)
+{
+ openFiles();
+
+ //setjmp(restart_label); /* Return here if he wanted to restart */
+
+ init(); /* Load, initialise and start the adventure */
+
+ while (TRUE) {
+#ifdef MALLOC
+ if (malloc_verify() == 0) syserr("Error in heap.");
+#endif
+ if (dbgflg)
+ debug();
+
+ eventchk();
+ cur.tick++;
+// (void) setjmp(jmpbuf);
+
+ /* Move all characters */
+ for (cur.act = ACTMIN; cur.act <= ACTMAX; cur.act++)
+ movactor();
+ }
+}
+
+} // End of namespace Alan2
+} // End of namespace Glk
diff --git a/engines/glk/alan2/main.h b/engines/glk/alan2/main.h
index 48c6d96382..7262a32c05 100644
--- a/engines/glk/alan2/main.h
+++ b/engines/glk/alan2/main.h
@@ -65,6 +65,7 @@ extern int dictsize; /* Number of entries in dictionary */
/* The text and message file */
extern Common::File *txtfil;
extern Common::WriteStream *logfil;
+extern Common::SeekableReadStream *codfil;
#undef ftell
#undef fgetc
@@ -79,7 +80,8 @@ extern Common::WriteStream *logfil;
/* File names */
-extern char *advnam;
+extern const char *advnam;
+extern char codfnm[256];
/* Screen formatting info */
extern int col, lin;
diff --git a/engines/glk/alan2/sysdep.cpp b/engines/glk/alan2/sysdep.cpp
index daa0417569..d36722c312 100644
--- a/engines/glk/alan2/sysdep.cpp
+++ b/engines/glk/alan2/sysdep.cpp
@@ -30,6 +30,17 @@
namespace Glk {
namespace Alan2 {
+#ifdef GLK
+extern void fprintf(Common::WriteStream *ws, const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ Common::String s = Common::String::vformat(fmt, args);
+ va_end(args);
+
+ ws->write(s.c_str(), s.size());
+}
+#endif
+
#ifdef _PROTOTYPES_
extern void syserr(char str[]);
#endif
diff --git a/engines/glk/alan2/sysdep.h b/engines/glk/alan2/sysdep.h
index 72769cb271..5e562cd68f 100644
--- a/engines/glk/alan2/sysdep.h
+++ b/engines/glk/alan2/sysdep.h
@@ -37,6 +37,7 @@
*/
#include "common/scummsys.h"
+#include "common/stream.h"
namespace Glk {
namespace Alan2 {
@@ -55,7 +56,7 @@ namespace Alan2 {
#undef rand
#define rand() g_vm->getRandomNumber(0x7fffffff)
#undef fprintf
-#define fprintf(FP, STR) FP->write(STR, strlen(STR) + 1)
+extern void fprintf(Common::WriteStream *ws, const char *fmt, ...);
#endif
/* Place definitions of OS and compiler here if necessary */
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index b87fea9311..3190b09ee6 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -31,6 +31,7 @@ MODULE_OBJS := \
advsys/game.o \
advsys/glk_interface.o \
advsys/vm.o \
+ alan2/acode.o \
alan2/alan2.o \
alan2/detection.o \
alan2/alan_version.o \
@@ -41,6 +42,7 @@ MODULE_OBJS := \
alan2/glkio.o \
alan2/glkstart.o \
alan2/inter.o \
+ alan2/main.o \
alan2/params.o \
alan2/parse.o \
alan2/readline.o \