diff options
38 files changed, 8789 insertions, 282 deletions
diff --git a/engines/glk/alan2/acode.h b/engines/glk/alan2/acode.h new file mode 100644 index 0000000000..5fee277c6c --- /dev/null +++ b/engines/glk/alan2/acode.h @@ -0,0 +1,306 @@ +/* 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. + * + */ + +#ifndef GLK_ALAN2_ACODE +#define GLK_ALAN2_ACODE + +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 int CodeValue; /* Definition for the packing process */ + +#ifdef UNUSED +#if INT_MAX==0x7fffffff +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 int CodeValue; /* Definition for the packing process */ +#elif LONG_MAX==0x7fffffff +typedef unsigned long Aword; /* Type for an ACODE word */ +typedef unsigned long Aaddr; /* Type for an ACODE address */ +typedef unsigned long Abool; /* Type for an ACODE Boolean value */ +typedef signed long Aint; /* Type for an ACODE Integer value */ +typedef long CodeValue; /* Definition for the packing process */ +#else +#error "Can't find a 32-bit integer type" +#endif +#endif + +/* Constants for the Acode file, words/block & bytes/block */ +#define BLOCKLEN 256L +#define BLOCKSIZE (BLOCKLEN*sizeof(Aword)) + + +/* Definitions for the packing process */ +#define VALUEBITS 16 + +#define EOFChar 256 +#define TOPVALUE (((CodeValue)1<<VALUEBITS) - 1) /* Highest value possible */ + +/* Half and quarter points in the code value range */ +#define ONEQUARTER (TOPVALUE/4+1) /* Point after first quarter */ +#define HALF (2*ONEQUARTER) /* Point after first half */ +#define THREEQUARTER (3*ONEQUARTER) /* Point after third quarter */ + + +/* AMACHINE Word Classes */ +typedef int WrdKind; +#define WRD_SYN 0 /* 1 - Synonym */ +#define WRD_ADJ 1 /* 2 - Adjective */ +#define WRD_ALL 2 /* 4 - All */ +#define WRD_BUT 3 /* 8 - But */ +#define WRD_CONJ 4 /* 16 - Conjunction */ +#define WRD_PREP 5 /* 32 - Preposition */ +#define WRD_DIR 6 /* 64 - Direction */ +#define WRD_IT 7 /* 128 - It */ +#define WRD_NOISE 8 /* 256 - Noise word */ +#define WRD_NOUN 9 /* 512 - Noun */ +#define WRD_ACT 10 /* 1024 - Actor */ +#define WRD_THEM 11 /* 2048 - Them */ +#define WRD_VRB 12 /* 4096 - Verb */ +#define WRD_CLASSES 13 + + + +/* Syntax element classifications */ +#define EOS (-2) /* End Of Syntax */ + +/* Syntax element flag bits */ +#define MULTIPLEBIT 0x1 +#define OMNIBIT 0x2 + + +/* Parameter Classes */ +typedef enum ClaKind { /* NOTE! These must have the same order as */ + CLA_OBJ = 1, /* the name classes in NAM.H */ + CLA_CNT = (int)CLA_OBJ<<1, + CLA_ACT = (int)CLA_CNT<<1, + CLA_NUM = (int)CLA_ACT<<1, + CLA_STR = (int)CLA_NUM<<1, + CLA_COBJ = (int)CLA_STR<<1, + CLA_CACT = (int)CLA_COBJ<<1 +} ClaKind; + + +/* Verb Qualifiers */ +typedef enum QualClass { + Q_DEFAULT, + Q_AFTER, + Q_BEFORE, + Q_ONLY +} QualClass; + + +/* The AMACHINE Operations */ +typedef enum OpClass { + C_CONST, + C_STMOP, + C_CURVAR +} OpClass; + +typedef enum InstClass { + I_PRINT, /* Print a string from the text file */ + I_QUIT, + I_LOOK, + I_SAVE, + I_RESTORE, + I_LIST, /* List contents of a container */ + I_EMPTY, + I_SCORE, + I_VISITS, + I_SCHEDULE, + I_CANCEL, + I_LOCATE, + I_MAKE, + I_SET, /* Set a numeric attribute to the */ + /* value on top of stack */ + I_STRSET, /* Set a string valued attribute to a */ + /* copy of the string on top of stack, */ + /* deallocate current contents first */ + I_GETSTR, /* Get a string contents from text */ + /* file, create a copy and push it */ + /* on top of stack */ + I_INCR, /* Increment an attribute */ + I_DECR, /* Decrement a numeric attribute */ + I_USE, + I_IN, + I_DESCRIBE, + I_SAY, + I_SAYINT, + I_SAYSTR, + I_IF, + I_ELSE, + I_ENDIF, + I_ATTRIBUTE, + I_STRATTR, /* Push a copy of a string attribute */ + I_HERE, + I_NEAR, + I_WHERE, + I_AND, + I_OR, + I_NE, + I_EQ, + I_STREQ, /* String compare */ + I_STREXACT, + I_LE, + I_GE, + I_LT, + I_GT, + I_PLUS, + I_MINUS, + I_MULT, + I_DIV, + I_NOT, + I_UMINUS, + I_RND, + I_SUM, /* SUM-aggregate */ + I_MAX, /* MAX-aggregate */ + I_COUNT, /* COUNT-aggregate */ + I_RETURN, + I_SYSTEM, + I_RESTART, /* INTRODUCED: v2.7 */ + I_BTW, /* INTRODUCED: v2.8 */ + I_CONTAINS, /* -""- */ + I_DEPSTART, /* -""- */ + I_DEPCASE, /* -""- */ + I_DEPEXEC, /* -""- */ + I_DEPELSE, /* -""- */ + I_DEPEND /* -""- */ +} InstClass; + + +typedef enum VarClass { + V_PARAM, + V_CURLOC, + V_CURACT, + V_CURVRB, + V_SCORE +} VarClass; + + +#define I_CLASS(x) ((x)>>28) +#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; + +/* Error message numbers */ +typedef enum MsgKind { + M_HUH, /* Obsolete */ + M_WHAT, + M_WHAT_ALL, + M_WHAT_IT, + M_WHAT_THEM, + M_MULTIPLE, + M_WANT, + M_NOUN, + M_AFTER_BUT, + M_BUT_ALL, + M_NOT_MUCH, + M_WHICH_ONE, + M_NO_SUCH, + M_NO_WAY, + M_CANT0, + M_CANT, + M_NOTHING, /* Obsolete */ + M_SEEOBJ1, + M_SEEOBJ2, + M_SEEOBJ3, + M_SEEOBJ4, + M_SEEACT, + M_CONTAINS1, + M_CONTAINS2, + M_CONTAINS3, + M_CONTAINS4, + M_CONTAINS5, + M_EMPTY1, + M_EMPTY2, + M_SCORE1, + M_SCORE2, + M_UNKNOWN_WORD, + M_MORE, + M_AGAIN, + M_SAVEWHERE, + M_SAVEOVERWRITE, + M_SAVEFAILED, + M_SAVEMISSING, + M_SAVEVERS, + M_SAVENAME, + M_RESTOREFROM, + M_REALLY, /* CHANGED: v2.7 from M_RESTART */ + M_QUITACTION, /* INTRODUCED: v2.7, so M_ARTICLE moved */ + M_ARTICLE, /* INTRODUCED: v2.6 but replaced the M_NOMSG*/ + MSGMAX +} MsgKind; + +#define M_ARTICLE26 M_QUITACTION +#define M_MSGMAX26 M_ARTICLE + +} // End of namespace Alan2 +} // End of namespace Glk + +#endif diff --git a/engines/glk/alan2/alan_version.cpp b/engines/glk/alan2/alan_version.cpp new file mode 100644 index 0000000000..d3e1b9dde7 --- /dev/null +++ b/engines/glk/alan2/alan_version.cpp @@ -0,0 +1,45 @@ +/* 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/alan_version.h" + +namespace Glk { +namespace Alan2 { + +Product alan = { + "Alan", + "Adventure Language System", + "Alan 2.8(6)", + "Alan 2.8(6) -- Adventure Language System (2001-07-13 14:35)", + "2001-07-13", + "14:35:07", + "Thomas Nilsson", + "", + "cygwin", + {"2.8(6)", 2, 8, 6, 995034907, ""} +}; + +static char *alanId = + "@(#)RELEASE "; + +} // End of namespace Alan2 +} // End of namespace Glk diff --git a/engines/glk/alan2/alan_version.h b/engines/glk/alan2/alan_version.h new file mode 100644 index 0000000000..1a75394bc5 --- /dev/null +++ b/engines/glk/alan2/alan_version.h @@ -0,0 +1,36 @@ +/* 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. + * + */ + +#ifndef GLK_ALAN2_ALAN_VERSION +#define GLK_ALAN2_ALAN_VERSION + +#include "glk/alan2/version.h" + +namespace Glk { +namespace Alan2 { + +extern Product alan; + +} // End of namespace Alan2 +} // End of namespace Glk + +#endif diff --git a/engines/glk/alan2/args.cpp b/engines/glk/alan2/args.cpp new file mode 100644 index 0000000000..aceb00b67a --- /dev/null +++ b/engines/glk/alan2/args.cpp @@ -0,0 +1,308 @@ +/* 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 <string> +#ifndef __PACIFIC__ +#include "glk/alan2/args.h" +#else +/* I have no idea at all why the include does not work in Pacific C ... */ +extern void args(int argc, char* argv[]); +#endif + +#include "glk/alan2/main.h" + +#ifdef __mac__ +#include "glk/alan2/macArgs.h" +#endif + +#ifdef __amiga__ +#include <libraries/dosextens.h> +#ifdef AZTEC_C +struct FileHandle *con = NULL; +#else +/* Geek Gadgets GCC */ +BPTR window; +BPTR cd; +#endif +#endif + +#ifdef GLK +#include "glk/alan2/alan2.h" +#include "glk/alan2/glkio.h" +#include "glk/alan2/sysdep.h" +#endif + +namespace Glk { +namespace Alan2 { + +#ifdef _PROTOTYPES_ +static void switches( + unsigned argc, + char *argv[] +) +#else +static void switches(argc, argv) + unsigned argc; + char *argv[]; +#endif +{ + uint i; + + advnam = ""; + for (i = 1; i < argc; i++) { + if (argv[i][0] == '-') { +#ifdef GLK + switch (g_vm->glk_char_to_lower(argv[i][1])) { +#else + switch (tolower(argv[i][1])) { +#endif + case 'i': + errflg = FALSE; + break; + case 't': + trcflg = TRUE; + break; + case 'd': + dbgflg = TRUE; + break; + case 's': + trcflg = TRUE; + stpflg = TRUE; + break; + case 'l': + logflg = TRUE; + break; + case 'v': + verbose = TRUE; + break; + case 'n': + statusflg = FALSE; + break; + default: + printf("Unrecognized switch, -%c\n", argv[i][1]); + usage(); + terminate(0); + } + } else { + advnam = argv[i]; + if (strcmp(&advnam[strlen(advnam)-4], ".acd") == 0 + || strcmp(&advnam[strlen(advnam)-4], ".ACD") == 0 + || strcmp(&advnam[strlen(advnam)-4], ".dat") == 0 + || strcmp(&advnam[strlen(advnam)-4], ".DAT") == 0) + advnam[strlen(advnam)-4] = '\0'; + } + } +} + + + +#ifdef __amiga__ + +#include <intuition/intuition.h> +#include <workbench/workbench.h> + +#include <clib/exec_protos.h> +#include <clib/dos_protos.h> +#include <clib/icon_protos.h> + +#include <fcntl.h> + +extern struct Library *IconBase; + +#ifndef AZTEC_C +/* Actually Geek Gadgets GCC with libnix */ + +/* Aztec C has its own pre-main wbparse which was used in Arun 2.7, with GCC we + need to do it ourselves. */ + +#include <clib/intuition_protos.h> + +extern unsigned long *__stdfiledes; /* The libnix standard I/O file descriptors */ + +void +wb_parse(void) +{ + char *cp; + struct DiskObject *dop; + struct FileHandle *fhp; + + if (_WBenchMsg->sm_NumArgs == 1) /* If no argument use program icon/info */ + dop = GetDiskObject((UBYTE *)_WBenchMsg->sm_ArgList[0].wa_Name); + else { + BPTR olddir = CurrentDir(_WBenchMsg->sm_ArgList[1].wa_Lock); + dop = GetDiskObject((UBYTE *)_WBenchMsg->sm_ArgList[1].wa_Name); + CurrentDir(olddir); + } + if (dop != 0 && (cp = (char *)FindToolType((UBYTE **)dop->do_ToolTypes, + (UBYTE *)"WINDOW")) != NULL) + ; + else /* Could not find a WINDOW tool type */ + cp = "CON:10/10/480/160/Arun:Default Window/CLOSE"; + if ((window = Open((UBYTE *)cp, (long)MODE_OLDFILE))) { + fhp = (struct FileHandle *) ((long)window << 2); + SetConsoleTask(fhp->fh_Type); + SelectInput(window); + SelectOutput(window); + __stdfiledes[0] = Input(); + __stdfiledes[1] = Output(); + } else + exit(-1L); + FreeDiskObject(dop); +} +#endif +#endif + + +#ifdef _PROTOTYPES_ +void args( + int argc, + char * argv[] +) +#else +void args(argc, argv) + int argc; + char *argv[]; +#endif +{ + char *prgnam; + +#ifdef __mac__ +#include <console.h> +#ifdef __MWERKS__ +#include <SIOUX.h> +#endif + short msg, files; + static char advbuf[256], prgbuf[256]; + /*AppFile af;*/ + OSErr oe; + +#ifdef __MWERKS__ + /*SIOUXSettings.setupmenus = FALSE;*/ + SIOUXSettings.autocloseonquit = FALSE; + SIOUXSettings.asktosaveonclose = FALSE; + SIOUXSettings.showstatusline = FALSE; +#endif + + GetMacArgs(advbuf); + advnam = advbuf; + +#else +#ifdef __amiga__ + + if (argc == 0) { /* If started from Workbench get WbArgs : Aztec C & GG GCC */ + struct WBStartup *WBstart; + + if ((IconBase = OpenLibrary("icon.library", 0)) == NULL) + syserr("Could not open 'icon.library'"); + /* If started from WB normal main is called with argc == 0 and argv = WBstartup message */ + WBstart = (struct WBStartup *)argv; +#ifndef AZTEC_C + /* Geek Gadgets GCC */ + wb_parse(); +#endif + advnam = prgnam = WBstart->sm_ArgList[0].wa_Name; + if (WBstart->sm_NumArgs > 0) { + cd = CurrentDir(DupLock(WBstart->sm_ArgList[1].wa_Lock)); + advnam = WBstart->sm_ArgList[1].wa_Name; + } + /* Possibly other tooltypes ... */ + } else { + /* Started from a CLI */ + if ((prgnam = strrchr(argv[0], '/')) == NULL + && (prgnam = strrchr(argv[0], ':')) == NULL) + prgnam = argv[0]; + else + prgnam++; + /* Now look at the switches and arguments */ + switches(argc, argv); + if (advnam[0] == '\0') + /* No game given, try program name */ + if (stricmp(prgnam, PROGNAME) != 0 + && strstr(prgnam, PROGNAME) == 0) + advnam = strdup(argv[0]); + } +#else +#if defined(__dos__) || defined(__win__) + if ((prgnam = strrchr(argv[0], '\\')) == NULL + && (prgnam = strrchr(argv[0], '/')) == NULL + && (prgnam = strrchr(argv[0], ':')) == NULL) + prgnam = argv[0]; + else + prgnam++; + if (strlen(prgnam) > 4 + && (strcmp(&prgnam[strlen(prgnam)-4], ".EXE") == 0 + || strcmp(&prgnam[strlen(prgnam)-4], ".exe") == 0)) + prgnam[strlen(prgnam)-4] = '\0'; + /* Now look at the switches and arguments */ + switches(argc, argv); + if (advnam[0] == '\0') + /* No game given, try program name */ + if (stricmp(prgnam, PROGNAME) != 0 + && strstr(prgnam, PROGNAME) == 0) + advnam = strdup(argv[0]); +#else +#if defined __vms__ + if ((prgnam = strrchr(argv[0], ']')) == NULL + && (prgnam = strrchr(argv[0], '>')) == NULL + && (prgnam = strrchr(argv[0], ':')) == NULL) + prgnam = argv[0]; + else + prgnam++; + if (strrchr(prgnam, ';') != NULL) + *strrchr(prgnam, ';') = '\0'; + if (strlen(prgnam) > 4 + && (strcmp(&prgnam[strlen(prgnam)-4], ".EXE") == 0 + || strcmp(&prgnam[strlen(prgnam)-4], ".exe") == 0)) + prgnam[strlen(prgnam)-4] = '\0'; + /* Now look at the switches and arguments */ + switches(argc, argv); + if (advnam[0] == '\0') + /* No game given, try program name */ + if (strcmp(prgnam, PROGNAME) != 0 + && strstr(prgnam, PROGNAME) == 0) + advnam = strdup(argv[0]); +#else +#if defined(__unix__) || defined(__APPLE__) + if ((prgnam = strrchr(argv[0], '/')) == NULL) + prgnam = strdup(argv[0]); + else + prgnam = strdup(&prgnam[1]); + if (strrchr(prgnam, ';') != NULL) + *strrchr(prgnam, ';') = '\0'; + /* Now look at the switches and arguments */ + switches(argc, argv); + if (advnam[0] == '\0') + /* No game given, try program name */ + if (strcmp(prgnam, PROGNAME) != 0 + && strstr(prgnam, PROGNAME) == 0) + advnam = strdup(argv[0]); +#else + Unimplemented OS! +#endif +#endif +#endif +#endif +#endif +} + +} // End of namespace Alan2 +} // End of namespace Glk diff --git a/engines/glk/alan2/args.h b/engines/glk/alan2/args.h new file mode 100644 index 0000000000..a86d5197fe --- /dev/null +++ b/engines/glk/alan2/args.h @@ -0,0 +1,50 @@ +/* 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. + * + */ + +#ifndef GLK_ALAN2_ARGS +#define GLK_ALAN2_ARGS + +/* Handles the various startup methods on all machines. + * + * Main function args() will set up global variable advnam and the flags, + * the terminal will also be set up and connected. + */ + +#include "glk/alan2/types.h" + +namespace Glk { +namespace Alan2 { + +#ifndef PROGNAME +#define PROGNAME "alan2" +#endif + +#ifdef _PROTOTYPES_ +extern void args(int argc, char *argv[]); +#else +extern void args(); +#endif + +} // End of namespace Alan2 +} // End of namespace Glk + +#endif diff --git a/engines/glk/alan2/debug.cpp b/engines/glk/alan2/debug.cpp new file mode 100644 index 0000000000..dc353c7729 --- /dev/null +++ b/engines/glk/alan2/debug.cpp @@ -0,0 +1,506 @@ +/* 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/types.h" +#ifdef HAVE_SHORT_FILENAMES +#include "glk/alan2/av.h" +#else +#include "glk/alan2/alan_version.h" +#endif + +#ifdef USE_READLINE +#include "glk/alan2/readline.h" +#endif + +#include "glk/alan2/inter.h" +#include "glk/alan2/main.h" +#include "glk/alan2/parse.h" +#include "glk/alan2/exe.h" + +#include "glk/alan2/debug.h" + +#ifdef GLK +#include "glk/alan2/glkio.h" +#endif + +namespace Glk { +namespace Alan2 { + +#ifdef _PROTOTYPES_ +static void showatrs( + Aword atradr +) +#else +static void showatrs(atradr) + Aword atradr; +#endif +{ + AtrElem *at; + int i; + char str[80]; + + if (atradr == 0) return; + + i = 1; + for (at = (AtrElem *) addrTo(atradr); !endOfTable(at); at++) { + sprintf(str, "$i%3ld: %ld (%s)", (long) i, (unsigned long) at->val, (char *) addrTo(at->stradr)); +#if ISO == 0 + fromIso(str, str); +#endif + output(str); + i++; + } +} + + +#ifdef _PROTOTYPES_ +static void showobjs(void) +#else +static void showobjs() +#endif +{ + char str[80]; + int obj; + + output("OBJECTS:"); + for (obj = OBJMIN; obj <= OBJMAX; obj++) { + sprintf(str, "$i%3ld: ", (long) obj); + output(str); + say(obj); + } +} + + +#ifdef _PROTOTYPES_ +static void showobj( + int obj +) +#else +static void showobj(obj) + int obj; +#endif +{ + char str[80]; +#define OBJ (obj-OBJMIN) + + + if (!isObj(obj)) { + sprintf(str, "Object number out of range. Between %ld and %ld, please.", (unsigned long) OBJMIN, (unsigned long) OBJMAX); + output(str); + return; + } + + sprintf(str, "OBJECT %d :", obj); + output(str); + say(obj); + + sprintf(str, "$iLocation = %ld", (unsigned long) where(obj)); + output(str); + if (isLoc(objs[OBJ].loc)) + say(objs[OBJ].loc); + else if (isCnt(objs[OBJ].loc)) { + if (isObj(objs[OBJ].loc)) { + output("in"); + say(objs[OBJ].loc); + } else if (isAct(objs[OBJ].loc)) { + output("carried by"); + say(objs[OBJ].loc); + } else + interpret(cnts[objs[OBJ].loc-CNTMIN].nam); + } else if (objs[OBJ].loc == 0) + output("nowhere"); + else + output("Illegal location!"); + + + output("$iAttributes ="); + showatrs(objs[OBJ].atrs); + +#undef OBJ +} + + +#ifdef _PROTOTYPES_ +static void showcnts(void) +#else +static void showcnts() +#endif +{ + char str[80]; + int cnt; +#define CNT (cnt-CNTMIN) + + output("CONTAINERS:"); + for (cnt = CNTMIN; cnt <= CNTMAX; cnt++) { + sprintf(str, "$i%3ld: ", (long) cnt); + output(str); + if (cnts[CNT].nam != 0) + interpret(cnts[CNT].nam); + if (cnts[CNT].parent != 0) + say(cnts[CNT].parent); + } + +#undef CNT +} + + +#ifdef _PROTOTYPES_ +static void showcnt( + int cnt +) +#else +static void showcnt(cnt) + int cnt; +#endif +{ + char str[80]; + int i; + Abool found = FALSE; +#define CNT (cnt-CNTMIN) + + if (cnt < CNTMIN || cnt > CNTMAX) { + sprintf(str, "Container number out of range. Between %ld and %ld, please.", (unsigned long) CNTMIN, (unsigned long) CNTMAX); + output(str); + return; + } + + sprintf(str, "CONTAINER %d :", cnt); + output(str); + if (cnts[CNT].nam != 0) + interpret(cnts[CNT].nam); + if (cnts[CNT].parent != 0) { + cnt = cnts[CNT].parent; + say(cnt); + sprintf(str, "$iLocation = %ld", (unsigned long) where(cnt)); + output(str); + } + output("$iContains "); + for (i = OBJMIN; i <= OBJMAX; i++) { + if (in(i, cnt)) { /* Yes, it's in this container */ + if (!found) { + output("$n"); + found = TRUE; + } + sprintf(str, "$t$t%d: ", i); + output(str); + say(i); + } + } + if (!found) + output("nothing"); + +#undef CNT +} + + +#ifdef _PROTOTYPES_ +static void showlocs(void) +#else +static void showlocs() +#endif +{ + char str[80]; + int loc; + + output("LOCATIONS:"); + for (loc = LOCMIN; loc <= LOCMAX; loc++) { + sprintf(str, "$i%3ld: ", (long) loc); + output(str); + say(loc); + } +} + + +#ifdef _PROTOTYPES_ +static void showloc( + int loc +) +#else +static void showloc(loc) + int loc; +#endif +{ + char str[80]; + + + if (!isLoc(loc)) { + sprintf(str, "Location number out of range. Between %ld and %ld, please.", (unsigned long) LOCMIN, (unsigned long) LOCMAX); + output(str); + return; + } + + sprintf(str, "LOCATION %d :", loc); + output(str); + say(loc); + + output("$iAttributes ="); + showatrs(locs[loc-LOCMIN].atrs); +} + + +#ifdef _PROTOTYPES_ +static void showacts(void) +#else +static void showacts() +#endif +{ + char str[80]; + int act; + + output("ACTORS:"); + for (act = ACTMIN; act <= ACTMAX; act++) { + sprintf(str, "$i%3ld:", (long) act); + output(str); + say(act); + } +} + + +#ifdef _PROTOTYPES_ +static void showact( + int act +) +#else +static void showact(act) + int act; +#endif +{ + char str[80]; + Boolean oldstp; + + if (!isAct(act)) { + sprintf(str, "Actor number out of range. Between %ld and %ld, please.", (unsigned long) ACTMIN, (unsigned long) ACTMAX); + output(str); + return; + } + + sprintf(str, "ACTOR %d :", act); + output(str); + oldstp = stpflg; stpflg = FALSE; /* Make sure not to trace this! */ + say(act); + stpflg = oldstp; + + sprintf(str, "$iLocation = %ld", (unsigned long) acts[act-ACTMIN].loc); + output(str); + if (isLoc(acts[act-ACTMIN].loc)) + say(acts[act-ACTMIN].loc); + else if (acts[act-ACTMIN].loc == 0) + output("nowhere"); + else + output("Illegal location!"); + + sprintf(str, "$iScript = %ld", (unsigned long) acts[act-ACTMIN].script); + output(str); + + sprintf(str, "$iStep = %ld", (unsigned long) acts[act-ACTMIN].step); + output(str); + + output("$iAttributes ="); + showatrs(acts[act-ACTMIN].atrs); +} + + +#ifdef _PROTOTYPES_ +static void showevts(void) +#else +static void showevts() +#endif +{ + int evt, i; + char str[80]; + Boolean scheduled; + + output("EVENTS:"); + for (evt = EVTMIN; evt <= EVTMAX; evt++) { + sprintf(str, "$i%d (%s):", evt, (char *)addrTo(evts[evt-EVTMIN].stradr)); +#if ISO == 0 + fromIso(str, str); +#endif + output(str); + scheduled = FALSE; + for (i = 0; i < etop; i++) + if ((scheduled = (eventq[i].event == evt))) + break; + if (scheduled) { + sprintf(str, "Scheduled for +%d, at ", eventq[i].time-cur.tick); + output(str); + say(eventq[i].where); + } else + output("Not scheduled."); + } +} + + +static Boolean trc, stp; +static int loc; + +#ifdef _PROTOTYPES_ +void saveInfo(void) +#else +void saveInfo() +#endif +{ + /* Save some important things */ + trc = trcflg; trcflg = FALSE; + stp = stpflg; stpflg = FALSE; + loc = cur.loc; cur.loc = where(HERO); +} + +#ifdef _PROTOTYPES_ +void restoreInfo(void) +#else +void restoreInfo() +#endif +{ + /* Restore! */ + trcflg = trc; + stpflg = stp; + cur.loc = loc; +} + + +#ifdef _PROTOTYPES_ +void debug(void) +#else +void debug() +#endif +{ + char buf[256]; + char c; + int i; + + saveInfo(); + while (TRUE) { + if (anyOutput) + para(); + do { + output("ABUG> "); +#ifdef USE_READLINE + (void) readline(buf); +#else + fgets(buf, 255, stdin); +#endif + lin = 1; + c = buf[0]; + i = 0; + sscanf(&buf[1], "%d", &i); + } while (buf && c == '\0'); + + switch (toUpper(c)) { + case 'H': + case '?': + output(alan.longHeader); + output("$nABUG Commands:\ + $iO [n] -- show object[s]\ + $iA [n] -- show actor[s]\ + $iL [n] -- show location[s]\ + $iC [n] -- show container[s]\ + $iE -- show events\ + $iG -- go on\ + $iT -- toggle trace mode\ + $iS -- toggle step mode\ + $iX -- exit debug mode\ + $iQ -- quit game"); + break; + case 'Q': + terminate(0); + case 'X': + dbgflg = FALSE; /* Fall through to 'G' */ + case 'G': + restoreInfo(); + return; + case 'O': + if (i == 0) + showobjs(); + else + showobj(i); + break; + case 'C': + if (i == 0) + showcnts(); + else + showcnt(i); + break; + case 'A': + if (i == 0) + showacts(); + else + showact(i); + break; + case 'L': + if (i == 0) + showlocs(); + else + showloc(i); + break; + case 'E': + showevts(); + break; + case 'S': + if ((stp = !stp)) + printf("Step on."); + else + printf("Step off."); + break; + case 'T': + if ((trc = !trc)) + printf("Trace on."); + else + printf("Trace off."); + break; + default: + output("Unknown ABUG command. ? for help."); + break; + } + } +} + + +/*====================================================================== + + debugsay() + + Say somethin, but make sure we don't disturb anything and that it is + shown to the player. + +*/ +#ifdef _PROTOTYPES_ +void debugsay(int item) +#else +void debugsay(item) + int item; +#endif +{ + saveInfo(); + needsp = FALSE; + col = 1; + if (item == 0) + printf("$null$"); + else + say(item); + needsp = FALSE; + col = 1; + restoreInfo(); +} + +} // End of namespace Alan2 +} // End of namespace Glk diff --git a/engines/glk/alan2/debug.h b/engines/glk/alan2/debug.h new file mode 100644 index 0000000000..aac870ec42 --- /dev/null +++ b/engines/glk/alan2/debug.h @@ -0,0 +1,47 @@ +/* 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. + * + */ + +/* TYPES */ + +#ifndef GLK_ALAN2_DEBUG +#define GLK_ALAN2_DEBUG + +namespace Glk { +namespace Alan2 { + +#ifdef _PROTOTYPES_ + +extern void saveInfo(void); +extern void restoreInfo(void); +extern void debug(void); +extern void debugsay(int item); +#else +extern void saveInfo(); +extern void restoreInfo(); +extern void debug(); +extern void debugsay(); +#endif + +} // End of namespace Alan2 +} // End of namespace Glk + +#endif diff --git a/engines/glk/alan2/decode.cpp b/engines/glk/alan2/decode.cpp new file mode 100644 index 0000000000..4ffdc2f3b9 --- /dev/null +++ b/engines/glk/alan2/decode.cpp @@ -0,0 +1,193 @@ +/* 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 <stdlib.h> +#include "glk/alan2/main.h" +#include "glk/alan2/decode.h" + +namespace Glk { +namespace Alan2 { + +/* Bit output */ +static int decodeBuffer; /* Bits to be input */ +static int bitsToGo; /* Bits still in buffer */ +static int garbageBits; /* Bits past EOF */ + + +#ifdef _PROTOTYPES_ +static int inputBit(void) +#else +static int inputBit() +#endif +{ + int bit; + + if (!bitsToGo) { /* More bits available ? */ + decodeBuffer = txtfil->readByte(); /* No, so get more */ + if (decodeBuffer == EOF) { + garbageBits++; + if (garbageBits > VALUEBITS-2) + syserr("Error in encoded data file."); + } else + bitsToGo = 8; /* Another Char, 8 new bits */ + } + bit = decodeBuffer&1; /* Get next bit */ + decodeBuffer = decodeBuffer>>1; /* and remove it */ + bitsToGo--; + return bit; +} + + +/* Current state of decoding */ + +static CodeValue value; /* Currently seen code value */ +static CodeValue low, high; /* Current code region */ + + +#ifdef _PROTOTYPES_ +void startDecoding(void) +#else +void startDecoding() +#endif +{ + int i; + + bitsToGo = 0; + garbageBits = 0; + + value = 0; + for (i = 0; i < VALUEBITS; i++) + value = 2*value + inputBit(); + low = 0; + high = TOPVALUE; +} + + +#ifdef _PROTOTYPES_ +int decodeChar(void) +#else +int decodeChar() +#endif +{ + long range; + int f; + int symbol; + + range = (long)(high-low) + 1; + f = (((long)(value-low)+1)*freq[0]-1)/range; + + /* Find the symbol */ + for (symbol = 1; (int)freq[symbol] > f; symbol++); + + high = low + range*freq[symbol-1]/freq[0]-1; + low = low + range*freq[symbol]/freq[0]; + + for (;;) { + if (high < HALF) + ; + else if (low >= HALF) { + value = value - HALF; + low = low - HALF; + high = high - HALF; + } else if (low >= ONEQUARTER && high < THREEQUARTER) { + value = value - ONEQUARTER; + low = low - ONEQUARTER; + high = high - ONEQUARTER; + } else + break; + + /* Scale up the range */ + low = 2*low; + high = 2*high+1; + value = 2*value + inputBit(); + } + return symbol-1; +} + + + +/* Structure for saved decode info */ +typedef struct DecodeInfo { + long fpos; + int buffer; + int bits; + CodeValue value; + CodeValue high; + CodeValue low; +} DecodeInfo; + + +/*====================================================================== + + pushDecode() + + Save so much info about the decoding process so it is possible to + restore and continue later. + + */ +#ifdef _PROTOTYPES_ +void *pushDecode(void) +#else +void *pushDecode() +#endif +{ + DecodeInfo *info; + + info = (DecodeInfo *) allocate(sizeof(DecodeInfo)); + info->fpos = txtfil->pos(); + info->buffer = decodeBuffer; + info->bits = bitsToGo; + info->value = value; + info->high = high; + info->low = low; + return(info); +} + + +/*====================================================================== + + popDecode() + + Restore enough info about the decoding process so it is possible to + continue after having decoded something else. + + */ +#ifdef _PROTOTYPES_ +void popDecode(void *i) +#else +void popDecode(i) + void *i; +#endif +{ + DecodeInfo *info = (DecodeInfo *) i; + fseek(txtfil, info->fpos, 0); + decodeBuffer = info->buffer; + bitsToGo = info->bits; + value = info->value; + high = info->high; + low = info->low; + + free(info); +} + +} // End of namespace Alan2 +} // End of namespace Glk diff --git a/engines/glk/alan2/decode.h b/engines/glk/alan2/decode.h new file mode 100644 index 0000000000..7ce15b41de --- /dev/null +++ b/engines/glk/alan2/decode.h @@ -0,0 +1,49 @@ +/* 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. + * + */ + +#ifndef GLK_ALAN2_DECODE +#define GLK_ALAN2_DECODE + +#include "glk/alan2/types.h" + +/* Arithmetic decoding module in Arun + */ + +namespace Glk { +namespace Alan2 { + +#ifdef _PROTOTYPES_ +extern void startDecoding(void); +extern int decodeChar(void); +extern void *pushDecode(void); +extern void popDecode(void *info); +#else +extern void startDecoding(); +extern int decodeChar(); +extern void *pushDecode(); +extern void popDecode(); +#endif + +} // End of namespace Alan2 +} // End of namespace Glk + +#endif diff --git a/engines/glk/alan2/exe.cpp b/engines/glk/alan2/exe.cpp new file mode 100644 index 0000000000..1cccf3d32d --- /dev/null +++ b/engines/glk/alan2/exe.cpp @@ -0,0 +1,1845 @@ +/* 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/types.h" +#include "glk/alan2/alan2.h" + +#ifdef USE_READLINE +#include "glk/alan2/readline.h" +#endif + +#include "glk/alan2/main.h" +#include "glk/alan2/parse.h" +#include "glk/alan2/inter.h" +#include "glk/alan2/stack.h" +#include "glk/alan2/decode.h" + +#include "glk/alan2/exe.h" + +namespace Glk { +namespace Alan2 { + +#define WIDTH 80 + +#define N_EVTS 100 + + +/* PUBLIC DATA */ + +/* The event queue */ +EvtqElem eventq[N_EVTS]; /* Event queue */ +int etop = 0; /* Event queue top pointer */ + +Boolean looking = FALSE; /* LOOKING? flag */ + +int dscrstkp = 0; /* Describe-stack pointer */ + + +#ifdef _PROTOTYPES_ +void dscrobjs(void); +void dscracts(void); +#else +void dscrobjs(); +void dscracts(); +#endif + + + +#ifdef _PROTOTYPES_ +void print(Aword fpos, Aword len) +#else +void print(fpos, len) + Aword fpos, len; +#endif +{ + char str[2*WIDTH]; /* String buffer */ + int outlen = 0; /* Current output length */ + int ch; + int i; + long savfp; /* Temporary saved text file position */ + static Boolean printFlag = FALSE; /* Printing already? */ + Boolean savedPrintFlag = printFlag; + void *info; /* Saved decoding info */ + + + if (len == 0) return; + + if (isHere(HERO)) { /* Check if the player will see it */ + if (printFlag) { /* Already printing? */ + /* Save current text file position and/or decoding info */ + if (header->pack) + info = pushDecode(); + else + savfp = ftell(txtfil); + } + printFlag = TRUE; /* We're printing now! */ + fseek(txtfil, fpos, 0); /* Position to start of text */ + if (header->pack) + startDecoding(); + for (outlen = 0; outlen != (int)len; outlen = outlen + strlen(str)) { + /* Fill the buffer from the beginning */ + for (i = 0; i <= WIDTH || (i > WIDTH && ch != ' '); i++) { + if (outlen + i == (int)len) /* No more characters? */ + break; + if (header->pack) + ch = decodeChar(); + else + ch = getc(txtfil); + if (ch == EOFChar) /* Or end of text? */ + break; + str[i] = ch; + } + str[i] = '\0'; +#if ISO == 0 + fromIso(str, str); +#endif + output(str); + } + /* And restore */ + printFlag = savedPrintFlag; + if (printFlag) { + if (header->pack) + popDecode(info); + else + fseek(txtfil, savfp, 0); + } + } +} + + +#ifdef _PROTOTYPES_ +void sys(Aword fpos, Aword len) +#else +void sys(fpos, len) + Aword fpos, len; +#endif +{ +#ifdef GLK + ::error("system calls aren't supported"); +#else + char *command; + + getstr(fpos, len); /* Returns address to string on stack */ + command = (char *)pop(); + int tmp = system(command); + free(command); +#endif +} + + +#ifdef _PROTOTYPES_ +void getstr(Aword fpos, Aword len) +#else +void getstr(fpos, len) + Aword fpos, len; +#endif +{ + char *buf = (char *)allocate(len+1); + + push((Aptr) buf); /* Push the address to the string */ + fseek(txtfil, fpos, 0); /* Position to start of text */ + if (header->pack) + startDecoding(); + while (len--) + if (header->pack) + *(buf++) = decodeChar(); + else + *(buf++) = getc(txtfil); + *buf = '\0'; +} + + + +#ifdef _PROTOTYPES_ +void score(Aword sc) +#else +void score(sc) + Aword sc; +#endif +{ + char buf[80]; + + if (sc == 0) { + prmsg(M_SCORE1); + sprintf(buf, "%d", cur.score); + output(buf); + prmsg(M_SCORE2); + sprintf(buf, "%ld.", (unsigned long) header->maxscore); + output(buf); + } else { + cur.score += scores[sc-1]; + scores[sc-1] = 0; + } +} + +#ifdef _PROTOTYPES_ +void visits(Aword v) +#else +void visits(v) + Aword v; +#endif +{ + cur.visits = v; +} + + +#ifdef _PROTOTYPES_ +Boolean confirm(MsgKind msgno) +#else +Boolean confirm(msgno) + MsgKind msgno; +#endif +{ + char buf[80]; + + /* This is a bit of a hack since we really want to compare the input, + it could be affirmative, but for now any input is NOT! */ + prmsg(msgno); + +#ifdef USE_READLINE + if (!readline(buf)) return TRUE; +#else + if (gets(buf) == NULL) return TRUE; +#endif + col = 1; + + return (buf[0] == '\0'); +} + + +#ifdef _PROTOTYPES_ +void quit(void) +#else +void quit() +#endif +{ + char buf[80]; + char choices[10]; + + para(); + while (TRUE) { + col = 1; + statusline(); + prmsg(M_QUITACTION); +#ifdef USE_READLINE + if (!readline(buf)) terminate(0); +#else + if (gets(buf) == NULL) terminate(0); +#endif + if (strcmp(buf, "restart") == 0) + //longjmp(restart_label, TRUE); + ::error("TODO: restart"); + else if (strcmp(buf, "restore") == 0) { + restore(); + return; + } else if (strcmp(buf, "quit") == 0) + terminate(0); + } + syserr("Fallthrough in QUIT"); +} + + + +#ifdef _PROTOTYPES_ +void restart(void) +#else +void restart() +#endif +{ + para(); + if (confirm(M_REALLY)) { + //longjmp(restart_label, TRUE); + ::error("TODO: restart"); + } else + return; + syserr("Fallthrough in RESTART"); +} + + + +#ifdef _PROTOTYPES_ +void cancl(Aword evt) +#else +void cancl(evt) + Aword evt; +#endif +{ + int i; + + for(i = etop-1; i>=0; i--) + if (eventq[i].event == evt) { + while (i < etop-1) { + eventq[i].event = eventq[i+1].event; + eventq[i].time = eventq[i+1].time; + eventq[i].where = eventq[i+1].where; + i++; + } + etop--; + return; + } +} + + +#ifdef _PROTOTYPES_ +void schedule(Aword evt, Aword whr, Aword aft) +#else +void schedule(evt, whr, aft) + Aword evt, whr, aft; +#endif +{ int i; + int time; + + cancl(evt); + /* Check for overflow */ + if (etop == N_EVTS) syserr("Out of event space."); + + time = cur.tick+aft; + + /* Bubble this event down */ + for (i = etop; i >= 1 && eventq[i-1].time <= time; i--) { + eventq[i].event = eventq[i-1].event; + eventq[i].time = eventq[i-1].time; + eventq[i].where = eventq[i-1].where; + } + + eventq[i].time = time; + eventq[i].where = whr; + eventq[i].event = evt; + etop++; +} + + +/*---------------------------------------------------------------------- + + getatr() + + Get an attribute value from an attribute list + + */ +#ifdef _PROTOTYPES_ +static Aptr getatr( + Aaddr atradr, /* IN - ACODE address to attribute table */ + Aaddr atr /* IN - The attribute to read */ +) +#else +static Aptr getatr(atradr, atr) + Aaddr atradr; /* IN - ACODE address to attribute table */ + Aaddr atr; /* IN - The attribute to read */ +#endif +{ + AtrElem *at; + + at = (AtrElem *) addrTo(atradr); + return at[atr-1].val; +} + + +/*---------------------------------------------------------------------- + + setatr() + + Set a particular attribute to a value. + + */ +#ifdef _PROTOTYPES_ +static void setatr( + Aaddr atradr, /* IN - ACODE address to attribute table */ + Aword atr, /* IN - attribute code */ + Aword val /* IN - new value */ +) +#else +static void setatr(atradr, atr, val) + Aaddr atradr; /* IN - ACODE address to attribute table */ + Aword atr; /* IN - attribute code */ + Aword val; /* IN - new value */ +#endif +{ + AtrElem *at; + + at = (AtrElem *) addrTo(atradr); + at[atr-1].val = val; +} + + +/*---------------------------------------------------------------------- + + make() + + */ + +#ifdef _PROTOTYPES_ +static void makloc(Aword loc, Aword atr, Aword val) +#else +static void makloc(loc, atr, val) + Aword loc, atr, val; +#endif +{ + setatr(locs[loc-LOCMIN].atrs, atr, val); +} + +#ifdef _PROTOTYPES_ +static void makobj(Aword obj, Aword atr, Aword val) +#else +static void makobj(obj, atr, val) + Aword obj, atr, val; +#endif +{ + setatr(objs[obj-OBJMIN].atrs, atr, val); +} + +#ifdef _PROTOTYPES_ +static void makact(Aword act, Aword atr, Aword val) +#else +static void makact(act, atr, val) + Aword act, atr, val; +#endif +{ + setatr(acts[act-ACTMIN].atrs, atr, val); +} + + +#ifdef _PROTOTYPES_ +void make(Aword id, Aword atr, Aword val) +#else +void make(id, atr, val) + Aword id, atr, val; +#endif +{ + char str[80]; + + if (isObj(id)) + makobj(id, atr, val); + else if (isLoc(id)) + makloc(id, atr, val); + else if (isAct(id)) + makact(id, atr, val); + else { + sprintf(str, "Can't MAKE item (%ld).", (unsigned long) id); + syserr(str); + } +} + + +/*---------------------------------------------------------------------------- + + set() + + */ + +#ifdef _PROTOTYPES_ +static void setloc(Aword loc, Aword atr, Aword val) +#else +static void setloc(loc, atr, val) + Aword loc, atr, val; +#endif +{ + setatr(locs[loc-LOCMIN].atrs, atr, val); + locs[loc-LOCMIN].describe = 0; +} + + +#ifdef _PROTOTYPES_ +static void setobj(Aword obj, Aword atr, Aword val) +#else +static void setobj(obj, atr, val) + Aword obj, atr, val; +#endif +{ + setatr(objs[obj-OBJMIN].atrs, atr, val); +} + +#ifdef _PROTOTYPES_ +static void setact(Aword act, Aword atr, Aword val) +#else +static void setact(act, atr, val) + Aword act, atr, val; +#endif +{ + setatr(acts[act-ACTMIN].atrs, atr, val); +} + + +#ifdef _PROTOTYPES_ +void set(Aword id, Aword atr, Aword val) +#else +void set(id, atr, val) + Aword id, atr, val; +#endif +{ + char str[80]; + + if (isObj(id)) + setobj(id, atr, val); + else if (isLoc(id)) + setloc(id, atr, val); + else if (isAct(id)) + setact(id, atr, val); + else { + sprintf(str, "Can't SET item (%ld).", (unsigned long) id); + syserr(str); + } +} + + +#ifdef _PROTOTYPES_ +void setstr(Aword id, Aword atr, Aword str) +#else +void setstr(id, atr, str) + Aword id, atr, str; +#endif +{ + free((char *)attribute(id, atr)); + set(id, atr, str); +} + + + +/*----------------------------------------------------------------------------- + + incr/decr + + */ + +/*---------------------------------------------------------------------- + + incratr() + + Increment a particular attribute by a value. + + */ +#ifdef _PROTOTYPES_ +static void incratr( + Aaddr atradr, /* IN - ACODE address to attribute table */ + Aword atr, /* IN - attribute code */ + Aword step /* IN - step to increment by */ +) +#else +static void incratr(atradr, atr, step) + Aaddr atradr, atr, step; +#endif +{ + AtrElem *at; + + at = (AtrElem *) addrTo(atradr); + at[atr-1].val += step; +} + + +#ifdef _PROTOTYPES_ +static void incrloc(Aword loc, Aword atr, Aword step) +#else +static void incrloc(loc, atr, step) + Aword loc, atr, step; +#endif +{ + incratr(locs[loc-LOCMIN].atrs, atr, step); + locs[loc-LOCMIN].describe = 0; +} + + +#ifdef _PROTOTYPES_ +static void incrobj(Aword obj, Aword atr, Aword step) +#else +static void incrobj(obj, atr, step) + Aword obj, atr, step; +#endif +{ + incratr(objs[obj-OBJMIN].atrs, atr, step); +} + +#ifdef _PROTOTYPES_ +static void incract(Aword act, Aword atr, Aword step) +#else +static void incract(act, atr, step) + Aword act, atr, step; +#endif +{ + incratr(acts[act-ACTMIN].atrs, atr, step); +} + + +#ifdef _PROTOTYPES_ +void incr(Aword id, Aword atr, Aword step) +#else +void incr(id, atr, step) + Aword id, atr, step; +#endif +{ + char str[80]; + + if (isObj(id)) + incrobj(id, atr, step); + else if (isLoc(id)) + incrloc(id, atr, step); + else if (isAct(id)) + incract(id, atr, step); + else { + sprintf(str, "Can't INCR item (%ld).", (unsigned long) id); + syserr(str); + } +} + +#ifdef _PROTOTYPES_ +void decr(Aword id, Aword atr, Aword step) +#else +void decr(id, atr, step) + Aword id, atr, step; +#endif +{ + char str[80]; + + if (isObj(id)) + incrobj(id, atr, -step); + else if (isLoc(id)) + incrloc(id, atr, -step); + else if (isAct(id)) + incract(id, atr, -step); + else { + sprintf(str, "Can't DECR item (%ld).", (unsigned long) id); + syserr(str); + } +} + + + +/*---------------------------------------------------------------------- + + attribute() + + */ + +#ifdef _PROTOTYPES_ +static Aptr locatr(Aword loc, Aword atr) +#else +static Aptr locatr(loc, atr) + Aword loc, atr; +#endif +{ + return getatr(locs[loc-LOCMIN].atrs, atr); +} + + + +#ifdef _PROTOTYPES_ +static Aptr objatr(Aword obj, Aword atr) +#else +static Aptr objatr(obj, atr) + Aword obj, atr; +#endif +{ + return getatr(objs[obj-OBJMIN].atrs, atr); +} + +#ifdef _PROTOTYPES_ +static Aptr actatr(Aword act, Aword atr) +#else +static Aptr actatr(act, atr) + Aword act, atr; +#endif +{ + return getatr(acts[act-ACTMIN].atrs, atr); +} + +#ifdef _PROTOTYPES_ +static Aptr litatr(Aword lit, Aword atr) +#else +static Aptr litatr(lit, atr) + Aword lit, atr; +#endif +{ + char str[80]; + + if (atr == 1) + return litValues[lit-LITMIN].value; + else { + sprintf(str, "Unknown attribute for literal (%ld).", (unsigned long) atr); + syserr(str); + } + return (Aptr)EOF; +} + + +#ifdef _PROTOTYPES_ +Aptr attribute(Aword id, Aword atr) +#else +Aptr attribute(id, atr) + Aword id, atr; +#endif +{ + char str[80]; + + if (isObj(id)) + return objatr(id, atr); + else if (isLoc(id)) + return locatr(id, atr); + else if (isAct(id)) + return actatr(id, atr); + else if (isLit(id)) + return litatr(id, atr); + else { + sprintf(str, "Can't ATTRIBUTE item (%ld).", (unsigned long) id); + syserr(str); + } + return (Aptr)EOF; +} + + +#ifdef _PROTOTYPES_ +Aptr strattr(Aword id, Aword atr) +#else +Aptr strattr(id, atr) + Aword id, atr; +#endif +{ + return (Aptr) strdup((char *)attribute(id, atr)); +} + + +/*---------------------------------------------------------------------- + + where() + + */ + +#ifdef _PROTOTYPES_ +static Aword objloc(Aword obj) +#else +static Aword objloc(obj) + Aword obj; +#endif +{ + if (isCnt(objs[obj-OBJMIN].loc)) /* In something ? */ + if (isObj(objs[obj-OBJMIN].loc) || isAct(objs[obj-OBJMIN].loc)) + return(where(objs[obj-OBJMIN].loc)); + else /* Containers not anywhere is where the hero is! */ + return(where(HERO)); + else + return(objs[obj-OBJMIN].loc); +} + + +#ifdef _PROTOTYPES_ +static Aword actloc(Aword act) +#else +static Aword actloc(act) + Aword act; +#endif +{ + return(acts[act-ACTMIN].loc); +} + + +#ifdef _PROTOTYPES_ +Aword where(Aword id) +#else +Aword where(id) + Aword id; +#endif +{ + char str[80]; + + if (isObj(id)) + return objloc(id); + else if (isAct(id)) + return actloc(id); + else { + sprintf(str, "Can't WHERE item (%ld).", (unsigned long) id); + syserr(str); + } + return (Aptr)EOF; +} + + + +/*---------------------------------------------------------------------- + + aggregates + + */ + +#ifdef _PROTOTYPES_ +Aint agrmax(Aword atr, Aword whr) +#else +Aint agrmax(atr, whr) + Aword atr, whr; +#endif +{ + Aword i; + Aint max = 0; + + for (i = OBJMIN; i <= OBJMAX; i++) { + if (isLoc(whr)) { + if (where(i) == whr && attribute(i, atr) > max) + max = attribute(i, atr); + } else if (objs[i-OBJMIN].loc == whr && attribute(i, atr) > max) + max = attribute(i, atr); + } + return(max); +} + +#ifdef _PROTOTYPES_ +Aint agrsum(Aword atr, Aword whr) +#else +Aint agrsum(atr, whr) + Aword atr, whr; +#endif +{ + Aword i; + Aint sum = 0; + + for (i = OBJMIN; i <= OBJMAX; i++) { + if (isLoc(whr)) { + if (where(i) == whr) + sum += attribute(i, atr); + } else if (objs[i-OBJMIN].loc == whr) + sum += attribute(i, atr); + } + return(sum); +} + + +#ifdef _PROTOTYPES_ +Aint agrcount(Aword whr) +#else +Aint agrcount(whr) + Aword whr; +#endif +{ + Aword i; + Aword count = 0; + + for (i = OBJMIN; i <= OBJMAX; i++) { + if (isLoc(whr)) { + if (where(i) == whr) + count++; + } else if (objs[i-OBJMIN].loc == whr) + count++; + } + return(count); +} + + +/*---------------------------------------------------------------------- + + locate() + + */ + +#ifdef _PROTOTYPES_ +static void locobj(Aword obj, Aword whr) +#else +static void locobj(obj, whr) + Aword obj, whr; +#endif +{ + if (isCnt(whr)) { /* Into a container */ + if (whr == obj) + syserr("Locating something inside itself."); + if (checklim(whr, obj)) + return; + else + objs[obj-OBJMIN].loc = whr; + } else { + objs[obj-OBJMIN].loc = whr; + /* Make sure the location is described since it's changed */ + locs[whr-LOCMIN].describe = 0; + } +} + + +#ifdef _PROTOTYPES_ +static void locact(Aword act, Aword whr) +#else +static void locact(act, whr) + Aword act, whr; +#endif +{ + Aword prevact = cur.act; + Aword prevloc = cur.loc; + + cur.loc = whr; + acts[act-ACTMIN].loc = whr; + if (act == HERO) { + if (locs[acts[act-ACTMIN].loc-LOCMIN].describe % (cur.visits+1) == 0) + look(); + else { + if (anyOutput) + para(); + say(where(HERO)); + prmsg(M_AGAIN); + newline(); + dscrobjs(); + dscracts(); + } + locs[where(HERO)-LOCMIN].describe++; + locs[where(HERO)-LOCMIN].describe %= (cur.visits+1); + } else + locs[whr-LOCMIN].describe = 0; + if (locs[cur.loc-LOCMIN].does != 0) { + cur.act = act; + interpret(locs[cur.loc-LOCMIN].does); + cur.act = prevact; + } + + if (cur.act != act) + cur.loc = prevloc; +} + + +#ifdef _PROTOTYPES_ +void locate(Aword id, Aword whr) +#else +void locate(id, whr) + Aword id, whr; +#endif +{ + char str[80]; + + if (isObj(id)) + locobj(id, whr); + else if (isAct(id)) + locact(id, whr); + else { + sprintf(str, "Can't LOCATE item (%ld).", (unsigned long) id); + syserr(str); + } +} + + +/*---------------------------------------------------------------------- + + isHere() + + */ + +#ifdef _PROTOTYPES_ +static Abool objhere(Aword obj) +#else +static Abool objhere(obj) + Aword obj; +#endif +{ + if (isCnt(objs[obj-OBJMIN].loc)) { /* In something? */ + if (isObj(objs[obj-OBJMIN].loc) || isAct(objs[obj-OBJMIN].loc)) + return(isHere(objs[obj-OBJMIN].loc)); + else /* If the container wasn't anywhere, assume where HERO is! */ + return(where(HERO) == cur.loc); + } else + return(objs[obj-OBJMIN].loc == cur.loc); +} + + +#ifdef _PROTOTYPES_ +static Aword acthere(Aword act) +#else +static Aword acthere(act) + Aword act; +#endif +{ + return(acts[act-ACTMIN].loc == cur.loc); +} + + +#ifdef _PROTOTYPES_ +Abool isHere(Aword id) +#else +Abool isHere(id) + Aword id; +#endif +{ + char str[80]; + + if (isObj(id)) + return objhere(id); + else if (isAct(id)) + return acthere(id); + else { + sprintf(str, "Can't HERE item (%ld).", (unsigned long) id); + syserr(str); + } + return (Abool)EOF; +} + +/*---------------------------------------------------------------------- + + isNear() + + */ + +#ifdef _PROTOTYPES_ +static Aword objnear(Aword obj) +#else +static Aword objnear(obj) + Aword obj; +#endif +{ + if (isCnt(objs[obj-OBJMIN].loc)) { /* In something? */ + if (isObj(objs[obj-OBJMIN].loc) || isAct(objs[obj-OBJMIN].loc)) + return(isNear(objs[obj-OBJMIN].loc)); + else /* If the container wasn't anywhere, assume here, so not nearby! */ + return(FALSE); + } else + return(exitto(where(obj), cur.loc)); +} + + +#ifdef _PROTOTYPES_ +static Aword actnear(Aword act) +#else +static Aword actnear(act) + Aword act; +#endif +{ + return(exitto(where(act), cur.loc)); +} + + +#ifdef _PROTOTYPES_ +Abool isNear(Aword id) +#else +Abool isNear(id) + Aword id; +#endif +{ + char str[80]; + + if (isObj(id)) + return objnear(id); + else if (isAct(id)) + return actnear(id); + else { + sprintf(str, "Can't NEAR item (%ld).", (unsigned long) id); + syserr(str); + } + return (Abool)EOF; +} + + + +/*---------------------------------------------------------------------- + + in() + + */ + +#ifdef _PROTOTYPES_ +Abool in(Aword obj, Aword cnt) +#else +Abool in(obj, cnt) + Aword obj; + Aword cnt; +#endif +{ + if (!isObj(obj)) + return(FALSE); + if (!isCnt(cnt)) + syserr("IN in a non-container."); + + return(objs[obj-OBJMIN].loc == cnt); +} + + +/*---------------------------------------------------------------------- + + say() + + */ + +#ifdef _PROTOTYPES_ +static void sayloc(Aword loc) +#else +static void sayloc(loc) + Aword loc; +#endif +{ + interpret(locs[loc-LOCMIN].nams); +} + + +#ifdef _PROTOTYPES_ +static void sayobj(Aword obj) +#else +static void sayobj(obj) + Aword obj; +#endif +{ + interpret(objs[obj-OBJMIN].dscr2); +} + +#ifdef _PROTOTYPES_ +static void sayact(Aword act) +#else +static void sayact(act) + Aword act; +#endif +{ + interpret(acts[act-ACTMIN].nam); +} + + +#ifdef _PROTOTYPES_ +void sayint(Aword val) +#else +void sayint(val) + Aword val; +#endif +{ + char buf[25]; + + if (isHere(HERO)) { + sprintf(buf, "%ld", (unsigned long) val); + output(buf); + } +} + + +#ifdef _PROTOTYPES_ +void saystr(char *str) +#else +void saystr(str) + char *str; +#endif +{ + if (isHere(HERO)) + output(str); + free(str); +} + + +#ifdef _PROTOTYPES_ +static void saylit(Aword lit) +#else +static void saylit(lit) + Aword lit; +#endif +{ + char *str; + + if (isNum(lit)) + sayint(litValues[lit-LITMIN].value); + else { + str = (char *)strdup((char *)litValues[lit-LITMIN].value); + saystr(str); + } +} + + +#ifdef _PROTOTYPES_ +void sayarticle(Aword id) +#else +void sayarticle(id) + Aword id; +#endif +{ + if (!isObj(id)) + syserr("Trying to say article of something *not* an object."); + if (objs[id-OBJMIN].art != 0) + interpret(objs[id-OBJMIN].art); + else + prmsg(M_ARTICLE); +} + + +#ifdef _PROTOTYPES_ +void say(Aword id) +#else +void say(id) + Aword id; +#endif +{ + char str[80]; + + if (isHere(HERO)) { + if (isObj(id)) + sayobj(id); + else if (isLoc(id)) + sayloc(id); + else if (isAct(id)) + sayact(id); + else if (isLit(id)) + saylit(id); + else { + sprintf(str, "Can't SAY item (%ld).", (unsigned long) id); + syserr(str); + } + } +} + + +/*---------------------------------------------------------------------- + + describe() + + */ + +#ifdef _PROTOTYPES_ +static void dscrloc(Aword loc) +#else +static void dscrloc(loc) + Aword loc; +#endif +{ + if (locs[loc-LOCMIN].dscr != 0) + interpret(locs[loc-LOCMIN].dscr); +} + + +#ifdef _PROTOTYPES_ +static void dscrobj(Aword obj) +#else +static void dscrobj(obj) + Aword obj; +#endif +{ + objs[obj-OBJMIN].describe = FALSE; + if (objs[obj-OBJMIN].dscr1 != 0) + interpret(objs[obj-OBJMIN].dscr1); + else { + prmsg(M_SEEOBJ1); + sayarticle(obj); + say(obj); + prmsg(M_SEEOBJ4); + if (objs[obj-OBJMIN].cont != 0) + list(obj); + } +} + + +#ifdef _PROTOTYPES_ +static void dscract(Aword act) +#else +static void dscract(act) + Aword act; +#endif +{ + ScrElem *scr = NULL; + + if (acts[act-ACTMIN].script != 0) { + for (scr = (ScrElem *) addrTo(acts[act-ACTMIN].scradr); !endOfTable(scr); scr++) + if (scr->code == acts[act-ACTMIN].script) + break; + if (endOfTable(scr)) scr = NULL; + } + if (scr != NULL && scr->dscr != 0) + interpret(scr->dscr); + else if (acts[act-ACTMIN].dscr != 0) + interpret(acts[act-ACTMIN].dscr); + else { + interpret(acts[act-ACTMIN].nam); + prmsg(M_SEEACT); + } + acts[act-ACTMIN].describe = FALSE; +} + + +static Aword dscrstk[255]; + +#ifdef _PROTOTYPES_ +void describe(Aword id) +#else +void describe(id) + Aword id; +#endif +{ + int i; + char str[80]; + + for (i = 0; i < dscrstkp; i++) + if (dscrstk[i] == id) + syserr("Recursive DESCRIBE."); + dscrstk[dscrstkp++] = id; + + if (isObj(id)) + dscrobj(id); + else if (isLoc(id)) + dscrloc(id); + else if (isAct(id)) + dscract(id); + else { + sprintf(str, "Can't DESCRIBE item (%ld).", (unsigned long) id); + syserr(str); + } + + dscrstkp--; +} + + +/*---------------------------------------------------------------------- + + use() + + */ + +#ifdef _PROTOTYPES_ +void use(Aword act, Aword scr) +#else +void use(act, scr) + Aword act, scr; +#endif +{ + char str[80]; + + if (!isAct(act)) { + sprintf(str, "Item is not an Actor (%ld).", (unsigned long) act); + syserr(str); + } + + acts[act-ACTMIN].script = scr; + acts[act-ACTMIN].step = 0; +} + + + +/*---------------------------------------------------------------------- + + list() + + */ + +#ifdef _PROTOTYPES_ +void list(Aword cnt) +#else +void list(cnt) + Aword cnt; +#endif +{ + int i; + Aword props; + Aword prevobj; + Boolean found = FALSE; + Boolean multiple = FALSE; + + /* Find container properties */ + if (isObj(cnt)) + props = objs[cnt-OBJMIN].cont; + else if (isAct(cnt)) + props = acts[cnt-ACTMIN].cont; + else + props = cnt; + + for (i = OBJMIN; i <= OBJMAX; i++) { + if (in(i, cnt)) { /* Yes, it's in this container */ + if (!found) { + found = TRUE; + if (cnts[props-CNTMIN].header != 0) + interpret(cnts[props-CNTMIN].header); + else { + prmsg(M_CONTAINS1); + if (cnts[props-CNTMIN].nam != 0) /* It has it's own name */ + interpret(cnts[props-CNTMIN].nam); + else + say(cnts[props-CNTMIN].parent); /* It is actually an object or actor */ + prmsg(M_CONTAINS2); + } + } else { + if (multiple) { + needsp = FALSE; + prmsg(M_CONTAINS3); + } + multiple = TRUE; + sayarticle(prevobj); + say(prevobj); + } + prevobj = i; + } + } + + if (found) { + if (multiple) + prmsg(M_CONTAINS4); + sayarticle(prevobj); + say(prevobj); + prmsg(M_CONTAINS5); + } else { + if (cnts[props-CNTMIN].empty != 0) + interpret(cnts[props-CNTMIN].empty); + else { + prmsg(M_EMPTY1); + if (cnts[props-CNTMIN].nam != 0) /* It has it's own name */ + interpret(cnts[props-CNTMIN].nam); + else + say(cnts[props-CNTMIN].parent); /* It is actually an actor or object */ + prmsg(M_EMPTY2); + } + } + needsp = TRUE; +} + + +/*---------------------------------------------------------------------- + + empty() + + */ + +#ifdef _PROTOTYPES_ +void empty(Aword cnt, Aword whr) +#else +void empty(cnt, whr) + Aword cnt; + Aword whr; +#endif +{ + int i; + + for (i = OBJMIN; i <= OBJMAX; i++) + if (in(i, cnt)) + locate(i, whr); +} + + + +/*----------------------------------------------------------------------*\ + + Description of current location + + dscrobjs() + dscracts() + look() + +\*----------------------------------------------------------------------*/ + +#ifdef _PROTOTYPES_ +void dscrobjs(void) +#else +void dscrobjs() +#endif +{ + int i; + int prevobj; + Boolean found = FALSE; + Boolean multiple = FALSE; + + /* First describe everything here with its own description */ + for (i = OBJMIN; i <= OBJMAX; i++) + if (objs[i-OBJMIN].loc == cur.loc && + objs[i-OBJMIN].describe && + objs[i-OBJMIN].dscr1) + describe(i); + + /* Then list everything else here */ + for (i = OBJMIN; i <= OBJMAX; i++) + if (objs[i-OBJMIN].loc == cur.loc && + objs[i-OBJMIN].describe) { + if (!found) { + prmsg(M_SEEOBJ1); + sayarticle(i); + say(i); + found = TRUE; + } else { + if (multiple) { + needsp = FALSE; + prmsg(M_SEEOBJ2); + sayarticle(prevobj); + say(prevobj); + } + multiple = TRUE; + } + prevobj = i; + } + + if (found) { + if (multiple) { + prmsg(M_SEEOBJ3); + sayarticle(prevobj); + say(prevobj); + } + prmsg(M_SEEOBJ4); + } + + /* Set describe flag for all objects */ + for (i = OBJMIN; i <= OBJMAX; i++) + objs[i-OBJMIN].describe = TRUE; +} + + +#ifdef _PROTOTYPES_ +void dscracts(void) +#else +void dscracts() +#endif +{ + int i; + + for (i = HERO+1; i <= ACTMAX; i++) + if (acts[i-ACTMIN].loc == cur.loc && + acts[i-ACTMIN].describe) + describe(i); + + /* Set describe flag for all actors */ + for (i = HERO; i <= ACTMAX; i++) + acts[i-ACTMIN].describe = TRUE; +} + + +#ifdef _PROTOTYPES_ +void look(void) +#else +void look() +#endif +{ + int i; + + if (looking) + syserr("Recursive LOOK."); + + looking = TRUE; + /* Set describe flag for all objects and actors */ + for (i = OBJMIN; i <= OBJMAX; i++) + objs[i-OBJMIN].describe = TRUE; + for (i = ACTMIN; i <= ACTMAX; i++) + acts[i-ACTMIN].describe = TRUE; + + if (anyOutput) + para(); + +g_vm->glk_set_style(style_Subheader); +needsp = FALSE; + say(cur.loc); + needsp = FALSE; + output("."); +g_vm->glk_set_style(style_Normal); + newline(); +needsp = FALSE; + describe(cur.loc); + dscrobjs(); + dscracts(); + looking = FALSE; +} + + + +static char savfnm[256]; + + +/*---------------------------------------------------------------------- + + save() + + */ + +#ifdef GARGLK +void save() { + g_vm->saveGame(); +} + +#else + +#ifdef _PROTOTYPES_ +void save(void) +#else +void save() +#endif +{ + int i; + char str[256]; + AtrElem *atr; + FILE *savfil; + + /* First save ? */ + if (savfnm[0] == '\0') { + strcpy(savfnm, advnam); + strcat(savfnm, ".sav"); + } + prmsg(M_SAVEWHERE); + sprintf(str, "(%s) : ", savfnm); + output(str); + +#ifdef USE_READLINE + readline(str); +#else + gets(str); +#endif + +frefid_t fref; +fref = g_vm->glk_fileref_create_by_prompt(fileusage_SavedGame, filemode_Write, 0); +if (fref == NULL) + error(M_SAVEFAILED); +strcpy(str, g_vm->garglk_fileref_get_name(fref)); +g_vm->glk_fileref_destroy(fref); + + if (str[0] == '\0') + strcpy(str, savfnm); + col = 1; + if ((savfil = fopen(str, READ_MODE)) != NULL) + /* It already existed */ + if (!confirm(M_SAVEOVERWRITE)) + error(MSGMAX); /* Return to player without saying anything */ + if ((savfil = fopen(str, WRITE_MODE)) == NULL) + error(M_SAVEFAILED); + strcpy(savfnm, str); + + /* Save version of interpreter and name of game */ + fwrite((void *)&header->vers, sizeof(Aword), 1, savfil); + fwrite((void *)advnam, strlen(advnam)+1, 1, savfil); + /* Save current values */ + fwrite((void *)&cur, sizeof(cur), 1, savfil); + /* Save actors */ + for (i = ACTMIN; i <= ACTMAX; i++) { + fwrite((void *)&acts[i-ACTMIN].loc, sizeof(Aword), 1, savfil); + fwrite((void *)&acts[i-ACTMIN].script, sizeof(Aword), 1, savfil); + fwrite((void *)&acts[i-ACTMIN].step, sizeof(Aword), 1, savfil); + fwrite((void *)&acts[i-ACTMIN].count, sizeof(Aword), 1, savfil); + if (acts[i-ACTMIN].atrs) + for (atr = (AtrElem *) addrTo(acts[i-ACTMIN].atrs); !endOfTable(atr); atr++) + fwrite((void *)&atr->val, sizeof(Aword), 1, savfil); + } + + /* Save locations */ + for (i = LOCMIN; i <= LOCMAX; i++) { + fwrite((void *)&locs[i-LOCMIN].describe, sizeof(Aword), 1, savfil); + if (locs[i-LOCMIN].atrs) + for (atr = (AtrElem *) addrTo(locs[i-LOCMIN].atrs); !endOfTable(atr); atr++) + fwrite((void *)&atr->val, sizeof(Aword), 1, savfil); + } + + /* Save objects */ + for (i = OBJMIN; i <= OBJMAX; i++) { + fwrite((void *)&objs[i-OBJMIN].loc, sizeof(Aword), 1, savfil); + if (objs[i-OBJMIN].atrs) + for (atr = (AtrElem *) addrTo(objs[i-OBJMIN].atrs); !endOfTable(atr); atr++) + fwrite((void *)&atr->val, sizeof(atr->val), 1, savfil); + } + + /* Save the event queue */ + eventq[etop].time = 0; /* Mark the top */ + fwrite((void *)&eventq[0], sizeof(eventq[0]), etop+1, savfil); + + /* Save scores */ + for (i = 0; scores[i] != EOF; i++) + fwrite((void *)&scores[i], sizeof(Aword), 1, savfil); + + fclose(savfil); +} +#endif + +/*---------------------------------------------------------------------- + + restore() + + */ + +#ifdef GARGLK +void restore() { + g_vm->loadGame(); +} + +#else + +#ifdef _PROTOTYPES_ +void restore(void) +#else +void restore() +#endif +{ + int i,tmp; + FILE *savfil; + char str[256]; + AtrElem *atr; + char savedVersion[4]; + char savedName[256]; + + /* First save ? */ + if (savfnm[0] == '\0') { + strcpy(savfnm, advnam); + strcat(savfnm, ".sav"); + } + prmsg(M_RESTOREFROM); + sprintf(str, "(%s) : ", savfnm); + output(str); +#ifdef USE_READLINE + readline(str); +#else + gets(str); +#endif + + if (str[0] == '\0') + strcpy(str, savfnm); + col = 1; + if (str[0] == '\0') + strcpy(str, savfnm); /* Use the name temporarily */ + if ((savfil = fopen(str, READ_MODE)) == NULL) + error(M_SAVEMISSING); + strcpy(savfnm, str); /* Save it for future use */ + + tmp = fread((void *)&savedVersion, sizeof(Aword), 1, savfil); + /* 4f - save file version check doesn't seem to work on PC's! */ + if (strncmp(savedVersion, header->vers, 4)) { + fclose(savfil); + error(M_SAVEVERS); + return; + } + i = 0; + while ((savedName[i++] = fgetc(savfil)) != '\0'); + if (strcmp(savedName, advnam) != 0) { + fclose(savfil); + error(M_SAVENAME); + return; + } + + /* Restore current values */ + tmp = fread((void *)&cur, sizeof(cur), 1, savfil); + /* Restore actors */ + for (i = ACTMIN; i <= ACTMAX; i++) { + tmp = fread((void *)&acts[i-ACTMIN].loc, sizeof(Aword), 1, savfil); + tmp = fread((void *)&acts[i-ACTMIN].script, sizeof(Aword), 1, savfil); + tmp = fread((void *)&acts[i-ACTMIN].step, sizeof(Aword), 1, savfil); + tmp = fread((void *)&acts[i-ACTMIN].count, sizeof(Aword), 1, savfil); + if (acts[i-ACTMIN].atrs) + for (atr = (AtrElem *) addrTo(acts[i-ACTMIN].atrs); !endOfTable(atr); atr++) + tmp = fread((void *)&atr->val, sizeof(Aword), 1, savfil); + } + + /* Restore locations */ + for (i = LOCMIN; i <= LOCMAX; i++) { + tmp = fread((void *)&locs[i-LOCMIN].describe, sizeof(Aword), 1, savfil); + if (locs[i-LOCMIN].atrs) + for (atr = (AtrElem *) addrTo(locs[i-LOCMIN].atrs); !endOfTable(atr); atr++) + tmp = fread((void *)&atr->val, sizeof(Aword), 1, savfil); + } + + /* Restore objects */ + for (i = OBJMIN; i <= OBJMAX; i++) { + tmp = fread((void *)&objs[i-OBJMIN].loc, sizeof(Aword), 1, savfil); + if (objs[i-OBJMIN].atrs) + for (atr = (AtrElem *) addrTo(objs[i-OBJMIN].atrs); !endOfTable(atr); atr++) + tmp = fread((void *)&atr->val, sizeof(atr->val), 1, savfil); + } + + /* Restore the eventq */ + etop = 0; + do { + tmp = fread((void *)&eventq[etop], sizeof(eventq[0]), 1, savfil); + etop++; + } while (eventq[etop-1].time != 0); + etop--; + + /* Restore scores */ + for (i = 0; scores[i] != EOF; i++) + tmp = fread((void *)&scores[i], sizeof(Aword), 1, savfil); + + fclose(savfil); +} + +#endif + +/*---------------------------------------------------------------------- + + rnd() + + */ + +#ifdef _PROTOTYPES_ +Aword rnd(Aword from, Aword to) +#else +Aword rnd(from, to) + Aword from, to; +#endif +{ + if (to == from) + return to; + else if (to > from) + return (rand()/10)%(to-from+1)+from; + else + return (rand()/10)%(from-to+1)+to; +} + +/*---------------------------------------------------------------------- + + btw() + + BETWEEN + + */ + +#ifdef _PROTOTYPES_ +Abool btw(Aint val, Aint low, Aint high) +#else +Abool btw(val, low, high) + Aint val, low, high; +#endif +{ + if (high > low) + return low <= val && val <= high; + else + return high <= val && val <= low; +} + + + +/*---------------------------------------------------------------------- + + contains() + + */ + +#ifdef _PROTOTYPES_ +Aword contains(Aptr string, Aptr substring) +#else +Aword contains(string, substring) + Aptr string, substring;; +#endif +{ + Abool found; + + strlow((char *)string); + strlow((char *)substring); + + found = (strstr((char *)string, (char *)substring) != 0); + + free((char *)string); + free((char *)substring); + + return(found); +} + + + +/*---------------------------------------------------------------------- + + streq() + + Compare two strings approximately, ignore case + + */ +#ifdef _PROTOTYPES_ +Abool streq(char a[], char b[]) +#else +Abool streq(a, b) + char a[], b[]; /* IN - Strings to compare */ +#endif +{ + Boolean eq; + + strlow(a); + strlow(b); + + eq = (strcmp(a, b) == 0); + + free(a); + free(b); + + return(eq); +} + +} // End of namespace Alan2 +} // End of namespace Glk diff --git a/engines/glk/alan2/exe.h b/engines/glk/alan2/exe.h new file mode 100644 index 0000000000..0acfdda6eb --- /dev/null +++ b/engines/glk/alan2/exe.h @@ -0,0 +1,127 @@ +/* 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. + * + */ + +#ifndef GLK_ALAN2_EXE +#define GLK_ALAN2_EXE + +/* Header file for instruction execution unit in Alan interpreter + */ + +namespace Glk { +namespace Alan2 { + +/* The event queue */ +extern EvtqElem eventq[]; /* Event queue */ +extern int etop; /* Event queue top pointer */ +extern Boolean looking; /* LOOKING? flag */ +extern int dscrstkp; /* Point into describe stack */ + +#ifdef _PROTOTYPES_ +extern void sys(Aword fpos, Aword len); +extern Boolean confirm(MsgKind msgno); +extern Aptr attribute(Aword item, Aword atr); +extern void say(Aword item); +extern void saynum(Aword num); +extern void saystr(char *str); +extern Aptr strattr(Aword id, Aword atr); +extern void setstr(Aword id, Aword atr, Aword str); +extern void getstr(Aword fpos, Aword len); +extern void print(Aword fpos, Aword len); +extern void look(void); +extern void make(Aword id, Aword atr, Aword val); +extern void set(Aword id, Aword atr, Aword val); +extern void incr(Aword id, Aword atr, Aword step); +extern void decr(Aword id, Aword atr, Aword step); +extern void use(Aword act, Aword scr); +extern void describe(Aword id); +extern void list(Aword cnt); +extern void locate(Aword id, Aword whr); +extern void empty(Aword cnt, Aword whr); +extern void score(Aword sc); +extern void visits(Aword v); +extern void schedule(Aword evt, Aword whr, Aword aft); +extern void cancl(Aword evt); +extern void quit(void); +extern void restart(void); +extern void save(void); +extern void restore(void); +extern void say(Aword id); +extern void sayint(Aword val); +extern Aword rnd(Aword from, Aword to); +extern Abool btw(Aint val, Aint from, Aint to); +extern Aword contains(Aptr string, Aptr substring); +extern Abool streq(char a[], char b[]); +extern Abool in(Aword obj, Aword cnt); +extern Aword where(Aword item); +extern Aint agrmax(Aword atr, Aword whr); +extern Aint agrsum(Aword atr, Aword whr); +extern Aint agrcount(Aword whr); +extern Abool isHere(Aword item); +extern Abool isNear(Aword item); + +#else +extern void sys(); +extern Boolean confirm(); +extern Aptr attribute(); +extern void say(); +extern void saynum(); +extern void saystr(); +extern Aptr strattr(); +extern void setstr(); +extern void getstr(); +extern void print(); +extern void look(); +extern void make(); +extern void set(); +extern void incr(); +extern void decr(); +extern void use(); +extern void describe(); +extern void list(); +extern void locate(); +extern void empty(); +extern void score(); +extern void visits(); +extern void schedule(); +extern void cancl(); +extern void quit(); +extern void restart(); +extern void save(); +extern void restore(); +extern void say(); +extern void sayint(); +extern Aword rnd(); +extern Abool btw(); +extern Aword contains() +extern Abool streq(); +extern Abool in(); +extern Aword where(); +extern Aword agrmax(); +extern Aword agrsum(); +extern Abool isHere(); +extern Abool isNear(); +#endif + +} // End of namespace Alan2 +} // End of namespace Glk + +#endif diff --git a/engines/glk/alan2/glkio.cpp b/engines/glk/alan2/glkio.cpp new file mode 100644 index 0000000000..346413170c --- /dev/null +++ b/engines/glk/alan2/glkio.cpp @@ -0,0 +1,47 @@ +/* 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/glk.h" +#include "glk/alan2/alan2.h" +#include "glk/alan2/glkio.h" + +namespace Glk { +namespace Alan2 { + +void glkio_printf(char *fmt, ...) { + va_list argp; + va_start(argp, fmt); + if (glkMainWin) { + char buf[1024]; /* FIXME: buf size should be foolproof */ + vsprintf(buf, fmt, argp); + g_vm->glk_put_string(buf); + } else { + // assume stdio is available in this case only + Common::String str = Common::String::vformat(fmt, argp); + warning(fmt, argp); + } + + va_end(argp); +} + +} // End of namespace Alan2 +} // End of namespace Glk diff --git a/engines/glk/alan2/glkio.h b/engines/glk/alan2/glkio.h new file mode 100644 index 0000000000..7dca2cab87 --- /dev/null +++ b/engines/glk/alan2/glkio.h @@ -0,0 +1,48 @@ +/* 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. + * + */ + +#ifndef GLK_ALAN2_GLKIO +#define GLK_ALAN2_GLKIO + +/* Header file for Glk output for Alan interpreter + */ + +#include "glk/windows.h" + +namespace Glk { +namespace Alan2 { + +winid_t glkMainWin; +winid_t glkStatusWin; + +/* NB: this header must be included in any file which calls print() */ + +#define print glkio_printf +#undef printf +#define printf glkio_printf + +void glkio_printf(char *, ...); + +} // End of namespace Alan2 +} // End of namespace Glk + +#endif diff --git a/engines/glk/alan2/glkstart.cpp b/engines/glk/alan2/glkstart.cpp new file mode 100644 index 0000000000..1119e18bf0 --- /dev/null +++ b/engines/glk/alan2/glkstart.cpp @@ -0,0 +1,65 @@ +/* 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/alan2.h" +#include "glk/alan2/glkstart.h" +#include "glk/alan2/glkio.h" +#include "glk/alan2/args.h" + +#include "glk/alan2/alan_version.h" + +namespace Glk { +namespace Alan2 { + +glkunix_argumentlist_t glkunix_arguments[] = { + { "-v", glkunix_arg_NoValue, "-v: verbose mode" }, + { "-l", glkunix_arg_NoValue, "-l: log player command and game output" }, + { "-i", glkunix_arg_NoValue, "-i: ignore version and checksum errors" }, + { "-d", glkunix_arg_NoValue, "-d: enter debug mode" }, + { "-t", glkunix_arg_NoValue, "-t: trace game execution" }, + { "-s", glkunix_arg_NoValue, "-s: single instruction trace" }, + { "", glkunix_arg_ValueFollows, "filename: The game file to load." }, + { NULL, glkunix_arg_End, NULL } +}; + +bool glkunix_startup_code(glkunix_startup_t *data) { + // first, open a window for error output + glkMainWin = g_vm->glk_window_open(0, 0, 0, wintype_TextBuffer, 0); + if (glkMainWin == nullptr) + error("FATAL ERROR: Cannot open initial window"); + + g_vm->glk_stylehint_set(wintype_TextGrid, style_User1, stylehint_ReverseColor, 1); + glkStatusWin = g_vm->glk_window_open(glkMainWin, winmethod_Above | + winmethod_Fixed, 1, wintype_TextGrid, 0); + g_vm->glk_set_window(glkMainWin); + + /* now process the command line arguments */ + args(data->argc, data->argv); + + g_vm->garglk_set_program_name(alan.shortHeader); + g_vm->garglk_set_program_info("Alan Interpreter 2.8.6 by Thomas Nilsson\n"); + + return true; +} + +} // End of namespace Alan2 +} // End of namespace Glk diff --git a/engines/glk/alan2/glkstart.h b/engines/glk/alan2/glkstart.h new file mode 100644 index 0000000000..7e3a24b4dc --- /dev/null +++ b/engines/glk/alan2/glkstart.h @@ -0,0 +1,70 @@ +/* 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. + * + */ + +#ifndef GLK_ALAN2_GLK_START +#define GLK_ALAN2_GLK_START + +/* This header defines an interface that must be used by program linked + with the various Unix Glk libraries -- at least, the three I wrote. + (I encourage anyone writing a Unix Glk library to use this interface, + but it's not part of the Glk spec.) + + Because Glk is *almost* perfectly portable, this interface *almost* + doesn't have to exist. In practice, it's small. +*/ + +namespace Glk { +namespace Alan2 { + +#define glkunix_arg_End (0) +#define glkunix_arg_ValueFollows (1) +#define glkunix_arg_NoValue (2) +#define glkunix_arg_ValueCanFollow (3) +#define glkunix_arg_NumberValue (4) + +typedef struct glkunix_argumentlist_struct { + char *name; + int argtype; + char *desc; +} glkunix_argumentlist_t; + +typedef struct glkunix_startup_struct { + int argc; + char **argv; +} glkunix_startup_t; + +/* The list of command-line arguments; this should be defined in your code. */ +extern glkunix_argumentlist_t glkunix_arguments[]; + +/* The external function; this should be defined in your code. */ +extern bool glkunix_startup_code(glkunix_startup_t *data); + +/* Some helpful utility functions which the library makes available + to your code. Obviously, this is nonportable; so you should + only call it from glkunix_startup_code(). +*/ +extern strid_t glkunix_stream_open_pathname(char *pathname, uint textmode, uint rock); + +} // End of namespace Alan2 +} // End of namespace Glk + +#endif diff --git a/engines/glk/alan2/inter.cpp b/engines/glk/alan2/inter.cpp new file mode 100644 index 0000000000..02b4f4819f --- /dev/null +++ b/engines/glk/alan2/inter.cpp @@ -0,0 +1,893 @@ +/* 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 <string> +#include "glk/alan2/types.h" +#include "glk/alan2/main.h" +#include "glk/alan2/parse.h" +#include "glk/alan2/exe.h" +#include "glk/alan2/stack.h" +#include "glk/alan2/sysdep.h" + +#include "glk/alan2/inter.h" + +#ifdef GLK +#include "glk/alan2/glkio.h" +#endif + +namespace Glk { +namespace Alan2 { + +/* PRIVATE DATA */ + +static int pc; + + +#ifdef _PROTOTYPES_ +static void if_( + Aword v +) +#else +static void if_(v) + Aword v; +#endif +{ + int lev = 1; + Aword i; + + if (!v) { + /* Skip to next ELSE or ENDIF on same level */ + while (TRUE) { + i = memory[pc++]; + if (I_CLASS(i) == (Aword)C_STMOP) + switch (I_OP(i)) { + case I_ELSE: + if (lev == 1) return; + break; + case I_IF: + lev++; + break; + case I_ENDIF: + lev--; + if (lev == 0) return; + break; + } + } + } +} + + +#ifdef _PROTOTYPES_ +static void else_(void) +#else +static void else_() +#endif +{ + int lev = 1; + Aword i; + + while (TRUE) { + /* Skip to ENDIF on the same level */ + i = memory[pc++]; + if (I_CLASS(i) == (Aword)C_STMOP) + switch (I_OP(i)) { + case I_ENDIF: + lev--; + if (lev == 0) return; + break; + case I_IF: + lev++; + break; + } + } +} + + +#ifdef _PROTOTYPES_ +static void depstart(void) +#else +static void depstart(void) +#endif +{ + /* A DEPSTART was executed so skip across the redundant DEPCASE to + start at the first expression */ + pc++; +} + + +#ifdef _PROTOTYPES_ +static void swap(void) +#else +static void swap() +#endif +{ + Aptr v1 = pop(); + Aptr v2 = pop(); + + push(v1); + push(v2); +} + + + +#ifdef _PROTOTYPES_ +static void depexec( + Aword v +) +#else +static void depexec(v) + Aword v; +#endif +{ + int lev = 1; + Aword i; + + if (!v) + /* The expression was not true, skip to next CASE on the same + level which could be a DEPCASE or DEPELSE */ + while (TRUE) { + i = memory[pc++]; + if (I_CLASS(i) == (Aword)C_STMOP) + switch (I_OP(i)) { + case I_DEPSTART: + lev++; + break; + case I_DEPEND: + if (lev == 1) return; + lev--; + break; + case I_DEPCASE: + case I_DEPELSE: + if (lev == 1) return; + break; + } + } +} + + +#ifdef _PROTOTYPES_ +static void depcase(void) +#else +static void depcase() +#endif +{ + int lev = 1; + Aword i; + + /* Skip to end of DEPENDING block (next DEPEND on same level) because + we have just executed a DEPCASE/DEPELSE statement as a result of a DEPCASE + catching */ + + while (TRUE) { + i = memory[pc++]; + if (I_CLASS(i) == (Aword)C_STMOP) + switch (I_OP(i)) { + case I_DEPSTART: + lev++; + break; + case I_DEPEND: + lev--; + if (lev == 0) return; + break; + } + } +} + + +#ifdef _PROTOTYPES_ +void interpret(Aaddr adr) +#else +void interpret(adr) + Aaddr adr; +#endif +{ + Aaddr oldpc; + Aword i; + + if (stpflg) printf("\n++++++++++++++++++++++++++++++++++++++++++++++++++"); + + oldpc = pc; + pc = adr; + while(TRUE) { + if (stpflg) printf("\n%4x: ", pc); + if (pc > memTop) + syserr("Interpreting outside program."); + + i = memory[pc++]; + + switch (I_CLASS(i)) { + case C_CONST: + if (stpflg) printf("PUSH \t%5ld", I_OP(i)); + push(I_OP(i)); + break; + case C_CURVAR: + switch (I_OP(i)) { + case V_PARAM: + if (stpflg) printf("PARAM \t%5ld\t\t(%ld)", top(), params[top()-1].code); + push(params[pop()-1].code); + break; + case V_CURLOC: + if (stpflg) printf("CURLOC \t\t\t(%d)", cur.loc); + push(cur.loc); + break; + case V_CURACT: + if (stpflg) printf("CURACT \t\t\t(%d)", cur.act); + push(cur.act); + break; + case V_CURVRB: + if (stpflg) printf("CURVRB \t\t\t(%d)", cur.vrb); + push(cur.vrb); + break; + case V_SCORE: + if (stpflg) printf("CURSCORE \t\t\t(%d)", cur.score); + push(cur.score); + break; + default: + syserr("Unknown CURVAR instruction."); + break; + } + break; + + case C_STMOP: + switch (I_OP(i)) { + case I_PRINT: { + Aptr fpos, len; + fpos = pop(); + len = pop(); + if (stpflg) { + printf("PRINT \t%5ld, %5ld\t\"", fpos, len); + col = 34; /* To format it better! */ + } + print((char *)fpos, len); + if (stpflg) + printf("\""); + break; + } + case I_SYSTEM: { + Aptr fpos, len; + fpos = pop(); + len = pop(); + if (stpflg) { + printf("SYSTEM \t%5ld, %5ld\t\"", fpos, len); + col = 34; /* To format it better! */ + } + sys(fpos, len); + break; + } + case I_GETSTR: { + Aptr fpos, len; + fpos = pop(); + len = pop(); + if (stpflg) + printf("GETSTR\t%5ld, %5ld", fpos, len); + getstr(fpos, len); + if (stpflg) + printf("\t(%ld)", top()); + break; + } + case I_QUIT: { + if (stpflg) + printf("QUIT"); + quit(); + break; + } + case I_LOOK: { + if (stpflg) + printf("LOOK"); + look(); + break; + } + case I_SAVE: { + if (stpflg) + printf("SAVE"); + save(); + break; + } + case I_RESTORE: { + if (stpflg) + printf("RESTORE"); + restore(); + break; + } + case I_RESTART: { + if (stpflg) + printf("RESTART"); + restart(); + break; + } + case I_LIST: { + Aptr cnt; + cnt = pop(); + if (stpflg) + printf("LIST \t%5ld", cnt); + list(cnt); + break; + } + case I_EMPTY: { + Aptr cnt, whr; + cnt = pop(); + whr = pop(); + if (stpflg) + printf("EMPTY \t%5ld, %5ld", cnt, whr); + empty(cnt, whr); + break; + } + case I_SCORE: { + Aptr sc; + sc = pop(); + if (stpflg) + printf("SCORE \t%5ld\t\t(%ld)", sc, scores[sc-1]); + score(sc); + break; + } + case I_VISITS: { + Aptr v; + v = pop(); + if (stpflg) + printf("VISITS \t%5ld", v); + visits(v); + break; + } + case I_SCHEDULE: { + Aptr evt, whr, aft; + evt = pop(); + whr = pop(); + aft = pop(); + if (stpflg) + printf("SCHEDULE \t%5ld, %5ld, %5ld", evt, whr, aft); + schedule(evt, whr, aft); + break; + } + case I_CANCEL: { + Aptr evt; + evt = pop(); + if (stpflg) + printf("CANCEL \t%5ld", evt); + cancl(evt); + break; + } + case I_MAKE: { + Aptr id, atr, val; + id = pop(); + atr = pop(); + val = pop(); + if (stpflg) { + printf("MAKE \t%5ld, %5ld, ", id, atr); + if (val) printf("TRUE"); else printf("FALSE"); + } + make(id, atr, val); + break; + } + case I_SET: { + Aptr id, atr, val; + id = pop(); + atr = pop(); + val = pop(); + if (stpflg) { + printf("SET \t%5ld, %5ld, %5ld", id, atr, val); + } + set(id, atr, val); + break; + } + case I_STRSET: { + Aptr id, atr, str; + id = pop(); + atr = pop(); + str = pop(); + if (stpflg) { + printf("STRSET\t%5ld, %5ld, %5ld", id, atr, str); + } + setstr(id, atr, str); + break; + } + case I_INCR: { + Aptr id, atr, step; + id = pop(); + atr = pop(); + step = pop(); + if (stpflg) { + printf("INCR\t%5ld, %5ld, %5ld", id, atr, step); + } + incr(id, atr, step); + break; + } + case I_DECR: { + Aptr id, atr, step; + id = pop(); + atr = pop(); + step = pop(); + if (stpflg) { + printf("DECR\t%5ld, %5ld, %5ld", id, atr, step); + } + decr(id, atr, step); + break; + } + case I_ATTRIBUTE: { + Aptr id, atr; + id = pop(); + atr = pop(); + if (stpflg) + printf("ATTRIBUTE %5ld, %5ld", id, atr); + push(attribute(id, atr)); + if (stpflg) + printf("\t(%ld)", top()); + break; + } + case I_STRATTR: { + Aptr id, atr; + id = pop(); + atr = pop(); + if (stpflg) + printf("STRATTR \t%5ld, %5ld", id, atr); + push(strattr(id, atr)); + if (stpflg) + printf("\t(%ld)", top()); + break; + } + case I_LOCATE: { + Aptr id, whr; + id = pop(); + whr = pop(); + if (stpflg) + printf("LOCATE \t%5ld, %5ld", id, whr); + locate(id, whr); + break; + } + case I_WHERE: { + Aptr id; + id = pop(); + if (stpflg) + printf("WHERE \t%5ld", id); + push(where(id)); + if (stpflg) + printf("\t\t(%ld)", top()); + break; + } + case I_HERE: { + Aptr id; + id = pop(); + if (stpflg) + printf("HERE \t%5ld", id); + push(isHere(id)); + if (stpflg) + if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)"); + break; + } + case I_NEAR: { + Aptr id; + id = pop(); + if (stpflg) + printf("NEAR \t%5ld", id); + push(isNear(id)); + if (stpflg) + if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)"); + break; + } + case I_USE: { + Aptr act, scr; + act = pop(); + scr = pop(); + if (stpflg) + printf("USE \t%5ld, %5ld", act, scr); + use(act, scr); + break; + } + case I_IN: { + Aptr obj, cnt; + obj = pop(); + cnt = pop(); + if (stpflg) + printf("IN \t%5ld, %5ld ", obj, cnt); + push(in(obj, cnt)); + if (stpflg) + if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)"); + break; + } + case I_DESCRIBE: { + Aptr id; + id = pop(); + if (stpflg) { + printf("DESCRIBE \t%5ld\t", id); + col = 34; /* To format it better! */ + } + describe(id); + break; + } + case I_SAY: { + Aptr id; + id = pop(); + if (stpflg) + printf("SAY \t%5ld\t\t\"", id); + say(id); + if (stpflg) + printf("\""); + break; + } + case I_SAYINT: { + Aptr val; + val = pop(); + if (stpflg) + printf("SAYINT\t%5ld\t\t\"", val); + sayint(val); + if (stpflg) + printf("\""); + break; + } + case I_SAYSTR: { + Aptr adr; + adr = pop(); + if (stpflg) + printf("SAYSTR\t%5ld\t\t\"", adr); + saystr((char *)adr); + if (stpflg) + printf("\""); + break; + } + case I_IF: { + Aptr v; + v = pop(); + if (stpflg) { + printf("IF \t"); + if (v) printf(" TRUE"); else printf("FALSE"); + } + if_(v); + break; + } + case I_ELSE: { + if (stpflg) + printf("ELSE"); + else_(); + break; + } + case I_ENDIF: { + if (stpflg) + printf("ENDIF"); + break; + } + case I_AND: { + Aptr lh, rh; + if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ + swap(); + rh = pop(); + lh = pop(); + if (stpflg) { + printf("AND \t"); + if (lh) printf("TRUE, "); else printf("FALSE, "); + if (rh) printf("TRUE"); else printf("FALSE"); + } + push(lh && rh); + if (stpflg) + if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)"); + break; + } + case I_OR: { + Aptr lh, rh; + if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ + swap(); + rh = pop(); + lh = pop(); + if (stpflg) { + printf("OR \t"); + if (lh) printf("TRUE, "); else printf("FALSE, "); + if (rh) printf("TRUE"); else printf("FALSE"); + } + push(lh || rh); + if (stpflg) + if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)"); + break; + } + case I_NE: { + Aptr lh, rh; + if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ + swap(); + rh = pop(); + lh = pop(); + if (stpflg) + printf("NE \t%5ld, %5ld", lh, rh); + push(lh != rh); + if (stpflg) + if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)"); + break; + } + case I_EQ: { + Aptr lh, rh; + if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ + swap(); + rh = pop(); + lh = pop(); + if (stpflg) + printf("EQ \t%5ld, %5ld", lh, rh); + push(lh == rh); + if (stpflg) + if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)"); + break; + } + case I_STREQ: { + Aptr lh, rh; + if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ + swap(); + rh = pop(); + lh = pop(); + if (stpflg) + printf("STREQ \t%5ld, %5ld", lh, rh); + push(streq((char *)lh, (char *)rh)); + if (stpflg) + if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)"); + break; + } + case I_STREXACT: { + Aptr lh, rh; + if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ + swap(); + rh = pop(); + lh = pop(); + if (stpflg) + printf("STREXACT \t%5ld, %5ld", lh, rh); + push(strcmp((char *)lh, (char *)rh) == 0); + if (stpflg) + if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)"); + free((void *)lh); + free((void *)rh); + break; + } + case I_LE: { + Aint lh, rh; + if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ + swap(); + rh = pop(); + lh = pop(); + if (stpflg) + printf("LE \t%5ld, %5ld", lh, rh); + push(lh <= rh); + if (stpflg) + if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)"); + break; + } + case I_GE: { + Aint lh, rh; + if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ + swap(); + rh = pop(); + lh = pop(); + if (stpflg) + printf("GE \t%5ld, %5ld", lh, rh); + push(lh >= rh); + if (stpflg) + if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)"); + break; + } + case I_LT: { + Aint lh, rh; + if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ + swap(); + rh = pop(); + lh = pop(); + if (stpflg) + printf("LT \t%5ld, %5ld", lh, rh); + push((signed int)lh < (signed int)rh); + if (stpflg) + if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)"); + break; + } + case I_GT: { + Aint lh, rh; + if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ + swap(); + rh = pop(); + lh = pop(); + if (stpflg) + printf("GT \t%5ld, %5ld", lh, rh); + push(lh > rh); + if (stpflg) + if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)"); + break; + } + case I_PLUS: { + Aint lh, rh; + if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ + swap(); + rh = pop(); + lh = pop(); + if (stpflg) + printf("PLUS \t%5ld, %5ld", lh, rh); + push(lh + rh); + if (stpflg) + printf("\t(%ld)", top()); + break; + } + case I_MINUS: { + Aint lh, rh; + if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ + swap(); + rh = pop(); + lh = pop(); + if (stpflg) + printf("MINUS \t%5ld, %5ld", lh, rh); + push(lh - rh); + if (stpflg) + printf("\t(%ld)", top()); + break; + } + case I_MULT: { + Aint lh, rh; + if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ + swap(); + rh = pop(); + lh = pop(); + if (stpflg) + printf("MULT \t%5ld, %5ld", lh, rh); + push(lh * rh); + if (stpflg) + printf("\t(%ld)", top()); + break; + } + case I_DIV: { + Aint lh, rh; + if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */ + swap(); + rh = pop(); + lh = pop(); + if (stpflg) + printf("DIV \t%5ld, %5ld", lh, rh); + push(lh / rh); + if (stpflg) + printf("\t(%ld)", top()); + break; + } + case I_NOT: { + Aptr val; + val = pop(); + if (stpflg) { + printf("NOT \t"); + if (val) printf("TRUE"); else printf("FALSE"); + } + push(!val); + if (stpflg) + if (top()) printf("\t\t(TRUE)"); else printf("\t\t(FALSE)"); + break; + } + case I_MAX: { + Aptr atr, whr; + atr = pop(); + whr = pop(); + if (stpflg) + printf("MAX \t%5ld, %5ld", atr, whr); + push(agrmax(atr, whr)); + if (stpflg) + printf("\t(%ld)", top()); + break; + } + case I_SUM: { + Aptr atr, whr; + atr = pop(); + whr = pop(); + if (stpflg) + printf("SUM \t%5ld, %5ld", atr, whr); + push(agrsum(atr, whr)); + if (stpflg) + printf("\t(%ld)", top()); + break; + } + case I_COUNT: { + Aptr whr; + whr = pop(); + if (stpflg) + printf("COUNT \t%5ld", whr); + push(agrcount(whr)); + if (stpflg) + printf("\t(%ld)", top()); + break; + } + case I_RND: { + Aptr from, to; + from = pop(); + to = pop(); + if (stpflg) + printf("RANDOM \t%5ld, %5ld", from, to); + push(rnd(from, to)); + if (stpflg) + printf("\t(%ld)", top()); + break; + } + case I_BTW: { + Aint low, high, val; + high = pop(); + low = pop(); + val = pop(); + if (stpflg) + printf("BETWEEN \t%5ld, %5ld, %5ld", val, low, high); + push(btw(val, low, high)); + if (stpflg) + printf("\t(%ld)", top()); + break; + } + case I_CONTAINS: { + Aptr string, substring; + substring = pop(); + string = pop(); + if (stpflg) + printf("CONTAINS \t%5ld, %5ld", string, substring); + push(contains(string, substring)); + if (stpflg) + printf("\t(%ld)", top()); + break; + } + + case I_DEPSTART: + if (stpflg) + printf("DEPSTART"); + depstart(); + break; + + case I_DEPCASE: + if (stpflg) + printf("DEPCASE"); + depcase(); + break; + + case I_DEPEXEC: { + Aptr v; + v = pop(); + if (stpflg) { + printf("DEPEXEC \t"); + if (v) printf(" TRUE"); else printf("FALSE"); + } + depexec(v); + break; + } + + case I_DEPELSE: + if (stpflg) + printf("DEPELSE"); + depcase(); + break; + + case I_DEPEND: + if (stpflg) + printf("DEPEND"); + break; + + case I_RETURN: + if (stpflg) + printf("RETURN\n--------------------------------------------------\n"); + pc = oldpc; + return; + + default: + syserr("Unknown STMOP instruction."); + break; + } + if (fail) { + pc = oldpc; + return; + } + break; + + default: + syserr("Unknown instruction class."); + break; + } + } +} + +} // End of namespace Alan2 +} // End of namespace Glk diff --git a/engines/glk/alan2/inter.h b/engines/glk/alan2/inter.h new file mode 100644 index 0000000000..a7fafefc59 --- /dev/null +++ b/engines/glk/alan2/inter.h @@ -0,0 +1,38 @@ +/* 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. + * + */ + +#ifndef GLK_ALAN2_INTER +#define GLK_ALAN2_INTER + +namespace Glk { +namespace Alan2 { + +#ifdef _PROTOTYPES_ +extern void interpret(Aaddr adr); +#else +extern void interpret(); +#endif + +} // End of namespace Alan2 +} // End of namespace Glk + +#endif diff --git a/engines/glk/alan2/main.h b/engines/glk/alan2/main.h new file mode 100644 index 0000000000..48c6d96382 --- /dev/null +++ b/engines/glk/alan2/main.h @@ -0,0 +1,155 @@ +/* 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. + * + */ + +#ifndef GLK_ALAN2_MAIN +#define GLK_ALAN2_MAIN + +/* Header file for main unit of ARUN Alan System interpreter */ + +#include "common/file.h" +#include "glk/alan2/types.h" + +namespace Glk { +namespace Alan2 { + +/* DATA */ + +#define MEMORYSIZE 1000L + +extern int memTop; /* Top of memory */ + +extern int conjWord; /* First conjunction in dictionary */ + +/* The Amachine memory */ +extern Aword *memory; +extern AcdHdr *header; + +/* Amachine variables */ +extern CurVars cur; + +/* Amachine data structures */ +extern WrdElem *dict; /* Dictionary pointer */ +extern ActElem *acts; /* Actor table pointer */ +extern LocElem *locs; /* Location table pointer */ +extern VrbElem *vrbs; /* Verb table pointer */ +extern StxElem *stxs; /* Syntax table pointer */ +extern ObjElem *objs; /* Object table pointer */ +extern CntElem *cnts; /* Container table pointer */ +extern RulElem *ruls; /* Rule table pointer */ +extern EvtElem *evts; /* Event table pointer */ +extern MsgElem *msgs; /* Message table pointer */ +extern Aword *scores; /* Score table pointer */ +extern Aword *freq; /* Cumulated frequencies */ + +extern int dictsize; /* Number of entries in dictionary */ + +/* The text and message file */ +extern Common::File *txtfil; +extern Common::WriteStream *logfil; + +#undef ftell +#undef fgetc +#undef getc +#undef fseek +#undef fclose +#define ftell(FP) FP->pos() +#define fgetc(FP) (FP->pos() >= FP->size()) ? EOF : FP->readByte() +#define getc(FP) (FP->pos() >= FP->size()) ? EOF : FP->readByte() +#define fseek(FP, OFS, WHENCE) FP->seek(OFS, WHENCE) +#define fclose(FP) delete FP + + +/* File names */ +extern char *advnam; + +/* Screen formatting info */ +extern int col, lin; +extern int paglen, pagwidth; + +/* Long jump buffer for restart */ +//extern jmp_buf restart_label; + +extern Boolean verbose, errflg, trcflg, dbgflg, stpflg, logflg, statusflg; +extern Boolean fail; +extern Boolean anyOutput; +extern Boolean needsp; + +#define endOfTable(x) eot((Aword *) x) + + +#ifdef _PROTOTYPES_ +extern void *allocate(unsigned long len); +extern void terminate(int code); +extern void usage(void); +extern void error(MsgKind msg); +extern void syserr(char *msg); +extern void statusline(void); +extern void output(char string[]); +extern void prmsg(MsgKind msg); +extern void para(void); +extern void newline(void); + +extern Boolean checklim(Aword cnt, Aword obj); +extern Boolean possible(void); +extern Boolean exitto(int to, int from); +extern void action(ParamElem *plst); +extern void go(int dir); + +extern Boolean eot(Aword *adr); +extern Boolean isObj(Aword x); +extern Boolean isCnt(Aword x); +extern Boolean isAct(Aword x); +extern Boolean isLoc(Aword x); +extern Boolean isLit(Aword x); +extern Boolean isNum(Aword x); +extern Boolean isStr(Aword x); + +/* Run the game! */ +extern void run(void); + +#else +extern void *allocate(); +extern void terminate(); +extern void syserr(); +extern void usage(); +extern void error(); +extern void output(); +extern void statusline(); +extern void prmsg(); +extern void print(); +extern void para(); +extern void newline(); +extern Boolean checklim(); +extern Boolean possible(); +extern Boolean eot(); +extern Boolean isObj(); +extern Boolean isCnt(); +extern Boolean isAct(); +extern Boolean isLoc(); +extern Boolean isLit(); +extern void run(); +#endif + +} // End of namespace Alan2 +} // End of namespace Glk + +#endif diff --git a/engines/glk/alan2/params.cpp b/engines/glk/alan2/params.cpp new file mode 100644 index 0000000000..b8851035f2 --- /dev/null +++ b/engines/glk/alan2/params.cpp @@ -0,0 +1,159 @@ +/* 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 <stdio.h> +#include "glk/alan2/types.h" +#include "glk/alan2/params.h" + +namespace Glk { +namespace Alan2 { + +#ifdef _PROTOTYPES_ +void compact(ParamElem a[]) +#else +void compact(a) + ParamElem a[]; +#endif +{ + int i, j; + + for (i = 0, j = 0; a[j].code != (Aword)EOF; j++) + if (a[j].code != 0) + a[i++] = a[j]; + a[i].code = (Aword)EOF; +} + + +#ifdef _PROTOTYPES_ +int lstlen(ParamElem a[]) +#else +int lstlen(a) + ParamElem a[]; +#endif +{ + int i = 0; + + while (a[i].code != (Aword)EOF) + i++; + return (i); +} + + +#ifdef _PROTOTYPES_ +Boolean inlst(ParamElem l[], Aword e) +#else +Boolean inlst(l, e) + ParamElem l[]; + Aword e; +#endif +{ + int i; + + for (i = 0; l[i].code != (Aword)EOF && l[i].code != e; i++); + return (l[i].code == e); +} + + +#ifdef _PROTOTYPES_ +void lstcpy(ParamElem a[], ParamElem b[]) +#else +void lstcpy(a, b) + ParamElem a[], b[]; +#endif +{ + int i; + + for (i = 0; b[i].code != (Aword)EOF; i++) + a[i] = b[i]; + a[i].code = (Aword)EOF; +} + + +#ifdef _PROTOTYPES_ +void sublst(ParamElem a[], ParamElem b[]) +#else +void sublst(a, b) + ParamElem a[], b[]; +#endif +{ + int i; + + for (i = 0; a[i].code != (Aword)EOF; i++) + if (inlst(b, a[i].code)) + a[i].code = 0; /* Mark empty */ + compact(a); +} + + +#ifdef _PROTOTYPES_ +void mrglst(ParamElem a[], ParamElem b[]) +#else +void mrglst(a, b) + ParamElem a[], b[]; +#endif +{ + int i,last; + + for (last = 0; a[last].code != (Aword)EOF; last++); /* Find end of list */ + for (i = 0; b[i].code != (Aword)EOF; i++) + if (!inlst(a, b[i].code)) { + a[last++] = b[i]; + a[last].code = (Aword)EOF; + } +} + + +#ifdef _PROTOTYPES_ +void isect(ParamElem a[], ParamElem b[]) +#else +void isect(a, b) + ParamElem a[], b[]; +#endif +{ + int i, last = 0; + + for (i = 0; a[i].code != (Aword)EOF; i++) + if (inlst(b, a[i].code)) + a[last++] = a[i]; + a[last].code = (Aword)EOF; +} + + +#ifdef _PROTOTYPES_ +void cpyrefs(ParamElem p[], Aword r[]) +#else +void cpyrefs(p, r) + ParamElem p[]; + Aword r[]; +#endif +{ + int i; + + for (i = 0; r[i] != (Aword)EOF; i++) { + p[i].code = r[i]; + p[i].firstWord = (Aword)EOF; + } + p[i].code = (Aword)EOF; +} + +} // End of namespace Alan2 +} // End of namespace Glk diff --git a/engines/glk/alan2/params.h b/engines/glk/alan2/params.h new file mode 100644 index 0000000000..82fa84be9c --- /dev/null +++ b/engines/glk/alan2/params.h @@ -0,0 +1,66 @@ +/* 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. + * + */ + +#ifndef GLK_ALAN2_PARAMS +#define GLK_ALAN2_PARAMS + +#include "glk/alan2/types.h" + +/* Various utility functions for handling parameters: + * + * compact() Compact a list, i.e remove any NULL elements + * lstlen() Count number of elements + * inlst() Check if an element is in the list + * sublst() Subract two lists + * lstcpy() Copy one list onto another + * mrglst() Merge the paramElems of one list into the first + * isect() Take the intersection of two lists + * cpyrefs() Copy the refs (in dictionary) to a paramList + */ + +namespace Glk { +namespace Alan2 { + +#ifdef _PROTOTYPES_ +extern void compact(ParamElem *a); +extern int lstlen(ParamElem *a); +extern Boolean inlst(ParamElem *l, Aword e); +extern void lstcpy(ParamElem *a, ParamElem *b); +extern void sublst(ParamElem *a, ParamElem *b); +extern void mrglst(ParamElem *a, ParamElem *b); +extern void isect(ParamElem *a, ParamElem *b); +extern void cpyrefs(ParamElem *p, Aword *r); +#else +extern void compact(); +extern int lstlen(); +extern Boolean inlst(); +extern void lstcpy(); +extern void sublst(); +extern void mrglst(); +extern void isect(); +extern void cpyrefs(); +#endif + +} // End of namespace Alan2 +} // End of namespace Glk + +#endif diff --git a/engines/glk/alan2/parse.cpp b/engines/glk/alan2/parse.cpp new file mode 100644 index 0000000000..4e54c5cd6d --- /dev/null +++ b/engines/glk/alan2/parse.cpp @@ -0,0 +1,846 @@ +/* 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 <string> +#include "glk/alan2/types.h" + +#ifdef USE_READLINE +#include "glk/alan2/readline.h" +#endif + +#include "glk/alan2/main.h" +#include "glk/alan2/inter.h" +#include "glk/alan2/exe.h" +#include "glk/alan2/term.h" +#include "glk/alan2/debug.h" +#include "glk/alan2/params.h" + +#include "glk/alan2/parse.h" + +#ifdef GLK +#include "glk/alan2/glkio.h" +#endif + +namespace Glk { +namespace Alan2 { + +#define LISTLEN 100 + + +/* PUBLIC DATA */ + +int wrds[LISTLEN/2] = {EOF}; /* List of parsed words */ +int wrdidx; /* and an index into it */ + +Boolean plural = FALSE; + + +/* Syntax Parameters */ +int paramidx; /* Index in params */ +ParamElem *params; /* List of params */ +static ParamElem *pparams; /* Previous parameter list */ +static ParamElem *mlst; /* Multiple objects list */ +static ParamElem *pmlst; /* Previous multiple list */ + +/* Literals */ +LitElem litValues[MAXPARAMS+1]; +int litCount; + +/* What did the user say? */ +int vrbwrd; /* The word he used */ +int vrbcode; /* The code for that verb */ + + +/*----------------------------------------------------------------------*\ + + SCAN DATA & PROCEDURES + + All procedures for getting a command and turning it into a list of + dictionary entries are placed here. + + buf + unknown() + lookup() + token + agetline() + scan() + +\*----------------------------------------------------------------------*/ + + +/* PRIVATE DATA */ + +static char buf[LISTLEN+1]; /* The input buffer */ +static char isobuf[LISTLEN+1]; /* The input buffer in ISO */ + + +static Boolean eol = TRUE; /* Looking at End of line? Yes, initially */ + + + +#ifdef _PROTOTYPES_ +static void unknown( + char token[] +) +#else +static void unknown(token) + char token[]; +#endif +{ + char *str = (char *)allocate((int)strlen(token)+4); + + str[0] = '\''; + strcpy(&str[1], token); + strcat(str, "'?"); +#if ISO == 0 + fromIso(str, str); +#endif + output(str); + free(str); + eol = TRUE; + error(M_UNKNOWN_WORD); +} + + + +static char *token; + + +#ifdef _PROTOTYPES_ +static int lookup( + char wrd[] +) +#else +static int lookup(wrd) + char wrd[]; +#endif +{ + int i; + + for (i = 0; !endOfTable(&dict[i]); i++) { + if (strcmp(wrd, (char *) addrTo(dict[i].wrd)) == 0) + return (i); + } + unknown(wrd); + return(EOF); +} + + +#ifdef _PROTOTYPES_ +static int number( + char token[] /* IN - The string to convert to a number */ +) +#else +static int number(token) + char token[]; /* IN - The string to convert to a number */ +#endif +{ + int i; + + sscanf(token, "%d", &i); + return i; +} + +#ifdef _PROTOTYPES_ +static char *gettoken( + char *buf +) +#else +static char *gettoken(buf) + char *buf; +#endif +{ + static char *marker; + static char oldch; + + if (buf == NULL) + *marker = oldch; + else + marker = buf; + while (*marker != '\0' && isSpace(*marker) && *marker != '\n') marker++; + buf = marker; + if (isISOLetter(*marker)) + while (*marker&&(isISOLetter(*marker)||isdigit(*marker)||*marker=='\'')) marker++; + else if (isdigit(*marker)) + while (isdigit(*marker)) marker++; + else if (*marker == '\"') { + marker++; + while (*marker != '\"') marker++; + marker++; + } else if (*marker == '\0' || *marker == '\n') + return NULL; + else + marker++; + oldch = *marker; + *marker = '\0'; + return buf; +} + + +#ifdef _PROTOTYPES_ +static void agetline(void) +#else +static void agetline() +#endif +{ + para(); + do { +#if defined(HAVE_ANSI) || defined(GLK) + statusline(); +#endif + printf("> "); + if (logflg) + fprintf(logfil, "> "); +#ifdef USE_READLINE + if (!readline(buf)) { + newline(); + quit(); + } +#else + if (fgets(buf, LISTLEN, stdin) == NULL) { + newline(); + quit(); + } +#endif + getPageSize(); + anyOutput = FALSE; + if (logflg) +#ifndef __amiga__ + fprintf(logfil, "%s\n", buf); +#else + fprintf(logfil, "%s", buf); +#endif +#if ISO == 0 + toIso(isobuf, buf, NATIVECHARSET); +#else + strcpy(isobuf, buf); +#endif + token = gettoken(isobuf); + if (token != NULL && strcmp("debug", token) == 0 && header->debug) { + dbgflg = TRUE; + debug(); + token = NULL; + } + } while (token == NULL); + eol = FALSE; + lin = 1; +} + + +#ifdef _PROTOTYPES_ +static void scan(void) +#else +static void scan() +#endif +{ + int i; + int w; + char *str; + + agetline(); + wrds[0] = 0; + for (i = 0; i < litCount; i++) + if (litValues[i].type == TYPSTR && litValues[i].value != 0) + free((char *) litValues[i].value); + i = 0; + litCount = 0; + do { + if (isISOLetter(token[0])) { + (void) stringLower(token); + w = lookup(token); + if (!isNoise(w)) + wrds[i++] = w; + } else if (isdigit(token[0])) { + if (litCount > MAXPARAMS) + syserr("Too many parameters."); + wrds[i++] = dictsize+litCount; /* Word outside dictionary = literal */ + litValues[litCount].type = TYPNUM; + litValues[litCount++].value = number(token); + } else if (token[0] == '\"') { + if (litCount > MAXPARAMS) + syserr("Too many parameters."); + wrds[i++] = dictsize+litCount; /* Word outside dictionary = literal */ + litValues[litCount].type = TYPSTR; + /* Remove the string quotes while copying */ + str = strdup(&token[1]); + str[strlen(token)-2] = '\0'; + litValues[litCount++].value = (Aptr) str; + } else if (token[0] == ',') { + wrds[i++] = conjWord; + } else + unknown(token); + wrds[i] = EOF; + eol = (token = gettoken(NULL)) == NULL; + } while (!eol); +} + + + +/*----------------------------------------------------------------------*\ + + PARSE DATA & PROCEDURES + + All procedures and data for getting a command and parsing it + + nonverb() - search for a non-verb command + buildall() - build a list of objects matching 'all' + unambig() - match an unambigous object reference + simple() - match a simple verb command + complex() - match a complex -"- + tryMatch()- to match a verb command + match() - find the verb class (not used currently) and 'tryMatch()' + +\*---------------------------------------------------------------------- */ + +static int allLength; /* No. of objects matching 'all' */ + + +#ifdef _PROTOTYPES_ +static void nonverb(void) +#else +static void nonverb() +#endif +{ + if (isDir(wrds[wrdidx])) { + wrdidx++; + if (wrds[wrdidx] != EOF && !isConj(wrds[wrdidx])) + error(M_WHAT); + else + go(dict[wrds[wrdidx-1]].code); + if (wrds[wrdidx] != EOF) + wrdidx++; + } else + error(M_WHAT); +} + + +#ifdef _PROTOTYPES_ +static void buildall( + ParamElem list[] +) +#else +static void buildall(list) + ParamElem list[]; +#endif +{ + int o, i = 0; + Boolean found = FALSE; + + for (o = OBJMIN; o <= OBJMAX; o++) + if (isHere(o)) { + found = TRUE; + list[i].code = o; + list[i++].firstWord = EOF; + } + if (!found) + error(M_WHAT_ALL); + else + list[i].code = EOF; +} + + +#ifdef _PROTOTYPES_ +static void unambig( + ParamElem plst[] +) +#else +static void unambig(plst) + ParamElem plst[]; +#endif +{ + int i; + Boolean found = FALSE; /* Adjective or noun found ? */ + static ParamElem *refs; /* Entities referenced by word */ + static ParamElem *savlst; /* Saved list for backup at EOF */ + int firstWord, lastWord; /* The words the player used */ + + if (refs == NULL) + refs = (ParamElem *)allocate((MAXENTITY+1)*sizeof(ParamElem)); + + if (savlst == NULL) + savlst = (ParamElem *)allocate((MAXENTITY+1)*sizeof(ParamElem)); + + if (isLiteral(wrds[wrdidx])) { + /* Transform the word into a reference to the literal value */ + plst[0].code = wrds[wrdidx++]-dictsize+LITMIN; + plst[0].firstWord = EOF; /* No words used! */ + plst[1].code = EOF; + return; + } + + plst[0].code = EOF; /* Make empty */ + if (isIt(wrds[wrdidx])) { + wrdidx++; + /* Use last object in previous command! */ + for (i = lstlen(pparams)-1; i >= 0 && (pparams[i].code == 0 || pparams[i].code >= LITMIN); i--); + if (i < 0) + error(M_WHAT_IT); + if (!isHere(pparams[i].code)) { + params[0].code = pparams[i].code; + params[0].firstWord = EOF; + params[1].code = EOF; + error(M_NO_SUCH); + } + plst[0] = pparams[i]; + plst[0].firstWord = EOF; /* No words used! */ + plst[1].code = EOF; + return; + } + + firstWord = wrdidx; + while (wrds[wrdidx] != EOF && isAdj(wrds[wrdidx])) { + /* If this word can be a noun and there is no noun following break loop */ + if (isNoun(wrds[wrdidx]) && (wrds[wrdidx+1] == EOF || !isNoun(wrds[wrdidx+1]))) + break; + cpyrefs(refs, (Aword *)addrTo(dict[wrds[wrdidx]].adjrefs)); + lstcpy(savlst, plst); /* To save it for backtracking */ + if (found) + isect(plst, refs); + else { + lstcpy(plst, refs); + found = TRUE; + } + wrdidx++; + } + if (wrds[wrdidx] != EOF) { + if (isNoun(wrds[wrdidx])) { + cpyrefs(refs, (Aword *)addrTo(dict[wrds[wrdidx]].nounrefs)); + if (found) + isect(plst, refs); + else { + lstcpy(plst, refs); + found = TRUE; + } + wrdidx++; + } else + error(M_NOUN); + } else if (found) { + if (isNoun(wrds[wrdidx-1])) { + /* Perhaps the last word was also a noun? */ + lstcpy(plst, savlst); /* Restore to before last adjective */ + cpyrefs(refs, (Aword *)addrTo(dict[wrds[wrdidx-1]].nounrefs)); + if (plst[0].code == EOF) + lstcpy(plst, refs); + else + isect(plst, refs); + } else + error(M_NOUN); + } + lastWord = wrdidx-1; + + /* Allow remote objects, but resolve ambiguities by presence */ + if (lstlen(plst) > 1) { + for (i=0; plst[i].code != EOF; i++) + if (!isHere(plst[i].code)) + plst[i].code = 0; + compact(plst); + } + + if (lstlen(plst) > 1 || (found && lstlen(plst) == 0)) { + params[0].code = 0; /* Just make it anything != EOF */ + params[0].firstWord = firstWord; /* Remember words for errors below */ + params[0].lastWord = lastWord; + params[1].code = EOF; /* But be sure to terminate */ + if (lstlen(plst) > 1) + error(M_WHICH_ONE); + else if (found && lstlen(plst) == 0) + error(M_NO_SUCH); + } else { + plst[0].firstWord = firstWord; + plst[0].lastWord = lastWord; + } +} + + +#ifdef _PROTOTYPES_ +static void simple( + ParamElem olst[] +) +#else +static void simple(olst) + ParamElem olst[]; +#endif +{ + static ParamElem *tlst = NULL; + int savidx = wrdidx; + Boolean savplur = FALSE; + int i; + + if (tlst == NULL) + tlst = (ParamElem *) allocate(sizeof(ParamElem)*(MAXENTITY+1)); + tlst[0].code = EOF; + + for (;;) { + if (isThem(wrds[wrdidx])) { + plural = TRUE; + for (i = 0; pmlst[i].code != EOF; i++) + if (!isHere(pmlst[i].code)) + pmlst[i].code = 0; + compact(pmlst); + if (lstlen(pmlst) == 0) + error(M_WHAT_THEM); + lstcpy(olst, pmlst); + olst[0].firstWord = EOF; /* No words used */ + wrdidx++; + } else { + unambig(olst); /* Look for unambigous noun phrase */ + if (lstlen(olst) == 0) { /* Failed! */ + lstcpy(olst, tlst); + wrdidx = savidx; + plural = savplur; + return; + } + } + mrglst(tlst, olst); + if (wrds[wrdidx] != EOF + && (isConj(wrds[wrdidx]) && + (isAdj(wrds[wrdidx+1]) || isNoun(wrds[wrdidx+1])))) { + /* More parameters in a conjunction separated list ? */ + savplur = plural; + savidx = wrdidx; + wrdidx++; + plural = TRUE; + } else { + lstcpy(olst, tlst); + return; + } + } +} + + +/*---------------------------------------------------------------------- + + complex() + + Above this procedure we can use the is* tests, but not below since + they work on words. Below all is converted to indices into the + entity tables. Particularly this goes for literals... + +*/ +#ifdef _PROTOTYPES_ +static void complex( + ParamElem olst[] +) +#else +static void complex(olst) + ParamElem olst[]; +#endif +{ + static ParamElem *alst = NULL; + + if (alst == NULL) + alst = (ParamElem *) allocate((MAXENTITY+1)*sizeof(ParamElem)); + + if (isAll(wrds[wrdidx])) { + plural = TRUE; + buildall(alst); /* Build list of all objects */ + wrdidx++; + if (wrds[wrdidx] != EOF && isBut(wrds[wrdidx])) { + wrdidx++; + simple(olst); + if (lstlen(olst) == 0) + error(M_AFTER_BUT); + sublst(alst, olst); + if (lstlen(alst) == 0) + error(M_NOT_MUCH); + } + lstcpy(olst, alst); + allLength = lstlen(olst); + } else + simple(olst); /* Look for simple noun group */ +} + + +#ifdef _PROTOTYPES_ +static Boolean claCheck( + ClaElem *cla /* IN - The cla elem to check */ +) +#else +static Boolean claCheck(cla) + ClaElem *cla; /* IN - The cla elem to check */ +#endif +{ + Boolean ok = FALSE; + + if ((cla->classes&(Aword)CLA_OBJ) != 0) + ok = ok || isObj(params[cla->code-1].code); + if ((cla->classes&(Aword)CLA_CNT) != 0) + ok = ok || isCnt(params[cla->code-1].code); + if ((cla->classes&(Aword)CLA_ACT) != 0) + ok = ok || isAct(params[cla->code-1].code); + if ((cla->classes&(Aword)CLA_NUM) != 0) + ok = ok || isNum(params[cla->code-1].code); + if ((cla->classes&(Aword)CLA_STR) != 0) + ok = ok || isStr(params[cla->code-1].code); + if ((cla->classes&(Aword)CLA_COBJ) != 0) + ok = ok || (isCnt(params[cla->code-1].code) && isObj(params[cla->code-1].code)); + if ((cla->classes&(Aword)CLA_CACT) != 0) + ok = ok || (isCnt(params[cla->code-1].code) && isAct(params[cla->code-1].code)); + return ok; +} + + +/*---------------------------------------------------------------------- + + resolve() + + In case the syntax did not indicate omnipotent powers (allowed + access to remote object), we need to remove non-present parameters + +*/ +static void resolve(ParamElem plst[]) +{ + int i; + + if (allLength > 0) return; /* ALL has already done this */ + + /* Resolve ambiguities by presence */ + for (i=0; plst[i].code != EOF; i++) + if (plst[i].code < LITMIN) /* Literals are always 'here' */ + if (!isHere(plst[i].code)) { + params[0] = plst[i]; /* Copy error param as first one for message */ + params[1].code = EOF; /* But be sure to terminate */ + error(M_NO_SUCH); + } +} + + +#ifdef _PROTOTYPES_ +static void tryMatch( + ParamElem mlst[] /* OUT - List of params allowed by multiple */ +) +#else +static void tryMatch(mlst) + ParamElem mlst[]; /* OUT - List of params allowed by multiple */ +#endif +{ + ElmElem *elms; /* Pointer to element list */ + StxElem *stx; /* Pointer to syntax list */ + ClaElem *cla; /* Pointer to class definitions */ + Boolean anyPlural = FALSE; /* Any parameter that was plural? */ + int i, p; + static ParamElem *tlst = NULL; /* List of params found by complex() */ + static Boolean *checked = NULL; /* Corresponding parameter checked? */ + + if (tlst == NULL) { + tlst = (ParamElem *) allocate((MAXENTITY+1)*sizeof(ParamElem)); + checked = (Boolean *) allocate((MAXENTITY+1)*sizeof(Boolean)); + } + + for (stx = stxs; !endOfTable(stx); stx++) + if (stx->code == vrbcode) + break; + if (endOfTable(stx)) + error(M_WHAT); + + elms = (ElmElem *) addrTo(stx->elms); + + while (TRUE) { + /* End of input? */ + if (wrds[wrdidx] == EOF || isConj(wrds[wrdidx])) { + while (!endOfTable(elms) && elms->code != EOS) + elms++; + if (endOfTable(elms)) + error(M_WHAT); + else + break; + } else { + /* A preposition? */ + if (isPrep(wrds[wrdidx])) { + while (!endOfTable(elms) && elms->code != dict[wrds[wrdidx]].code) + elms++; + if (endOfTable(elms)) + error(M_WHAT); + else + wrdidx++; + } else { + /* Must be a parameter! */ + while (!endOfTable(elms) && elms->code != 0) + elms++; + if (endOfTable(elms)) + error(M_WHAT); + /* Get it! */ + plural = FALSE; + complex(tlst); + if (lstlen(tlst) == 0) /* No object!? */ + error(M_WHAT); + if ((elms->flags & OMNIBIT) == 0) /* Omnipotent parameter? */ + /* If its not an omnipotent parameter, resolve by presence */ + resolve(tlst); + if (plural) { + if ((elms->flags & MULTIPLEBIT) == 0) /* Allowed multiple? */ + error(M_MULTIPLE); + else { + /* + Mark this as the multiple position in which to insert + actual parameter values later + */ + params[paramidx++].code = 0; + lstcpy(mlst, tlst); + anyPlural = TRUE; + } + } else + params[paramidx++] = tlst[0]; + params[paramidx].code = EOF; + } + elms = (ElmElem *) addrTo(elms->next); + } + } + + /* Now perform class checks */ + if (elms->next == 0) /* No verb code, verb not declared! */ + error(M_CANT0); + + for (p = 0; params[p].code != EOF; p++) /* Mark all parameters unchecked */ + checked[p] = FALSE; + for (cla = (ClaElem *) addrTo(elms->next); !endOfTable(cla); cla++) { + if (params[cla->code-1].code == 0) { + /* This was a multiple parameter, so check all and remove failing */ + for (i = 0; mlst[i].code != EOF; i++) { + params[cla->code-1] = mlst[i]; + if (!claCheck(cla)) { + /* Multiple could be both an explicit list of params and an ALL */ + if (allLength == 0) { + char marker[80]; + /* + It wasn't ALL, we need to say something about it, so + prepare a printout with $1/2/3 + */ + sprintf(marker, "($%ld)", (unsigned long) cla->code); + output(marker); + interpret(cla->stms); + para(); + } + mlst[i].code = 0; /* In any case remove it from the list */ + } + } + params[cla->code-1].code = 0; + } else { + if (!claCheck(cla)) { + interpret(cla->stms); + error(MSGMAX); /* Return to player without saying anything */ + } + } + checked[cla->code-1] = TRUE; /* Remember that it's already checked */ + } + /* Now check the rest of the parameters, must be objects */ + for (p = 0; params[p].code != EOF; p++) + if (!checked[p]) { + if (params[p].code == 0) { + /* This was a multiple parameter, check all and remove failing */ + for (i = 0; mlst[i].code != EOF; i++) + if (mlst[i].code != 0) /* Skip any empty slots */ + if (!isObj(mlst[i].code)) + mlst[i].code = 0; + } else if (!isObj(params[p].code)) + error(M_CANT0); + } + + /* Set verb code */ + cur.vrb = ((Aword *) cla)[1]; /* Take first word after end of table! */ + + /* Finally, if ALL was used, try to find out what was applicable */ + if (allLength > 0) { + for (p = 0; params[p].code != 0; p++); /* Find multiple marker */ + for (i = 0; i < allLength; i++) { + if (mlst[i].code != 0) { /* Already empty? */ + params[p] = mlst[i]; + if (!possible()) + mlst[i].code = 0; /* Remove this from list */ + } + } + params[p].code = 0; /* Restore multiple marker */ + compact(mlst); + if (lstlen(mlst) == 0) { + params[0].code = EOF; + error(M_WHAT_ALL); + } + } else if (anyPlural) { + compact(mlst); + if (lstlen(mlst) == 0) + /* If there where multiple parameters but non left, exit without a */ + /* word, assuming we have already said enough */ + error(MSGMAX); + } + plural = anyPlural; /* Remember that we found plural objects */ +} + + +#ifdef _PROTOTYPES_ +static void match( + ParamElem *mlst /* OUT - List of params allowed by multiple */ +) +#else +static void match(mlst) + ParamElem *mlst; /* OUT - List of params allowed by multiple */ +#endif +{ + tryMatch(mlst); /* ... to understand what he said */ + if (wrds[wrdidx] != EOF && !isConj(wrds[wrdidx])) + error(M_WHAT); + if (wrds[wrdidx] != EOF) /* More on this line? */ + wrdidx++; /* If so skip the AND */ +} + + +#ifdef _PROTOTYPES_ +void parse(void) +#else +void parse() +#endif +{ + if (mlst == NULL) { /* Allocate large enough paramlists */ + mlst = (ParamElem *) allocate(sizeof(ParamElem)*(MAXENTITY+1)); + mlst[0].code = EOF; + pmlst = (ParamElem *) allocate(sizeof(ParamElem)*(MAXENTITY+1)); + params = (ParamElem *) allocate(sizeof(ParamElem)*(MAXENTITY+1)); + params[0].code = EOF; + pparams = (ParamElem *) allocate(sizeof(ParamElem)*(MAXENTITY+1)); + } + + if (wrds[wrdidx] == EOF) { + wrdidx = 0; + scan(); + } else if (anyOutput) + para(); + + allLength = 0; + paramidx = 0; + lstcpy(pparams, params); + params[0].code = EOF; + lstcpy(pmlst, mlst); + mlst[0].code = EOF; + if (isVerb(wrds[wrdidx])) { + vrbwrd = wrds[wrdidx]; + vrbcode = dict[vrbwrd].code; + wrdidx++; + match(mlst); + action(mlst); /* mlst contains possible multiple params */ + } else { + params[0].code = EOF; + pmlst[0].code = EOF; + nonverb(); + } +} + +} // End of namespace Alan2 +} // End of namespace Glk diff --git a/engines/glk/alan2/parse.h b/engines/glk/alan2/parse.h new file mode 100644 index 0000000000..067c73fb3b --- /dev/null +++ b/engines/glk/alan2/parse.h @@ -0,0 +1,54 @@ +/* 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. + * + */ + +#ifndef GLK_ALAN2_PARSE +#define GLK_ALAN2_PARSE + +/* Parse data for ALAN interpreter module. */ + +namespace Glk { +namespace Alan2 { + +extern int wrds[]; /* List of Parsed Word */ +extern int wrdidx; /* and an index into it */ + +extern ParamElem *params; /* List of parameters */ +extern Boolean plural; + +extern LitElem litValues[]; +extern int litCount; + +extern int vrbwrd; + +#ifdef _PROTOTYPES_ + +/* Parse a new player command */ +extern void parse(void); + +#else +extern void parse(); +#endif + +} // End of namespace Alan2 +} // End of namespace Glk + +#endif diff --git a/engines/glk/alan2/readline.cpp b/engines/glk/alan2/readline.cpp new file mode 100644 index 0000000000..c96b26c13d --- /dev/null +++ b/engines/glk/alan2/readline.cpp @@ -0,0 +1,560 @@ +/* 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/types.h" + +#ifdef GLK + +#include "glk/alan2/alan2.h" +#include "glk/alan2/readline.h" +#include "glk/alan2/main.h" +#include "glk/alan2/glkio.h" + +namespace Glk { +namespace Alan2 { + +/*====================================================================== + + readline() + + Read a line from the user, with history and editing + + */ + +/* 4f - length of user buffer should be used */ +Boolean readline(char usrbuf[]) +{ + event_t event; + g_vm->glk_request_line_event(glkMainWin, usrbuf, 255, 0); + /* FIXME: buffer size should be infallible: all existing calls use 256 or + 80 character buffers, except parse which uses LISTLEN (currently 100) + */ + do + { + g_vm->glk_select(&event); + if (evtype_Arrange == event.type) + statusline(); + } while (event.type != evtype_LineInput); + usrbuf[event.val1] = 0; + return TRUE; +} + +} // End of namespace Alan2 +} // End of namespace Glk + +#else + +#include "glk/alan2/sysdep.h" + +#ifdef HAVE_TERMIO +#include <termios.h> +#endif + +#ifdef __PACIFIC__ +#include <unixio.h> +#else +//#include <unistd.h> +#endif + +#include "glk/alan2/readline.h" + +#include "glk/alan2/main.h" + +namespace Glk { +namespace Alan2 { + +#ifdef HAVE_TERMIO +/*----------------------------------------------------------------------*\ + + termio handling + +\*----------------------------------------------------------------------*/ + +static struct termios term; + +static void newtermio() +{ + struct termios newterm; + tcgetattr(0, &term); + newterm=term; + newterm.c_lflag&=~(ECHO|ICANON); + newterm.c_cc[VMIN]=1; + newterm.c_cc[VTIME]=0; + tcsetattr(0, TCSANOW, &newterm); +} + +static void restoretermio() +{ + tcsetattr(0, TCSANOW, &term); +} + +#endif + + +/*----------------------------------------------------------------------*\ + + Global character buffers etc. + +\*----------------------------------------------------------------------*/ + +static unsigned char buffer[LINELENGTH+1]; +static int bufidx; + +static unsigned char *history[HISTORYLENGTH]; +static int histidx; /* Index where to store next history */ +static int histp; /* Points to the history recalled last */ + +static unsigned char ch; +static int endOfInput = 0; +static Boolean change; +static Boolean insert = TRUE; + + +/*----------------------------------------------------------------------*\ + + Character map types and maps + +\*----------------------------------------------------------------------*/ + +typedef struct {unsigned char min, max; void (*hook)(char ch);} KeyMap; + +/* Forward declaration of hooks */ +static void escHook(char ch); +static void insertCh(char ch); +static void arrowHook(char ch); +static void upArrow(char ch); +static void downArrow(char ch); +static void rightArrow(char ch); +static void leftArrow(char ch); +static void insertToggle(char ch); +static void newLine(char ch); +static void delFwd(char ch); +static void delBwd(char ch); + +#ifdef __XXunix__ +static KeyMap keymap[] = { + {0x00, 0x07, NULL}, + {0x08, 0x08, delBwd}, + {0x09, 0x09, NULL}, + {0x0a, 0x0a, newLine}, + {0x1b, 0x1b, escHook}, + {0x1c, 0x7e, insertCh}, + {0x7f, 0x7f, delFwd}, + {0x80, 0xff, insertCh}, + {0x00, 0x00, NULL} +}; + +/* I can't figure out what really coverns the esc-map characters... */ +#ifdef __solarisX__ +static KeyMap escmap[] = { + {0x00, 0x4e, NULL}, + {0x4f, 0x4f, arrowHook}, + {0x50, 0xff, NULL}, + {0x00, 0x00, NULL} +}; +#else +static KeyMap escmap[] = { + {0x00, 0x5a, NULL}, + {0x5b, 0x5b, arrowHook}, + {0x5c, 0xff, NULL}, + {0x00, 0x00, NULL} +}; +#endif + +static KeyMap arrowmap[] = { + {0x00, 0x31, NULL}, + {0x32, 0x32, insertToggle}, + {0x33, 0x40, NULL}, + {0x41, 0x41, upArrow}, + {0x42, 0x42, downArrow}, + {0x43, 0x43, rightArrow}, + {0x44, 0x44, leftArrow}, + {0x45, 0xff, NULL}, + {0x00, 0x00, NULL} +}; + +#endif + +#ifdef __win__ +static KeyMap keymap[] = { + {0x00, 0x01, NULL}, + {0x02, 0x02, leftArrow}, + {0x03, 0x05, NULL}, + {0x06, 0x06, rightArrow}, + {0x07, 0x07, NULL}, + {0x08, 0x08, delBwd}, + {0x09, 0x09, NULL}, + {0x0a, 0x0a, newLine}, + {0x1b, 0x1b, escHook}, + {0x1c, 0x7e, insertCh}, + {0x7f, 0x7f, delFwd}, + {0x80, 0xff, insertCh}, + {0x00, 0x00, NULL} +}; + +static KeyMap escmap[] = { + {0x00, 0x5a, NULL}, + {0x5b, 0x5b, arrowHook}, + {0x5c, 0xff, NULL}, + {0x00, 0x00, NULL} +}; + +static KeyMap arrowmap[] = { + {0x00, 0x31, NULL}, + {0x32, 0x32, insertToggle}, + {0x33, 0x40, NULL}, + {0x41, 0x41, upArrow}, + {0x42, 0x42, downArrow}, + {0x43, 0x43, rightArrow}, + {0x44, 0x44, leftArrow}, + {0x45, 0xff, NULL}, + {0x00, 0x00, NULL} +}; + +#endif + +#ifdef __dos__ +static KeyMap keymap[] = { + {0x00, 0x01, NULL}, + {0x02, 0x02, leftArrow}, + {0x03, 0x05, NULL}, + {0x06, 0x06, rightArrow}, + {0x07, 0x07, NULL}, + {0x08, 0x08, delBwd}, + {0x09, 0x09, NULL}, + {0x0a, 0x0a, newLine}, + {0x1b, 0x1b, escHook}, + {0x1c, 0x7e, insertCh}, + {0x7f, 0x7f, delFwd}, + {0x80, 0xff, insertCh}, + {0x00, 0x00, NULL} +}; + +static KeyMap escmap[] = { + {0x00, 0x5a, NULL}, + {0x5b, 0x5b, arrowHook}, + {0x5c, 0xff, NULL}, + {0x00, 0x00, NULL} +}; + +static KeyMap arrowmap[] = { + {0x00, 0x31, NULL}, + {0x32, 0x32, insertToggle}, + {0x33, 0x40, NULL}, + {0x41, 0x41, upArrow}, + {0x42, 0x42, downArrow}, + {0x43, 0x43, rightArrow}, + {0x44, 0x44, leftArrow}, + {0x45, 0xff, NULL}, + {0x00, 0x00, NULL} +}; + +#endif + + +static void doBeep(void) +{ + write(1, "\7", 1); +} + + +static void backspace(void) +{ + write(1, "\b", 1); +} + + +static void erase() +{ + int i; + + for (i = 0; i < bufidx; i++) backspace(); /* Backup to beginning of text */ + for (i = 0; i < strlen((char *)buffer); i++) write(1, " ", 1); /* Erase all text */ + for (i = 0; i < strlen((char *)buffer); i++) backspace(); /* Backup to beginning of text */ +} + +/*----------------------------------------------------------------------*\ + + Character handling hook functions + +\*----------------------------------------------------------------------*/ + +static void execute(KeyMap map[], unsigned char ch) +{ + int i = 0; + + for (i = 0; i <= 256; i++) { + if (i > 0 && map[i].min == 0x00) break; /* End marker is a 0,0,NULL */ + if (map[i].min <= ch && ch <= map[i].max) { + if (map[i].hook != NULL) { + map[i].hook(ch); + return; + } else + doBeep(); + } + } + doBeep(); +} + + +static void upArrow(char ch) +{ + /* Is there more history ? */ + if (history[(histp+HISTORYLENGTH-1)%HISTORYLENGTH] == NULL || + (histp+HISTORYLENGTH-1)%HISTORYLENGTH == histidx) { + write(1, "\7", 1); + return; + } + + erase(); + + /* Backup history pointer */ + histp = (histp+HISTORYLENGTH-1)%HISTORYLENGTH; + + /* Copy the history and write it */ + strcpy((char *)buffer, (char *)history[histp]); + bufidx = strlen((char *)buffer); + write(1, (void *)buffer, strlen((char *)buffer)); + +} + + +static void downArrow(char ch) +{ + /* Is there more history ? */ + if (histp == histidx) { + write(1, "\7", 1); + return; + } + + erase(); + + /* Advance history pointer */ + histp = (histp+1)%HISTORYLENGTH; + + /* If we are not at the most recent history entry, copy the history and write it */ + if (histp != histidx) { + strcpy((char *)buffer, (char *)history[histp]); + bufidx = strlen((char *)buffer); + write(1, (void *)buffer, strlen((char *)buffer)); + } else { + bufidx = 0; + buffer[0] = '\0'; + } +} + + +static void rightArrow(char ch) +{ + if (bufidx > LINELENGTH || buffer[bufidx] == '\0') + doBeep(); + else { + write(1, (void *)&buffer[bufidx], 1); + bufidx++; + } +} + + +static void leftArrow(char ch) +{ + if (bufidx == 0) + doBeep(); + else { + bufidx--; + backspace(); + } +} + + +static void insertToggle(char ch) +{ + read(0, &ch, 1); + if (ch != 'z') + doBeep(); + else + insert = !insert; +} + + +static void delBwd(char ch) +{ + if (bufidx == 0) + doBeep(); + else { + int i; + + change = TRUE; + backspace(); + bufidx--; + for (i = 0; i <= strlen((char *)&buffer[bufidx+1]); i++) + buffer[bufidx+i] = buffer[bufidx+1+i]; + write(1, (void *)&buffer[bufidx], strlen((char *)&buffer[bufidx])); + write(1, " ", 1); + for (i = 0; i <= strlen((char *)&buffer[bufidx]); i++) backspace(); + } +} + +static void delFwd(char ch) +{ + if (bufidx > LINELENGTH || buffer[bufidx] == '\0') + doBeep(); + else { + int i; + + change = TRUE; + strcpy((char *)&buffer[bufidx], (char *)&buffer[bufidx+1]); + write(1, (void *)&buffer[bufidx], strlen((char *)&buffer[bufidx])); + write(1, " ", 1); + for (i = 0; i <= strlen((char *)&buffer[bufidx]); i++) backspace(); + } +} + +static void escHook(char ch) { + read(0, &ch, 1); + execute(escmap, ch); +} + +static void arrowHook(char ch) { + read(0, &ch, 1); + execute(arrowmap, ch); +} + +static void newLine(char ch) +{ + endOfInput = 1; + write(1, "\n", 1); + + /* If the input is not the same as the previous, save it in the history */ + if (change && strlen((char *)buffer) > 0) { + if (history[histidx] == NULL) + history[histidx] = (unsigned char *)allocate(LINELENGTH+1); + strcpy((char *)history[histidx], (char *)buffer); + histidx = (histidx+1)%HISTORYLENGTH; + } +} + + +static void insertCh(char ch) { + if (bufidx > LINELENGTH) + doBeep(); + else { + /* If at end advance the NULL */ + if (buffer[bufidx] == '\0') + buffer[bufidx+1] = '\0'; + else if (insert) { + int i; + + /* If insert mode is on, move the characters ahead */ + for (i = strlen((char *)buffer); i >= bufidx; i--) + buffer[i+1] = buffer[i]; + write(1, (void *)&buffer[bufidx], strlen((char *)&buffer[bufidx])); + for (i = strlen((char *)&buffer[bufidx]); i > 0; i--) backspace(); + } + change = TRUE; + buffer[bufidx] = ch; + write(1, &ch, 1); + bufidx++; + } +} + + +/*---------------------------------------------------------------------- + + echoOff() + + */ +static void echoOff() +{ +#ifdef HAVE_TERMIO + newtermio(); +#else +#ifdef __win__ +#include <windows.h> +#include <winbase.h> +#include <wincon.h> + + DWORD handle = GetStdHandle(STD_INPUT_HANDLE); + + (void) SetConsoleMode(handle, 0); + +#endif +#endif +} + + +/*---------------------------------------------------------------------- + + echoOn() + + */ +static void echoOn() +{ +#ifdef HAVE_TERMIO + restoretermio(); +#else +#ifdef __win__ +#include <windows.h> +#include <winbase.h> +#include <wincon.h> + + DWORD handle = GetStdHandle(STD_INPUT_HANDLE); + (void) SetConsoleMode(handle, ENABLE_ECHO_INPUT); + +#endif +#endif +} + + +/*====================================================================== + + readline() + + Read a line from the user, with history and editing + + */ + +/* 4f - length of user buffer should be used */ +Boolean readline(char usrbuf[]) +{ + fflush(stdout); + bufidx = 0; + histp = histidx; + buffer[0] = '\0'; + change = TRUE; + echoOff(); + endOfInput = 0; + while (!endOfInput) { + if (read(0, (void *)&ch, 1) != 1) { + echoOn(); + return FALSE; + } + execute(keymap, ch); + } + echoOn(); + strcpy(usrbuf, (char *)buffer); + return TRUE; +} + +} // End of namespace Alan2 +} // End of namespace Glk + +#endif diff --git a/engines/glk/alan2/readline.h b/engines/glk/alan2/readline.h new file mode 100644 index 0000000000..a50022415d --- /dev/null +++ b/engines/glk/alan2/readline.h @@ -0,0 +1,46 @@ +/* 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. + * + */ + +#ifndef GLK_ALAN2_READLINE +#define GLK_ALAN2_READLINE + +/* Header file for user input, history andediting support */ + +#include "glk/alan2/types.h" + +namespace Glk { +namespace Alan2 { + +#define LINELENGTH 80 +#define HISTORYLENGTH 20 + +#ifdef _PROTOTYPES_ +extern Boolean readline(char usrbuf[]); + +#else +extern Boolean readline(); +#endif + +} // End of namespace Alan2 +} // End of namespace Glk + +#endif diff --git a/engines/glk/alan2/reverse.cpp b/engines/glk/alan2/reverse.cpp new file mode 100644 index 0000000000..cf3e851226 --- /dev/null +++ b/engines/glk/alan2/reverse.cpp @@ -0,0 +1,552 @@ +/* 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/types.h" +#include "glk/alan2/main.h" +#include "glk/alan2/reverse.h" + +namespace Glk { +namespace Alan2 { + +/*---------------------------------------------------------------------- + + reversed() + + Return the reversed bytes in the Aword + +*/ +#ifdef _PROTOTYPES_ +Aword reversed(Aword w) /* IN - The ACODE word to swap bytes of */ +#else +Aword reversed(w) + Aword w; /* IN - The ACODE word to swap bytes of */ +#endif +{ + Aword s; /* The swapped ACODE word */ + char *wp, *sp; + int i; + + wp = (char *) &w; + sp = (char *) &s; + + for (i = 0; i < sizeof(Aword); i++) + sp[sizeof(Aword)-1 - i] = wp[i]; + + return s; +} + + +#ifdef _PROTOTYPES_ +void reverse(Aword *w) /* IN - The ACODE word to reverse bytes in */ +#else +void reverse(w) + Aword *w; /* IN - The ACODE word to reverse bytes in */ +#endif +{ + *w = reversed(*w); +} + + +#ifdef _PROTOTYPES_ +static void reverseTable(Aword adr, int len) +#else +static void reverseTable(adr, len) + Aword adr; + int len; +#endif +{ + Aword *e = &memory[adr]; + int i; + + if (adr != 0) + while (!endOfTable(e)) { + for (i = 0; i < len/(int)sizeof(Aword); i++) { + reverse(e); + e++; + } + } +} + + +#ifdef _PROTOTYPES_ +static void reverseStms(Aword adr) +#else +static void reverseStms(adr) + Aword adr; +#endif +{ + Aword *e = &memory[adr]; + + if (adr != 0) + while (TRUE) { + reverse(e); + if (*e == ((Aword)C_STMOP<<28|(Aword)I_RETURN)) break; + e++; + } +} + + +#ifdef _PROTOTYPES_ +static void reverseMsgs(Aword adr) +#else +static void reverseMsgs(adr) + Aword adr; +#endif +{ + MsgElem *e = (MsgElem *) &memory[adr]; + + if (adr != 0 && !endOfTable(e)) { + reverseTable(adr, sizeof(MsgElem)); + while (!endOfTable(e)) { + reverseStms(e->stms); + e++; + } + } +} + + +#ifdef _PROTOTYPES_ +static void reverseWrds(Aword adr) +#else +static void reverseWrds(adr) + Aword adr; +#endif +{ + WrdElem *e = (WrdElem *) &memory[adr]; + + if (adr != 0 && !endOfTable(e)) { + reverseTable(adr, sizeof(WrdElem)); + while (!endOfTable(e)) { + if ((e->_class & (1L<<WRD_SYN)) == 0) { /* Do not do this for synonyms */ + reverseTable(e->adjrefs, sizeof(Aword)); + reverseTable(e->nounrefs, sizeof(Aword)); + } + e++; + } + } +} + +#ifdef _PROTOTYPES_ +static void reverseChks(Aword adr) +#else +static void reverseChks(adr) + Aword adr; +#endif +{ + ChkElem *e = (ChkElem *) &memory[adr]; + + if (adr != 0 && !endOfTable(e)) { + reverseTable(adr, sizeof(ChkElem)); + while (!endOfTable(e)) { + reverseStms(e->exp); + reverseStms(e->stms); + e++; + } + } +} + +#ifdef _PROTOTYPES_ +static void reverseAlts(Aword adr) +#else +static void reverseAlts(adr) + Aword adr; +#endif +{ + AltElem *e = (AltElem *)&memory[adr]; + + if (adr != 0 && !endOfTable(e) && !e->done) { + reverseTable(adr, sizeof(AltElem)); + e->done = TRUE; + while (!endOfTable(e)) { + reverseChks(e->checks); + reverseStms(e->action); + e++; + } + } +} + + +#ifdef _PROTOTYPES_ +static void reverseVrbs(Aword adr) +#else +static void reverseVrbs(adr) + Aword adr; +#endif +{ + VrbElem *e = (VrbElem *)&memory[adr]; + + if (adr != 0 && !endOfTable(e)) { + reverseTable(adr, sizeof(VrbElem)); + while (!endOfTable(e)) { + reverseAlts(e->alts); + e++; + } + } +} + + +#ifdef _PROTOTYPES_ +static void reverseSteps(Aword adr) +#else +static void reverseSteps(adr) + Aword adr; +#endif +{ + StepElem *e = (StepElem *) &memory[adr]; + + if (adr != 0 && !endOfTable(e)) { + reverseTable(adr, sizeof(StepElem)); + while (!endOfTable(e)) { + reverseStms(e->exp); + reverseStms(e->stm); + e++; + } + } +} + + +#ifdef _PROTOTYPES_ +static void reverseScrs(Aword adr) +#else +static void reverseScrs(adr) + Aword adr; +#endif +{ + ScrElem *e = (ScrElem *) &memory[adr]; + + if (adr != 0 && !endOfTable(e)) { + reverseTable(adr, sizeof(ScrElem)); + while (!endOfTable(e)) { + reverseStms(e->dscr); + reverseSteps(e->steps); + e++; + } + } +} + + +#ifdef _PROTOTYPES_ +static void reverseActs(Aword adr) +#else +static void reverseActs(adr) + Aword adr; +#endif +{ + ActElem *e = (ActElem *) &memory[adr]; + + if (adr != 0 && !endOfTable(e)) { + reverseTable(adr, sizeof(ActElem)); + while (!endOfTable(e)) { + reverseStms(e->nam); + reverseTable(e->atrs, sizeof(AtrElem)); + reverseScrs(e->scradr); + reverseVrbs(e->vrbs); + reverseStms(e->dscr); + e++; + } + } +} + +#ifdef _PROTOTYPES_ +static void reverseObjs(Aword adr, Boolean v2_5) +#else +static void reverseObjs(adr, v2_5) + Aword adr; + Boolean v2_5; /* TRUE if it's a v2.5 format game */ +#endif +{ + ObjElem *e = (ObjElem *) &memory[adr]; + ObjElem25 *e25 = (ObjElem25 *) &memory[adr]; + + if (v2_5) { + if (adr != 0 && !endOfTable(e25)) { + reverseTable(adr, sizeof(ObjElem25)); + while (!endOfTable(e25)) { + reverseTable(e25->atrs, sizeof(AtrElem)); + reverseVrbs(e25->vrbs); + reverseStms(e25->dscr1); + reverseStms(e25->dscr2); + e25++; + } + } + } else { + if (adr != 0 && !endOfTable(e)) { + reverseTable(adr, sizeof(ObjElem)); + while (!endOfTable(e)) { + reverseTable(e->atrs, sizeof(AtrElem)); + reverseVrbs(e->vrbs); + reverseStms(e->art); + reverseStms(e->dscr1); + reverseStms(e->dscr2); + e++; + } + } + } +} + + +#ifdef _PROTOTYPES_ +static void reverseExts(Aword adr) +#else +static void reverseExts(adr) + Aword adr; +#endif +{ + ExtElem *e = (ExtElem *) &memory[adr]; + + if (adr != 0 && !endOfTable(e)) { + reverseTable(adr, sizeof(ExtElem)); + while (!endOfTable(e)) { + if (!e->done) { + reverseChks(e->checks); + reverseStms(e->action); + } + e++; + } + } +} + +#ifdef _PROTOTYPES_ +static void reverseLocs(Aword adr) +#else +static void reverseLocs(adr) + Aword adr; +#endif +{ + LocElem *e = (LocElem *) &memory[adr]; + + if (adr != 0 && !endOfTable(e)) { + reverseTable(adr, sizeof(LocElem)); + while (!endOfTable(e)) { + reverseStms(e->nams); + reverseStms(e->dscr); + reverseStms(e->does); + reverseTable(e->atrs, sizeof(AtrElem)); + reverseExts(e->exts); + reverseVrbs(e->vrbs); + e++; + } + } +} + + +#ifdef _PROTOTYPES_ +static void reverseClas(Aword adr) +#else +static void reverseClas(adr) + Aword adr; +#endif +{ + ClaElem *e = (ClaElem *) &memory[adr]; + + if (adr != 0 && !endOfTable(e)) { + reverseTable(adr, sizeof(ClaElem)); + while (!endOfTable(e)) { + reverseStms(e->stms); + e++; + } + } + if (adr) + reverse(&((Aword *)e)[1]); /* The verb code is stored after the table */ +} + + +#ifdef _PROTOTYPES_ +static void reverseElms(Aword adr) +#else +static void reverseElms(adr) + Aword adr; +#endif +{ + ElmElem *e = (ElmElem *) &memory[adr]; + + if (adr != 0 && !endOfTable(e)) { + reverseTable(adr, sizeof(ElmElem)); + while (!endOfTable(e)) { + if (e->code == EOS) reverseClas(e->next); + else reverseElms(e->next); + e++; + } + } +} + + +#ifdef _PROTOTYPES_ +static void reverseStxs(Aword adr) +#else +static void reverseStxs(adr) + Aword adr; +#endif +{ + StxElem *e = (StxElem *) &memory[adr]; + + if (adr != 0 && !endOfTable(e)) { + reverseTable(adr, sizeof(StxElem)); + while (!endOfTable(e)) { + reverseElms(e->elms); + e++; + } + } +} + +#ifdef _PROTOTYPES_ +static void reverseEvts(Aword adr) +#else +static void reverseEvts(adr) + Aword adr; +#endif +{ + EvtElem *e = (EvtElem *) &memory[adr]; + + if (adr != 0 && !endOfTable(e)) { + reverseTable(adr, sizeof(EvtElem)); + while (!endOfTable(e)) { + reverseStms(e->code); + e++; + } + } +} + + + +#ifdef _PROTOTYPES_ +static void reverseLims(Aword adr) +#else +static void reverseLims(adr) + Aword adr; +#endif +{ + LimElem *e = (LimElem *) &memory[adr]; + + if (adr != 0 && !endOfTable(e)) { + reverseTable(adr, sizeof(LimElem)); + while (!endOfTable(e)) { + reverseStms(e->stms); + e++; + } + } +} + + +#ifdef _PROTOTYPES_ +static void reverseCnts(Aword adr) +#else +static void reverseCnts(adr) + Aword adr; +#endif +{ + CntElem *e = (CntElem *) &memory[adr]; + + if (adr != 0 && !endOfTable(e)) { + reverseTable(adr, sizeof(CntElem)); + while (!endOfTable(e)) { + reverseLims(e->lims); + reverseStms(e->header); + reverseStms(e->empty); + reverseStms(e->nam); + e++; + } + } +} + + +#ifdef _PROTOTYPES_ +static void reverseRuls(Aword adr) +#else +static void reverseRuls(adr) + Aword adr; +#endif +{ + RulElem *e = (RulElem *) &memory[adr]; + + if (adr != 0 && !endOfTable(e)) { + reverseTable(adr, sizeof(RulElem)); + while (!endOfTable(e)) { + reverseStms(e->exp); + reverseStms(e->stms); + e++; + } + } +} + + + +/*---------------------------------------------------------------------- + + reverseHdr() + + Reverse the header structure. + +*/ +#ifdef _PROTOTYPES_ +void reverseHdr(AcdHdr *hdr) +#else +void reverseHdr(hdr) + AcdHdr *hdr; +#endif +{ + int i; + + /* Reverse all words in the header except the first (version marking) */ + for (i = 1; i < sizeof(AcdHdr)/sizeof(Aword); i++) + reverse(&((Aword *)hdr)[i]); +} + +/*---------------------------------------------------------------------- + + reverseACD() + + Traverse all the data structures and reverse all integers. + Only performed in architectures with reversed byte ordering, which + makes the .ACD files fully compatible across architectures + + */ +#ifdef _PROTOTYPES_ +void reverseACD(Boolean v2_5) +#else +void reverseACD(v2_5) + Boolean v2_5; +#endif +{ + reverseHdr(header); + reverseWrds(header->dict); + reverseTable(header->oatrs, sizeof(AtrElem)); + reverseTable(header->latrs, sizeof(AtrElem)); + reverseTable(header->aatrs, sizeof(AtrElem)); + reverseActs(header->acts); + reverseObjs(header->objs, v2_5); + reverseLocs(header->locs); + reverseStxs(header->stxs); + reverseVrbs(header->vrbs); + reverseEvts(header->evts); + reverseCnts(header->cnts); + reverseRuls(header->ruls); + reverseTable(header->init, sizeof(IniElem)); + reverseStms(header->start); + reverseMsgs(header->msgs); + + reverseTable(header->scores, sizeof(Aword)); + reverseTable(header->freq, sizeof(Aword)); +} + +} // End of namespace Alan2 +} // End of namespace Glk diff --git a/engines/glk/alan2/reverse.h b/engines/glk/alan2/reverse.h new file mode 100644 index 0000000000..40807ce403 --- /dev/null +++ b/engines/glk/alan2/reverse.h @@ -0,0 +1,46 @@ +/* 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. + * + */ + +#ifndef GLK_ALAN2_REVERSE +#define GLK_ALAN2_REVERSE + +namespace Glk { +namespace Alan2 { + +#ifdef _PROTOTYPES_ + +extern void reverseHdr(AcdHdr *hdr); +extern void reverseACD(Boolean v25); +extern void reverse(Aword *word); +extern Aword reversed(Aword word); + +#else +extern void reverseHdr(); +extern void reverseACD(); +extern void reverse(); +extern Aword reversed(); +#endif + +} // End of namespace Alan2 +} // End of namespace Glk + +#endif diff --git a/engines/glk/alan2/rules.cpp b/engines/glk/alan2/rules.cpp new file mode 100644 index 0000000000..d00d1f3955 --- /dev/null +++ b/engines/glk/alan2/rules.cpp @@ -0,0 +1,83 @@ +/* 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/types.h" +#include "glk/alan2/main.h" +#include "glk/alan2/inter.h" +#include "glk/alan2/debug.h" +#include "glk/alan2/exe.h" +#include "glk/alan2/stack.h" + +#include "glk/alan2/rules.h" + +#ifdef GLK +#include "glk/alan2/glkio.h" +#endif + +namespace Glk { +namespace Alan2 { + +#ifdef _PROTOTYPES_ +void rules(void) +#else +void rules() +#endif +{ + Boolean change = TRUE; + int i; + + for (i = 1; !endOfTable(&ruls[i-1]); i++) + ruls[i-1].run = FALSE; + + while (change) { + change = FALSE; + for (i = 1; !endOfTable(&ruls[i-1]); i++) + if (!ruls[i-1].run) { + if (trcflg) { + printf("\n<RULE %d (at ", i); + debugsay(cur.loc); + if (!stpflg) + printf("), Evaluating"); + else + printf("), Evaluating:>\n"); + } + interpret(ruls[i-1].exp); + if (pop()) { + change = TRUE; + ruls[i-1].run = TRUE; + if (trcflg) + if (!stpflg) + printf(", Executing:>\n"); + else { + printf("\nRULE %d (at ", i); + debugsay(cur.loc); + printf("), Executing:>\n"); + } + interpret(ruls[i-1].stms); + } else if (trcflg && !stpflg) + printf(":>\n"); + } + } +} + +} // End of namespace Alan2 +} // End of namespace Glk diff --git a/engines/glk/alan2/rules.h b/engines/glk/alan2/rules.h new file mode 100644 index 0000000000..1cc0b909e3 --- /dev/null +++ b/engines/glk/alan2/rules.h @@ -0,0 +1,44 @@ +/* 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. + * + */ + +#ifndef GLK_ALAN2_RULES +#define GLK_ALAN2_RULES + +/* Header file for rules handler in Alan interpreter */ + +namespace Glk { +namespace Alan2 { + +/* TYPES */ + +#ifdef _PROTOTYPES_ + +extern void rules(void); + +#else +extern void rules(); +#endif + +} // End of namespace Alan2 +} // End of namespace Glk + +#endif diff --git a/engines/glk/alan2/stack.cpp b/engines/glk/alan2/stack.cpp new file mode 100644 index 0000000000..ccce1475d1 --- /dev/null +++ b/engines/glk/alan2/stack.cpp @@ -0,0 +1,74 @@ +/* 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/types.h" +#include "glk/alan2/main.h" +#include "glk/alan2/stack.h" + +namespace Glk { +namespace Alan2 { + +/* PRIVATE DATA */ + +#define STACKSIZE 100 + +/* The AMACHINE STACK */ +static Aptr stack[STACKSIZE]; +static int stackp = 0; + + +#ifdef _PROTOTYPES_ +void push(Aptr i) +#else +void push(i) + Aptr i; +#endif +{ + if (stackp == STACKSIZE) + syserr("Out of stack space."); + stack[stackp++] = i; +} + + +#ifdef _PROTOTYPES_ +Aptr pop(void) +#else +Aptr pop() +#endif +{ + if (stackp == 0) + syserr("Stack underflow."); + return(stack[--stackp]); +} + + +#ifdef _PROTOTYPES_ +Aptr top(void) +#else +Aptr top() +#endif +{ + return(stack[stackp-1]); +} + +} // End of namespace Alan2 +} // End of namespace Glk diff --git a/engines/glk/alan2/stack.h b/engines/glk/alan2/stack.h new file mode 100644 index 0000000000..7f10c080b6 --- /dev/null +++ b/engines/glk/alan2/stack.h @@ -0,0 +1,48 @@ +/* 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. + * + */ + +#ifndef GLK_ALAN2_STACK +#define GLK_ALAN2_STACK + +/* Header file for stack handler in Alan interpreter */ + +namespace Glk { +namespace Alan2 { + +/* TYPES */ + +#ifdef _PROTOTYPES_ + +extern Aptr pop(void); +extern void push(Aptr item); +extern Aptr top(void); + +#else +extern Aptr pop(); +extern void push(); +extern Aptr top(); +#endif + +} // End of namespace Alan2 +} // End of namespace Glk + +#endif diff --git a/engines/glk/alan2/sysdep.cpp b/engines/glk/alan2/sysdep.cpp new file mode 100644 index 0000000000..daa0417569 --- /dev/null +++ b/engines/glk/alan2/sysdep.cpp @@ -0,0 +1,493 @@ +/* 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 <string.h> +#include "glk/alan2/sysdep.h" + +#ifdef GLK +#include "glk/alan2/alan2.h" +#endif + +namespace Glk { +namespace Alan2 { + +#ifdef _PROTOTYPES_ +extern void syserr(char str[]); +#endif + +#ifdef __vms__ + +char *strdup(char str[]) /* IN - String to duplicate */ +{ + char *new = (char *) malloc(strlen(str)+1); + + if (!new) + syserr("Out of memory"); + strcpy(new, str); + return new; +} + +#endif + + +#ifdef __mac__ + +char *strdup(char str[]) /* IN - String to duplicate */ +{ + char *new = (char *) malloc((size_t)((int)strlen(str)+1)); + + if (!new) + syserr("Out of memory"); + strcpy(new, str); + return new; +} + +#endif + + +#ifdef __vms__ + +/* Cheat implementation of strftime */ +size_t strftime ( + char *outbuf, + size_t len, + const char *format, + const struct tm *t) +{ + char buf[100]; + time_t ticks; + + time(&ticks); + strcpy(buf, ctime(&ticks)); + buf[strlen(buf)-1] = '\0'; + strcpy(outbuf, &buf[4]); +} + +#endif + +#ifdef __dos__ +#endif + +#ifdef GLK + +/* Note to Glk maintainers: 'native' characters are used for output, in this + case, Glk's Latin-1. ISO characters are Alan's internal representation, + stored in the .DAT file, and must be converted to native before printing. + Glk could just use the ISO routines directly, but its safer to maintain + its own tables to guard against future changes in either Alan or Glk (ie. a + move to Unicode). + */ + +static char spcChrs[] = +{ + '\x0A', /* linefeed */ + '\x20', /* space */ + '\xA0', /* non-breaking space */ + '\x00' +}; + +static char lowChrs[] = +{ + '\x61', /* a */ '\x62', /* b */ '\x63', /* c */ '\x64', /* d */ + '\x65', /* e */ '\x66', /* f */ '\x67', /* g */ '\x68', /* h */ + '\x69', /* i */ '\x6A', /* j */ '\x6B', /* k */ '\x6C', /* l */ + '\x6D', /* m */ '\x6E', /* n */ '\x6F', /* o */ '\x70', /* p */ + '\x71', /* q */ '\x72', /* r */ '\x73', /* s */ '\x74', /* t */ + '\x75', /* u */ '\x76', /* v */ '\x77', /* w */ '\x78', /* x */ + '\x79', /* y */ '\x7A', /* z */ '\xDF', /* ss <small sharp s> */ + '\xE0', /* a grave */ '\xE1', /* a acute */ + '\xE2', /* a circumflex */ '\xE3', /* a tilde */ + '\xE4', /* a diaeresis */ '\xE5', /* a ring */ + '\xE6', /* ae */ '\xE7', /* c cedilla */ + '\xE8', /* e grave */ '\xE9', /* e acute */ + '\xEA', /* e circumflex */ '\xEB', /* e diaeresis */ + '\xEC', /* i grave */ '\xED', /* i acute */ + '\xEE', /* i circumflex */ '\xEF', /* i diaeresis */ + '\xF0', /* <small eth> */ '\xF1', /* n tilde */ + '\xF2', /* o grave */ '\xF3', /* o acute */ + '\xF4', /* o circumflex */ '\xF5', /* o tilde */ + '\xF6', /* o diaeresis */ '\xF8', /* o slash */ + '\xF9', /* u grave */ '\xFA', /* u acute */ + '\xFB', /* u circumflex */ '\xFC', /* u diaeresis */ + '\xFD', /* y acute */ '\xFE', /* <small thorn> */ + '\xFF', /* y diaeresis */ '\x00' +}; + +/* FIXME: ss <small sharp s> and y diaeresis have no UC analogues + Are they really considered LC? + */ + +static char uppChrs[] = +{ + '\x41', /* A */ '\x42', /* B */ '\x43', /* C */ '\x44', /* D */ + '\x45', /* E */ '\x46', /* F */ '\x47', /* G */ '\x48', /* H */ + '\x49', /* I */ '\x4A', /* J */ '\x4B', /* K */ '\x4C', /* L */ + '\x4D', /* M */ '\x4E', /* N */ '\x4F', /* O */ '\x50', /* P */ + '\x51', /* Q */ '\x52', /* R */ '\x53', /* S */ '\x54', /* T */ + '\x55', /* U */ '\x56', /* V */ '\x57', /* W */ '\x58', /* X */ + '\x59', /* Y */ '\x5A', /* Z */ + '\xC0', /* A grave */ '\xC1', /* A acute */ + '\xC2', /* A circumflex */ '\xC3', /* A tilde */ + '\xC4', /* A diaeresis */ '\xC5', /* A ring */ + '\xC6', /* AE */ '\xC7', /* C cedilla */ + '\xC8', /* E grave */ '\xC9', /* E acute */ + '\xCA', /* E circumflex */ '\xCB', /* E diaeresis */ + '\xCC', /* I grave */ '\xCD', /* I acute */ + '\xCE', /* I circumflex */ '\xCF', /* I diaeresis */ + '\xD0', /* <capital eth> */ '\xD1', /* N tilde */ + '\xD2', /* O grave */ '\xD3', /* O acute */ + '\xD4', /* O circumflex */ '\xD5', /* O tilde */ + '\xD6', /* O diaeresis */ '\xD8', /* O slash */ + '\xD9', /* U grave */ '\xDA', /* U acute */ + '\xDB', /* U circumflex */ '\xDC', /* U diaeresis */ + '\xDD', /* Y acute */ '\xDE', /* <capital thorn> */ + '\x00' +}; + +#else + +/* Theses work on native character sets */ + +static char spcChrs[] = " \t\n"; + +#ifdef __amiga__ + +/* Which can't read 8-bit chars but is ISO */ +static char lowChrs[] = "abcdefghijklmnopqrstuvwxyz\340\341\342\343\344\345\346\347\351\352\353\354\355\356\357\360\361\362\363\364\365\366\370\371\372\373\374\375\376\377"; + +static char uppChrs[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337"; + +#else + +/* Use native characters */ +static char lowChrs[] = "abcdefghijklmnopqrstuvwxyzàáâãäåæçéêëìíîïðñòóôõöøùúûüýþÿ"; + +static char uppChrs[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÛÝÞß"; + +#endif +#endif + +int isSpace(int c) /* IN - Native character to test */ +{ + return (c != '\0' && strchr(spcChrs, c) != 0); +} + + +int isLower(int c) /* IN - Native character to test */ +{ + return (c != '\0' && strchr(lowChrs, c) != 0); +} + + +int isUpper(int c) /* IN - Native character to test */ +{ + return (c != '\0' && strchr(uppChrs, c) != 0); +} + +int isLetter(int c) /* IN - Native character to test */ +{ + return(c != '\0' && (isLower(c)? !0: isUpper(c))); +} + + +int toLower(int c) /* IN - Native character to convert */ +{ +#ifdef GLK + return g_vm->glk_char_to_lower(c); +#else +#ifdef __dos__ + char *cp; + + if ((cp = strchr(uppChrs, c)) != 0) + return(lowChrs[cp-uppChrs]); + else + return c; +#else +#ifdef __mac__ + char *cp; + + if ((cp = strchr(uppChrs, c)) != 0) + return(lowChrs[cp-uppChrs]); + else + return c; +#else + return (isUpper(c)? c + ('a' - 'A'): c); +#endif +#endif +#endif +} + +int toUpper(int c) /* IN - Native character to convert */ +{ +#ifdef GLK + return g_vm->glk_char_to_upper(c); +#else +#ifdef __dos__ + char *cp; + + if ((cp = strchr(lowChrs, c)) != 0) + return(uppChrs[cp-lowChrs]); + else + return c; +#else +#ifdef __mac__ + char *cp; + + if ((cp = strchr(lowChrs, c)) != 0) + return(uppChrs[cp-lowChrs]); + else + return c; +#else + return (isLower(c)? c - ('a' - 'A'): c); +#endif +#endif +#endif +} + +char *strlow(char str[]) /* INOUT - Native string to convert */ +{ + char *s; + + for (s = str; *s; s++) + *s = toLower(*s); + return(str); +} + + +char *strupp(char str[]) /* INOUT - Native string to convert */ +{ + char *s; + + for (s = str; *s; s++) + *s = toUpper(*s); + return(str); +} + + +/* The following work on ISO characters */ + +int isLowerCase(int c) /* IN - ISO character to test */ +{ + static char lowChrs[] = "abcdefghijklmnopqrstuvwxyz\340\341\342\343\344\345\346\347\351\352\353\354\355\356\357\360\361\362\363\364\365\366\370\371\372\373\374\375\376\377"; + return (c != '\0' && strchr(lowChrs, c) != 0); +} + + +int isUpperCase(int c) /* IN - ISO character to test */ +{ + static char uppChrs[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337"; + return (c != '\0' && strchr(uppChrs, c) != 0); +} + + +int isISOLetter(int c) /* IN - ISO character to test */ +{ + return (isLowerCase(c) || isUpperCase(c)); +} + + +char toLowerCase(int c) /* IN - ISO character to convert */ +{ + return (isUpperCase(c)? c + ('a' - 'A'): c); +} + + +char toUpperCase(int c) /* IN - ISO character to convert */ +{ + return (isLowerCase(c)? c - ('a' - 'A'): c); +} + + +char *stringLower(char str[]) /* INOUT - ISO string to convert */ +{ + char *s; + + for (s = str; *s; s++) + *s = toLowerCase(*s); + return(str); +} + + +char *stringUpper(char str[]) /* INOUT - ISO string to convert */ +{ + char *s; + + for (s = str; *s; s++) + *s = toUpperCase(*s); + return(str); +} + + +/*---------------------------------------------------------------------- + toIso + + Converts the incoming string to ISO character set. The original is + in the current character set which in the case of the compiler might + be other than the native. + + */ +void toIso(char copy[], /* OUT - Mapped string */ + char original[], /* IN - string to convert */ + int charset) /* IN - the current character set */ +{ +static unsigned char macMap[256] += { +0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0A,0x0E,0x0F, +0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F, +0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F, +0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, +0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F, +0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F, +0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F, +0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F, +0xC4,0xC5,0xC7,0xC9,0xD1,0xD6,0xDC,0xE1,0xE0,0xE2,0xE4,0xE3,0xE5,0xE7,0xE9,0xE8, +0xEA,0xEB,0xED,0xEC,0xEE,0xEF,0xF1,0xF3,0xF2,0xF4,0xF6,0xF5,0xFA,0xF9,0xFB,0xFC, +0xB9,0xB0,0xA2,0xA3,0xA7,0xB7,0xB6,0xDF,0xAE,0xA9,0xB2,0xB4,0xA8,0xD7,0xC6,0xD8, +0xA4,0xB1,0xCD,0xCC,0xA5,0xB5,0xF0,0xCA,0xDE,0xFE,0xA6,0xAA,0xBA,0xD4,0xE6,0xF8, +0xBF,0xA1,0xAC,0xCE,0xCF,0xC8,0xD0,0xAB,0xBB,0xCB,0xA0,0xC0,0xC3,0xD5,0xDD,0xFD, +0xAD,0xAF,0xDA,0xD9,0xB8,0xB3,0xF7,0xC2,0xFF,0xBC,0xBD,0xBE,0xC1,0xD2,0xD3,0xDB, +0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, +0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F}; + +static unsigned char dosMap[256] += { +0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0A,0x0E,0x0F, +0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F, +0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F, +0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, +0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F, +0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F, +0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F, +0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F, +0xC7,0xFC,0xE9,0xE2,0xE4,0xE0,0xE5,0xE7,0xEA,0xEB,0xE8,0xEF,0xEE,0xEC,0xC4,0xC5, +0xC9,0xE6,0xC6,0xF4,0xF6,0xF2,0xFB,0xF9,0xFF,0xD6,0xDC,0xA2,0xA3,0xA5,0xDE,0xA6, +0xE1,0xED,0xF3,0xFA,0xF1,0xD1,0xAA,0xBA,0xBF,0xC0,0xC1,0xBD,0xBC,0xCF,0xAB,0xBB, +0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, +0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, +0xA1,0xA7,0xAD,0xB3,0xB8,0xB9,0xC3,0xCE,0xD2,0xD3,0xDB,0xDD,0xE3,0xF5,0xF8,0xFD, +0xA9,0xDF,0xC8,0xB6,0xCA,0xA4,0xB5,0xAE,0xD5,0xD0,0xD4,0xF0,0xD7,0xD8,0xCB,0xC2, +0xBE,0xB1,0xD9,0xDA,0xCD,0xCC,0xF7,0xA8,0xB0,0xB7,0xAF,0xAC,0xFE,0xB2,0xB4,0xA0}; + unsigned char *o, *c; + + switch (charset) { + case 0: /* ISO */ + if (copy != original) + (void)strcpy(copy, original); + break; + case 1: /* Mac */ + for (o = (unsigned char *)original, c = (unsigned char *)copy; *o; o++, c++) + *c = macMap[*o]; + *c = '\0'; + break; + + case 2: /* Dos */ + for (o = (unsigned char *)original, c = (unsigned char *)copy; *o; o++, c++) + *c = dosMap[*o]; + *c = '\0'; + break; + } +} + +/*---------------------------------------------------------------------- + + fromIso + + Converts a string from global Iso format to native. Only used in + interpreter so character set is known at compile time. + + */ +void fromIso(char copy[], /* OUT - Mapped string */ + char original[]) /* IN - string to convert */ +{ +#if ISO == 0 + static unsigned char map[256] +#if defined __mac__ + = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0D,0x0B,0x0C,0x0D,0x0E,0x0F, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F, + 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F, + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, + 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F, + 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F, + 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F, + 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F, + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF, + 0xCA,0xC1,0xA2,0xA3,0xB0,0xB4,0xBA,0xA4,0xAC,0xA9,0xBB,0xC7,0xC2,0xD0,0xA8,0xD1, + 0xA1,0xB1,0xAA,0xD5,0xAB,0xB5,0xA6,0xA5,0xD4,0xA0,0xBC,0xC8,0xD9,0xDA,0xDB,0xC0, + 0xCB,0xDC,0xD7,0xCC,0x80,0x81,0xAE,0x82,0xC5,0x83,0xB7,0xC9,0xB3,0xB2,0xC3,0xC4, + 0xC6,0x84,0xDD,0xDE,0xBD,0xCD,0x85,0xAD,0xAF,0xD3,0xD2,0xDF,0x86,0xCE,0xB8,0xA7, + 0x88,0x87,0x89,0x8B,0x8A,0x8C,0xBE,0x8D,0x8F,0x8E,0x90,0x91,0x93,0x92,0x94,0x95, + 0xB6,0x96,0x98,0x97,0x99,0x9B,0x9A,0xD6,0xBF,0x9D,0x9C,0x9E,0x9F,0xCF,0xB9,0xD8} +#else +#if defined __dos__ + = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0D,0x0B,0x0C,0x0D,0x0E,0x0F, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F, + 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F, + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, + 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F, + 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F, + 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F, + 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F, + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, + 0xFF,0xD0,0x9B,0x9C,0xE5,0x9D,0x9F,0xD1,0xF7,0xE0,0xA6,0xAE,0xFB,0xD2,0xE7,0xFA, + 0xF8,0xF1,0xFD,0xD3,0xFE,0xE6,0xE3,0xF9,0xD4,0xD5,0xA7,0xAF,0xAC,0xAB,0xF0,0xA8, + 0xA9,0xAA,0xEF,0xD6,0x8E,0x8F,0x92,0x80,0xE2,0x90,0xE4,0xEE,0xF5,0xF4,0xD7,0xAD, + 0xE9,0xA5,0xD8,0xD9,0xEA,0xE8,0x99,0xEC,0xED,0xF2,0xF3,0xDA,0x9A,0xDB,0x9E,0xE1, + 0x85,0xA0,0x83,0xDC,0x84,0x86,0x91,0x87,0x8A,0x82,0x88,0x89,0x8D,0xA1,0x8C,0x8B, + 0xEB,0xA4,0x95,0xA2,0x93,0xDD,0x94,0xF6,0xDE,0x97,0xA3,0x96,0x81,0xDF,0xFC,0x98} +#endif + ; +#endif + unsigned char *o, *c; + + for (o = (unsigned char *)original, c = (unsigned char *)copy; *o; o++, c++) + *c = map[*o]; + *c = '\0'; +#else + if (copy != original) + (void)strcpy(copy, original); +#endif +} + + +/*---------------------------------------------------------------------- + toNative + + Converts the incoming string to the native character set from any of + the others. The original is in the current character set which in + the case of the compiler might be other than the native. + + */ +void toNative(char copy[], /* OUT - Mapped string */ + char original[], /* IN - string to convert */ + int charset) /* IN - the current character set */ +{ + toIso(copy, original, charset); + if (NATIVECHARSET != 0) + fromIso(copy, copy); +} + +} // End of namespace Alan2 +} // End of namespace Glk diff --git a/engines/glk/alan2/sysdep.h b/engines/glk/alan2/sysdep.h new file mode 100644 index 0000000000..72769cb271 --- /dev/null +++ b/engines/glk/alan2/sysdep.h @@ -0,0 +1,409 @@ +/* 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. + * + */ + +#ifndef GLK_ALAN2_SYSDEP +#define GLK_ALAN2_SYSDEP + +/* System dependencies file for Alan Adventure Language system + * + * N.B.The test for symbols used here should really be of three types + * - processor name(like PC, x86, ...) + * - os name(DOS, WIN32, Solaris2, ...) + * - compiler name andversion(DJGPP, CYGWIN, GCC271, THINK-C, ...) + * + * The set symbols should indicate if a feature is on or off like the GNU + * AUTOCONFIG package does. + * + * This is not completely done yet! + */ + +#include "common/scummsys.h" + +namespace Glk { +namespace Alan2 { + +#define GLK +#define _PROTOTYPES_ +#define __win__ + +#ifdef GLK +#undef isdigit +#define isdigit Common::isDigit +#undef stricmp +#define stricmp scumm_stricmp +#undef strdup +#define strdup scumm_strdup +#undef rand +#define rand() g_vm->getRandomNumber(0x7fffffff) +#undef fprintf +#define fprintf(FP, STR) FP->write(STR, strlen(STR) + 1) +#endif + +/* Place definitions of OS and compiler here if necessary */ +#ifdef AZTEC_C +#define __amiga__ +#endif + +#ifndef __sun__ +#ifdef sun +#define __sun__ +#endif +#endif + +#ifdef _INCLUDE_HPUX_SOURCE +#define __hp__ +#endif + +#ifndef __unix__ +#ifdef unix +#define __unix__ +#endif +#endif + +#ifdef vax +#define __vms__ +#endif + +#ifdef THINK_C +#define __mac__ +#endif + +#ifdef __MWERKS__ +#ifdef macintosh +#define __mac__ +#else +#define __dos__ +#endif +#endif + +#ifdef DOS +#define __dos__ +#endif + +#ifdef __BORLANDC__ +#define __dos__ +#endif + +#ifdef __CYGWIN__ +#define __win__ +#endif + +#ifdef __MINGW32__ +#define __win__ +#endif + +#ifdef __PACIFIC__ +#define __dos__ +#define HAVE_SHORT_FILENAMES +#endif + + +/*---------------------------------------------------------------------- + + Below follows OS and compiler dependent settings. They should not be + changed except for introducing new sections when porting to new + environments. + + */ + +/************/ +/* Includes */ +/************/ + +#ifndef GLK +#include <stdio.h> +#include <ctype.h> +#endif + +#ifdef __STDC__ +#define _PROTOTYPES_ +#include <stdlib.h> +#include <string.h> +#endif + +#ifdef __vms__ +/* Our VAXC doesn't define __STDC__ */ +#define _PROTOTYPES_ +#include <stdlib.h> +#include <string.h> +#endif + + +#ifdef __mac__ +#define _PROTOTYPES_ +#include <stdlib.h> +#include <string.h> +#include <unix.h> +#endif + +#ifdef __MWERKS__ +#define strdup _strdup +#endif + +/***********************/ +/* ISO character sets? */ +/***********************/ + +/* Common case first */ +#define ISO 1 +#define NATIVECHARSET 0 + +#ifdef GLK +#undef ISO +#define ISO 1 +#undef NATIVECHARSET +#define NATIVECHARSET 0 +#else /* Glk is ISO, no matter what the OS */ + +#ifdef __dos__ +#undef ISO +#define ISO 0 +#undef NATIVECHARSET +#define NATIVECHARSET 2 +#endif + +#ifdef __win__ +#undef ISO +#define ISO 1 +#undef NATIVECHARSET +#define NATIVECHARSET 2 +#endif + +#ifdef __mac__ +#undef ISO +#define ISO 0 +#undef NATIVECHARSET +#define NATIVECHARSET 1 +#endif + +#endif + +/**************************/ +/* Strings for file modes */ +/**************************/ +#define READ_MODE "r" +#define WRITE_MODE "w" + +#ifdef __mac__ +/* File open mode (binary) */ +#undef READ_MODE +#define READ_MODE "rb" +#undef WRITE_MODE +#define WRITE_MODE "wb" +#endif + +#ifdef __dos__ +/* File open mode (binary) */ +#undef READ_MODE +#define READ_MODE "rb" +#undef WRITE_MODE +#define WRITE_MODE "wb" +#endif + +#ifdef __win__ +/* File open mode (binary) */ +#undef READ_MODE +#define READ_MODE "rb" +#undef WRITE_MODE +#define WRITE_MODE "wb" +#endif + +/*****************/ +/* Byte ordering */ +/*****************/ + +#ifdef __dos__ +#define REVERSED +#endif + +#ifdef __vms__ +#define REVERSED +#endif + +#ifdef __win__ +#ifndef REVERSED +#define REVERSED +#endif +#endif + + +/****************************/ +/* Allocates cleared bytes? */ +/****************************/ + +#ifdef __CYGWIN__ +#define NOTCALLOC +#endif + +#ifdef __MINGW32__ +#define NOTCALLOC +#endif + +#ifdef __unix__ +#define NOTCALLOC +#endif + + +/****************/ +/* Have termio? */ +/****************/ + +#ifdef GLK +/* don't need TERMIO */ +#else + +#ifdef __CYGWIN__ +#define HAVE_TERMIO +#endif + +#ifdef __unix__ +#define HAVE_TERMIO +#endif + +#endif + +/*******************************/ +/* Is ANSI control available? */ +/*******************************/ + +#ifdef GLK +/* don't need ANSI */ +#else + +#ifdef __CYGWIN__ +#define HAVE_ANSI +#endif + +#endif + +/******************************/ +/* Use the READLINE function? */ +/******************************/ + +#ifdef GLK +/* Glk always uses readline(), no matter what the OS */ +#define USE_READLINE +#else + +#ifdef __unix__ +#define USE_READLINE +#endif + +#ifdef x__dos__ +#define USE_READLINE +#endif + +#ifdef __win__ +#define USE_READLINE +#endif + +#endif + +/* Special cases and definition overrides */ +#ifdef __unix__ +#define MULTI +#endif + + + + +#ifdef __vms__ + +#define MULTI + +extern char *strdup(char str[]); + +/* Cheat implementation of strftime */ +extern size_t strftime (char *, size_t, const char *, const struct tm *); + +#endif + +#ifdef __mac__ + +extern char *strdup(char *str); + +#endif + + +#ifdef __dos__ + +/* Return codes */ +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +#endif + + +#ifdef _PROTOTYPES_ + +/* Native character functions */ +extern int isSpace(int c); /* IN - Native character to test */ +extern int isLower(int c); /* IN - Native character to test */ +extern int isUpper(int c); /* IN - Native character to test */ +extern int isLetter(int c); /* IN - Native character to test */ +extern int toLower(int c); /* IN - Native character to convert */ +extern int toUpper(int c); /* IN - Native character to convert */ +extern char *strlow(char str[]); /* INOUT - Native string to convert */ +extern char *strupp(char str[]); /* INOUT - Native string to convert */ + +/* ISO character functions */ +extern int isISOLetter(int c); /* IN - ISO character to test */ +extern char toLowerCase(int c); /* IN - ISO character to convert */ +extern char toUpperCase(int c); /* IN - ISO character to convert */ +extern char *stringLower(char str[]); /* INOUT - ISO string to convert */ +extern char *stringUpper(char str[]); /* INOUT - ISO string to convert */ + +/* ISO string conversion functions */ +extern void toIso(char copy[], /* OUT - Mapped string */ + char original[], /* IN - string to convert */ + int charset); /* IN - The current character set */ + +extern void fromIso(char copy[], /* OUT - Mapped string */ + char original[]); /* IN - string to convert */ + +extern void toNative(char copy[], /* OUT - Mapped string */ + char original[], /* IN - string to convert */ + int charset); /* IN - current character set */ +#else +extern int isSpace(); +extern int isLower(); +extern int isUpper(); +extern int isLetter(); +extern int toLower(); +extern int toUpper(); +extern char *strlow(); +extern char *strupp(); + +extern int isISOLetter(); +extern char toLowerCase(); +extern char toUpperCase(); +extern char *stringLower(); +extern char *stringUpper(); + +extern void toIso(); +extern void fromIso(); +#endif + +} // End of namespace Alan2 +} // End of namespace Glk + +#endif diff --git a/engines/glk/alan2/term.cpp b/engines/glk/alan2/term.cpp new file mode 100644 index 0000000000..cf60fc5bbe --- /dev/null +++ b/engines/glk/alan2/term.cpp @@ -0,0 +1,123 @@ +/* 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/main.h" +#include "glk/alan2/term.h" + +namespace Glk { +namespace Alan2 { + +/*====================================================================== + + getPageSize() + + Try to get the current page size from the system, else use the ones + from the header. + + */ +#ifdef _PROTOTYPES_ +void getPageSize(void) +#else +void getPageSize() +#endif +{ +#ifdef GLK + paglen = 0; + pagwidth = 0; + +#else +#ifdef HAVE_TERMIO + +#include <sys/termios.h> + + extern int ioctl(); + + struct winsize win; + int ecode; + + ecode = ioctl(1, TIOCGWINSZ, &win); + + if (ecode != 0 || win.ws_row == 0) + paglen = header->paglen; + else + paglen = win.ws_row; + + if (ecode != 0 || win.ws_col == 0) + pagwidth = header->pagwidth; + else + pagwidth = win.ws_col; + +#else +#ifdef __amiga__ +#include <libraries/dosextens.h> +#include <intuition/intuition.h> +#include <graphics/text.h> +#include <clib/exec_protos.h> + + struct Process * proc; + struct InfoData *id; + struct Window *win; + struct TextFont *textFont; + struct StandardPacket *packet; + + proc = (struct Process *) FindTask(0L); + + id = (struct InfoData *) allocate(sizeof(struct InfoData)); + + if (proc->pr_ConsoleTask) { + packet = (struct StandardPacket *) allocate(sizeof(struct StandardPacket)); + packet->sp_Msg.mn_Node.ln_Name = (char *)&(packet->sp_Pkt); + packet->sp_Pkt.dp_Link = & packet->sp_Msg; + packet->sp_Pkt.dp_Port = & proc->pr_MsgPort; + packet->sp_Pkt.dp_Type = ACTION_DISK_INFO; + + packet->sp_Pkt.dp_Arg1 = ((LONG) id) >> 2; + + PutMsg ((struct MsgPort *) proc->pr_ConsoleTask, & packet->sp_Msg); + WaitPort(&proc->pr_MsgPort); + GetMsg(&proc->pr_MsgPort); + free((char *)packet); + + win = (struct Window *) id->id_VolumeNode; + free(id); + + /* Calculate number of characters and lines w.r.t font size and borders */ + textFont = win->IFont; + paglen = win->Height/textFont->tf_YSize-2; + pagwidth = win->Width/textFont->tf_XSize-3; + } else { + paglen = header->paglen; + pagwidth = header->pagwidth; + } + +#else + + paglen = header->paglen; + pagwidth = header->pagwidth; + +#endif +#endif +#endif +} + +} // End of namespace Alan2 +} // End of namespace Glk diff --git a/engines/glk/alan2/term.h b/engines/glk/alan2/term.h new file mode 100644 index 0000000000..339a3b5e82 --- /dev/null +++ b/engines/glk/alan2/term.h @@ -0,0 +1,42 @@ +/* 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. + * + */ + +#ifndef GLK_ALAN2_TERM +#define GLK_ALAN2_TERM + +/* Header file for terminal functions in ARUN, the Alan interpreter */ + +namespace Glk { +namespace Alan2 { + +#ifdef _PROTOTYPES_ + +extern void getPageSize(void); + +#else +extern void getPageSize(); +#endif + +} // End of namespace Alan2 +} // End of namespace Glk + +#endif diff --git a/engines/glk/alan2/types.h b/engines/glk/alan2/types.h index 7da9e1dc58..2de31c06bf 100644 --- a/engines/glk/alan2/types.h +++ b/engines/glk/alan2/types.h @@ -23,248 +23,261 @@ #ifndef GLK_ALAN2_TYPES #define GLK_ALAN2_TYPES +#include "glk/alan2/sysdep.h" #include "glk/alan2/acode.h" namespace Glk { namespace Alan2 { -// CONSTANTS - -#define ACTMIN (_vm->header->actmin) -#define ACTMAX (_vm->header->actmax) -#define OBJMIN (_vm->header->objmin) -#define OBJMAX (_vm->header->objmax) -#define LOCMIN (_vm->header->locmin) -#define LOCMAX (_vm->header->locmax) -#define CNTMIN (_vm->header->cntmin) -#define CNTMAX (_vm->header->cntmax) -#define LITMIN (_vm->header->locmax + 1) -#define LITMAX (_vm->header->locmax + 1 + litCount) -#define EVTMIN (_vm->header->evtmin) -#define EVTMAX (_vm->header->evtmax) +/* CONSTANTS */ + +#ifndef __mac__ +#ifndef TRUE +#define TRUE (0==0) +#endif +#ifndef FALSE +#define FALSE (!TRUE) +#endif +#endif + +#define ACTMIN (header->actmin) +#define ACTMAX (header->actmax) +#define OBJMIN (header->objmin) +#define OBJMAX (header->objmax) +#define LOCMIN (header->locmin) +#define LOCMAX (header->locmax) +#define CNTMIN (header->cntmin) +#define CNTMAX (header->cntmax) +#define LITMIN (header->locmax+1) +#define LITMAX (header->locmax+1+litCount) +#define EVTMIN (header->evtmin) +#define EVTMAX (header->evtmax) #define HERO ACTMIN -#define addrTo(x) (&_vm->memory[x]) - -// The word classes are represented as numbers but in the dictonary they are generated as bits -#define isVerb(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_VRB))!=0) -#define isConj(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_CONJ))!=0) -#define isBut(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_BUT))!=0) -#define isThem(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_THEM))!=0) -#define isIt(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_IT))!=0) -#define isNoun(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_NOUN))!=0) -#define isAdj(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_ADJ))!=0) -#define isPrep(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_PREP))!=0) -#define isAll(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_ALL))!=0) -#define isDir(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_DIR))!=0) -#define isNoise(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_NOISE))!=0) +#define addrTo(x) (&memory[x]) + +/* The word classes are represented as numbers but in the dictonary they are generated as bits */ +#define isVerb(word) (word < dictsize && (dict[word]._class&((Aword)1L<<WRD_VRB))!=0) +#define isConj(word) (word < dictsize && (dict[word]._class&((Aword)1L<<WRD_CONJ))!=0) +#define isBut(word) (word < dictsize && (dict[word]._class&((Aword)1L<<WRD_BUT))!=0) +#define isThem(word) (word < dictsize && (dict[word]._class&((Aword)1L<<WRD_THEM))!=0) +#define isIt(word) (word < dictsize && (dict[word]._class&((Aword)1L<<WRD_IT))!=0) +#define isNoun(word) (word < dictsize && (dict[word]._class&((Aword)1L<<WRD_NOUN))!=0) +#define isAdj(word) (word < dictsize && (dict[word]._class&((Aword)1L<<WRD_ADJ))!=0) +#define isPrep(word) (word < dictsize && (dict[word]._class&((Aword)1L<<WRD_PREP))!=0) +#define isAll(word) (word < dictsize && (dict[word]._class&((Aword)1L<<WRD_ALL))!=0) +#define isDir(word) (word < dictsize && (dict[word]._class&((Aword)1L<<WRD_DIR))!=0) +#define isNoise(word) (word < dictsize && (dict[word]._class&((Aword)1L<<WRD_NOISE))!=0) #define isLiteral(word) (word >= dictsize) -// TYPES - -// Amachine variables -struct CurVars { - int vrb; - int obj; - int loc; - int act; - int tick; - int score; - int visits; -}; - -// The various tables -struct WrdElem { // Dictionary - Aaddr wrd; // ACODE address to string - Aword wordClass; // Word class - Aword code; - Aaddr adjrefs; // Address to reference list - Aaddr nounrefs; // Address to reference list -}; - -struct ActElem { // ACTOR TABLE - Aword loc; // Location - Abool describe; // Description flag - Aaddr nam; // Address to name printing code - Aaddr atrs; // Address to attribute list - Aword cont; // Code for the container props if any - Aword script; // Which script is he using - Aaddr scradr; // Address to script table - Aword step; - Aword count; - Aaddr vrbs; - Aaddr dscr; // Address of description code -}; - -struct ScrElem { // SCRIPT TABLE - Aword code; // Script number - Aaddr dscr; // Optional description statements - Aaddr steps; // Address to steps -}; - -struct StepElem { // STEP TABLE - Aword after; // After how many ticks? - Aaddr exp; // Address to expression saying when - Aaddr stm; // Address to the actual code -}; - -struct LocElem { // LOCATION TABLE - Aaddr nams; // Address of name printing code - Aaddr dscr; // Address of description code - Aaddr does; // Address of does code - Aword describe; // Description flag & counter - Aaddr atrs; // Address of attribute list - Aaddr exts; // Address of exit list - Aaddr vrbs; // Address of local verb list -}; - -struct ExtElem { // EXIT TABLE structure - Abool done; // Flag for reverse/convert process - Aword code; // Direction code - Aaddr checks; // Address of check table - Aaddr action; // Address of action code - Aword next; // Number of next location -}; - -struct ChkElem { // CHECK TABLE - Aaddr exp; // ACODE address to expression code - Aaddr stms; // ACODE address to statement code -}; - -struct VrbElem { // VERB TABLE - Aword code; // Code for the verb - Aaddr alts; // Address to alternatives -}; - -struct StxElem { // SYNTAX TABLE - Aword code; // Code for verb word - Aaddr elms; // Address to element tables -}; - -struct ElmElem26 { // ELEMENT TABLES - Aword code; // Code for this element, 0 -> parameter - Abool multiple; // May be multiple (if parameter) - Aaddr next; // Address to next element table ... - // ... or class check if EOS -}; - -struct ElmElem { // ELEMENT TABLES - Aword code; // Code for this element, 0 -> parameter - Aword flags; // Flags for multiple/omni (if parameter) - // CHANGED: v2.7 from Abool for multiple - Aaddr next; // Address to next element table ... - // ... or class check if EOS -}; - -struct ClaElem { // CLASS DEFINITION TABLE - Aword code; // Parameter number - Aword classes; // Parameter classes - Aaddr stms; // Exception statements -}; - -struct AltElem { // VERB ALTERNATIVE TABLE - Abool done; // Flag for patching (reverse/convert) process - Aword param; // Parameter number - Aword qual; // Verb execution qualifier - Aaddr checks; // Address of the check table - Aaddr action; // Address of the action code -}; - -struct AtrElem { // ATTRIBUTE LIST - Aword val; // Its value - Aaddr stradr; // Address to the name -}; - -struct ObjElem25 { // OBJECT TABLE of 2.5 format - Aword loc; // Current location - Abool describe; // Describe flag - Aaddr atrs; // Address of attribute list - Aword cont; // Index to container properties if any - Aaddr vrbs; // Address to local verb table - Aaddr dscr1; // Address to Aword description code - Aaddr dscr2; // Address to short description code -}; - -struct ObjElem { // OBJECT TABLE - Aword loc; // Current location - Abool describe; // Describe flag - Aaddr atrs; // Address of attribute list - Aword cont; // Index to container properties if any - Aaddr vrbs; // Address to local verb table - Aaddr dscr1; // Address to Aword description code - Aaddr art; // Article printing code? Else use default - // INTRODUCED: v2.6 - Aaddr dscr2; // Address to short description code -}; - -struct CntElem { // CONTAINER TABLE - Aaddr lims; // Address to limit check code - Aaddr header; // Address to header code - Aaddr empty; // Address to empty code - Aword parent; // Object or actor index - Aaddr nam; // Address to statement printing name -}; - -struct LimElem { // LIMIT Type - Aword atr; // Attribute that limits - Aword val; // And the limiting value - Aaddr stms; // Statements if fail -}; - -struct RulElem { // RULE TABLE - Abool run; // Is rule already run? - Aaddr exp; // Address to expression code - Aaddr stms; // Address to run -}; - -struct EvtElem { // EVENT TABLE - Aaddr stradr; // Address to name string - Aaddr code; // Address of code to run -}; - -struct EvtqElem { // EVENT QUEUE ELEMENT - int time; - int event; - int where; -}; - -struct IniElem { // STRING INITIALISATION TABLE - Aword fpos; // File position - Aword len; // Length - Aword adr; // Where to store the string -}; - -struct MsgElem26 { // MESSAGE TABLE - Aword fpos; // File position - Aword len; // Length of message -}; - -struct MsgElem { // MESSAGE TABLE - Aaddr stms; // Address to statements - // Changed v2.7 from fpos+len in .dat -}; - -struct ParamElem { // PARAMETER - Aword code; // Code for this parameter (0=multiple) - Aword firstWord; // Index to first word used by player - Aword lastWord; // d:o to last -}; - -enum Type { - TYPNUM, - TYPSTR -}; - -struct LitElem { // LITERAL - Type type; - Aptr value; -}; +/* TYPES */ + +#ifndef __mac__ +typedef int Boolean; /* Boolean values within interpreter */ +#endif + +/* Amachine variables */ +typedef struct CurVars { + int + vrb, + obj, + loc, + act, + tick, + score, + visits; +} CurVars; + +/* The various tables */ +typedef struct WrdElem { /* Dictionary */ + Aaddr wrd; /* ACODE address to string */ + Aword _class; /* Word class */ + Aword code; + Aaddr adjrefs; /* Address to reference list */ + Aaddr nounrefs; /* Address to reference list */ +} WrdElem; + +typedef struct ActElem { /* ACTOR TABLE */ + Aword loc; /* Location */ + Abool describe; /* Description flag */ + Aaddr nam; /* Address to name printing code */ + Aaddr atrs; /* Address to attribute list */ + Aword cont; /* Code for the container props if any */ + Aword script; /* Which script is he using */ + Aaddr scradr; /* Address to script table */ + Aword step; + Aword count; + Aaddr vrbs; + Aaddr dscr; /* Address of description code */ +} ActElem; + +typedef struct ScrElem { /* SCRIPT TABLE */ + Aword code; /* Script number */ + Aaddr dscr; /* Optional description statements */ + Aaddr steps; /* Address to steps */ +} ScrElem; + +typedef struct StepElem { /* STEP TABLE */ + Aword after; /* After how many ticks? */ + Aaddr exp; /* Address to expression saying when */ + Aaddr stm; /* Address to the actual code */ +} StepElem; + +typedef struct LocElem { /* LOCATION TABLE */ + Aaddr nams; /* Address of name printing code */ + Aaddr dscr; /* Address of description code */ + Aaddr does; /* Address of does code */ + Aword describe; /* Description flag & counter */ + Aaddr atrs; /* Address of attribute list */ + Aaddr exts; /* Address of exit list */ + Aaddr vrbs; /* Address of local verb list */ +} LocElem; + +typedef struct ExtElem { /* EXIT TABLE structure */ + Abool done; /* Flag for reverse/convert process */ + Aword code; /* Direction code */ + Aaddr checks; /* Address of check table */ + Aaddr action; /* Address of action code */ + Aword next; /* Number of next location */ +} ExtElem; + +typedef struct ChkElem { /* CHECK TABLE */ + Aaddr exp; /* ACODE address to expression code */ + Aaddr stms; /* ACODE address to statement code */ +} ChkElem; + +typedef struct VrbElem { /* VERB TABLE */ + Aword code; /* Code for the verb */ + Aaddr alts; /* Address to alternatives */ +} VrbElem; + +typedef struct StxElem { /* SYNTAX TABLE */ + Aword code; /* Code for verb word */ + Aaddr elms; /* Address to element tables */ +} StxElem; + +typedef struct ElmElem26 { /* ELEMENT TABLES */ + Aword code; /* Code for this element, 0 -> parameter */ + Abool multiple; /* May be multiple (if parameter) */ + Aaddr next; /* Address to next element table ... */ + /* ... or class check if EOS */ +} ElmElem26; + +typedef struct ElmElem { /* ELEMENT TABLES */ + Aword code; /* Code for this element, 0 -> parameter */ + Aword flags; /* Flags for multiple/omni (if parameter) */ + /* CHANGED: v2.7 from Abool for multiple */ + Aaddr next; /* Address to next element table ... */ + /* ... or class check if EOS */ +} ElmElem; + +typedef struct ClaElem { /* CLASS DEFINITION TABLE */ + Aword code; /* Parameter number */ + Aword classes; /* Parameter classes */ + Aaddr stms; /* Exception statements */ +} ClaElem; + +typedef struct AltElem { /* VERB ALTERNATIVE TABLE */ + Abool done; /* Flag for patching (reverse/convert) process */ + Aword param; /* Parameter number */ + Aword qual; /* Verb execution qualifier */ + Aaddr checks; /* Address of the check table */ + Aaddr action; /* Address of the action code */ +} AltElem; + +typedef struct AtrElem { /* ATTRIBUTE LIST */ + Aword val; /* Its value */ + Aaddr stradr; /* Address to the name */ +} AtrElem; + +typedef struct ObjElem25 { /* OBJECT TABLE of 2.5 format*/ + Aword loc; /* Current location */ + Abool describe; /* Describe flag */ + Aaddr atrs; /* Address of attribute list */ + Aword cont; /* Index to container properties if any */ + Aaddr vrbs; /* Address to local verb table */ + Aaddr dscr1; /* Address to Aword description code */ + Aaddr dscr2; /* Address to short description code */ +} ObjElem25; + +typedef struct ObjElem { /* OBJECT TABLE */ + Aword loc; /* Current location */ + Abool describe; /* Describe flag */ + Aaddr atrs; /* Address of attribute list */ + Aword cont; /* Index to container properties if any */ + Aaddr vrbs; /* Address to local verb table */ + Aaddr dscr1; /* Address to Aword description code */ + Aaddr art; /* Article printing code? Else use default */ + /* INTRODUCED: v2.6 */ + Aaddr dscr2; /* Address to short description code */ +} ObjElem; + +typedef struct CntElem { /* CONTAINER TABLE */ + Aaddr lims; /* Address to limit check code */ + Aaddr header; /* Address to header code */ + Aaddr empty; /* Address to empty code */ + Aword parent; /* Object or actor index */ + Aaddr nam; /* Address to statement printing name */ +} CntElem; + +typedef struct LimElem { /* LIMIT Type */ + Aword atr; /* Attribute that limits */ + Aword val; /* And the limiting value */ + Aaddr stms; /* Statements if fail */ +} LimElem; + +typedef struct RulElem { /* RULE TABLE */ + Abool run; /* Is rule already run? */ + Aaddr exp; /* Address to expression code */ + Aaddr stms; /* Address to run */ +} RulElem; + +typedef struct EvtElem { /* EVENT TABLE */ + Aaddr stradr; /* Address to name string */ + Aaddr code; /* Address of code to run */ +} EvtElem; + +typedef struct EvtqElem { /* EVENT QUEUE ELEMENT */ + int time; + int event; + int where; +} EvtqElem; + +typedef struct IniElem { /* STRING INITIALISATION TABLE */ + Aword fpos; /* File position */ + Aword len; /* Length */ + Aword adr; /* Where to store the string */ +} IniElem; + +typedef struct MsgElem26 { /* MESSAGE TABLE */ + Aword fpos; /* File position */ + Aword len; /* Length of message */ +} MsgElem26; + +typedef struct MsgElem { /* MESSAGE TABLE */ + Aaddr stms; /* Address to statements*/ + /* Changed v2.7 from fpos+len in .dat */ +} MsgElem; + + +typedef struct ParamElem { /* PARAMETER */ + Aword code; /* Code for this parameter (0=multiple) */ + Aword firstWord; /* Index to first word used by player */ + Aword lastWord; /* d:o to last */ +} ParamElem; + +typedef enum Type {TYPNUM, TYPSTR} Type; + +typedef struct LitElem { /* LITERAL */ + Type type; + Aptr value; +} LitElem; #define MAXPARAMS 9 -#define MAXENTITY (_vm->header->actmax) +#define MAXENTITY (header->actmax) } // End of namespace Alan2 } // End of namespace Glk diff --git a/engines/glk/alan2/util.h b/engines/glk/alan2/util.h index 5ea14106bd..21993eb80d 100644 --- a/engines/glk/alan2/util.h +++ b/engines/glk/alan2/util.h @@ -23,65 +23,11 @@ #ifndef GLK_ALAN2_UTIL #define GLK_ALAN2_UTIL -#include "glk/alan2/acode.h" -#include "glk/alan2/alan2.h" #include "glk/alan2/types.h" namespace Glk { namespace Alan2 { -// TODO: Move these -extern LitElem *litValues; -extern uint32 litCount; // for LITMAX - defined in parse.cpp -extern ActElem *acts; // Actor table pointer -extern ObjElem *objs; // Object table pointer - -// Type checks -inline bool isObj(Aword x) { - return x >= OBJMIN && x <= OBJMAX; -} - -inline bool isAct(Aword x) { - return x >= ACTMIN && x <= ACTMAX; -} - -inline bool isCnt(Aword x) { - return (x >= CNTMIN && x <= CNTMAX) || - (isObj(x) && objs[x - OBJMIN].cont != 0) || - (isAct(x) && acts[x - ACTMIN].cont != 0); -} - -inline bool isLoc(Aword x) { - return x >= LOCMIN && x <= LOCMAX; -} - -inline bool isNum(Aword x) { - return x >= LITMIN && x <= LITMAX && litValues[x - LITMIN].type == TYPNUM; -} - -inline bool isStr(Aword x) { - return x >= LITMIN && x <= LITMAX && litValues[x - LITMIN].type == TYPSTR; -} - -inline bool isLit(Aword x) { - return x >= LITMIN && x <= LITMAX; -} - -inline bool endOfTable(LimElem *addr) { - Aword *x = (Aword *)addr; - return *x == (Aword)EOF; -} - -inline bool endOfTable(ScrElem *addr) { - Aword *x = (Aword *)addr; - return *x == (Aword)EOF; -} - -inline bool endOfTable(ExtElem *addr) { - Aword *x = (Aword *)addr; - return *x == (Aword)EOF; -} - } // End of namespace Alan2 } // End of namespace Glk diff --git a/engines/glk/alan2/version.h b/engines/glk/alan2/version.h new file mode 100644 index 0000000000..3bb90ad066 --- /dev/null +++ b/engines/glk/alan2/version.h @@ -0,0 +1,59 @@ +/* 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. + * + */ + +#ifndef GLK_ALAN2_VERSION +#define GLK_ALAN2_VERSION + +#include "common/system.h" + +namespace Glk { +namespace Alan2 { + +typedef int64 Time; + +struct Version { + char* string; + int version; + int revision; + int correction; + Time time; + char *state; +}; + +struct Product { + char* name; + char* slogan; + char* shortHeader; + char* longHeader; + char* date; + char* time; + char* user; + char* host; + char* ostype; + Version version; +}; + + +} // End of namespace Alan2 +} // End of namespace Glk + +#endif diff --git a/engines/glk/module.mk b/engines/glk/module.mk index bfda72d34a..b87fea9311 100644 --- a/engines/glk/module.mk +++ b/engines/glk/module.mk @@ -33,6 +33,22 @@ MODULE_OBJS := \ advsys/vm.o \ alan2/alan2.o \ alan2/detection.o \ + alan2/alan_version.o \ + alan2/args.o \ + alan2/debug.o \ + alan2/decode.o \ + alan2/exe.o \ + alan2/glkio.o \ + alan2/glkstart.o \ + alan2/inter.o \ + alan2/params.o \ + alan2/parse.o \ + alan2/readline.o \ + alan2/reverse.o \ + alan2/rules.o \ + alan2/stack.o \ + alan2/sysdep.o \ + alan2/term.o \ frotz/bitmap_font.o \ frotz/config.o \ frotz/detection.o \ |