Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

297
engines/glk/alan2/acode.h Normal file
View File

@@ -0,0 +1,297 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef GLK_ALAN2_ACODE
#define GLK_ALAN2_ACODE
#include "common/stream.h"
namespace Glk {
namespace Alan2 {
typedef size_t Aptr; /* Type for an ACODE memory address */
typedef uint32 Aword; /* Type for an ACODE word */
typedef uint32 Aaddr; /* Type for an ACODE address */
typedef uint32 Abool; /* Type for an ACODE Boolean value */
typedef int32 Aint; /* Type for an ACODE Integer value */
typedef int CodeValue; /* Definition for the packing process */
/* 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 */
// End of data
#define EOD ((uint32)-1)
// End of syntax
#define EOS ((uint32)-2)
/* Syntax element flag bits */
#define MULTIPLEBIT 0x1
#define OMNIBIT 0x2
/* Parameter Classes */
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
};
/* Verb Qualifiers */
enum QualClass {
Q_DEFAULT,
Q_AFTER,
Q_BEFORE,
Q_ONLY
};
/* The AMACHINE Operations */
enum OpClass {
C_CONST,
C_STMOP,
C_CURVAR
};
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 /* -""- */
};
enum VarClass {
V_PARAM,
V_CURLOC,
V_CURACT,
V_CURVRB,
V_SCORE
};
#define I_CLASS(x) ((x)>>28)
#define I_OP(x) ((x&0x8000000)?(x)|0x0f0000000:(x)&0x0fffffff)
#include "common/pack-start.h" // START STRUCT PACKING
/**
* Game header
*/
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 - Unused - Length of a page */
Aword pagwidth; /* 05 - Unused - 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 */
} PACKED_STRUCT;
#include "common/pack-end.h" // END STRUCT PACKING
/* Error message numbers */
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
};
#define M_ARTICLE26 M_QUITACTION
#define M_MSGMAX26 M_ARTICLE
} // End of namespace Alan2
} // End of namespace Glk
#endif

197
engines/glk/alan2/alan2.cpp Normal file
View File

@@ -0,0 +1,197 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "glk/alan2/alan2.h"
#include "glk/alan2/exe.h"
#include "glk/alan2/main.h"
#include "glk/alan2/glkio.h"
#include "common/system.h"
#include "common/config-manager.h"
#include "common/translation.h"
#include "common/error.h"
#include "common/scummsys.h"
#include "common/serializer.h"
#include "glk/glk.h"
#include "glk/streams.h"
namespace Glk {
namespace Alan2 {
Alan2 *g_vm = nullptr;
Alan2::Alan2(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc),
vm_exited_cleanly(false), _restartFlag(false), _saveSlot(-1), _pendingLook(false) {
g_vm = this;
txtfil = nullptr;
logfil = nullptr;
memory = nullptr;
}
void Alan2::runGame() {
if (initialize())
Glk::Alan2::run();
deinitialize();
}
bool Alan2::initialize() {
// Set up adventure name
_advName = getFilename();
if (_advName.size() > 4 && _advName[_advName.size() - 4] == '.')
_advName = Common::String(_advName.c_str(), _advName.size() - 4);
// first, open a window for error output
glkMainWin = g_vm->glk_window_open(nullptr, 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);
// Set up the code file to point to the already opened game file
codfil = &_gameFile;
if (_gameFile.size() < 8) {
GUIErrorMessage(_("This is too short to be a valid Alan2 file."));
return false;
}
uint32 version = _gameFile.readUint32BE();
if (version != MKTAG(2, 8, 1, 0) && version != MKTAG(2, 6, 0, 0)) {
GUIErrorMessage(_("This is not a valid Alan2 file."));
return false;
}
// Open up the text file
txtfil = new Common::File();
if (!txtfil->open(Common::Path(Common::String::format("%s.dat", _advName.c_str())))) {
GUIErrorMessage("Could not open adventure text data file");
delete txtfil;
return false;
}
// Check for a save being loaded directly from the launcher
_saveSlot = ConfMan.hasKey("save_slot") ? ConfMan.getInt("save_slot") : -1;
return true;
}
void Alan2::deinitialize() {
free(memory);
delete txtfil;
delete logfil;
}
Common::Error Alan2::readSaveData(Common::SeekableReadStream *rs) {
Common::Serializer s(rs, nullptr);
synchronizeSave(s);
return Common::kNoError;
}
Common::Error Alan2::writeGameData(Common::WriteStream *ws) {
Common::Serializer s(nullptr, ws);
synchronizeSave(s);
ws->flush();
return Common::kNoError;
}
// This works around gcc errors for passing packed structure fields
void syncVal(Common::Serializer &s, void *fld) {
uint32 v = READ_UINT32(fld);
s.syncAsUint32LE(v);
if (s.isLoading())
WRITE_UINT32(fld, v);
}
static void syncActors(Common::Serializer &s) {
for (uint i = ACTMIN; i <= ACTMAX; ++i) {
syncVal(s, &acts[i - ACTMIN].loc);
syncVal(s, &acts[i - ACTMIN].script);
syncVal(s, &acts[i - ACTMIN].step);
syncVal(s, &acts[i - ACTMIN].count);
if (acts[i - ACTMIN].atrs) {
for (AtrElem *atr = (AtrElem *)addrTo(acts[i - ACTMIN].atrs); !endOfTable(atr); ++atr)
syncVal(s, &atr->val);
}
}
}
static void syncLocations(Common::Serializer &s) {
for (uint i = LOCMIN; i <= LOCMAX; ++i) {
syncVal(s, &locs[i - LOCMIN].describe);
if (locs[i - LOCMIN].atrs)
for (AtrElem *atr = (AtrElem *)addrTo(locs[i - LOCMIN].atrs); !endOfTable(atr); atr++)
syncVal(s, &atr->val);
}
}
static void syncObjects(Common::Serializer &s) {
for (uint i = OBJMIN; i <= OBJMAX; ++i) {
syncVal(s, &objs[i - OBJMIN].loc);
if (objs[i - OBJMIN].atrs)
for (AtrElem *atr = (AtrElem *)addrTo(objs[i - OBJMIN].atrs); !endOfTable(atr); atr++)
syncVal(s, &atr->val);
}
}
static void syncEventQueue(Common::Serializer &s) {
int i;
EvtqElem *arr = eventq;
if (s.isLoading()) {
i = 0;
do {
arr[i].synchronize(s);
i++;
} while (arr[i - 1].time != 0);
etop = i - 1;
} else {
// Mark the top
arr[etop].time = 0;
for (i = 0; i <= etop; ++i)
arr[i].synchronize(s);
}
}
static void syncScores(Common::Serializer &s) {
for (int i = 0; scores[i] != EOD; i++)
syncVal(s, &scores[i]);
}
void Alan2::synchronizeSave(Common::Serializer &s) {
// Sync various savegame data
cur.synchronize(s);
syncActors(s);
syncLocations(s);
syncObjects(s);
syncEventQueue(s);
syncScores(s);
}
} // End of namespace Alan2
} // End of namespace Glk

107
engines/glk/alan2/alan2.h Normal file
View File

@@ -0,0 +1,107 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/* Based on Alan2 interpreter version 2.8(6) */
#ifndef GLK_ALAN2
#define GLK_ALAN2
#include "common/scummsys.h"
#include "common/serializer.h"
#include "common/stack.h"
#include "glk/glk_api.h"
namespace Glk {
namespace Alan2 {
/**
* Alan2 game interpreter
*/
class Alan2 : public GlkAPI {
private:
bool _restartFlag;
public:
bool vm_exited_cleanly;
Common::String _advName;
int _saveSlot;
bool _pendingLook;
private:
/**
* Initialization
*/
bool initialize();
/**
* Deinitialization
*/
void deinitialize();
/**
* Synchronize data to or from a save file
*/
void synchronizeSave(Common::Serializer &s);
public:
/**
* Constructor
*/
Alan2(OSystem *syst, const GlkGameDescription &gameDesc);
/**
* Run the game
*/
void runGame() override;
/**
* Flag for the game to restart
*/
void setRestart(bool flag) { _restartFlag = flag; }
/**
* Returns whether the game should restart
*/
bool shouldRestart() const { return _restartFlag; }
/**
* Returns the running interpreter type
*/
InterpreterType getInterpreterType() const override {
return INTERPRETER_ALAN2;
}
/**
* Load a savegame from the passed Quetzal file chunk stream
*/
Common::Error readSaveData(Common::SeekableReadStream *rs) override;
/**
* Save the game. The passed write stream represents access to the UMem chunk
* in the Quetzal save file that will be created
*/
Common::Error writeGameData(Common::WriteStream *ws) override;
};
extern Alan2 *g_vm;
} // End of namespace Alan2
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,41 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#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, ""}
};
} // End of namespace Alan2
} // End of namespace Glk

View File

@@ -0,0 +1,35 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#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

View File

@@ -0,0 +1,57 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "glk/alan2/alan2.h"
#include "glk/alan2/args.h"
#include "glk/alan2/glkio.h"
#include "glk/alan2/main.h"
#include "glk/alan2/sysdep.h"
namespace Glk {
namespace Alan2 {
static void switches(unsigned argc, char *argv[]) {
}
void args(int argc, char *argv[]) {
char *prgnam;
if ((prgnam = strrchr(argv[0], '\\')) == nullptr
&& (prgnam = strrchr(argv[0], '/')) == nullptr
&& (prgnam = strrchr(argv[0], ':')) == nullptr)
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 (scumm_stricmp(prgnam, PROGNAME) != 0
&& strstr(prgnam, PROGNAME) == nullptr)
advnam = scumm_strdup(argv[0]);
}
} // End of namespace Alan2
} // End of namespace Glk

43
engines/glk/alan2/args.h Normal file
View File

@@ -0,0 +1,43 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#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 {
#define PROGNAME "alan2"
extern void args(int argc, char *argv[]);
} // End of namespace Alan2
} // End of namespace Glk
#endif

396
engines/glk/alan2/debug.cpp Normal file
View File

@@ -0,0 +1,396 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "glk/alan2/types.h"
#include "glk/alan2/alan_version.h"
#include "glk/alan2/debug.h"
#include "glk/alan2/exe.h"
#include "glk/alan2/glkio.h"
#include "glk/alan2/inter.h"
#include "glk/alan2/main.h"
#include "glk/alan2/parse.h"
namespace Glk {
namespace Alan2 {
static void showatrs(Aword atradr) {
AtrElem *at;
int i;
char str[80];
if (atradr == 0) return;
i = 1;
for (at = (AtrElem *) addrTo(atradr); !endOfTable(at); at++) {
Common::sprintf_s(str, "$i%3ld: %ld (%s)", (long) i, (unsigned long) at->val, (char *) addrTo(at->stradr));
output(str);
i++;
}
}
static void showobjs() {
char str[80];
uint obj;
output("OBJECTS:");
for (obj = OBJMIN; obj <= OBJMAX; obj++) {
Common::sprintf_s(str, "$i%3ld: ", (long) obj);
output(str);
say(obj);
}
}
static void showobj(int obj) {
char str[80];
#define OBJ (obj-OBJMIN)
if (!isObj(obj)) {
Common::sprintf_s(str, "Object number out of range. Between %ld and %ld, please.", (unsigned long) OBJMIN, (unsigned long) OBJMAX);
output(str);
return;
}
Common::sprintf_s(str, "OBJECT %d :", obj);
output(str);
say(obj);
Common::sprintf_s(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
}
static void showcnts() {
char str[80];
uint cnt;
#define CNT (cnt-CNTMIN)
output("CONTAINERS:");
for (cnt = CNTMIN; cnt <= CNTMAX; cnt++) {
Common::sprintf_s(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
}
static void showcnt(int cnt) {
char str[80];
uint i;
Abool found = FALSE;
#define CNT (int)(cnt - CNTMIN)
if (cnt < (int)CNTMIN || cnt >(int)CNTMAX) {
Common::sprintf_s(str, "Container number out of range. Between %ld and %ld, please.", (unsigned long) CNTMIN, (unsigned long) CNTMAX);
output(str);
return;
}
Common::sprintf_s(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);
Common::sprintf_s(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;
}
Common::sprintf_s(str, "$t$t%d: ", i);
output(str);
say(i);
}
}
if (!found)
output("nothing");
#undef CNT
}
static void showlocs() {
char str[80];
uint loc;
output("LOCATIONS:");
for (loc = LOCMIN; loc <= LOCMAX; loc++) {
Common::sprintf_s(str, "$i%3ld: ", (long) loc);
output(str);
say(loc);
}
}
static void showloc(int loc) {
char str[80];
if (!isLoc(loc)) {
Common::sprintf_s(str, "Location number out of range. Between %ld and %ld, please.", (unsigned long) LOCMIN, (unsigned long) LOCMAX);
output(str);
return;
}
Common::sprintf_s(str, "LOCATION %d :", loc);
output(str);
say(loc);
output("$iAttributes =");
showatrs(locs[loc - LOCMIN].atrs);
}
static void showacts() {
char str[80];
uint act;
output("ACTORS:");
for (act = ACTMIN; act <= ACTMAX; act++) {
Common::sprintf_s(str, "$i%3ld:", (long) act);
output(str);
say(act);
}
}
static void showact(int act) {
char str[80];
Boolean oldstp;
if (!isAct(act)) {
Common::sprintf_s(str, "Actor number out of range. Between %ld and %ld, please.", (unsigned long) ACTMIN, (unsigned long) ACTMAX);
output(str);
return;
}
Common::sprintf_s(str, "ACTOR %d :", act);
output(str);
oldstp = stpflg;
stpflg = FALSE; /* Make sure not to trace this! */
say(act);
stpflg = oldstp;
Common::sprintf_s(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!");
Common::sprintf_s(str, "$iScript = %ld", (unsigned long) acts[act - ACTMIN].script);
output(str);
Common::sprintf_s(str, "$iStep = %ld", (unsigned long) acts[act - ACTMIN].step);
output(str);
output("$iAttributes =");
showatrs(acts[act - ACTMIN].atrs);
}
static void showevts() {
int i;
char str[80];
Boolean scheduled;
output("EVENTS:");
for (uint evt = EVTMIN; evt <= EVTMAX; evt++) {
Common::sprintf_s(str, "$i%d (%s):", evt, (char *)addrTo(evts[evt - EVTMIN].stradr));
output(str);
scheduled = FALSE;
for (i = 0; i < etop; i++)
if ((scheduled = (eventq[i].event == (int)evt)))
break;
if (scheduled) {
Common::sprintf_s(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;
void saveInfo() {
/* Save some important things */
trc = trcflg;
trcflg = FALSE;
stp = stpflg;
stpflg = FALSE;
loc = cur.loc;
cur.loc = where(HERO);
}
void restoreInfo() {
/* Restore! */
trcflg = trc;
stpflg = stp;
cur.loc = loc;
}
void debug() {
char buf[256];
char c;
int i;
saveInfo();
while (TRUE) {
if (anyOutput)
para();
do {
output("ABUG> ");
(void)readline(buf, sizeof(buf));
lin = 1;
c = buf[0];
i = 0;
(void)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': {
Context ctx;
terminate(ctx, 0);
break;
}
case 'X':
dbgflg = FALSE;
restoreInfo();
return;
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.
*/
void debugsay(int item) {
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

38
engines/glk/alan2/debug.h Normal file
View File

@@ -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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/* TYPES */
#ifndef GLK_ALAN2_DEBUG
#define GLK_ALAN2_DEBUG
namespace Glk {
namespace Alan2 {
extern void saveInfo();
extern void restoreInfo();
extern void debug();
extern void debugsay(int item);
} // End of namespace Alan2
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,163 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#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 EOD */
static int inputBit() {
int bit;
if (!bitsToGo) { /* More bits available ? */
decodeBuffer = txtfil->readByte(); /* No, so get more */
if ((uint)decodeBuffer == EOD) {
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 */
void startDecoding() {
int i;
bitsToGo = 0;
garbageBits = 0;
value = 0;
for (i = 0; i < VALUEBITS; i++)
value = 2 * value + inputBit();
low = 0;
high = TOPVALUE;
}
int decodeChar() {
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.
*/
void *pushDecode() {
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.
*/
void popDecode(void *i) {
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

View File

@@ -0,0 +1,41 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef GLK_ALAN2_DECODE
#define GLK_ALAN2_DECODE
#include "glk/alan2/types.h"
/* Arithmetic decoding module in Arun
*/
namespace Glk {
namespace Alan2 {
extern void startDecoding(void);
extern int decodeChar(void);
extern void *pushDecode(void);
extern void popDecode(void *info);
} // End of namespace Alan2
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,101 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "glk/alan2/detection.h"
#include "glk/alan2/detection_tables.h"
#include "common/debug.h"
#include "common/file.h"
#include "common/md5.h"
#include "engines/game.h"
namespace Glk {
namespace Alan2 {
void Alan2MetaEngine::getSupportedGames(PlainGameList &games) {
for (const PlainGameDescriptor *pd = ALAN2_GAME_LIST; pd->gameId; ++pd) {
games.push_back(*pd);
}
}
const GlkDetectionEntry* Alan2MetaEngine::getDetectionEntries() {
return ALAN2_GAMES;
}
GameDescriptor Alan2MetaEngine::findGame(const char *gameId) {
for (const PlainGameDescriptor *pd = ALAN2_GAME_LIST; pd->gameId; ++pd) {
if (!strcmp(gameId, pd->gameId))
return *pd;
}
return GameDescriptor::empty();
}
bool Alan2MetaEngine::detectGames(const Common::FSList &fslist, DetectedGames &gameList) {
// Loop through the files of the folder
for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
// Check for a recognised filename
if (file->isDirectory())
continue;
Common::String filename = file->getName();
bool hasExt = filename.hasSuffixIgnoreCase(".acd");
if (!hasExt)
continue;
// Open up the file and calculate the md5
Common::File gameFile;
if (!gameFile.open(*file))
continue;
uint32 version = gameFile.readUint32BE();
if (version != MKTAG(2, 8, 1, 0) && version != MKTAG(2, 6, 0, 0))
continue;
gameFile.seek(0);
Common::String md5 = Common::computeStreamMD5AsString(gameFile, 5000);
size_t filesize = gameFile.size();
gameFile.close();
// Check for known games
const GlkDetectionEntry *p = ALAN2_GAMES;
while (p->_gameId && (md5 != p->_md5 || filesize != p->_filesize))
++p;
if (!p->_gameId) {
const PlainGameDescriptor &desc = ALAN2_GAME_LIST[0];
gameList.push_back(GlkDetectedGame(desc.gameId, desc.description, filename, md5, filesize));
} else {
PlainGameDescriptor gameDesc = findGame(p->_gameId);
gameList.push_back(GlkDetectedGame(p->_gameId, gameDesc.description, p->_extra, filename, p->_language));
}
}
return !gameList.empty();
}
void Alan2MetaEngine::detectClashes(Common::StringMap &map) {
for (const PlainGameDescriptor *pd = ALAN2_GAME_LIST; pd->gameId; ++pd) {
if (map.contains(pd->gameId))
error("Duplicate game Id found - %s", pd->gameId);
map[pd->gameId] = "";
}
}
} // End of namespace Alan2
} // End of namespace Glk

View File

@@ -0,0 +1,67 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef GLK_ALAN2_DETECTION
#define GLK_ALAN2_DETECTION
#include "common/fs.h"
#include "common/hash-str.h"
#include "engines/game.h"
#include "glk/detection.h"
namespace Glk {
namespace Alan2 {
/**
* Meta engine for Alan2 interpreter
*/
class Alan2MetaEngine {
public:
/**
* Get a list of supported games
*/
static void getSupportedGames(PlainGameList &games);
/**
* Get the detection entries
*/
static const GlkDetectionEntry* getDetectionEntries();
/**
* Returns a game description for the given game Id, if it's supported
*/
static GameDescriptor findGame(const char *gameId);
/**
* Detect supported games
*/
static bool detectGames(const Common::FSList &fslist, DetectedGames &gameList);
/**
* Check for game Id clashes with other sub-engines
*/
static void detectClashes(Common::StringMap &map);
};
} // End of namespace Alan2
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,106 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/game.h"
#include "common/gui_options.h"
#include "common/language.h"
namespace Glk {
namespace Alan2 {
const PlainGameDescriptor ALAN2_GAME_LIST[] = {
{ "alan2", "Alan2 Game" },
// Unsupported 2.6 games
{ "hollywoodmurders", "The Hollywood Murders" },
// Supported 2.8.1 games
{ "artifiction", "Artifiction" },
{ "bantams", "Even Bantams get the Blues" },
{ "bugged", "Bugged" },
{ "cc", "CC" },
{ "chasing", "The Chasing" },
{ "closet", "Closet" },
{ "crystalball", "Crystal Ball" },
{ "dinnertime", "Dinnertime" },
{ "hebgb", "The HeBGB Horror!" },
{ "arthursnightout", "King Arthur's Night Out" },
{ "knotundone", "Knot To Be Undone" },
{ "lostinnewyork", "Lost In New York" },
{ "mazemapper", "Mazemapper" },
{ "meanstory", "The Mean Story" },
{ "outofthestudy", "Out Of The Study" },
{ "plsghints", "Painless Little Stupid Games Hints" },
{ "puddlespath", "Puddles on the Path" },
{ "sardoria", "Sardoria" },
{ "skipbreak", "Skipping Breakfast" },
{ "speedif11p6", "SpeedIF 11 - part six" },
{ "presidentadventures", "The Adventures of the President of the United States" },
{ "thechasing", "The Chasing" },
{ "nobread", "There Is No Bread" },
{ "afteryou", "They're After You" },
{ "tgttos", "To Get To The Other Side" },
{ "zeroone", "Zero One" },
{ nullptr, nullptr }
};
const GlkDetectionEntry ALAN2_GAMES[] = {
// Unsupported 2.6 games
DT_ENTRY0("hollywoodmurders", "e6da6dfa85dd471a251ce485af710730", 95232),
// Supported 2.8.1 games
DT_ENTRY0("artifiction", "2615ba29c6030ec50454fdded1049b44", 40960),
DT_ENTRY0("bantams", "8c4be4f2e21f9770523ea0c4a180cb8a", 40960),
DT_ENTRY0("bugged", "f4eed3db3771a456143744a0e36653db", 112640),
DT_ENTRY0("cc", "47f4a5436ce07d65bb828e2938f81952", 53248),
DT_ENTRY1("chasing", "1.0", "10ad37b6dd6d9f399578b28e644914ca", 144384),
DT_ENTRY1("chasing", "1.1", "718ffcc9dfe85cfd8c6f50f541a3926e", 147456),
DT_ENTRY0("closet", "5d724469e6240cde0c16c959f50ebc93", 37888),
DT_ENTRY0("crystalball", "625e15e14081847cd26842a52839a07c", 11264),
DT_ENTRY0("dinnertime", "1c0bad19156e8bdefe9e19d99f96f7d8", 9216),
DT_ENTRY0("hebgb", "87f9516bc4217afb5c329cb1ae01d861", 173056),
DT_ENTRY0("hebgb", "96f016f4657a801686d1d1da5dd6f382", 157696),
DT_ENTRY0("knotundone", "a4249a82d7211398adc9917c773c58fa", 25600),
DT_ENTRY0("arthursnightout", "c8c87b88a9250cec2f03af3a347d3c05", 50176),
DT_ENTRY0("lostinnewyork", "483a8c7c84f3bb5af61150fd770806e5", 30720),
DT_ENTRY0("mazemapper", "8e7409758c3535201aeb901923b20064", 30720),
DT_ENTRY0("meanstory", "e4ae6873d6f2ab74fb2ec35b27752397", 13312),
DT_ENTRY1("outofthestudy", "1.0", "089082d50b232b07fc31cf60aeefb5ae", 102400),
DT_ENTRY1("outofthestudy", "1.3", "cc4ab3f1b406a8ce04adcfb641c3b250", 110592),
DT_ENTRY0("plsghints", "fb9df41138691a77ea3489986fe8856c", 10240),
DT_ENTRY0("puddlespath", "5b6bf831263f43b6e9f26517fae6294b", 104448),
DT_ENTRY0("sardoria", "b48ba08ae33b5cb224bcb4ce0eea36bc", 150528),
DT_ENTRY0("sardoria", "1b0e03cbdcb74d59a92920d093fc7446", 143360),
DT_ENTRY0("skipbreak", "a0f7e71f00fd4d26eacc82637da84cb0", 44032),
DT_ENTRY0("speedif11p6", "0c8a517bd49c3f6ed28d44e5a294de06", 32768),
DT_ENTRY0("presidentadventures", "74caac5475f8801ac27d76a3d2e034ad", 53248),
DT_ENTRY0("thechasing", "10ad37b6dd6d9f399578b28e644914ca", 144384),
DT_ENTRY0("nobread", "7a85bef5bc441bbaa8a6321e063ec711", 30720),
DT_ENTRY0("afteryou", "998ca167b0e9ffb671203b2057d06bef", 17408),
DT_ENTRY0("tgttos", "0fed94b37b8add48938d8288ca5e7e4f", 29696),
DT_ENTRY0("zeroone", "1e2f65611c41040f60caaf5f26e61367", 59392),
DT_END_MARKER
};
} // End of namespace Alan2
} // End of namespace Glk

1158
engines/glk/alan2/exe.cpp Normal file

File diff suppressed because it is too large Load Diff

84
engines/glk/alan2/exe.h Normal file
View File

@@ -0,0 +1,84 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef GLK_ALAN2_EXE
#define GLK_ALAN2_EXE
/* Header file for instruction execution unit in Alan interpreter
*/
#include "glk/alan2/types.h"
#include "glk/jumps.h"
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 */
extern void sys(Aword fpos, Aword len);
extern Boolean confirm(MsgKind msgno);
extern Aptr attribute(Aword item, Aword atr);
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(CONTEXT);
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);
} // End of namespace Alan2
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,92 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "glk/glk.h"
#include "glk/alan2/alan2.h"
#include "glk/alan2/glkio.h"
#include "glk/alan2/main.h"
namespace Glk {
namespace Alan2 {
winid_t glkMainWin;
winid_t glkStatusWin;
void glkio_printf(const char *fmt, ...) {
// If there's a savegame being loaded from the launcher, ignore any text out
if (g_vm->_saveSlot != -1)
return;
va_list argp;
va_start(argp, fmt);
if (glkMainWin) {
char buf[1024]; /* FIXME: buf size should be foolproof */
Common::vsprintf_s(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);
}
/*======================================================================
readline()
Read a line from the user, with history and editing
*/
/* 4f - length of user buffer should be used */
Boolean readline(char usrbuf[], size_t maxlen) {
if (g_vm->_pendingLook) {
g_vm->_pendingLook = false;
glkio_printf("look\n");
Common::strcpy_s(usrbuf, maxlen, "look");
} else {
event_t event;
g_vm->glk_request_line_event(glkMainWin, usrbuf, maxlen, 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();
if (g_vm->shouldQuit())
return false;
} while (event.type != evtype_LineInput);
usrbuf[event.val1] = 0;
}
return TRUE;
}
} // End of namespace Alan2
} // End of namespace Glk

53
engines/glk/alan2/glkio.h Normal file
View File

@@ -0,0 +1,53 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef GLK_ALAN2_GLKIO
#define GLK_ALAN2_GLKIO
/* Header file for Glk output for Alan interpreter
*/
#include "glk/windows.h"
#include "glk/alan2/types.h"
namespace Glk {
namespace Alan2 {
extern winid_t glkMainWin;
extern winid_t glkStatusWin;
/* NB: this header must be included in any file which calls print() */
#undef printf
#define printf glkio_printf
void glkio_printf(const char *, ...);
#define LINELENGTH 80
#define HISTORYLENGTH 20
extern Boolean readline(char usrbuf[], size_t maxlen);
} // End of namespace Alan2
} // End of namespace Glk
#endif

887
engines/glk/alan2/inter.cpp Normal file
View File

@@ -0,0 +1,887 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "glk/alan2/types.h"
#include "glk/alan2/exe.h"
#include "glk/alan2/inter.h"
#include "glk/alan2/glkio.h"
#include "glk/alan2/main.h"
#include "glk/alan2/parse.h"
#include "glk/alan2/stack.h"
#include "glk/alan2/sysdep.h"
namespace Glk {
namespace Alan2 {
/* PRIVATE DATA */
static int pc;
static void if_(Aword v) {
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;
default:
break;
}
}
}
}
static void else_() {
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;
default:
break;
}
}
}
static void depstart() {
/* A DEPSTART was executed so skip across the redundant DEPCASE to
start at the first expression */
pc++;
}
static void swap() {
Aptr v1 = pop();
Aptr v2 = pop();
push(v1);
push(v2);
}
static void depexec(Aword v) {
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;
default:
break;
}
}
}
static void depcase() {
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;
default:
break;
}
}
}
void interpret(Aaddr adr) {
Context ctx;
interpret(ctx, adr);
}
void interpret(CONTEXT, Aaddr adr) {
Aaddr oldpc;
Aword i;
if (stpflg) printf("\n++++++++++++++++++++++++++++++++++++++++++++++++++");
oldpc = pc;
pc = adr;
while (TRUE) {
if (stpflg) printf("\n%4x: ", pc);
if (pc > (int)memTop)
syserr("Interpreting outside program.");
i = memory[pc++];
switch (I_CLASS(i)) {
case C_CONST:
if (stpflg) printf("PUSH \t%5u", I_OP(i));
push(I_OP(i));
break;
case C_CURVAR:
switch (I_OP(i)) {
case V_PARAM:
if (stpflg) printf("PARAM \t%5lu\t\t(%u)", 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(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");
CALL0(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(%u)", 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 sayAdr;
sayAdr = pop();
if (stpflg)
printf("SAYSTR\t%5ld\t\t\"", sayAdr);
saystr((char *)sayAdr);
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%5d, %5d", 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%5d, %5d", 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%5d, %5d", 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%5d, %5d", 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%5d, %5d", 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%5d, %5d", 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%5d, %5d", 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%5d, %5d", 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%5d, %5d, %5d", 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

36
engines/glk/alan2/inter.h Normal file
View File

@@ -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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef GLK_ALAN2_INTER
#define GLK_ALAN2_INTER
#include "glk/jumps.h"
namespace Glk {
namespace Alan2 {
extern void interpret(Aaddr adr);
extern void interpret(CONTEXT, Aaddr adr);
} // End of namespace Alan2
} // End of namespace Glk
#endif

1417
engines/glk/alan2/main.cpp Normal file

File diff suppressed because it is too large Load Diff

127
engines/glk/alan2/main.h Normal file
View File

@@ -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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#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"
#include "glk/jumps.h"
namespace Glk {
namespace Alan2 {
/* DATA */
#define MEMORYSIZE 1000L
extern Aaddr 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;
extern Common::SeekableReadStream *codfil;
#undef ftell
#undef fgetc
#undef getc
#undef fseek
#undef fclose
#define ftell(FP) FP->pos()
#define fgetc(FP) (FP->pos() >= FP->size()) ? EOD : FP->readByte()
#define getc(FP) (FP->pos() >= FP->size()) ? EOD : FP->readByte()
#define fseek(FP, OFS, WHENCE) FP->seek(OFS, WHENCE)
#define fclose(FP) delete FP
/* File names */
extern const char *advnam;
/* Screen formatting info */
extern int col, lin;
extern Boolean verbose, errflg, trcflg, dbgflg, stpflg, logflg, statusflg;
extern Boolean fail;
extern Boolean anyOutput;
extern Boolean needsp;
#define endOfTable(x) eot((const void *)x)
extern void *allocate(unsigned long len);
extern void terminate(CONTEXT, int code);
extern void usage(void);
extern void error(CONTEXT, MsgKind msg);
extern void syserr(const char *msg);
extern void statusline(void);
extern void output(const 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(CONTEXT, ParamElem *plst);
extern void go(CONTEXT, int dir);
extern Boolean eot(const void *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);
} // End of namespace Alan2
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,100 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "glk/alan2/types.h"
#include "glk/alan2/params.h"
namespace Glk {
namespace Alan2 {
void compact(ParamElem a[]) {
int i, j;
for (i = 0, j = 0; a[j].code != (Aword)EOD; j++)
if (a[j].code != 0)
a[i++] = a[j];
a[i].code = (Aword)EOD;
}
int lstlen(ParamElem a[]) {
int i = 0;
while (a[i].code != (Aword)EOD)
i++;
return (i);
}
Boolean inlst(ParamElem l[], Aword e) {
int i;
for (i = 0; l[i].code != (Aword)EOD && l[i].code != e; i++);
return (l[i].code == e);
}
void lstcpy(ParamElem a[], ParamElem b[]) {
int i;
for (i = 0; b[i].code != (Aword)EOD; i++)
a[i] = b[i];
a[i].code = (Aword)EOD;
}
void sublst(ParamElem a[], ParamElem b[]) {
int i;
for (i = 0; a[i].code != (Aword)EOD; i++)
if (inlst(b, a[i].code))
a[i].code = 0; /* Mark empty */
compact(a);
}
void mrglst(ParamElem a[], ParamElem b[]) {
int i, last;
for (last = 0; a[last].code != (Aword)EOD; last++); /* Find end of list */
for (i = 0; b[i].code != (Aword)EOD; i++)
if (!inlst(a, b[i].code)) {
a[last++] = b[i];
a[last].code = (Aword)EOD;
}
}
void isect(ParamElem a[], ParamElem b[]) {
int i, last = 0;
for (i = 0; a[i].code != (Aword)EOD; i++)
if (inlst(b, a[i].code))
a[last++] = a[i];
a[last].code = (Aword)EOD;
}
void cpyrefs(ParamElem p[], Aword r[]) {
int i;
for (i = 0; r[i] != (Aword)EOD; i++) {
p[i].code = r[i];
p[i].firstWord = (Aword)EOD;
}
p[i].code = (Aword)EOD;
}
} // End of namespace Alan2
} // End of namespace Glk

View File

@@ -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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#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 {
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);
} // End of namespace Alan2
} // End of namespace Glk
#endif

737
engines/glk/alan2/parse.cpp Normal file
View File

@@ -0,0 +1,737 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "glk/alan2/alan2.h"
#include "glk/alan2/debug.h"
#include "glk/alan2/exe.h"
#include "glk/alan2/glkio.h"
#include "glk/alan2/inter.h"
#include "glk/alan2/main.h"
#include "glk/alan2/params.h"
#include "glk/alan2/parse.h"
#include "glk/alan2/types.h"
namespace Glk {
namespace Alan2 {
#define LISTLEN 100
/* PUBLIC DATA */
Aword wrds[LISTLEN / 2] = {EOD}; // 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 */
static void unknown(CONTEXT, char token[]) {
size_t ln = strlen(token) + 4;
char *str = (char *)allocate((int)ln);
str[0] = '\'';
Common::strcpy_s(&str[1], ln, token);
Common::strcat_s(str, ln, "'?");
output(str);
free(str);
eol = TRUE;
CALL1(error, M_UNKNOWN_WORD)
}
static char *token;
static int lookup(CONTEXT, char wrd[]) {
int i;
for (i = 0; !endOfTable(&dict[i]); i++) {
if (strcmp(wrd, (char *) addrTo(dict[i].wrd)) == 0)
return (i);
}
R0CALL1(unknown, wrd)
return EOD;
}
/* IN - The string to convert to a number */
static int number(char tok[]) {
int i;
(void)sscanf(tok, "%d", &i);
return i;
}
static char *gettoken(char *tokBuf) {
static char *marker;
static char oldch;
if (tokBuf == nullptr)
*marker = oldch;
else
marker = tokBuf;
while (*marker != '\0' && isSpace(*marker) && *marker != '\n') marker++;
tokBuf = marker;
if (isISOLetter(*marker))
while (*marker && (isISOLetter(*marker) || Common::isDigit(*marker) || *marker == '\'')) marker++;
else if (Common::isDigit(*marker))
while (Common::isDigit(*marker)) marker++;
else if (*marker == '\"') {
marker++;
while (*marker != '\"') marker++;
marker++;
} else if (*marker == '\0' || *marker == '\n')
return nullptr;
else
marker++;
oldch = *marker;
*marker = '\0';
return tokBuf;
}
static void agetline(CONTEXT) {
para();
do {
statusline();
printf("> ");
if (logflg)
fprintf(logfil, "> ");
if (!readline(buf, sizeof(buf))) {
if (g_vm->shouldQuit())
return;
newline();
CALL0(quit)
}
anyOutput = FALSE;
if (logflg)
fprintf(logfil, "%s\n", buf);
Common::strcpy_s(isobuf, buf);
token = gettoken(isobuf);
if (token != nullptr && strcmp("debug", token) == 0 && header->debug) {
dbgflg = TRUE;
debug();
token = nullptr;
}
} while (token == nullptr);
eol = FALSE;
lin = 1;
}
static void scan(CONTEXT) {
int i;
int w;
char *str;
CALL0(agetline)
if (g_vm->shouldQuit())
return;
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);
FUNC1(lookup, w, token);
if (!isNoise(w))
wrds[i++] = w;
} else if (Common::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 = scumm_strdup(&token[1]);
str[strlen(token) - 2] = '\0';
litValues[litCount++].value = (Aptr) str;
} else if (token[0] == ',') {
wrds[i++] = conjWord;
} else {
CALL1(unknown, token)
}
wrds[i] = EOD;
eol = (token = gettoken(nullptr)) == nullptr;
} 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' */
static void nonverb(CONTEXT) {
if (isDir(wrds[wrdidx])) {
wrdidx++;
if (wrds[wrdidx] != EOD && !isConj(wrds[wrdidx])) {
CALL1(error, M_WHAT)
} else {
CALL1(go, dict[wrds[wrdidx - 1]].code)
}
if (wrds[wrdidx] != EOD)
wrdidx++;
} else {
CALL1(error, M_WHAT)
}
}
static void buildall(CONTEXT, ParamElem list[]) {
int i = 0;
Boolean found = FALSE;
for (uint o = OBJMIN; o <= OBJMAX; o++)
if (isHere(o)) {
found = TRUE;
list[i].code = o;
list[i++].firstWord = EOD;
}
if (!found) {
CALL1(error, M_WHAT_ALL)
} else {
list[i].code = EOD;
}
}
static void unambig(CONTEXT, ParamElem plst[]) {
int i;
Boolean found = FALSE; /* Adjective or noun found ? */
static ParamElem *refs; /* Entities referenced by word */
static ParamElem *savlst; /* Saved list for backup at EOD */
int firstWord, lastWord; /* The words the player used */
if (refs == nullptr)
refs = (ParamElem *)allocate((MAXENTITY + 1) * sizeof(ParamElem));
if (savlst == nullptr)
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 = EOD; /* No words used! */
plst[1].code = EOD;
return;
}
plst[0].code = EOD; /* 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) {
CALL1(error, M_WHAT_IT)
}
if (!isHere(pparams[i].code)) {
params[0].code = pparams[i].code;
params[0].firstWord = EOD;
params[1].code = EOD;
CALL1(error, M_NO_SUCH)
}
plst[0] = pparams[i];
plst[0].firstWord = EOD; /* No words used! */
plst[1].code = EOD;
return;
}
firstWord = wrdidx;
while (wrds[wrdidx] != EOD && 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] == EOD || !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] != EOD) {
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
CALL1(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 == EOD)
lstcpy(plst, refs);
else
isect(plst, refs);
} else {
CALL1(error, M_NOUN)
}
}
lastWord = wrdidx - 1;
/* Allow remote objects, but resolve ambiguities by presence */
if (lstlen(plst) > 1) {
for (i = 0; plst[i].code != EOD; 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 != EOD */
params[0].firstWord = firstWord; /* Remember words for errors below */
params[0].lastWord = lastWord;
params[1].code = EOD; /* But be sure to terminate */
if (lstlen(plst) > 1) {
CALL1(error, M_WHICH_ONE)
} else if (found && lstlen(plst) == 0) {
CALL1(error, M_NO_SUCH)
}
} else {
plst[0].firstWord = firstWord;
plst[0].lastWord = lastWord;
}
}
static void simple(CONTEXT, ParamElem olst[]) {
static ParamElem *tlst = nullptr;
int savidx = wrdidx;
Boolean savplur = FALSE;
int i;
if (tlst == nullptr)
tlst = (ParamElem *) allocate(sizeof(ParamElem) * (MAXENTITY + 1));
tlst[0].code = EOD;
for (;;) {
if (isThem(wrds[wrdidx])) {
plural = TRUE;
for (i = 0; pmlst[i].code != EOD; i++)
if (!isHere(pmlst[i].code))
pmlst[i].code = 0;
compact(pmlst);
if (lstlen(pmlst) == 0) {
CALL1(error, M_WHAT_THEM)
}
lstcpy(olst, pmlst);
olst[0].firstWord = EOD; /* No words used */
wrdidx++;
} else {
// Look for unambigous noun phrase
CALL1(unambig, olst)
if (lstlen(olst) == 0) { /* Failed! */
lstcpy(olst, tlst);
wrdidx = savidx;
plural = savplur;
return;
}
}
mrglst(tlst, olst);
if (wrds[wrdidx] != EOD
&& (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...
*/
static void complex(CONTEXT, ParamElem olst[]) {
static ParamElem *alst = nullptr;
if (alst == nullptr)
alst = (ParamElem *) allocate((MAXENTITY + 1) * sizeof(ParamElem));
if (isAll(wrds[wrdidx])) {
plural = TRUE;
// Build list of all objects
CALL1(buildall, alst)
wrdidx++;
if (wrds[wrdidx] != EOD && isBut(wrds[wrdidx])) {
wrdidx++;
CALL1(simple, olst)
if (lstlen(olst) == 0)
CALL1(error, M_AFTER_BUT)
sublst(alst, olst);
if (lstlen(alst) == 0)
CALL1(error, M_NOT_MUCH)
}
lstcpy(olst, alst);
allLength = lstlen(olst);
} else {
// Look for simple noun group
CALL1(simple, olst)
}
}
static Boolean claCheck(ClaElem *cla /* IN - The cla elem to check */) {
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(CONTEXT, ParamElem plst[]) {
int i;
if (allLength > 0) return; /* ALL has already done this */
/* Resolve ambiguities by presence */
for (i = 0; plst[i].code != EOD; 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 = EOD; /* But be sure to terminate */
CALL1(error, M_NO_SUCH)
}
}
/* OUT - List of params allowed by multiple */
static void tryMatch(CONTEXT, ParamElem matchLst[]) {
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 = nullptr; /* List of params found by complex() */
static Boolean *checked = nullptr; /* Corresponding parameter checked? */
if (tlst == nullptr) {
tlst = (ParamElem *) allocate((MAXENTITY + 1) * sizeof(ParamElem));
checked = (Boolean *) allocate((MAXENTITY + 1) * sizeof(Boolean));
}
for (stx = stxs; !endOfTable(stx); stx++)
if ((int)stx->code == vrbcode)
break;
if (endOfTable(stx)) {
CALL1(error, M_WHAT)
}
elms = (ElmElem *) addrTo(stx->elms);
while (TRUE) {
/* End of input? */
if (wrds[wrdidx] == EOD || isConj(wrds[wrdidx])) {
while (!endOfTable(elms) && elms->code != EOS)
elms++;
if (endOfTable(elms)) {
CALL1(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)) {
CALL1(error, M_WHAT)
} else
wrdidx++;
} else {
/* Must be a parameter! */
while (!endOfTable(elms) && elms->code != 0)
elms++;
if (endOfTable(elms)) {
CALL1(error, M_WHAT)
}
/* Get it! */
plural = FALSE;
CALL1(complex, tlst)
if (lstlen(tlst) == 0) {
/* No object!? */
CALL1(error, M_WHAT)
}
/* Omnipotent parameter? */
if ((elms->flags & OMNIBIT) == 0) {
/* If its not an omnipotent parameter, resolve by presence */
CALL1(resolve, tlst)
}
if (plural) {
/* Allowed multiple? */
if ((elms->flags & MULTIPLEBIT) == 0) {
CALL1(error, M_MULTIPLE)
} else {
/*
Mark this as the multiple position in which to insert
actual parameter values later
*/
params[paramidx++].code = 0;
lstcpy(matchLst, tlst);
anyPlural = TRUE;
}
} else
params[paramidx++] = tlst[0];
params[paramidx].code = EOD;
}
elms = (ElmElem *) addrTo(elms->next);
}
}
/* Now perform class checks */
if (elms->next == 0) {
/* No verb code, verb not declared! */
CALL1(error, M_CANT0)
}
for (p = 0; params[p].code != EOD; 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; matchLst[i].code != EOD; i++) {
params[cla->code - 1] = matchLst[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
*/
Common::sprintf_s(marker, "($%ld)", (unsigned long) cla->code);
output(marker);
interpret(cla->stms);
para();
}
matchLst[i].code = 0; /* In any case remove it from the list */
}
}
params[cla->code - 1].code = 0;
} else {
if (!claCheck(cla)) {
/* Return to player without saying anything */
interpret(cla->stms);
CALL1(error, MSGMAX)
}
}
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 != EOD; p++)
if (!checked[p]) {
if (params[p].code == 0) {
/* This was a multiple parameter, check all and remove failing */
for (i = 0; matchLst[i].code != EOD; i++)
if (matchLst[i].code != 0) /* Skip any empty slots */
if (!isObj(matchLst[i].code))
matchLst[i].code = 0;
} else if (!isObj(params[p].code)) {
CALL1(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 (matchLst[i].code != 0) { /* Already empty? */
params[p] = matchLst[i];
if (!possible())
matchLst[i].code = 0; /* Remove this from list */
}
}
params[p].code = 0; /* Restore multiple marker */
compact(matchLst);
if (lstlen(matchLst) == 0) {
params[0].code = EOD;
CALL1(error, M_WHAT_ALL)
}
} else if (anyPlural) {
compact(matchLst);
if (lstlen(matchLst) == 0)
/* If there where multiple parameters but non left, exit without a */
/* word, assuming we have already said enough */
CALL1(error, MSGMAX)
}
plural = anyPlural; /* Remember that we found plural objects */
}
/* OUT - List of params allowed by multiple */
static void match(CONTEXT, ParamElem *matchLst) {
/* ... to understand what he said */
CALL1(tryMatch, matchLst)
if (wrds[wrdidx] != EOD && !isConj(wrds[wrdidx])) {
CALL1(error, M_WHAT)
}
if (wrds[wrdidx] != EOD) /* More on this line? */
wrdidx++; /* If so skip the AND */
}
void parse(CONTEXT) {
if (mlst == nullptr) { /* Allocate large enough paramlists */
mlst = (ParamElem *) allocate(sizeof(ParamElem) * (MAXENTITY + 1));
mlst[0].code = EOD;
pmlst = (ParamElem *) allocate(sizeof(ParamElem) * (MAXENTITY + 1));
params = (ParamElem *) allocate(sizeof(ParamElem) * (MAXENTITY + 1));
params[0].code = EOD;
pparams = (ParamElem *) allocate(sizeof(ParamElem) * (MAXENTITY + 1));
}
if (wrds[wrdidx] == EOD) {
wrdidx = 0;
CALL0(scan)
if (g_vm->shouldQuit())
return;
} else if (anyOutput)
para();
allLength = 0;
paramidx = 0;
lstcpy(pparams, params);
params[0].code = EOD;
lstcpy(pmlst, mlst);
mlst[0].code = EOD;
if (isVerb(wrds[wrdidx])) {
vrbwrd = wrds[wrdidx];
vrbcode = dict[vrbwrd].code;
wrdidx++;
CALL1(match, mlst)
/* mlst contains possible multiple params */
CALL1(action, mlst)
} else {
params[0].code = EOD;
pmlst[0].code = EOD;
CALL0(nonverb)
}
}
} // End of namespace Alan2
} // End of namespace Glk

49
engines/glk/alan2/parse.h Normal file
View File

@@ -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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef GLK_ALAN2_PARSE
#define GLK_ALAN2_PARSE
/* Parse data for ALAN interpreter module. */
#include "engines/glk/jumps.h"
namespace Glk {
namespace Alan2 {
extern Aword 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;
// Parse a new player command
extern void parse(CONTEXT);
} // End of namespace Alan2
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,384 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#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
*/
Aword reversed(Aword w /* IN - The ACODE word to swap bytes of */) {
Aword s; /* The swapped ACODE word */
char *wp, *sp;
wp = (char *) &w;
sp = (char *) &s;
for (uint i = 0; i < sizeof(Aword); i++)
sp[sizeof(Aword) - 1 - i] = wp[i];
return s;
}
void reverse(Aword *w /* IN - The ACODE word to reverse bytes in */) {
*w = reversed(*w);
}
static void reverseTable(Aword adr, int len) {
Aword *e = &memory[adr];
int i;
if (adr != 0)
while (!endOfTable(e)) {
for (i = 0; i < len / (int)sizeof(Aword); i++) {
reverse(e);
e++;
}
}
}
static void reverseStms(Aword adr) {
Aword *e = &memory[adr];
if (adr != 0)
while (TRUE) {
reverse(e);
if (*e == ((Aword)C_STMOP << 28 | (Aword)I_RETURN)) break;
e++;
}
}
static void reverseMsgs(Aword adr) {
MsgElem *e = (MsgElem *) &memory[adr];
if (adr != 0 && !endOfTable(e)) {
reverseTable(adr, sizeof(MsgElem));
while (!endOfTable(e)) {
reverseStms(e->stms);
e++;
}
}
}
static void reverseWrds(Aword adr) {
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++;
}
}
}
static void reverseChks(Aword adr) {
ChkElem *e = (ChkElem *) &memory[adr];
if (adr != 0 && !endOfTable(e)) {
reverseTable(adr, sizeof(ChkElem));
while (!endOfTable(e)) {
reverseStms(e->exp);
reverseStms(e->stms);
e++;
}
}
}
static void reverseAlts(Aword adr) {
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++;
}
}
}
static void reverseVrbs(Aword adr) {
VrbElem *e = (VrbElem *)&memory[adr];
if (adr != 0 && !endOfTable(e)) {
reverseTable(adr, sizeof(VrbElem));
while (!endOfTable(e)) {
reverseAlts(e->alts);
e++;
}
}
}
static void reverseSteps(Aword adr) {
StepElem *e = (StepElem *) &memory[adr];
if (adr != 0 && !endOfTable(e)) {
reverseTable(adr, sizeof(StepElem));
while (!endOfTable(e)) {
reverseStms(e->exp);
reverseStms(e->stm);
e++;
}
}
}
static void reverseScrs(Aword adr) {
ScrElem *e = (ScrElem *) &memory[adr];
if (adr != 0 && !endOfTable(e)) {
reverseTable(adr, sizeof(ScrElem));
while (!endOfTable(e)) {
reverseStms(e->dscr);
reverseSteps(e->steps);
e++;
}
}
}
static void reverseActs(Aword adr) {
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++;
}
}
}
static void reverseObjs(Aword adr, Boolean v2_5) {
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++;
}
}
}
}
static void reverseExts(Aword adr) {
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++;
}
}
}
static void reverseLocs(Aword adr) {
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++;
}
}
}
static void reverseClas(Aword adr) {
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 */
}
static void reverseElms(Aword adr) {
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++;
}
}
}
static void reverseStxs(Aword adr) {
StxElem *e = (StxElem *) &memory[adr];
if (adr != 0 && !endOfTable(e)) {
reverseTable(adr, sizeof(StxElem));
while (!endOfTable(e)) {
reverseElms(e->elms);
e++;
}
}
}
static void reverseEvts(Aword adr) {
EvtElem *e = (EvtElem *) &memory[adr];
if (adr != 0 && !endOfTable(e)) {
reverseTable(adr, sizeof(EvtElem));
while (!endOfTable(e)) {
reverseStms(e->code);
e++;
}
}
}
static void reverseLims(Aword adr) {
LimElem *e = (LimElem *) &memory[adr];
if (adr != 0 && !endOfTable(e)) {
reverseTable(adr, sizeof(LimElem));
while (!endOfTable(e)) {
reverseStms(e->stms);
e++;
}
}
}
static void reverseCnts(Aword adr) {
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++;
}
}
}
static void reverseRuls(Aword adr) {
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.
*/
void reverseHdr(AcdHdr *hdr) {
// Reverse all words in the header except the first (version marking)
for (uint 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
*/
void reverseACD(Boolean v2_5) {
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

View File

@@ -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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef GLK_ALAN2_REVERSE
#define GLK_ALAN2_REVERSE
namespace Glk {
namespace Alan2 {
extern void reverseHdr(AcdHdr *hdr);
extern void reverseACD(Boolean v25);
extern void reverse(Aword *word);
extern Aword reversed(Aword word);
} // End of namespace Alan2
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,75 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "glk/alan2/types.h"
#include "glk/alan2/debug.h"
#include "glk/alan2/exe.h"
#include "glk/alan2/inter.h"
#include "glk/alan2/glkio.h"
#include "glk/alan2/main.h"
#include "glk/alan2/rules.h"
#include "glk/alan2/stack.h"
namespace Glk {
namespace Alan2 {
void rules() {
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

37
engines/glk/alan2/rules.h Normal file
View File

@@ -0,0 +1,37 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef GLK_ALAN2_RULES
#define GLK_ALAN2_RULES
/* Header file for rules handler in Alan interpreter */
namespace Glk {
namespace Alan2 {
/* TYPES */
extern void rules(void);
} // End of namespace Alan2
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,55 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#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;
void push(Aptr i) {
if (stackp == STACKSIZE)
syserr("Out of stack space.");
stack[stackp++] = i;
}
Aptr pop() {
if (stackp == 0)
syserr("Stack underflow.");
return (stack[--stackp]);
}
Aptr top() {
return (stack[stackp - 1]);
}
} // End of namespace Alan2
} // End of namespace Glk

39
engines/glk/alan2/stack.h Normal file
View File

@@ -0,0 +1,39 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef GLK_ALAN2_STACK
#define GLK_ALAN2_STACK
/* Header file for stack handler in Alan interpreter */
namespace Glk {
namespace Alan2 {
/* TYPES */
extern Aptr pop(void);
extern void push(Aptr item);
extern Aptr top(void);
} // End of namespace Alan2
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,311 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "glk/alan2/alan2.h"
#include "glk/alan2/sysdep.h"
namespace Glk {
namespace Alan2 {
void syserr(char str[]);
void fprintf(Common::WriteStream *ws, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
Common::String s = Common::String::vformat(fmt, args);
va_end(args);
ws->write(s.c_str(), s.size());
}
/* 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'
};
int isSpace(int c) { /* IN - Native character to test */
return (c != '\0' && strchr(spcChrs, c) != nullptr);
}
int isLower(int c) { /* IN - Native character to test */
return (c != '\0' && strchr(lowChrs, c) != nullptr);
}
int isUpper(int c) { /* IN - Native character to test */
return (c != '\0' && strchr(uppChrs, c) != nullptr);
}
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 */
return g_vm->glk_char_to_lower(c);
}
int toUpper(int c) { /* IN - Native character to convert */
return g_vm->glk_char_to_upper(c);
}
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 lowChars[] = "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(lowChars, c) != nullptr);
}
int isUpperCase(int c) { /* IN - ISO character to test */
static char upperChars[] = "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(upperChars, c) != nullptr);
}
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);
}
#if 0
/*----------------------------------------------------------------------
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;
default:
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 (copy != original)
(void)strcpy(copy, original);
}
/*----------------------------------------------------------------------
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);
}
#endif
} // End of namespace Alan2
} // End of namespace Glk

View File

@@ -0,0 +1,90 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#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"
#include "common/stream.h"
namespace Glk {
namespace Alan2 {
#define GLK
#define __win__
#undef fprintf
extern void fprintf(Common::WriteStream *ws, const char *fmt, ...);
/***********************/
/* Common case first */
#define ISO 1
#define NATIVECHARSET 0
/* 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 */
#if 0
/* 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 */
#endif
} // End of namespace Alan2
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,52 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "glk/alan2/types.h"
namespace Glk {
namespace Alan2 {
// This works around gcc errors for passing packed structure fields
static void syncVal(Common::Serializer &s, void *fld) {
uint32 v = READ_UINT32(fld);
s.syncAsSint32LE(v);
if (s.isLoading())
WRITE_UINT32(fld, v);
}
void CurVars::synchronize(Common::Serializer &s) {
syncVal(s, &vrb);
syncVal(s, &obj);
syncVal(s, &loc);
syncVal(s, &act);
syncVal(s, &tick);
syncVal(s, &score);
syncVal(s, &visits);
}
void EvtqElem::synchronize(Common::Serializer &s) {
syncVal(s, &time);
syncVal(s, &event);
syncVal(s, &where);
}
} // End of namespace Alan2
} // End of namespace Glk

296
engines/glk/alan2/types.h Normal file
View File

@@ -0,0 +1,296 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef GLK_ALAN2_TYPES
#define GLK_ALAN2_TYPES
#include "glk/alan2/sysdep.h"
#include "glk/alan2/acode.h"
#include "common/serializer.h"
#include "common/stream.h"
namespace Glk {
namespace Alan2 {
/* CONSTANTS */
#ifndef TRUE
#define TRUE (0==0)
#endif
#ifndef FALSE
#define FALSE (!TRUE)
#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) (&memory[x])
/* The word classes are represented as numbers but in the dictonary they are generated as bits */
#define isVerb(word) ((int)word < dictsize && (dict[word]._class&((Aword)1L<<WRD_VRB))!=0)
#define isConj(word) ((int)word < dictsize && (dict[word]._class&((Aword)1L<<WRD_CONJ))!=0)
#define isBut(word) ((int)word < dictsize && (dict[word]._class&((Aword)1L<<WRD_BUT))!=0)
#define isThem(word) ((int)word < dictsize && (dict[word]._class&((Aword)1L<<WRD_THEM))!=0)
#define isIt(word) ((int)word < dictsize && (dict[word]._class&((Aword)1L<<WRD_IT))!=0)
#define isNoun(word) ((int)word < dictsize && (dict[word]._class&((Aword)1L<<WRD_NOUN))!=0)
#define isAdj(word) ((int)word < dictsize && (dict[word]._class&((Aword)1L<<WRD_ADJ))!=0)
#define isPrep(word) ((int)word < dictsize && (dict[word]._class&((Aword)1L<<WRD_PREP))!=0)
#define isAll(word) ((int)word < dictsize && (dict[word]._class&((Aword)1L<<WRD_ALL))!=0)
#define isDir(word) ((int)word < dictsize && (dict[word]._class&((Aword)1L<<WRD_DIR))!=0)
#define isNoise(word) ((int)word < dictsize && (dict[word]._class&((Aword)1L<<WRD_NOISE))!=0)
#define isLiteral(word) ((int)word >= dictsize)
/* TYPES */
typedef int Boolean; /* Boolean values within interpreter */
/* Amachine variables */
struct CurVars {
int
vrb,
obj,
loc,
act,
tick,
score,
visits;
/**
* Read or write data to/from a save file
*/
void synchronize(Common::Serializer &s);
};
#include "common/pack-start.h" // START STRUCT PACKING
/* The various tables */
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 */
} PACKED_STRUCT;
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 */
} PACKED_STRUCT;
struct ScrElem { /* SCRIPT TABLE */
Aword code; /* Script number */
Aaddr dscr; /* Optional description statements */
Aaddr steps; /* Address to steps */
} PACKED_STRUCT;
struct StepElem { /* STEP TABLE */
Aword after; /* After how many ticks? */
Aaddr exp; /* Address to expression saying when */
Aaddr stm; /* Address to the actual code */
} PACKED_STRUCT;
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 */
} PACKED_STRUCT;
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 */
} PACKED_STRUCT;
struct ChkElem { /* CHECK TABLE */
Aaddr exp; /* ACODE address to expression code */
Aaddr stms; /* ACODE address to statement code */
} PACKED_STRUCT;
struct VrbElem { /* VERB TABLE */
Aword code; /* Code for the verb */
Aaddr alts; /* Address to alternatives */
} PACKED_STRUCT;
struct StxElem { /* SYNTAX TABLE */
Aword code; /* Code for verb word */
Aaddr elms; /* Address to element tables */
} PACKED_STRUCT;
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 */
} PACKED_STRUCT;
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 */
} PACKED_STRUCT;
struct ClaElem { /* CLASS DEFINITION TABLE */
Aword code; /* Parameter number */
Aword classes; /* Parameter classes */
Aaddr stms; /* Exception statements */
} PACKED_STRUCT;
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 */
} PACKED_STRUCT;
struct AtrElem { /* ATTRIBUTE LIST */
Aword val; /* Its value */
Aaddr stradr; /* Address to the name */
} PACKED_STRUCT;
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 */
} PACKED_STRUCT;
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 */
} PACKED_STRUCT;
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 */
} PACKED_STRUCT;
struct LimElem { /* LIMIT Type */
Aword atr; /* Attribute that limits */
Aword val; /* And the limiting value */
Aaddr stms; /* Statements if fail */
} PACKED_STRUCT;
struct RulElem { /* RULE TABLE */
Abool run; /* Is rule already run? */
Aaddr exp; /* Address to expression code */
Aaddr stms; /* Address to run */
} PACKED_STRUCT;
struct EvtElem { /* EVENT TABLE */
Aaddr stradr; /* Address to name string */
Aaddr code; /* Address of code to run */
} PACKED_STRUCT;
struct EvtqElem { /* EVENT QUEUE ELEMENT */
int time;
int event;
int where;
/**
* Read or write data to/from a save file
*/
void synchronize(Common::Serializer &s);
} PACKED_STRUCT;
struct IniElem { /* STRING INITIALISATION TABLE */
Aword fpos; /* File position */
Aword len; /* Length */
Aword adr; /* Where to store the string */
} PACKED_STRUCT;
struct MsgElem26 { /* MESSAGE TABLE */
Aword fpos; /* File position */
Aword len; /* Length of message */
} PACKED_STRUCT;
struct MsgElem { /* MESSAGE TABLE */
Aaddr stms; /* Address to statements*/
/* Changed v2.7 from fpos+len in .dat */
} PACKED_STRUCT;
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 */
} PACKED_STRUCT;
enum Type { TYPNUM, TYPSTR };
struct LitElem { /* LITERAL */
Type type;
Aptr value;
} PACKED_STRUCT;
#include "common/pack-end.h" // END STRUCT PACKING
#define MAXPARAMS 9
#define MAXENTITY (header->actmax)
} // End of namespace Alan2
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,57 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef GLK_ALAN2_VERSION
#define GLK_ALAN2_VERSION
#include "common/system.h"
namespace Glk {
namespace Alan2 {
typedef int64 Time;
struct Version {
const char *string;
int version;
int revision;
int correction;
Time time;
const char *state;
};
struct Product {
const char *name;
const char *slogan;
const char *shortHeader;
const char *longHeader;
const char *date;
const char *time;
const char *user;
const char *host;
const char *ostype;
const Version version;
};
} // End of namespace Alan2
} // End of namespace Glk
#endif