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

View File

@@ -0,0 +1,45 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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/alan3/acode.h"
namespace Glk {
namespace Alan3 {
void AttributeEntry::synchronize(Common::Serializer &s) {
// We have to do some annoying temporary copy of the fields to get around gcc
// errors about getting references to fields of packed structures
Aint c = code;
Aptr v = value;
Aaddr i = id;
s.syncAsSint32LE(c);
s.syncAsSint32LE(v);
s.syncAsSint32LE(i);
if (s.isLoading()) {
code = c;
value = v;
id = i;
}
}
} // End of namespace Alan3
} // End of namespace Glk

736
engines/glk/alan3/acode.h Normal file
View File

@@ -0,0 +1,736 @@
/* 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_ACODE
#define GLK_ACODE
#include "common/scummsys.h"
#include "common/serializer.h"
namespace Glk {
namespace Alan3 {
#define ACODEEXTENSION ".a3c"
typedef uint32 Aptr; /* Type for an ACODE memory address used in the structures */
/* TODO: Here's the major 32->64bit problem: Aptrs are 32 bit to fit
into the 32-bit structure of the Amachine, but sometimes this is
used to store a *real* pointer value, which on 64-bit machines are
64bits. */
typedef uint32 Aword; /* Type for an ACODE word */
typedef uint32 Aaddr; /* Type for an ACODE address */
typedef uint32 Aid; /* Type for an ACODE Instance Id value */
typedef int32 Abool; /* Type for an ACODE Boolean value */
typedef int32 Aint; /* Type for an ACODE Integer value */
typedef int32 Aset; /* Type for an ACODE Set value */
typedef int CodeValue; /* Definition for the packing process */
#ifndef TRUE
#define TRUE (0==0)
#endif
#ifndef FALSE
#define FALSE (!TRUE)
#endif
/* Constants for the Acode file, words/block & bytes/block */
#define BLOCKLEN 256L
#define BLOCKSIZE (BLOCKLEN*sizeof(Aword))
/* Definitions for the packing process */
#define VALUEBITS 16
#define EOFChar 256
#define TOPVALUE (((CodeValue)1<<VALUEBITS) - 1) /* Highest value possible */
/* Half and quarter points in the code value range */
#define ONEQUARTER (TOPVALUE/4+1) /* Point after first quarter */
#define HALF (2*ONEQUARTER) /* Point after first half */
#define THREEQUARTER (3*ONEQUARTER) /* Point after third quarter */
/* AMACHINE Word Classes, bit positions */
typedef int WordKind;
#define SYNONYM_WORD 0
#define SYNONYM_BIT (((Aword)1)<<SYNONYM_WORD)
#define ADJECTIVE_WORD (SYNONYM_WORD+1)
#define ADJECTIVE_BIT (((Aword)1)<<ADJECTIVE_WORD)
#define ALL_WORD (ADJECTIVE_WORD+1)
#define ALL_BIT (((Aword)1)<<ALL_WORD)
#define EXCEPT_WORD (ALL_WORD+1)
#define EXCEPT_BIT (((Aword)1)<<EXCEPT_WORD)
#define CONJUNCTION_WORD (EXCEPT_WORD+1)
#define CONJUNCTION_BIT (((Aword)1)<<CONJUNCTION_WORD)
#define PREPOSITION_WORD (CONJUNCTION_WORD+1)
#define PREPOSITION_BIT (((Aword)1)<<PREPOSITION_WORD)
#define DIRECTION_WORD (PREPOSITION_WORD+1)
#define DIRECTION_BIT (((Aword)1)<<DIRECTION_WORD)
#define IT_WORD (DIRECTION_WORD+1)
#define IT_BIT (((Aword)1)<<IT_WORD)
#define NOISE_WORD (IT_WORD+1)
#define NOISE_BIT (((Aword)1)<<NOISE_WORD)
#define NOUN_WORD (NOISE_WORD+1)
#define NOUN_BIT (((Aword)1)<<NOUN_WORD)
#define THEM_WORD (NOUN_WORD+1)
#define THEM_BIT (((Aword)1)<<THEM_WORD)
#define VERB_WORD (THEM_WORD+1)
#define VERB_BIT (((Aword)1)<<VERB_WORD)
#define PRONOUN_WORD (VERB_WORD+1)
#define PRONOUN_BIT (((Aword)1)<<PRONOUN_WORD)
#define WRD_CLASSES (PRONOUN_WORD+1)
/* The #nowhere and NO_LOCATION constants */
#define NO_LOCATION 0
#define NOWHERE 1
/* Syntax element classifications */
// End of file/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
};
/* AMACHINE Text Styles */
enum TextStyle {
NORMAL_STYLE,
EMPHASIZED_STYLE,
PREFORMATTED_STYLE,
ALERT_STYLE,
QUOTE_STYLE
};
#define CONSTANT(op) ((Aword)op)
#define INSTRUCTION(op) ((((Aword)C_STMOP)<<28)|((Aword)op))
#define CURVAR(op) ((((Aword)C_CURVAR)<<28)|((Aword)op))
enum InstClass {
I_LINE, /* Source line debug info */
I_PRINT, /* Print a string from the text file */
I_STYLE, /* Set output text style */
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, /* Set a boolean attribute to the */
/* value on top of stack */
I_SET, /* Set a numeric attribute to the */
/* value on top of stack */
I_SETSTR, /* Set a string valued attribute to */
/* the string on top of stack, */
/* deallocate current contents first */
I_SETSET, /* Set a Set valued attribute to */
/* the Set on top of stack, */
/* deallocate current contents first */
I_NEWSET, /* Push a new, empty set at the top of stack */
I_ATTRIBUTE, /* Push the value of an attribute */
I_ATTRSTR, /* Push a copy of a string attribute */
I_ATTRSET, /* Push a copy of a set attribute */
I_UNION, /* Add a set from the top of stack to a */
/* set valued attribute */
I_GETSTR, /* Get a string contents from text
file, create a copy and push it
on top of stack */
I_INCR, /* Increase an attribute */
I_DECR, /* Decrease a numeric attribute */
I_INCLUDE, /* Include a value in the set on stack top */
I_EXCLUDE, /* Remove a value from the set on stack top */
I_SETSIZE, /* Push number of members in a set */
I_SETMEMB, /* Push the member with index <top>-1
from set <top> */
I_CONTSIZE, /* Push number of members in a container */
I_CONTMEMB, /* Push the member with index <top>-1
from container <top> */
I_USE,
I_STOP,
I_AT,
I_IN,
I_INSET,
I_HERE,
I_NEARBY,
I_NEAR,
I_WHERE, /* Current position of an instance */
I_LOCATION, /* The *location* an instance is at */
I_DESCRIBE,
I_SAY,
I_SAYINT,
I_SAYSTR,
I_IF,
I_ELSE,
I_ENDIF,
I_AND,
I_OR,
I_NE,
I_EQ,
I_STREQ, /* String compare */
I_STREXACT, /* Exact match */
I_LE,
I_GE,
I_LT,
I_GT,
I_PLUS,
I_MINUS,
I_MULT,
I_DIV,
I_NOT,
I_UMINUS,
I_RND,
I_RETURN,
I_SYSTEM,
I_RESTART,
I_BTW,
I_CONTAINS,
I_DUP,
I_DEPEND,
I_DEPCASE,
I_DEPEXEC,
I_DEPELSE,
I_ENDDEP,
I_ISA,
I_FRAME,
I_SETLOCAL,
I_GETLOCAL,
I_ENDFRAME,
I_LOOP,
I_LOOPNEXT,
I_LOOPEND,
I_SUM, /* Aggregates: */
I_MAX,
I_MIN,
I_COUNT, /* COUNT aggregate & limit meta-attribute */
I_SHOW,
I_PLAY,
I_CONCAT,
I_STRIP,
I_POP,
I_TRANSCRIPT,
I_DUPSTR /* Duplicate the string on the top of the stack */
};
enum SayForm {
SAY_SIMPLE,
SAY_DEFINITE,
SAY_INDEFINITE,
SAY_NEGATIVE,
SAY_PRONOUN
};
enum VarClass {
V_PARAM,
V_CURLOC,
V_CURACT,
V_CURVRB,
V_SCORE,
V_CURRENT_INSTANCE,
V_MAX_INSTANCE
};
/* For transitivity in HERE, IN etc. */
enum ATrans {
TRANSITIVE = 0,
DIRECT = 1,
INDIRECT = 2
};
/* Predefined attributes, one is for containers and the other for locations
and since instances cannot be both, the attributes can have the same number */
#define OPAQUEATTRIBUTE 1
#define VISITSATTRIBUTE 1
#define PREDEFINEDATTRIBUTES OPAQUEATTRIBUTE
#define I_CLASS(x) ((x)>>28)
#define I_OP(x) ((x&0x08000000)?(x)|0xf0000000:(x)&0x0fffffff)
/* AMACHINE Table entry types */
#define AwordSizeOf(x) (sizeof(x)/sizeof(Aword))
#include "common/pack-start.h" // START STRUCT PACKING
struct ArticleEntry {
Aaddr address; /* Address of article code */
Abool isForm; /* Is the article a complete form? */
} PACKED_STRUCT;
struct ClassEntry { /* CLASS TABLE */
Aword code; /* Own code */
Aaddr id; /* Address to identifier string */
Aint parent; /* Code for the parent class, 0 if none */
Aaddr name; /* Address to name printing code */
Aint pronoun; /* Code for the pronoun word */
Aaddr initialize; /* Address to initialization statements */
Aaddr descriptionChecks; /* Address of description checks */
Aaddr description; /* Address of description code */
ArticleEntry definite; /* Definite article entry */
ArticleEntry indefinite; /* Indefinite article entry */
ArticleEntry negative; /* Negative article entry */
Aaddr mentioned; /* Address of code for Mentioned clause */
Aaddr verbs; /* Address of verb table */
Aaddr entered; /* Address of code for Entered clause */
} PACKED_STRUCT;
struct InstanceEntry { /* INSTANCE TABLE */
Aint code; /* Own code */
Aaddr id; /* Address to identifier string */
Aint parent; /* Code for the parent class, 0 if none */
Aaddr name; /* Address to name printing code */
Aint pronoun; /* Word code for the pronoun */
Aint initialLocation; /* Code for current location */
Aaddr initialize; /* Address to initialization statements */
Aint container; /* Code for a possible container property */
Aaddr initialAttributes; /* Address of attribute list */
Aaddr checks; /* Address of description checks */
Aaddr description; /* Address of description code */
ArticleEntry definite; /* Definite article entry */
ArticleEntry indefinite; /* Indefinite article entry */
ArticleEntry negative; /* Negative article entry */
Aaddr mentioned; /* Address to short description code */
Aaddr verbs; /* Address of local verb list */
Aaddr entered; /* Address of entered code (location only) */
Aaddr exits; /* Address of exit list */
} PACKED_STRUCT;
struct AttributeEntry { /* ATTRIBUTE LIST */
Aint code; /* Its code */
Aptr value; /* Its value, a string has a dynamic
string pointer, a set has a pointer
to a dynamically allocated set */
Aaddr id; /* Address to the name */
/**
* Save/resotre data from save file
*/
void synchronize(Common::Serializer &s);
} PACKED_STRUCT;
struct AttributeHeaderEntry { /* ATTRIBUTE LIST in header */
Aint code; /* Its code */
Aword value; /* Its value, a string has a dynamic
string pointer, a set has a pointer
to a dynamically allocated set */
Aaddr id; /* Address to the name */
} PACKED_STRUCT;
struct ExitEntry { /* EXIT TABLE structure */
Aword code; /* Direction code */
Aaddr checks; /* Address of check table */
Aaddr action; /* Address of action code */
Aword target; /* Id for the target location */
} PACKED_STRUCT;
struct RuleEntry { /* RULE TABLE */
Abool alreadyRun;
Aaddr exp; /* Address to expression code */
Aaddr stms; /* Address to run */
} PACKED_STRUCT;
#define RESTRICTIONCLASS_CONTAINER (-2)
#define RESTRICTIONCLASS_INTEGER (-3)
#define RESTRICTIONCLASS_STRING (-4)
struct RestrictionEntry { /* PARAMETER RESTRICTION TABLE */
Aint parameterNumber; /* Parameter number */
Aint _class; /* Parameter class code */
Aaddr stms; /* Exception statements */
} PACKED_STRUCT;
struct ContainerEntry { /* CONTAINER TABLE */
Aword owner; /* Owner instance index */
Aint _class; /* Class to allow in container */
Aaddr limits; /* Address to limit check code */
Aaddr header; /* Address to header code */
Aaddr empty; /* Address to code for header when empty */
Aaddr extractChecks; /* Address to check before extracting */
Aaddr extractStatements; /* Address to execute when extracting */
} PACKED_STRUCT;
struct ElementEntry { /* SYNTAX ELEMENT TABLES */
Aint code; /* Code for this element, 0 -> parameter */
Aword flags; /* Flags for multiple/omni (if parameter), syntax number/verb of EOS */
Aaddr next; /* Address to next element table ... */
/* ... or restrictions if code == EOS */
} PACKED_STRUCT;
struct SyntaxEntryPreBeta2 { /* SYNTAX TABLE */
Aint code; /* Code for verb word */
Aaddr elms; /* Address to element tables */
} PACKED_STRUCT;
struct SyntaxEntry { /* SYNTAX TABLE */
Aint code; /* Code for verb word, or 0 if starting with parameter */
Aaddr elms; /* Address to element tables */
Aaddr parameterNameTable; /* Address to a table of id-addresses giving the names of the parameters */
} PACKED_STRUCT;
struct ParameterMapEntry { /* PARAMETER MAPPING TABLE */
Aint syntaxNumber;
Aaddr parameterMapping;
Aint verbCode;
} PACKED_STRUCT;
struct EventEntry { /* EVENT TABLE */
Aaddr id; /* Address to name string */
Aaddr code;
} PACKED_STRUCT;
struct ScriptEntry { /* SCRIPT TABLE */
Aaddr id; /* Address to name string */
Aint code; /* Script number */
Aaddr description; /* Optional description statements */
Aaddr steps; /* Address to steps */
} PACKED_STRUCT;
struct StepEntry { /* STEP TABLE */
Aaddr after; /* Expression to say after how many ticks? */
Aaddr exp; /* Expression to condition saying when */
Aaddr stms; /* Address to the actual code */
} PACKED_STRUCT;
struct AltEntry { /* VERB ALTERNATIVE TABLE */
Aword qual; /* Verb execution qualifier */
Aint param; /* Parameter number */
Aaddr checks; /* Address of the check table */
Aaddr action; /* Address of the action code */
} PACKED_STRUCT;
struct SourceFileEntry { /* SOURCE FILE NAME TABLE */
Aint fpos;
Aint len;
} PACKED_STRUCT;
struct SourceLineEntry { /* SOURCE LINE TABLE */
Aint file;
Aint line;
} PACKED_STRUCT;
struct StringInitEntry { /* STRING INITIALISATION TABLE */
Aword fpos; /* File position */
Aword len; /* Length */
Aint instanceCode; /* Where to store it */
Aint attributeCode;
} PACKED_STRUCT;
struct SetInitEntry { /* SET INITIALISATION TABLE */
Aint size; /* Size of the initial set */
Aword setAddress; /* Address to the initial set */
Aint instanceCode; /* Where to store it */
Aint attributeCode;
} PACKED_STRUCT;
struct DictionaryEntry { /* Dictionary */
Aaddr string; /* ACODE address to string */
Aword classBits; /* Word class */
Aword code;
Aaddr adjectiveRefs; /* Address to reference list */
Aaddr nounRefs; /* Address to reference list */
Aaddr pronounRefs; /* Address to reference list */
} PACKED_STRUCT;
/* AMACHINE Header */
struct ACodeHeader {
/* Important info */
char tag[4]; /* "ALAN" */
byte version[4]; /* Version of compiler */
Aword uid; /* Unique id of the compiled game */
Aword size; /* Size of ACD-file in Awords */
/* Options */
Abool pack; /* Is the text packed and encoded ? */
Aword stringOffset; /* Offset to string data in game file */
Aword pageLength; /* Length of a displayed page */
Aword pageWidth; /* and width */
Aword debug; /* Option: debug */
/* Data structures */
Aaddr classTableAddress;
Aword classMax;
Aword entityClassId;
Aword thingClassId;
Aword objectClassId;
Aword locationClassId;
Aword actorClassId;
Aword literalClassId;
Aword integerClassId;
Aword stringClassId;
Aaddr instanceTableAddress; /* Instance table */
Aword instanceMax; /* Highest number of an instance */
Aword theHero; /* The hero instance code (id) */
Aaddr containerTableAddress;
Aword containerMax;
Aaddr scriptTableAddress;
Aword scriptMax;
Aaddr eventTableAddress;
Aword eventMax;
Aaddr syntaxTableAddress;
Aaddr parameterMapAddress;
Aword syntaxMax;
Aaddr dictionary;
Aaddr verbTableAddress;
Aaddr ruleTableAddress;
Aaddr messageTableAddress;
/* Miscellaneous */
Aint attributesAreaSize; /* Size of attribute data area in Awords */
Aint maxParameters; /* Maximum number of parameters in any syntax */
Aaddr stringInitTable; /* String init table address */
Aaddr setInitTable; /* Set init table address */
Aaddr start; /* Address to Start code */
Aword maximumScore; /* Maximum score */
Aaddr scores; /* Score table */
Aint scoreCount; /* Max index into scores table */
Aaddr sourceFileTable; /* Table of fpos/len for source filenames */
Aaddr sourceLineTable; /* Table of available source lines to break on */
Aaddr freq; /* Address to Char freq's for coding */
Aword acdcrc; /* Checksum for acd code (excl. hdr) */
Aword txtcrc; /* Checksum for text data file */
Aaddr ifids; /* Address to IFIDS */
Aaddr prompt;
} PACKED_STRUCT;
struct Pre3_0beta2Header {
/* Important info */
char tag[4]; /* "ALAN" */
byte version[4]; /* Version of compiler */
Aword uid; /* Unique id of the compiled game */
Aword size; /* Size of ACD-file in Awords */
/* Options */
Abool pack; /* Is the text packed ? */
Aword stringOffset; /* Offset to string data in game file */
Aword pageLength; /* Length of a page */
Aword pageWidth; /* and width */
Aword debug; /* Option: debug */
/* Data structures */
Aaddr classTableAddress; /* Class table */
Aword classMax; /* Number of classes */
Aword entityClassId;
Aword thingClassId;
Aword objectClassId;
Aword locationClassId;
Aword actorClassId;
Aword literalClassId;
Aword integerClassId;
Aword stringClassId;
Aaddr instanceTableAddress; /* Instance table */
Aword instanceMax; /* Highest number of an instance */
Aword theHero; /* The hero instance code (id) */
Aaddr containerTableAddress;
Aword containerMax;
Aaddr scriptTableAddress;
Aword scriptMax;
Aaddr eventTableAddress;
Aword eventMax;
Aaddr syntaxTableAddress;
Aaddr parameterMapAddress;
Aword syntaxMax;
Aaddr dictionary;
Aaddr verbTableAddress;
Aaddr ruleTableAddress;
Aaddr messageTableAddress;
/* Miscellaneous */
Aint attributesAreaSize; /* Size of attribute data area in Awords */
Aint maxParameters; /* Maximum number of parameters in any syntax */
Aaddr stringInitTable; /* String init table address */
Aaddr setInitTable; /* Set init table address */
Aaddr start; /* Address to Start code */
Aword maximumScore; /* Maximum score */
Aaddr scores; /* Score table */
Aint scoreCount; /* Max index into scores table */
Aaddr sourceFileTable; /* Table of fpos/len for source filenames */
Aaddr sourceLineTable; /* Table of available source lines to break on */
Aaddr freq; /* Address to Char freq's for coding */
Aword acdcrc; /* Checksum for acd code (excl. hdr) */
Aword txtcrc; /* Checksum for text data file */
Aaddr ifids; /* Address to IFIDS */
} PACKED_STRUCT;
struct Pre3_0alpha5Header {
/* Important info */
char tag[4]; /* "ALAN" */
byte version[4]; /* Version of compiler */
Aword uid; /* Unique id of the compiled game */
Aword size; /* Size of ACD-file in Awords */
/* Options */
Abool pack; /* Is the text packed ? */
Aword stringOffset; /* Offset to string data in game file */
Aword pageLength; /* Length of a page */
Aword pageWidth; /* and width */
Aword debug; /* Option: debug */
/* Data structures */
Aaddr classTableAddress; /* Class table */
Aword classMax; /* Number of classes */
Aword entityClassId;
Aword thingClassId;
Aword objectClassId;
Aword locationClassId;
Aword actorClassId;
Aword literalClassId;
Aword integerClassId;
Aword stringClassId;
Aaddr instanceTableAddress; /* Instance table */
Aword instanceMax; /* Highest number of an instance */
Aword theHero; /* The hero instance code (id) */
Aaddr containerTableAddress;
Aword containerMax;
Aaddr scriptTableAddress;
Aword scriptMax;
Aaddr eventTableAddress;
Aword eventMax;
Aaddr syntaxTableAddress;
Aaddr parameterMapAddress;
Aword syntaxMax;
Aaddr dictionary;
Aaddr verbTableAddress;
Aaddr ruleTableAddress;
Aaddr messageTableAddress;
/* Miscellaneous */
Aint attributesAreaSize; /* Size of attribute data area in Awords */
Aint maxParameters; /* Maximum number of parameters in any syntax */
Aaddr stringInitTable; /* String init table address */
Aaddr setInitTable; /* Set init table address */
Aaddr start; /* Address to Start code */
Aword maximumScore; /* Maximum score */
Aaddr scores; /* Score table */
Aint scoreCount; /* Max index into scores table */
Aaddr sourceFileTable; /* Table of fpos/len for source filenames */
Aaddr sourceLineTable; /* Table of available source lines to break on */
Aaddr freq; /* Address to Char freq's for coding */
Aword acdcrc; /* Checksum for acd code (excl. hdr) */
Aword txtcrc; /* Checksum for text data file */
} PACKED_STRUCT;
#include "common/pack-end.h" // END STRUCT PACKING
/* Error message numbers */
enum MsgKind {
M_UNKNOWN_WORD,
M_WHAT,
M_WHAT_WORD,
M_MULTIPLE,
M_NOUN,
M_AFTER_BUT,
M_BUT_ALL,
M_NOT_MUCH,
M_WHICH_ONE_START,
M_WHICH_ONE_COMMA,
M_WHICH_ONE_OR,
M_NO_SUCH,
M_NO_WAY,
M_CANT0,
M_SEE_START,
M_SEE_COMMA,
M_SEE_AND,
M_SEE_END,
M_CONTAINS,
M_CARRIES,
M_CONTAINS_COMMA,
M_CONTAINS_AND,
M_CONTAINS_END,
M_EMPTY,
M_EMPTYHANDED,
M_CANNOTCONTAIN,
M_SCORE,
M_MORE,
M_AGAIN,
M_SAVEWHERE,
M_SAVEOVERWRITE,
M_SAVEFAILED,
M_RESTOREFROM,
M_SAVEMISSING,
M_NOTASAVEFILE,
M_SAVEVERS,
M_SAVENAME,
M_REALLY,
M_QUITACTION,
M_UNDONE,
M_NO_UNDO,
M_WHICH_PRONOUN_START,
M_WHICH_PRONOUN_FIRST,
M_IMPOSSIBLE_WITH,
M_CONTAINMENT_LOOP,
M_CONTAINMENT_LOOP2,
MSGMAX
};
#define NO_MSG MSGMAX
} // End of namespace Alan3
} // End of namespace Glk
#endif

128
engines/glk/alan3/act.cpp Normal file
View File

@@ -0,0 +1,128 @@
/* 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/alan3/act.h"
#include "glk/alan3/alt_info.h"
#include "glk/alan3/exe.h"
#include "glk/alan3/lists.h"
#include "glk/alan3/msg.h"
#include "glk/alan3/output.h"
#include "glk/alan3/syserr.h"
namespace Glk {
namespace Alan3 {
/*----------------------------------------------------------------------*/
static void executeCommand(CONTEXT, int verb, Parameter parameters[]) {
static AltInfo *altInfos = nullptr; /* Need to survive lots of different exits...*/
int altIndex;
bool flag;
/* Did we leave anything behind last time... */
if (altInfos != nullptr)
free(altInfos);
altInfos = findAllAlternatives(verb, parameters);
FUNC2(anyCheckFailed, flag, altInfos, EXECUTE_CHECK_BODY_ON_FAIL)
if (flag)
return;
/* Check for anything to execute... */
if (!anythingToExecute(altInfos))
CALL1(error, M_CANT0)
/* Now perform actions! First try any BEFORE or ONLY from inside out */
for (altIndex = lastAltInfoIndex(altInfos); altIndex >= 0; altIndex--) {
if (altInfos[altIndex].alt != nullptr) // TODO Can this ever be NULL? Why?
if (altInfos[altIndex].alt->qual == (Aword)Q_BEFORE
|| altInfos[altIndex].alt->qual == (Aword)Q_ONLY) {
FUNC1(executedOk, flag, &altInfos[altIndex])
if (!flag)
CALL0(abortPlayerCommand)
if (altInfos[altIndex].alt->qual == (Aword)Q_ONLY)
return;
}
}
/* Then execute any not declared as AFTER, i.e. the default */
for (altIndex = 0; !altInfos[altIndex].end; altIndex++) {
if (altInfos[altIndex].alt != nullptr) {
if (altInfos[altIndex].alt->qual != (Aword)Q_AFTER) {
FUNC1(executedOk, flag, &altInfos[altIndex])
if (!flag)
CALL0(abortPlayerCommand)
}
}
}
/* Finally, the ones declared as AFTER */
for (altIndex = lastAltInfoIndex(altInfos); altIndex >= 0; altIndex--) {
if (altInfos[altIndex].alt != nullptr) {
FUNC1(executedOk, flag, &altInfos[altIndex])
if (!flag)
CALL0(abortPlayerCommand)
}
}
}
/*======================================================================
action()
Execute the command. Handles acting on multiple items
such as ALL, THEM or lists of objects.
*/
void action(CONTEXT, int verb, Parameter parameters[], Parameter multipleMatches[]) {
int multiplePosition;
char marker[10];
multiplePosition = findMultiplePosition(parameters);
if (multiplePosition != -1) {
Common::sprintf_s(marker, "($%d)", multiplePosition + 1); /* Prepare a printout with $1/2/3 */
for (int i = 0; !isEndOfArray(&multipleMatches[i]); i++) {
copyParameter(&parameters[multiplePosition], &multipleMatches[i]);
setGlobalParameters(parameters); /* Need to do this here since the marker use them */
output(marker);
// WARNING: The original did a temporary grabbing of the returnLabel setjmp point here.
// Which is why I manually check the context return instead of using the CALL macro
executeCommand(context, verb, parameters);
if (context._break && context._label.hasPrefix("return"))
context._break = false;
if (context._break)
return;
if (multipleMatches[i + 1].instance != EOD)
para();
}
parameters[multiplePosition].instance = 0;
} else {
setGlobalParameters(parameters);
CALL2(executeCommand, verb, parameters)
}
}
} // End of namespace Alan3
} // End of namespace Glk

38
engines/glk/alan3/act.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/>.
*
*/
#ifndef GLK_ALAN3_ACT
#define GLK_ALAN3_ACT
/* Header file for action unit of ARUN Alan System interpreter */
#include "glk/jumps.h"
#include "glk/alan3/params.h"
namespace Glk {
namespace Alan3 {
extern void action(CONTEXT, int verb, Parameter *parameters, Parameter *multipleMatches);
} // End of namespace Alan3
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,81 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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/alan3/actor.h"
#include "glk/alan3/instance.h"
#include "glk/alan3/memory.h"
#include "glk/alan3/lists.h"
#include "glk/alan3/inter.h"
#include "glk/alan3/msg.h"
#include "glk/alan3/container.h"
namespace Glk {
namespace Alan3 {
/*======================================================================*/
ScriptEntry *scriptOf(int actor) {
ScriptEntry *scr;
if (admin[actor].script != 0) {
for (scr = (ScriptEntry *) pointerTo(header->scriptTableAddress); !isEndOfArray(scr); scr++)
if (scr->code == admin[actor].script)
break;
if (!isEndOfArray(scr))
return scr;
}
return nullptr;
}
/*======================================================================*/
StepEntry *stepOf(int actor) {
StepEntry *step;
ScriptEntry *scr = scriptOf(actor);
if (scr == nullptr) return nullptr;
step = (StepEntry *)pointerTo(scr->steps);
step = &step[admin[actor].step];
return step;
}
/*======================================================================*/
void describeActor(CONTEXT, int actor) {
ScriptEntry *script = scriptOf(actor);
if (script != nullptr && script->description != 0) {
CALL1(interpret, script->description)
} else if (hasDescription(actor)) {
CALL1(describeAnything, actor)
} else {
printMessageWithInstanceParameter(M_SEE_START, actor);
printMessage(M_SEE_END);
if (instances[actor].container != 0)
CALL1(describeContainer, actor)
}
admin[actor].alreadyDescribed = TRUE;
}
} // End of namespace Alan3
} // End of namespace Glk

39
engines/glk/alan3/actor.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_ALAN3_ACTOR
#define GLK_ALAN3_ACTOR
#include "glk/alan3/acode.h"
#include "glk/jumps.h"
namespace Glk {
namespace Alan3 {
/* FUNCTIONS */
extern ScriptEntry *scriptOf(int actor);
extern StepEntry *stepOf(int actor);
extern void describeActor(CONTEXT, int actor);
} // End of namespace Alan3
} // End of namespace Glk
#endif

124
engines/glk/alan3/alan3.cpp Normal file
View File

@@ -0,0 +1,124 @@
/* 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/alan3/alan3.h"
#include "glk/alan3/exe.h"
#include "glk/alan3/main.h"
#include "glk/alan3/glkio.h"
#include "glk/alan3/options.h"
#include "glk/alan3/output.h"
#include "glk/alan3/save.h"
#include "glk/alan3/syserr.h"
#include "common/system.h"
#include "common/error.h"
#include "common/scummsys.h"
#include "common/serializer.h"
#include "glk/glk.h"
#include "glk/streams.h"
namespace Glk {
namespace Alan3 {
Alan3 *g_vm = nullptr;
Alan3::Alan3(OSystem *syst, const GlkGameDescription &gameDesc) : GlkIO(syst, gameDesc) {
g_vm = this;
// main
codfil = nullptr;
textFile = nullptr;
memory = nullptr;
// exe
printFlag = false;
// options
verboseOption = false;
ignoreErrorOption = false;
debugOption = false;
traceSectionOption = false;
tracePushOption = false;
traceStackOption = false;
traceSourceOption = false;
traceInstructionOption = false;
transcriptOption = false;
logOption = false;
statusLineOption = true;
regressionTestOption = false;
// output
anyOutput = false;
capitalize = false;
needSpace = false;
skipSpace = false;
// syserr
setSyserrHandler(nullptr);
}
void Alan3::runGame() {
if (initialize())
Glk::Alan3::run();
deinitialize();
}
bool Alan3::initialize() {
if (!GlkIO::initialize())
syserr("FATAL ERROR: Cannot open initial window");
// Set up adventure name
_advName = getFilename();
if (_advName.size() > 4 && _advName[_advName.size() - 4] == '.')
_advName = Common::String(_advName.c_str(), _advName.size() - 4);
// In Alan 3, the text data comes from the adventure file itself
Common::File *txt = new Common::File();
if (!txt->open(Common::Path(getFilename()))) {
GUIErrorMessage("Could not open adventure file for text data");
delete txt;
return false;
}
textFile = txt;
// Set up the code file to point to the already opened game file
codfil = &_gameFile;
return true;
}
void Alan3::deinitialize() {
free(memory);
delete textFile;
// delete logfil;
}
Common::Error Alan3::readSaveData(Common::SeekableReadStream *rs) {
return Glk::Alan3::restoreGame(rs) ? Common::kNoError : Common::kReadingFailed;
}
Common::Error Alan3::writeGameData(Common::WriteStream *ws) {
Glk::Alan3::saveGame(ws);
return Common::kNoError;
}
} // End of namespace Alan3
} // End of namespace Glk

83
engines/glk/alan3/alan3.h Normal file
View File

@@ -0,0 +1,83 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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 Alan 3 interpreter 3.0beta6 */
#ifndef GLK_ALAN3
#define GLK_ALAN3
#include "glk/alan3/glkio.h"
namespace Glk {
namespace Alan3 {
/**
* Alan3 game interpreter
*/
class Alan3 : public GlkIO {
public:
Common::String _advName;
private:
/**
* Initialization
*/
bool initialize();
/**
* Deinitialization
*/
void deinitialize();
public:
/**
* Constructor
*/
Alan3(OSystem *syst, const GlkGameDescription &gameDesc);
/**
* Run the game
*/
void runGame() override;
/**
* Returns the running interpreter type
*/
InterpreterType getInterpreterType() const override {
return INTERPRETER_ALAN3;
}
/**
* 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 Alan3 *g_vm;
} // End of namespace Alan3
} // 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/alan3/alan_version.h"
namespace Glk {
namespace Alan3 {
const Product alan = {
"Alan",
"Adventure Language System",
"Alan 3.0beta6",
"Alan 3.0beta6 -- Adventure Language System (2017-09-08 10:18)",
"2017-09-08",
"10:18:25",
"Thomas",
"thoni64",
"cygwin32",
{"3.0beta6", 3, 0, 6, 1504858705, "beta"}
};
} // End of namespace Alan3
} // 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_ALAN3_ALAN_VERSION
#define GLK_ALAN3_ALAN_VERSION
#include "glk/alan3/version.h"
namespace Glk {
namespace Alan3 {
extern const Product alan;
} // End of namespace Alan3
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,379 @@
/* 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/alan3/alt_info.h"
#include "glk/alan3/types.h"
#include "glk/alan3/checkentry.h"
#include "glk/alan3/debug.h"
#include "glk/alan3/inter.h"
#include "glk/alan3/glkio.h"
#include "glk/alan3/lists.h"
#include "glk/alan3/instance.h"
#include "glk/alan3/options.h"
#include "glk/alan3/memory.h"
#include "glk/alan3/current.h"
#include "glk/alan3/class.h"
#include "glk/alan3/params.h"
#include "glk/alan3/literal.h"
#include "glk/alan3/syntax.h"
namespace Glk {
namespace Alan3 {
/* Types */
typedef AltInfo *AltInfoFinder(int verb, Parameter parameters[]);
/*======================================================================*/
void primeAltInfo(AltInfo *altInfo, int level, int parameter, int instance, int cls) {
altInfo->level = level;
altInfo->parameter = parameter;
altInfo->instance = instance;
altInfo->_class = cls;
altInfo->done = FALSE;
altInfo->end = FALSE;
}
/*----------------------------------------------------------------------*/
static void traceInstanceAndItsClass(CONTEXT, Aid instance, Aid cls) {
CALL1(traceSay, instance)
printf("[%d]", instance);
if (cls != NO_CLASS)
printf(", inherited from %s[%d]", idOfClass(cls), cls);
}
/*----------------------------------------------------------------------*/
static void traceAltInfo(CONTEXT, AltInfo *alt) {
switch (alt->level) {
case GLOBAL_LEVEL:
printf("GLOBAL");
break;
case LOCATION_LEVEL:
printf("in (location) ");
CALL2(traceInstanceAndItsClass, current.location, alt->_class)
break;
case PARAMETER_LEVEL: {
char *parameterName = parameterNameInSyntax(current.verb, alt->parameter);
if (parameterName != nullptr)
printf("in parameter %s(#%d)=", parameterName, alt->parameter);
else
printf("in parameter #%d=", alt->parameter);
CALL2(traceInstanceAndItsClass, globalParameters[alt->parameter - 1].instance, alt->_class)
break;
}
default:
break;
}
}
/*----------------------------------------------------------------------*/
static void traceVerbCheck(CONTEXT, AltInfo *alt, bool execute) {
if (traceSectionOption && execute) {
printf("\n<VERB %d, ", current.verb);
CALL1(traceAltInfo, alt)
printf(", CHECK:>\n");
}
}
/*======================================================================*/
bool checkFailed(CONTEXT, AltInfo *altInfo, bool execute) {
if (altInfo->alt != nullptr && altInfo->alt->checks != 0) {
R0CALL2(traceVerbCheck, altInfo, execute)
// TODO Why does this not generate a regression error with !
// Need a new regression case?
R0FUNC2(checksFailed, fail, altInfo->alt->checks, execute)
return fail;
}
return FALSE;
}
/*----------------------------------------------------------------------*/
static void traceVerbExecution(CONTEXT, AltInfo *alt) {
if (traceSectionOption) {
printf("\n<VERB %d, ", current.verb);
CALL1(traceAltInfo, alt)
printf(", DOES");
switch (alt->alt->qual) {
case Q_BEFORE:
printf(" (BEFORE)");
break;
case Q_ONLY:
printf(" (ONLY)");
break;
case Q_AFTER:
printf(" (AFTER)");
break;
case Q_DEFAULT:
default:
break;
}
printf(":>\n");
}
}
/*======================================================================*/
bool executedOk(CONTEXT, AltInfo *altInfo) {
fail = FALSE;
if (!altInfo->done && altInfo->alt->action != 0) {
R0CALL1(traceVerbExecution, altInfo)
current.instance = altInfo->instance;
R0CALL1(interpret, altInfo->alt->action)
}
altInfo->done = TRUE;
return !fail;
}
/*======================================================================*/
bool canBeExecuted(AltInfo *altInfo) {
return altInfo->alt != nullptr && altInfo->alt->action != 0;
}
/*======================================================================*/
AltInfo *duplicateAltInfoArray(AltInfo original[]) {
int size;
AltInfo *duplicate;
for (size = 0; original[size].end != TRUE; size++)
;
size++;
duplicate = (AltInfo *)allocate(size * sizeof(AltInfo));
memcpy(duplicate, original, size * sizeof(AltInfo));
return duplicate;
}
/*======================================================================*/
int lastAltInfoIndex(AltInfo altInfo[]) {
int altIndex;
/* Loop to last alternative */
for (altIndex = -1; !altInfo[altIndex + 1].end; altIndex++)
;
return altIndex;
}
/*----------------------------------------------------------------------*/
static AltInfo *nextFreeAltInfo(AltInfoArray altInfos) {
return &altInfos[lastAltInfoIndex(altInfos) + 1];
}
/*----------------------------------------------------------------------*/
static void addAlternative(AltInfoArray altInfos, int verb, int level, Aint parameterNumber, Aint theClass, Aid theInstance, AltEntryFinder finder) {
AltInfo *altInfoP = nextFreeAltInfo(altInfos);
altInfoP->alt = (*finder)(verb, parameterNumber, theInstance, theClass);
if (altInfoP->alt != nullptr) {
primeAltInfo(altInfoP, level, parameterNumber, theInstance, theClass);
altInfoP[1].end = TRUE;
}
}
/*----------------------------------------------------------------------*/
static void addGlobalAlternatives(AltInfoArray altInfos, int verb, AltEntryFinder finder) {
addAlternative(altInfos, verb, GLOBAL_LEVEL, NO_PARAMETER, NO_CLASS, NO_INSTANCE, finder);
}
/*----------------------------------------------------------------------*/
static void addAlternativesFromParents(AltInfoArray altInfos, int verb, int level, Aint parameterNumber, Aint theClass, Aid theInstance, AltEntryFinder finder) {
if (classes[theClass].parent != 0)
addAlternativesFromParents(altInfos, verb, level,
parameterNumber,
classes[theClass].parent,
theInstance,
finder);
addAlternative(altInfos, verb, level, parameterNumber, theClass, theInstance, finder);
}
/*----------------------------------------------------------------------*/
static void addAlternativesFromLocation(AltInfoArray altInfos, int verb, Aid location, AltEntryFinder finder) {
if (admin[location].location != 0)
addAlternativesFromLocation(altInfos, verb, admin[location].location, finder);
addAlternativesFromParents(altInfos, verb,
LOCATION_LEVEL,
NO_PARAMETER,
instances[location].parent,
location,
finder);
addAlternative(altInfos, verb, LOCATION_LEVEL, NO_PARAMETER, NO_CLASS, location, finder);
}
/*----------------------------------------------------------------------*/
static void addAlternativesFromParameter(AltInfoArray altInfos, int verb, Parameter parameters[], int parameterNumber, AltEntryFinder finder) {
Aid parent;
Aid theInstance = parameters[parameterNumber - 1].instance;
if (isLiteral(theInstance))
parent = literals[literalFromInstance(theInstance)]._class;
else
parent = instances[theInstance].parent;
addAlternativesFromParents(altInfos, verb, PARAMETER_LEVEL, parameterNumber, parent, theInstance, finder);
if (!isLiteral(theInstance))
addAlternative(altInfos, verb, PARAMETER_LEVEL, parameterNumber, NO_CLASS, theInstance, finder);
}
/*======================================================================*/
bool anyCheckFailed(CONTEXT, AltInfoArray altInfo, bool execute) {
int altIndex;
bool flag;
if (altInfo != nullptr)
for (altIndex = 0; !altInfo[altIndex].end; altIndex++) {
current.instance = altInfo[altIndex].instance;
R0FUNC2(checkFailed, flag, &altInfo[altIndex], execute)
return flag;
}
return FALSE;
}
/*======================================================================*/
bool anythingToExecute(AltInfo altInfo[]) {
int altIndex;
/* Check for anything to execute... */
if (altInfo != nullptr)
for (altIndex = 0; !altInfo[altIndex].end; altIndex++)
if (canBeExecuted(&altInfo[altIndex]))
return TRUE;
return FALSE;
}
/*----------------------------------------------------------------------*/
static VerbEntry *findVerbEntry(int verbCode, VerbEntry *entries) {
VerbEntry *verbEntry;
for (verbEntry = entries; !isEndOfArray(verbEntry); verbEntry++) {
if (verbEntry->code < 0) {
/* Verb codes are negative for Meta verbs, if so they are also 1 off to avoid EOD */
if (abs(verbEntry->code) - 1 == verbCode)
return verbEntry;
} else {
if (verbEntry->code == verbCode)
return verbEntry;
}
}
return nullptr;
}
/*----------------------------------------------------------------------*/
static AltEntry *findAlternative(Aaddr verbTableAddress, int verbCode, int parameterNumber) {
AltEntry *alt;
VerbEntry *verbEntry;
if (verbTableAddress == 0) return nullptr;
verbEntry = findVerbEntry(verbCode, (VerbEntry *) pointerTo(verbTableAddress));
if (verbEntry != nullptr)
for (alt = (AltEntry *) pointerTo(verbEntry->alts); !isEndOfArray(alt); alt++) {
if (alt->param == parameterNumber || alt->param == 0) {
if (verbEntry->code < 0) current.meta = TRUE;
return alt;
}
}
return nullptr;
}
/*----------------------------------------------------------------------*/
static AltEntry *alternativeFinder(int verb, int parameterNumber, int theInstance, int theClass) {
if ((Aword)theClass != NO_CLASS)
return findAlternative(classes[theClass].verbs, verb, parameterNumber);
else if ((Aword)theInstance != NO_INSTANCE)
return findAlternative(instances[theInstance].verbs, verb, parameterNumber);
else
return findAlternative(header->verbTableAddress, verb, parameterNumber);
}
/*======================================================================*/
AltInfo *findAllAlternatives(int verb, Parameter parameters[]) {
int parameterNumber;
AltInfo altInfos[1000];
altInfos[0].end = TRUE;
addGlobalAlternatives(altInfos, verb, &alternativeFinder);
addAlternativesFromLocation(altInfos, verb, current.location, &alternativeFinder);
for (parameterNumber = 1; !isEndOfArray(&parameters[parameterNumber - 1]); parameterNumber++) {
addAlternativesFromParameter(altInfos, verb, parameters, parameterNumber, &alternativeFinder);
}
return duplicateAltInfoArray(altInfos);
}
/*----------------------------------------------------------------------*/
static bool possibleWithFinder(CONTEXT, int verb, Parameter parameters[], AltInfoFinder *finder) {
bool anything;
AltInfo *allAlternatives;
bool flag;
allAlternatives = finder(verb, parameters);
// TODO Need to do this since anyCheckFailed() call execute() which assumes the global parameters
setGlobalParameters(parameters);
R0FUNC2(anyCheckFailed, flag, allAlternatives, DONT_EXECUTE_CHECK_BODY_ON_FAIL)
if (flag)
anything = FALSE;
else
anything = anythingToExecute(allAlternatives);
if (allAlternatives != nullptr)
deallocate(allAlternatives);
return (anything);
}
/*======================================================================*/
bool possible(CONTEXT, int verb, Parameter inParameters[], ParameterPosition parameterPositions[]) {
// This is a wrapper for possibleWithFinder() which is used in unit tests
// possible() should be used "for real".
return possibleWithFinder(context, verb, inParameters, findAllAlternatives);
}
} // End of namespace Alan3
} // End of namespace Glk

View File

@@ -0,0 +1,88 @@
/* 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_ALAN3_ALT_INFO
#define GLK_ALAN3_ALT_INFO
/* An info node about the Verb Alternatives found and possibly executed */
#include "glk/alan3/types.h"
#include "glk/alan3/acode.h"
#include "glk/jumps.h"
#include "glk/alan3/params.h"
#include "glk/alan3/parameter_position.h"
namespace Glk {
namespace Alan3 {
/* Constants */
#define GLOBAL_LEVEL (0)
#define LOCATION_LEVEL (1)
#define PARAMETER_LEVEL (2)
#define NO_PARAMETER ((Aword)-1)
#define NO_INSTANCE ((Aword)-1)
#define NO_CLASS ((Aword)-1)
/* tryCheck() flags */
#define EXECUTE_CHECK_BODY_ON_FAIL TRUE
#define DONT_EXECUTE_CHECK_BODY_ON_FAIL FALSE
/* Types */
struct AltInfo {
bool end; /* Indicator of end in AltInfoArray, first empty has TRUE here */
AltEntry *alt;
bool done;
Aint level; /* 0 - Global, 1 - location, 2 - parameter */
Aid _class; /* In which class, only used for tracing */
Aid instance; /* In which instance the Alternative was found,
used to set current.instance and tracing */
Aid parameter; /* In which parameter, only used for tracing */
};
typedef AltEntry *(*AltEntryFinder)(int verb, int parameterNumber, int theInstance, int theClass);
typedef AltInfo AltInfoArray[];
/* Data */
/* Functions */
extern void primeAltInfo(AltInfo *altInfo, int level, int parameter, int instance, int cls);
extern bool executedOk(CONTEXT, AltInfo *altInfo);
extern bool checkFailed(CONTEXT, AltInfo *altInfo, bool execute);
extern bool canBeExecuted(AltInfo *altInfo);
extern AltInfo *duplicateAltInfoArray(AltInfoArray altInfos);
extern int lastAltInfoIndex(AltInfoArray altInfos);
extern bool anyCheckFailed(CONTEXT, AltInfoArray altInfos, bool execute);
extern bool anythingToExecute(AltInfoArray altInfos);
extern bool possible(CONTEXT, int verb, Parameter parameters[], ParameterPosition parameterPositions[]);
extern AltInfo *findAllAlternatives(int verb, Parameter parameters[]);
} // End of namespace Alan3
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,59 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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/alan3/attribute.h"
#include "glk/alan3/syserr.h"
#include "glk/alan3/current.h"
#include "glk/alan3/lists.h"
namespace Glk {
namespace Alan3 {
/*----------------------------------------------------------------------*/
static AttributeEntry *findAttribute(AttributeEntry *attributeTable, int attributeCode) {
AttributeEntry *attribute = attributeTable;
while (attribute->code != attributeCode) {
attribute++;
if (isEndOfArray(attribute))
syserr("Attribute not found.");
}
return attribute;
}
/*======================================================================*/
Aptr getAttribute(AttributeEntry *attributeTable, int attributeCode) {
AttributeEntry *attribute = findAttribute(attributeTable, attributeCode);
return attribute->value;
}
/*======================================================================*/
void setAttribute(AttributeEntry *attributeTable, int attributeCode, Aptr newValue) {
AttributeEntry *attribute = findAttribute(attributeTable, attributeCode);
attribute->value = newValue;
gameStateChanged = TRUE;
}
} // End of namespace Alan3
} // End of namespace Glk

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_ALAN3_ATTRIBUTE
#define GLK_ALAN3_ATTRIBUTE
#include "glk/alan3/acode.h"
namespace Glk {
namespace Alan3 {
/* FUNCTIONS */
extern Aptr getAttribute(AttributeEntry *attributeTable, int attributeCode);
extern void setAttribute(AttributeEntry *attributeTable, int attributeCode, Aptr newValue);
} // End of namespace Alan3
} // End of namespace Glk
#endif

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/>.
*
*/
#include "glk/alan3/checkentry.h"
#include "glk/alan3/inter.h"
#include "glk/alan3/lists.h"
#include "glk/alan3/memory.h"
namespace Glk {
namespace Alan3 {
bool checksFailed(CONTEXT, Aaddr adr, bool execute) {
CheckEntry *chk = (CheckEntry *) pointerTo(adr);
bool flag;
if (chk->exp == 0) {
if (execute == EXECUTE_CHECK_BODY_ON_FAIL)
R0CALL1(interpret, chk->stms)
return TRUE;
} else {
while (!isEndOfArray(chk)) {
R0FUNC1(evaluate, flag, chk->exp)
if (!flag) {
if (execute == EXECUTE_CHECK_BODY_ON_FAIL)
R0CALL1(interpret, chk->stms)
return TRUE;
}
chk++;
}
return FALSE;
}
}
} // End of namespace Alan3
} // End of namespace Glk

View File

@@ -0,0 +1,56 @@
/* 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_ALAN3_CHECKENTRY
#define GLK_ALAN3_CHECKENTRY
#include "glk/alan3/types.h"
#include "glk/alan3/acode.h"
#include "glk/jumps.h"
namespace Glk {
namespace Alan3 {
/* CONSTANTS */
#ifndef EXECUTE_CHECK_BODY_ON_FAIL
#define EXECUTE_CHECK_BODY_ON_FAIL TRUE
#define DONT_EXECUTE_CHECK_BODY_ON_FAIL FALSE
#endif
/* TYPES */
struct CheckEntry { /* CHECK TABLE */
Aaddr exp; /* ACODE address to expression code */
Aaddr stms; /* ACODE address to statement code */
};
/* DATA */
typedef CheckEntry CheckEntryArray[];
/* FUNCTIONS */
extern bool checksFailed(CONTEXT, Aaddr adr, bool execute);
} // End of namespace Alan3
} // End of namespace Glk
#endif

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/>.
*
*/
#include "glk/alan3/class.h"
#include "glk/alan3/types.h"
namespace Glk {
namespace Alan3 {
/* PUBLIC DATA */
ClassEntry *classes; /* Class table pointer */
/*======================================================================*/
char *idOfClass(int theClass) {
return (char *)pointerTo(classes[theClass].id);
}
} // End of namespace Alan3
} // End of namespace Glk

39
engines/glk/alan3/class.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_ALAN3_CLASS
#define GLK_ALAN3_CLASS
#include "glk/alan3/acode.h"
namespace Glk {
namespace Alan3 {
/* DATA */
extern ClassEntry *classes; /* Class table pointer */
/* FUNCTIONS */
extern char *idOfClass(int theClass);
} // End of namespace Alan3
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,68 @@
/* 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/alan3/compatibility.h"
namespace Glk {
namespace Alan3 {
/*----------------------------------------------------------------------*/
static bool is3_0Alpha(const byte version[]) {
return version[3] == 3 && version[2] == 0 && version[0] == 'a';
}
/*----------------------------------------------------------------------*/
static bool is3_0Beta(const byte version[]) {
return version[3] == 3 && version[2] == 0 && version[0] == 'b';
}
/*----------------------------------------------------------------------*/
static int correction(const byte version[]) {
return version[1];
}
/*======================================================================*/
bool isPreAlpha5(const byte version[4]) {
return is3_0Alpha(version) && correction(version) < 5;
}
/*======================================================================*/
bool isPreBeta2(const byte version[4]) {
return is3_0Alpha(version) || (is3_0Beta(version) && correction(version) == 1);
}
/*======================================================================*/
bool isPreBeta3(const byte version[4]) {
return is3_0Alpha(version) || (is3_0Beta(version) && correction(version) <= 2);
}
/*======================================================================*/
bool isPreBeta4(const byte version[4]) {
return is3_0Alpha(version) || (is3_0Beta(version) && correction(version) <= 3);
}
/*======================================================================*/
bool isPreBeta5(const byte version[4]) {
return is3_0Alpha(version) || (is3_0Beta(version) && correction(version) <= 4);
}
} // End of namespace Alan3
} // 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_ALAN3_COMPATIBILITY
#define GLK_ALAN3_COMPATIBILITY
#include "glk/alan3/types.h"
namespace Glk {
namespace Alan3 {
/* FUNCTIONS: */
extern bool isPreAlpha5(const byte version[4]);
extern bool isPreBeta2(const byte version[4]);
extern bool isPreBeta3(const byte version[4]);
extern bool isPreBeta4(const byte version[4]);
extern bool isPreBeta5(const byte version[4]);
extern char *decodedGameVersion(const byte version[]);
} // End of namespace Alan3
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,185 @@
/* 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/alan3/container.h"
#include "glk/alan3/instance.h"
#include "glk/alan3/syserr.h"
#include "glk/alan3/inter.h"
#include "glk/alan3/lists.h"
#include "glk/alan3/memory.h"
#include "glk/alan3/current.h"
#include "glk/alan3/msg.h"
#include "glk/alan3/output.h"
namespace Glk {
namespace Alan3 {
/* PUBLIC DATA */
ContainerEntry *containers; /* Container table pointer */
/*----------------------------------------------------------------------*/
static int countInContainer(int containerIndex) { /* IN - the container to count in */
int j = 0;
for (uint instanceIndex = 1; instanceIndex <= header->instanceMax; instanceIndex++)
if (isIn(instanceIndex, containerIndex, DIRECT))
/* Then it's in this container also */
j++;
return (j);
}
/*----------------------------------------------------------------------*/
static int sumAttributeInContainer(
Aint containerIndex, /* IN - the container to sum */
Aint attributeIndex /* IN - the attribute to sum over */
) {
uint instanceIndex;
int sum = 0;
for (instanceIndex = 1; instanceIndex <= header->instanceMax; instanceIndex++)
if (isIn(instanceIndex, containerIndex, DIRECT)) { /* Then it's directly in this cont */
if (instances[instanceIndex].container != 0) /* This is also a container! */
sum = sum + sumAttributeInContainer(instanceIndex, attributeIndex);
sum = sum + getInstanceAttribute(instanceIndex, attributeIndex);
}
return (sum);
}
/*----------------------------------------------------------------------*/
static bool containerIsEmpty(int container) {
uint i;
for (i = 1; i <= header->instanceMax; i++)
if (isDescribable(i) && isIn(i, container, TRANSITIVE))
return FALSE;
return TRUE;
}
/*======================================================================*/
void describeContainer(CONTEXT, int container) {
if (!containerIsEmpty(container) && !isOpaque(container))
CALL1(list, container)
}
/*======================================================================*/
bool passesContainerLimits(CONTEXT, Aint theContainer, Aint theAddedInstance) {
LimitEntry *limit;
Aword props;
if (!isAContainer(theContainer))
syserr("Checking limits for a non-container.");
/* Find the container properties */
props = instances[theContainer].container;
if (containers[props].limits != 0) { /* Any limits at all? */
for (limit = (LimitEntry *) pointerTo(containers[props].limits); !isEndOfArray(limit); limit++)
if ((int)limit->atr == 1 - I_COUNT) { /* TODO This is actually some encoding of the attribute number, right? */
if (countInContainer(theContainer) >= (int)limit->val) {
R0CALL1(interpret, limit->stms)
return (FALSE);
}
} else {
if (sumAttributeInContainer(theContainer, limit->atr) + getInstanceAttribute(theAddedInstance, limit->atr) > limit->val) {
R0CALL1(interpret, limit->stms)
return (FALSE);
}
}
}
return (TRUE);
}
/*======================================================================*/
int containerSize(int container, ATrans trans) {
Aword i;
Aint count = 0;
for (i = 1; i <= header->instanceMax; i++) {
if (isIn(i, container, trans))
count++;
}
return (count);
}
/*======================================================================*/
void list(CONTEXT, int container) {
uint i;
Aword props;
Aword foundInstance[2] = {0, 0};
int found = 0;
Aint previousThis = current.instance;
current.instance = container;
/* Find container table entry */
props = instances[container].container;
if (props == 0) syserr("Trying to list something not a container.");
for (i = 1; i <= header->instanceMax; i++) {
if (isDescribable(i)) {
/* We can only see objects and actors directly in this container... */
if (admin[i].location == container) { /* Yes, it's in this container */
if (found == 0) {
if (containers[props].header != 0) {
CALL1(interpret, containers[props].header)
} else {
if (isAActor(containers[props].owner))
printMessageWithInstanceParameter(M_CARRIES, containers[props].owner);
else
printMessageWithInstanceParameter(M_CONTAINS, containers[props].owner);
}
foundInstance[0] = i;
} else if (found == 1)
foundInstance[1] = i;
else {
printMessageWithInstanceParameter(M_CONTAINS_COMMA, i);
}
found++;
}
}
}
if (found > 0) {
if (found > 1)
printMessageWithInstanceParameter(M_CONTAINS_AND, foundInstance[1]);
printMessageWithInstanceParameter(M_CONTAINS_END, foundInstance[0]);
} else {
if (containers[props].empty != 0) {
CALL1(interpret, containers[props].empty)
} else {
if (isAActor(containers[props].owner))
printMessageWithInstanceParameter(M_EMPTYHANDED, containers[props].owner);
else
printMessageWithInstanceParameter(M_EMPTY, containers[props].owner);
}
}
needSpace = TRUE;
current.instance = previousThis;
}
} // End of namespace Alan3
} // End of namespace Glk

View File

@@ -0,0 +1,45 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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_ALAN3_CONTAINER
#define GLK_ALAN3_CONTAINER
#include "glk/alan3/types.h"
#include "glk/alan3/acode.h"
#include "glk/jumps.h"
namespace Glk {
namespace Alan3 {
/* DATA */
extern ContainerEntry *containers; /* Container table pointer */
/* FUNCTIONS */
extern int containerSize(int container, ATrans trans);
extern bool passesContainerLimits(CONTEXT, Aint container, Aint addedInstance);
extern void describeContainer(CONTEXT, int container);
extern void list(CONTEXT, int cnt);
} // End of namespace Alan3
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,46 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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/alan3/current.h"
namespace Glk {
namespace Alan3 {
/* PUBLIC DATA */
CurVars current;
bool gameStateChanged = FALSE;
void CurVars::synchronize(Common::Serializer &s) {
s.syncAsSint32LE(syntax);
s.syncAsSint32LE(verb);
s.syncAsSint32LE(location);
s.syncAsSint32LE(actor);
s.syncAsSint32LE(instance);
s.syncAsSint32LE(tick);
s.syncAsSint32LE(score);
s.syncAsSint32LE(visits);
s.syncAsSint32LE(sourceLine);
s.syncAsSint32LE(sourceFile);
s.syncAsUint32LE(meta);
}
} // End of namespace Alan3
} // End of namespace Glk

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_ALAN3_CURRENT
#define GLK_ALAN3_CURRENT
#include "glk/alan3/types.h"
namespace Glk {
namespace Alan3 {
/* TYPES */
struct CurVars {
int syntax,
verb,
location,
actor,
instance,
tick,
score,
visits,
sourceLine,
sourceFile;
bool meta;
/**
* Save/load data from save file
*/
void synchronize(Common::Serializer &s);
};
/* DATA */
extern CurVars current;
extern bool gameStateChanged;
} // End of namespace Alan3
} // End of namespace Glk
#endif

1107
engines/glk/alan3/debug.cpp Normal file

File diff suppressed because it is too large Load Diff

58
engines/glk/alan3/debug.h Normal file
View File

@@ -0,0 +1,58 @@
/* 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_ALAN3_DEBUG
#define GLK_ALAN3_DEBUG
/* Header file for debug handler in Alan interpreter */
#include "glk/alan3/types.h"
#include "glk/jumps.h"
namespace Glk {
namespace Alan3 {
/* Types: */
struct Breakpoint {
int line;
int file;
};
/* Data: */
extern int breakpointCount;
extern Breakpoint breakpoint[];
/* Functions: */
extern void saveInfo(void);
extern void restoreInfo(void);
extern int breakpointIndex(int file, int line);
extern char *sourceFileName(int file);
extern char *readSourceLine(int file, int line);
extern void showSourceLine(int fileNumber, int line);
extern void debug(CONTEXT, bool calledFromBreakpoint, int line, int fileNumber);
extern void traceSay(CONTEXT, int item);
} // End of namespace Alan3
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,176 @@
/* 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/alan3/decode.h"
#include "glk/alan3/acode.h"
#include "glk/alan3/syserr.h"
#include "glk/alan3/exe.h"
#include "glk/alan3/memory.h"
namespace Glk {
namespace Alan3 {
/* PUBLIC DATA */
Aword *freq; /* Cumulative character frequencies */
/* PRIVATE DATA */
/* 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(void) {
int bit;
/* More bits available ? */
if (!bitsToGo) {
/* No, so get more */
decodeBuffer = (textFile->pos() >= textFile->size()) ? EOD : textFile->readByte();
if (decodeBuffer == (int)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(void) {
int i;
bitsToGo = 0;
garbageBits = 0;
value = 0;
for (i = 0; i < VALUEBITS; i++)
value = 2 * value + inputBit();
low = 0;
high = TOPVALUE;
}
int decodeChar(void) {
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 */
struct DecodeInfo {
long fpos;
int buffer;
int bits;
CodeValue value;
CodeValue high;
CodeValue low;
};
/*======================================================================
pushDecode()
Save so much info about the decoding process so it is possible to
restore and continue later.
*/
void *pushDecode(void) {
DecodeInfo *info;
info = (DecodeInfo *)allocate(sizeof(DecodeInfo));
info->fpos = textFile->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;
textFile->seek(info->fpos);
decodeBuffer = info->buffer;
bitsToGo = info->bits;
value = info->value;
high = info->high;
low = info->low;
free(info);
}
} // End of namespace Alan3
} // End of namespace Glk

View File

@@ -0,0 +1,45 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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_ALAN3_DECODE
#define GLK_ALAN3_DECODE
/* Arithmetic decoding module in Arun */
#include "glk/alan3/types.h"
namespace Glk {
namespace Alan3 {
/* DATA */
extern Aword *freq; /* Cumulated character frequencies for text decoding */
/* FUNCTIONS */
extern void startDecoding(void);
extern int decodeChar(void);
extern void *pushDecode(void);
extern void popDecode(void *info);
} // End of namespace Alan3
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,98 @@
/* 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/alan3/detection.h"
#include "glk/alan3/detection_tables.h"
#include "common/debug.h"
#include "common/file.h"
#include "common/md5.h"
#include "engines/game.h"
namespace Glk {
namespace Alan3 {
void Alan3MetaEngine::getSupportedGames(PlainGameList &games) {
for (const PlainGameDescriptor *pd = ALAN3_GAME_LIST; pd->gameId; ++pd) {
games.push_back(*pd);
}
}
const GlkDetectionEntry* Alan3MetaEngine::getDetectionEntries() {
return ALAN3_GAMES;
}
GameDescriptor Alan3MetaEngine::findGame(const char *gameId) {
for (const PlainGameDescriptor *pd = ALAN3_GAME_LIST; pd->gameId; ++pd) {
if (!strcmp(gameId, pd->gameId))
return *pd;
}
return GameDescriptor::empty();
}
bool Alan3MetaEngine::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(".a3c");
if (!hasExt)
continue;
// Open up the file and calculate the md5
Common::File gameFile;
if (!gameFile.open(*file) || gameFile.readUint32BE() != MKTAG('A', 'L', 'A', 'N'))
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 = ALAN3_GAMES;
while (p->_gameId && (md5 != p->_md5 || filesize != p->_filesize))
++p;
if (!p->_gameId) {
const PlainGameDescriptor &desc = ALAN3_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, filename));
}
}
return !gameList.empty();
}
void Alan3MetaEngine::detectClashes(Common::StringMap &map) {
for (const PlainGameDescriptor *pd = ALAN3_GAME_LIST; pd->gameId; ++pd) {
if (map.contains(pd->gameId))
error("Duplicate game Id found - %s", pd->gameId);
map[pd->gameId] = "";
}
}
} // End of namespace Alan3
} // 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_ALAN3_DETECTION
#define GLK_ALAN3_DETECTION
#include "common/fs.h"
#include "common/hash-str.h"
#include "engines/game.h"
#include "glk/detection.h"
namespace Glk {
namespace Alan3 {
/**
* Meta engine for Alan3 interpreter
*/
class Alan3MetaEngine {
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 Alan3
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,74 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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/language.h"
namespace Glk {
namespace Alan3 {
const PlainGameDescriptor ALAN3_GAME_LIST[] = {
{ "alan3", "Alan3 Game" },
{ "catchcat", "Catch That Cat" },
{ "christmasparty", "The Christmas Party" },
{ "deadleaves", "City of Dead Leaves" },
{ "enterthedark", "Enter The Dark" },
{ "fishmess", "A Very Hairy Fish-Mess" },
{ "forbidden", "The Ngah Angah School of Forbidden Wisdom" },
{ "hwmurders", "Hollywood Murders" },
{ "indigosoul", "IN-D-I-GO SOUL" },
{ "misguided", "Mis/Guided" },
{ "onaar", "Onaar" },
{ "room206", "Room 206" },
{ "tedpaladin", "Ted Paladin And The Case Of The Abandoned House" },
{ "tedstrikesback", "Ted Strikes Back" },
{ "thesealedroom", "The Sealed Room" },
{ "vrgambler", "VR Gambler" },
{ "waldospie", "Waldo's Pie" },
{ "wyldkyndproject", "The Wyldkynd Project" },
{ nullptr, nullptr }
};
const GlkDetectionEntry ALAN3_GAMES[] = {
DT_ENTRY0("catchcat", "758325a2c46f72218a82f22736ea7017", 43878),
DT_ENTRY0("christmasparty", "86b87969d124c213632398980ec87c23", 94892),
DT_ENTRY0("deadleaves", "7c228698507508043d1d3938695e28cd", 90139),
DT_ENTRY0("enterthedark", "739add0fec3dbd18a63389826ffeba4d", 78900),
DT_ENTRY0("fishmess", "e9952cfbe2adef5dcef82abd57661f60", 312561),
DT_ENTRY0("forbidden", "8ce2b96851d43a72c84144632d6a084f", 122072),
DT_ENTRY0("hwmurders", "abadbb15faf7f0b7324222fdea6bd495", 213539),
DT_ENTRY0("indigosoul", "2c87486c4a44f5ef5a704a0b55763c61", 163903),
DT_ENTRY0("misguided", "cc2c6e724d599e731efa9b7a34ae4f51", 672613),
DT_ENTRY0("onaar", "f809531286f1757ab113fe3592a49d3b", 1516301),
DT_ENTRY0("room206", "eb5711ecfad102ee4d9fda7fcb3ddf78", 364156),
DT_ENTRY0("tedpaladin", "6132d401ea7c05b474e598a37b642bd9", 292486),
DT_ENTRY0("tedstrikesback", "6085ede584b3705370b2a689cc96419a", 407634),
DT_ENTRY0("thesealedroom", "06a81cb30efff9c63e7f7d3aff554d3d", 306937),
DT_ENTRY0("vrgambler", "c29b8276a9a1be1444193eb3724bf0fd", 938147),
DT_ENTRY0("waldospie", "fcd53ac4669f85845c1cbbaad6082724", 511956),
DT_ENTRY0("wyldkyndproject", "35b2f168cb78d7df46638dcb583f5e15", 1333195),
DT_END_MARKER
};
} // End of namespace Alan3
} // End of namespace Glk

View File

@@ -0,0 +1,134 @@
/* 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/alan3/dictionary.h"
#include "glk/alan3/word.h"
namespace Glk {
namespace Alan3 {
/* PUBLIC DATA */
DictionaryEntry *dictionary; /* Dictionary pointer */
int dictionarySize;
int conjWord; /* First conjunction in dictionary, for ',' */
/* Word class query methods, move to Word.c */
/* Word classes are numbers but in the dictionary they are generated as bits */
static bool isVerb(int wordCode) {
return wordCode < dictionarySize && (dictionary[wordCode].classBits & VERB_BIT) != 0;
}
bool isVerbWord(int wordIndex) {
return isVerb(playerWords[wordIndex].code);
}
bool isConjunction(int wordCode) {
return wordCode < dictionarySize && (dictionary[wordCode].classBits & CONJUNCTION_BIT) != 0;
}
bool isConjunctionWord(int wordIndex) {
return isConjunction(playerWords[wordIndex].code);
}
static bool isExcept(int wordCode) {
return wordCode < dictionarySize && (dictionary[wordCode].classBits & EXCEPT_BIT) != 0;
}
bool isExceptWord(int wordIndex) {
return isExcept(playerWords[wordIndex].code);
}
static bool isThem(int wordCode) {
return wordCode < dictionarySize && (dictionary[wordCode].classBits & THEM_BIT) != 0;
}
bool isThemWord(int wordIndex) {
return isThem(playerWords[wordIndex].code);
}
static bool isIt(int wordCode) {
return wordCode < dictionarySize && (dictionary[wordCode].classBits & IT_BIT) != 0;
}
bool isItWord(int wordIndex) {
return isIt(playerWords[wordIndex].code);
}
static bool isNoun(int wordCode) {
return wordCode < dictionarySize && (dictionary[wordCode].classBits & NOUN_BIT) != 0;
}
bool isNounWord(int wordIndex) {
return isNoun(playerWords[wordIndex].code);
}
static bool isAdjective(int wordCode) {
return wordCode < dictionarySize && (dictionary[wordCode].classBits & ADJECTIVE_BIT) != 0;
}
bool isAdjectiveWord(int wordIndex) {
return isAdjective(playerWords[wordIndex].code);
}
static bool isPreposition(int wordCode) {
return wordCode < dictionarySize && (dictionary[wordCode].classBits & PREPOSITION_BIT) != 0;
}
bool isPrepositionWord(int wordIndex) {
return isPreposition(playerWords[wordIndex].code);
}
bool isAll(int wordCode) {
return wordCode < dictionarySize && (dictionary[wordCode].classBits & ALL_BIT) != 0;
}
bool isAllWord(int wordIndex) {
return isAll(playerWords[wordIndex].code);
}
static bool isDir(int wordCode) {
return wordCode < dictionarySize && (dictionary[wordCode].classBits & DIRECTION_BIT) != 0;
}
bool isDirectionWord(int wordIndex) {
return isDir(playerWords[wordIndex].code);
}
bool isNoise(int wordCode) {
return wordCode < dictionarySize && (dictionary[wordCode].classBits & NOISE_BIT) != 0;
}
bool isPronoun(int wordCode) {
return wordCode < dictionarySize && (dictionary[wordCode].classBits & PRONOUN_BIT) != 0;
}
bool isPronounWord(int wordIndex) {
return isPronoun(playerWords[wordIndex].code);
}
bool isLiteralWord(int wordIndex) {
return playerWords[wordIndex].code >= dictionarySize;
}
} // End of namespace Alan3
} // End of namespace Glk

View File

@@ -0,0 +1,59 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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_ALAN3_DICTIONARY
#define GLK_ALAN3_DICTIONARY
#include "glk/alan3/acode.h"
#include "glk/alan3/types.h"
namespace Glk {
namespace Alan3 {
/* DATA */
extern DictionaryEntry *dictionary;
extern int dictionarySize;
extern int conjWord; /* First conjunction in dictionary */
/* FUNCTIONS */
extern bool isVerbWord(int wordIndex);
extern bool isConjunctionWord(int wordIndex);
extern bool isExceptWord(int wordIndex);
extern bool isThemWord(int wordIndex);
extern bool isItWord(int wordIndex);
extern bool isNounWord(int wordIndex);
extern bool isAdjectiveWord(int wordIndex);
extern bool isPrepositionWord(int wordIndex);
extern bool isAllWord(int wordIndex);
extern bool isDirectionWord(int wordIndex);
extern bool isPronounWord(int wordIndex);
extern bool isLiteralWord(int wordIndex);
extern bool isConjunction(int wordCode);
extern bool isAll(int wordCode);
extern bool isNoise(int wordCode);
extern bool isPronoun(int wordCode);
} // End of namespace Alan3
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,40 @@
/* 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/alan3/event.h"
namespace Glk {
namespace Alan3 {
/* PUBLIC DATA */
int eventQueueSize = 0;
EventQueueEntry *eventQueue = nullptr;
int eventQueueTop = 0;
EventEntry *events;
void EventQueueEntry::synchronize(Common::Serializer &s) {
s.syncAsSint32LE(after);
s.syncAsSint32LE(event);
s.syncAsSint32LE(where);
}
} // End of namespace Alan3
} // End of namespace Glk

57
engines/glk/alan3/event.h Normal file
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_ALAN3_EVENT
#define GLK_ALAN3_EVENT
#include "common/serializer.h"
#include "glk/alan3/acode.h"
#include "glk/alan3/types.h"
namespace Glk {
namespace Alan3 {
/**
* Event queue entries
*/
struct EventQueueEntry {
int after;
int event;
int where;
/**
* Save/load from a save file
*/
void synchronize(Common::Serializer &s);
};
/* DATA */
/* Event queue */
extern int eventQueueSize;
extern EventQueueEntry *eventQueue;
extern int eventQueueTop; /* Event queue top pointer */
extern EventEntry *events; /* Event table pointer */
} // End of namespace Alan3
} // End of namespace Glk
#endif

664
engines/glk/alan3/exe.cpp Normal file
View File

@@ -0,0 +1,664 @@
/* 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/alan3/exe.h"
#include "glk/alan3/actor.h"
#include "glk/alan3/alan3.h"
#include "glk/alan3/current.h"
#include "glk/alan3/decode.h"
#include "glk/alan3/event.h"
#include "glk/alan3/glkio.h"
#include "glk/alan3/lists.h"
#include "glk/alan3/instance.h"
#include "glk/alan3/inter.h"
#include "glk/alan3/memory.h"
#include "glk/alan3/msg.h"
#include "glk/alan3/output.h"
#include "glk/alan3/options.h"
#include "glk/alan3/save.h"
#include "glk/alan3/score.h"
#include "glk/alan3/state.h"
#include "glk/alan3/syserr.h"
#include "glk/alan3/sysdep.h"
#include "glk/alan3/types.h"
#include "glk/alan3/utils.h"
#include "glk/alan3/word.h"
#include "common/stream.h"
namespace Glk {
namespace Alan3 {
// PUBLIC DATA
Common::SeekableReadStream *textFile;
// PUBLIC DATA - formerly method statics
bool printFlag; // Printing already?
/* PRIVATE CONSTANTS */
#define WIDTH 80
/*======================================================================*/
void print(Aword fpos, Aword len) {
char str[2 * WIDTH]; /* String buffer */
uint outlen = 0; /* Current output length */
int ch = 0;
int i;
long savfp = 0; /* Temporary saved text file position */
bool savedPrintFlag = printFlag;
void *info = nullptr; /* Saved decoding info */
if (len == 0) return;
if (isHere(HERO, /*TRUE*/ DIRECT)) { /* Check if the player will see it */
if (printFlag) { /* Already printing? */
/* Save current text file position and/or decoding info */
if (header->pack)
info = pushDecode();
else
savfp = textFile->pos();
}
printFlag = TRUE; /* We're printing now! */
/* Position to start of text */
textFile->seek(fpos + header->stringOffset);
if (header->pack)
startDecoding();
for (outlen = 0; outlen != len; outlen = outlen + strlen(str)) {
/* Fill the buffer from the beginning */
for (i = 0; i <= WIDTH || (i > WIDTH && ch != ' '); i++) {
if (outlen + i == len) /* No more characters? */
break;
if (header->pack)
ch = decodeChar();
else
ch = textFile->readByte();
if (ch == EOFChar)
break; // Or end of text?
str[i] = ch;
}
str[i] = '\0';
output(str);
}
/* And restore */
printFlag = savedPrintFlag;
if (printFlag) {
if (header->pack)
popDecode(info);
else
textFile->seek(savfp);
}
}
}
/*======================================================================*/
void sys(Aword fpos, Aword len) {
syserr("sys calls are unsupported");
}
/*======================================================================*/
char *getStringFromFile(Aword fpos, Aword len) {
char *buf = (char *)allocate(len + 1);
char *bufp = buf;
/* Position to start of text */
textFile->seek(fpos + header->stringOffset);
if (header->pack)
startDecoding();
while (len--)
if (header->pack)
*(bufp++) = decodeChar();
else
*(bufp++) = textFile->readByte();
/* Terminate string with zero */
*bufp = '\0';
return buf;
}
/*======================================================================*/
void score(Aword sc) {
if (sc == 0) {
ParameterArray messageParameters = newParameterArray();
addParameterForInteger(messageParameters, current.score);
addParameterForInteger(messageParameters, header->maximumScore);
addParameterForInteger(messageParameters, current.tick);
printMessageWithParameters(M_SCORE, messageParameters);
freeParameterArray(messageParameters);
} else {
current.score += scores[sc - 1];
scores[sc - 1] = 0;
gameStateChanged = TRUE;
}
}
/*======================================================================*/
void visits(Aword v) {
current.visits = v;
}
/*----------------------------------------------------------------------*/
static void sayUndoneCommand(char *words) {
static Parameter *messageParameters = nullptr;
messageParameters = (Parameter *)ensureParameterArrayAllocated(messageParameters);
current.location = where(HERO, DIRECT);
clearParameterArray(messageParameters);
addParameterForString(&messageParameters[0], words);
setEndOfArray(&messageParameters[1]);
printMessageWithParameters(M_UNDONE, messageParameters);
}
/*======================================================================*/
void undo(CONTEXT) {
forgetGameState();
if (anySavedState()) {
recallGameState();
sayUndoneCommand(recreatePlayerCommand());
} else {
printMessage(M_NO_UNDO);
}
LONG_JUMP_LABEL("returnUndo")
}
/*======================================================================*/
void quitGame(CONTEXT) {
char buf[80];
bool flag;
current.location = where(HERO, DIRECT);
para();
while (!g_vm->shouldQuit()) {
col = 1;
CALL0(g_io->statusLine)
printMessage(M_QUITACTION);
FUNC2(g_io->readLine, flag, buf, 80)
if (!flag)
CALL1(terminate, 0)
if (scumm_stricmp(buf, "restart") == 0) {
LONG_JUMP_LABEL("restart")
} else if (scumm_stricmp(buf, "restore") == 0) {
g_vm->loadGame();
return;
} else if (scumm_stricmp(buf, "quit") == 0) {
CALL1(terminate, 0)
} else if (scumm_stricmp(buf, "undo") == 0) {
if (gameStateChanged) {
rememberCommands();
rememberGameState();
CALL0(undo)
} else {
if (anySavedState()) {
recallGameState();
sayUndoneCommand(playerWordsAsCommandString());
} else {
printMessage(M_NO_UNDO);
}
LONG_JUMP_LABEL("returnUndo")
}
}
}
syserr("Fallthrough in QUIT");
}
/*======================================================================*/
void restartGame(CONTEXT) {
Aint previousLocation = current.location;
current.location = where(HERO, DIRECT);
para();
bool flag;
FUNC1(confirm, flag, M_REALLY)
if (flag) {
LONG_JUMP_LABEL("restart")
}
current.location = previousLocation;
}
/*======================================================================*/
void cancelEvent(Aword theEvent) {
int i;
for (i = eventQueueTop - 1; i >= 0; i--)
if (eventQueue[i].event == (int)theEvent) {
while (i < eventQueueTop - 1) {
eventQueue[i].event = eventQueue[i + 1].event;
eventQueue[i].after = eventQueue[i + 1].after;
eventQueue[i].where = eventQueue[i + 1].where;
i++;
}
eventQueueTop--;
return;
}
}
/*----------------------------------------------------------------------*/
static void increaseEventQueue(void) {
eventQueue = (EventQueueEntry *)realloc(eventQueue, (eventQueueTop + 2) * sizeof(EventQueueEntry));
if (eventQueue == nullptr) syserr("Out of memory in increaseEventQueue()");
eventQueueSize = eventQueueTop + 2;
}
/*----------------------------------------------------------------------*/
static void moveEvent(int to, int from) {
eventQueue[to].event = eventQueue[from].event;
eventQueue[to].after = eventQueue[from].after;
eventQueue[to].where = eventQueue[from].where;
}
/*======================================================================*/
void schedule(Aword event, Aword where, Aword after) {
uint i;
if (event == 0) syserr("NULL event");
cancelEvent(event);
/* Check for overflow */
if (eventQueue == nullptr || eventQueueTop == eventQueueSize) {
increaseEventQueue();
assert(eventQueue);
}
/* Bubble this event down */
for (i = eventQueueTop; i >= 1 && eventQueue[i - 1].after <= (int)after; i--) {
moveEvent(i, i - 1);
}
eventQueue[i].after = after;
eventQueue[i].where = where;
eventQueue[i].event = event;
eventQueueTop++;
}
// TODO Move to string.c?
/*======================================================================*/
Aptr concat(Aptr as1, Aptr as2) {
char *s1 = (char *)fromAptr(as1);
char *s2 = (char *)fromAptr(as2);
size_t ln = strlen(s1) + strlen(s2) + 1;
char *result = (char *)allocate(ln);
Common::strcpy_s(result, ln, s1);
Common::strcat_s(result, ln, s2);
return toAptr(result);
}
/*----------------------------------------------------------------------*/
static char *stripCharsFromStringForwards(int count, char *initialString, char **theRest) {
int stripPosition;
char *strippedString;
char *rest;
if (count > (int)strlen(initialString))
stripPosition = strlen(initialString);
else
stripPosition = count;
rest = scumm_strdup(&initialString[stripPosition]);
strippedString = scumm_strdup(initialString);
strippedString[stripPosition] = '\0';
*theRest = rest;
return strippedString;
}
/*----------------------------------------------------------------------*/
static char *stripCharsFromStringBackwards(Aint count, char *initialString, char **theRest) {
int stripPosition;
char *strippedString;
char *rest;
if (count > (int)strlen(initialString))
stripPosition = 0;
else
stripPosition = strlen(initialString) - count;
strippedString = scumm_strdup(&initialString[stripPosition]);
rest = scumm_strdup(initialString);
rest[stripPosition] = '\0';
*theRest = rest;
return strippedString;
}
/*----------------------------------------------------------------------*/
static int countLeadingBlanks(char *string, int position) {
static char blanks[] = " ";
return strspn(&string[position], blanks);
}
/*----------------------------------------------------------------------*/
static int skipWordForwards(char *string, int position) {
char separators[] = " .,?";
uint i;
for (i = position; i <= strlen(string) && strchr(separators, string[i]) == nullptr; i++)
;
return i;
}
/*----------------------------------------------------------------------*/
static char *stripWordsFromStringForwards(Aint count, char *initialString, char **theRest) {
int skippedChars;
int position = 0;
char *stripped;
int i;
for (i = count; i > 0; i--) {
/* Ignore any initial blanks */
skippedChars = countLeadingBlanks(initialString, position);
position += skippedChars;
position = skipWordForwards(initialString, position);
}
stripped = (char *)allocate(position + 1);
strncpy(stripped, initialString, position);
stripped[position] = '\0';
skippedChars = countLeadingBlanks(initialString, position);
*theRest = scumm_strdup(&initialString[position + skippedChars]);
return (stripped);
}
/*----------------------------------------------------------------------*/
static int skipWordBackwards(char *string, int position) {
char separators[] = " .,?";
int i;
for (i = position; i > 0 && strchr(separators, string[i - 1]) == nullptr; i--)
;
return i;
}
/*----------------------------------------------------------------------*/
static int countTrailingBlanks(char *string, int position) {
int skippedChars, i;
skippedChars = 0;
if (position > (int)strlen(string) - 1)
syserr("position > length in countTrailingBlanks");
for (i = position; i >= 0 && string[i] == ' '; i--)
skippedChars++;
return (skippedChars);
}
/*----------------------------------------------------------------------*/
static char *stripWordsFromStringBackwards(Aint count, char *initialString, char **theRest) {
int skippedChars;
char *stripped;
int strippedLength;
int position = strlen(initialString);
int i;
for (i = count; i > 0 && position > 0; i--) {
position -= 1;
/* Ignore trailing blanks */
skippedChars = countTrailingBlanks(initialString, position);
if (position - skippedChars < 0) break; /* No more words to strip */
position -= skippedChars;
position = skipWordBackwards(initialString, position);
}
skippedChars = countLeadingBlanks(initialString, 0);
strippedLength = strlen(initialString) - position - skippedChars;
stripped = (char *)allocate(strippedLength + 1);
strncpy(stripped, &initialString[position + skippedChars], strippedLength);
stripped[strippedLength] = '\0';
if (position > 0) {
skippedChars = countTrailingBlanks(initialString, position - 1);
position -= skippedChars;
}
*theRest = scumm_strdup(initialString);
(*theRest)[position] = '\0';
return (stripped);
}
/*======================================================================*/
Aptr strip(bool stripFromBeginningNotEnd, int count, bool stripWordsNotChars, int id, int atr) {
char *initialString = (char *)fromAptr(getInstanceAttribute(id, atr));
char *theStripped;
char *theRest;
if (stripFromBeginningNotEnd) {
if (stripWordsNotChars)
theStripped = stripWordsFromStringForwards(count, initialString, &theRest);
else
theStripped = stripCharsFromStringForwards(count, initialString, &theRest);
} else {
if (stripWordsNotChars)
theStripped = stripWordsFromStringBackwards(count, initialString, &theRest);
else
theStripped = stripCharsFromStringBackwards(count, initialString, &theRest);
}
setInstanceStringAttribute(id, atr, theRest);
return toAptr(theStripped);
}
/*======================================================================*/
int getContainerMember(int container, int index, bool directly) {
uint i;
Aint count = 0;
for (i = 1; i <= header->instanceMax; i++) {
if (isIn(i, container, DIRECT)) {
count++;
if (count == index)
return i;
}
}
apperr("Index not in container in 'containerMember()'");
return 0;
}
/***********************************************************************\
Description Handling
\***********************************************************************/
/*======================================================================*/
void empty(CONTEXT, int cnt, int whr) {
uint i;
for (i = 1; i <= header->instanceMax; i++)
if (isIn(i, cnt, DIRECT))
CALL2(locate, i, whr)
}
/*======================================================================*/
void use(CONTEXT, int actor, int script) {
char str[80];
StepEntry *step;
if (!isAActor(actor)) {
Common::sprintf_s(str, "Instance is not an Actor (%d).", actor);
syserr(str);
}
admin[actor].script = script;
admin[actor].step = 0;
step = stepOf(actor);
if (step != nullptr && step->after != 0) {
FUNC1(evaluate, admin[actor].waitCount, step->after)
}
gameStateChanged = TRUE;
}
/*======================================================================*/
void stop(int act) {
char str[80];
if (!isAActor(act)) {
Common::sprintf_s(str, "Instance is not an Actor (%d).", act);
syserr(str);
}
admin[act].script = 0;
admin[act].step = 0;
gameStateChanged = TRUE;
}
static int randomValue = 0;
/*----------------------------------------------------------------------*/
int randomInteger(int from, int to) {
if (regressionTestOption) {
int ret = from + randomValue;
/* Generate them in sequence */
if (ret > to) {
ret = from;
randomValue = 1;
} else if (ret == to)
randomValue = 0;
else
randomValue++;
return ret;
} else {
if (to == from)
return to;
else if (to > from)
return (g_vm->getRandomNumber(0x7fffffff) / 10) % (to - from + 1) + from;
else
return (g_vm->getRandomNumber(0x7fffffff) / 10) % (from - to + 1) + to;
}
}
/*----------------------------------------------------------------------*/
bool between(int val, int low, int high) {
if (high > low)
return low <= val && val <= high;
else
return high <= val && val <= low;
}
/*======================================================================*/
bool contains(Aptr string, Aptr substring) {
bool found;
strlow((char *)fromAptr(string));
strlow((char *)fromAptr(substring));
found = (strstr((char *)fromAptr(string), (char *)fromAptr(substring)) != nullptr);
return found;
}
/*======================================================================*/
bool streq(char a[], char b[]) {
bool eq;
strlow(a);
strlow(b);
eq = (strcmp(a, b) == 0);
return eq;
}
/*======================================================================*/
void startTranscript(void) {
if (logFile == nullptr) {
Common::String filename = g_vm->getTargetName() + ".log";
uint fileUsage = transcriptOption ? fileusage_Transcript : fileusage_InputRecord;
frefid_t logFileRef = g_vm->glk_fileref_create_by_name(fileUsage, filename.c_str(), 0);
logFile = g_vm->glk_stream_open_file(logFileRef, filemode_Write, 0);
if (logFile == nullptr) {
transcriptOption = FALSE;
logOption = FALSE;
} else {
transcriptOption = TRUE;
}
}
}
/*======================================================================*/
void stopTranscript(void) {
if (logFile != nullptr) {
if (transcriptOption || logOption)
delete logFile;
logFile = nullptr;
transcriptOption = FALSE;
logOption = FALSE;
}
}
} // End of namespace Alan3
} // End of namespace Glk

89
engines/glk/alan3/exe.h Normal file
View File

@@ -0,0 +1,89 @@
/* 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_ALAN3_EXE
#define GLK_ALAN3_EXE
/* Header file for instruction execution unit in Alan interpreter */
/* IMPORTS */
#include "glk/alan3/sysdep.h"
#include "glk/jumps.h"
#include "glk/alan3/acode.h"
#include "glk/alan3/types.h"
#include "glk/alan3/set.h"
#include "common/stream.h"
namespace Glk {
namespace Alan3 {
/* CONSTANTS */
#define NO_JUMP_RETURN 0
#define ERROR_RETURN 1
#define UNDO_RETURN 2
/* DATA */
extern Common::SeekableReadStream *textFile; // The text and message file
extern bool printFlag;
/* FUNCTIONS */
extern void sys(Aword fpos, Aword len);
extern void sayInteger(int val);
extern void sayString(char *str);
extern Aptr strip(bool stripFromBeginningNotEnd, int count, bool stripWordsNotChars, int id, int atr);
extern Aptr concat(Aptr s1, Aptr s2);
extern char *getStringFromFile(Aword fpos, Aword len);
extern void print(Aword fpos, Aword len);
extern void score(Aword sc);
extern void visits(Aword v);
extern void undo(CONTEXT);
extern void quitGame(CONTEXT);
extern void restartGame(CONTEXT);
extern void use(CONTEXT, int act, int scr);
extern void stop(int act);
extern void empty(CONTEXT, int cnt, int whr);
extern int getContainerMember(int container, int index, bool directly);
extern int randomInContainer(int cont);
extern void schedule(Aword evt, Aword whr, Aword aft);
extern void cancelEvent(Aword evt);
extern int randomInteger(int from, int to);
extern bool between(int val, int from, int to);
extern bool contains(Aptr string, Aptr substring);
extern bool streq(char a[], char b[]);
extern void include(int instance, int atr, Aword member);
extern void exclude(int instance, int atr, Aword member);
extern void increase(int instance, int atr, Aword step);
extern void decrease(int instance, int atr, Aword step);
extern void startTranscript(void);
extern void stopTranscript(void);
} // End of namespace Alan3
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,234 @@
/* 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/>.
*
*/
/*-
* Copyright (c) 1989, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Guido van Rossum.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
* Compares a filename or pathname to a pattern.
*/
#include "glk/alan3/fnmatch.h"
#include "common/scummsys.h"
namespace Glk {
namespace Alan3 {
#define EOS '\0'
#define RANGE_MATCH 1
#define RANGE_NOMATCH 0
#define RANGE_ERROR (-1)
static int rangematch(const char *, char, int, char **);
int fnmatch(const char *pattern, const char *string, int flags) {
const char *stringstart;
char *newp;
char c, test;
for (stringstart = string;;)
switch (c = *pattern++) {
case EOS:
if ((flags & FNM_LEADING_DIR) && *string == '/')
return (0);
return (*string == EOS ? 0 : FNM_NOMATCH);
case '?':
if (*string == EOS)
return (FNM_NOMATCH);
if (*string == '/' && (flags & FNM_PATHNAME))
return (FNM_NOMATCH);
if (*string == '.' && (flags & FNM_PERIOD) &&
(string == stringstart ||
((flags & FNM_PATHNAME) && *(string - 1) == '/')))
return (FNM_NOMATCH);
++string;
break;
case '*':
c = *pattern;
/* Collapse multiple stars. */
while (c == '*')
c = *++pattern;
if (*string == '.' && (flags & FNM_PERIOD) &&
(string == stringstart ||
((flags & FNM_PATHNAME) && *(string - 1) == '/')))
return (FNM_NOMATCH);
/* Optimize for pattern with * at end or before /. */
if (c == EOS)
if (flags & FNM_PATHNAME)
return ((flags & FNM_LEADING_DIR) ||
strchr(string, '/') == nullptr ?
0 : FNM_NOMATCH);
else
return (0);
else if (c == '/' && flags & FNM_PATHNAME) {
if ((string = strchr(string, '/')) == nullptr)
return (FNM_NOMATCH);
break;
}
/* General case, use recursion. */
while ((test = *string) != EOS) {
if (!fnmatch(pattern, string, flags & ~FNM_PERIOD))
return (0);
if (test == '/' && flags & FNM_PATHNAME)
break;
++string;
}
return (FNM_NOMATCH);
case '[':
if (*string == EOS)
return (FNM_NOMATCH);
if (*string == '/' && (flags & FNM_PATHNAME))
return (FNM_NOMATCH);
if (*string == '.' && (flags & FNM_PERIOD) &&
(string == stringstart ||
((flags & FNM_PATHNAME) && *(string - 1) == '/')))
return (FNM_NOMATCH);
switch (rangematch(pattern, *string, flags, &newp)) {
case RANGE_ERROR:
goto norm;
case RANGE_MATCH:
pattern = newp;
break;
case RANGE_NOMATCH:
return (FNM_NOMATCH);
default:
break;
}
++string;
break;
case '\\':
if (!(flags & FNM_NOESCAPE)) {
if ((c = *pattern++) == EOS) {
c = '\\';
--pattern;
}
}
/* FALLTHROUGH */
default:
norm:
if (c == *string)
;
else if ((flags & FNM_CASEFOLD) &&
(tolower((unsigned char)c) ==
tolower((unsigned char)*string)))
;
else
return (FNM_NOMATCH);
string++;
break;
}
/* NOTREACHED */
}
static int
rangematch(const char *pattern, char test, int flags, char **newp) {
int negate, ok;
char c, c2;
/*
* A bracket expression starting with an unquoted circumflex
* character produces unspecified results (IEEE 1003.2-1992,
* 3.13.2). This implementation treats it like '!', for
* consistency with the regular expression syntax.
* J.T. Conklin (conklin@ngai.kaleida.com)
*/
if ((negate = (*pattern == '!' || *pattern == '^')))
++pattern;
if (flags & FNM_CASEFOLD)
test = tolower((unsigned char)test);
/*
* A right bracket shall lose its special meaning and represent
* itself in a bracket expression if it occurs first in the list.
* -- POSIX.2 2.8.3.2
*/
ok = 0;
c = *pattern++;
do {
if (c == '\\' && !(flags & FNM_NOESCAPE))
c = *pattern++;
if (c == EOS)
return (RANGE_ERROR);
if (c == '/' && (flags & FNM_PATHNAME))
return (RANGE_NOMATCH);
if (flags & FNM_CASEFOLD)
c = tolower((unsigned char)c);
if (*pattern == '-'
&& (c2 = *(pattern + 1)) != EOS && c2 != ']') {
pattern += 2;
if (c2 == '\\' && !(flags & FNM_NOESCAPE))
c2 = *pattern++;
if (c2 == EOS)
return (RANGE_ERROR);
if (flags & FNM_CASEFOLD)
c2 = tolower((unsigned char)c2);
if (c <= test && test <= c2)
ok = 1;
} else if (c == test)
ok = 1;
} while ((c = *pattern++) != ']');
*newp = const_cast<char *>(pattern);
return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH);
}
} // End of namespace Alan3
} // End of namespace Glk

View File

@@ -0,0 +1,82 @@
/* 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_ALAN3_FNMATCH
#define GLK_ALAN3_FNMATCH
/*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)fnmatch.h 8.1 (Berkeley) 6/2/93
*/
namespace Glk {
namespace Alan3 {
#define FNM_NOMATCH 1 /* Match failed. */
#define FNM_NOSYS 2 /* Function not supported (unused). */
#define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */
#define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */
#define FNM_PERIOD 0x04 /* Period must be matched by period. */
#ifndef _POSIX_SOURCE
#define FNM_LEADING_DIR 0x08 /* Ignore /<tail> after Imatch. */
#define FNM_CASEFOLD 0x10 /* Case insensitive search. */
#define FNM_IGNORECASE FNM_CASEFOLD
#define FNM_FILE_NAME FNM_PATHNAME
#endif
extern int fnmatch(const char *pattern, const char *string, int flags);
} // End of namespace Alan3
} // End of namespace Glk
#endif

237
engines/glk/alan3/glkio.cpp Normal file
View File

@@ -0,0 +1,237 @@
/* 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/alan3/glkio.h"
#include "glk/alan3/acode.h"
#include "glk/alan3/current.h"
#include "glk/alan3/instance.h"
#include "glk/alan3/options.h"
#include "glk/alan3/output.h"
#include "common/config-manager.h"
namespace Glk {
namespace Alan3 {
GlkIO *g_io;
GlkIO::GlkIO(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc),
glkMainWin(nullptr), glkStatusWin(nullptr), onStatusLine(false), _saveSlot(-1),
_soundChannel(nullptr) {
g_io = this;
}
bool GlkIO::initialize() {
// first, open a window for error output
glkMainWin = glk_window_open(nullptr, 0, 0, wintype_TextBuffer, 0);
if (glkMainWin == nullptr)
return false;
glk_stylehint_set(wintype_TextGrid, style_User1, stylehint_ReverseColor, 1);
glkStatusWin = glk_window_open(glkMainWin, winmethod_Above |
winmethod_Fixed, 1, wintype_TextGrid, 0);
glk_set_window(glkMainWin);
// Check for a save being loaded directly from the launcher
_saveSlot = ConfMan.hasKey("save_slot") ? ConfMan.getInt("save_slot") : -1;
return true;
}
void GlkIO::print(const char *fmt, ...) {
// If there's a savegame being loaded from the launcher, ignore any text out
if (_saveSlot != -1)
return;
va_list argp;
va_start(argp, fmt);
Common::String str = Common::String::vformat(fmt, argp);
va_end(argp);
if (glkMainWin) {
glk_put_string(str.c_str());
} else {
// assume stdio is available in this case only
warning("%s", str.c_str());
}
}
void GlkIO::showImage(int image, int align) {
uint ecode;
if (_saveSlot != -1)
return;
if ((glk_gestalt(gestalt_Graphics, 0) == 1) &&
(glk_gestalt(gestalt_DrawImage, wintype_TextBuffer) == 1)) {
glk_window_flow_break(glkMainWin);
printf("\n");
ecode = glk_image_draw(glkMainWin, image, imagealign_MarginLeft, 0);
(void)ecode;
}
}
void GlkIO::playSound(int sound) {
if (_saveSlot != -1)
return;
#ifdef GLK_MODULE_SOUND
if (glk_gestalt(gestalt_Sound, 0) == 1) {
if (_soundChannel == nullptr)
_soundChannel = glk_schannel_create(0);
if (_soundChannel) {
glk_schannel_stop(_soundChannel);
(void)glk_schannel_play(_soundChannel, sound);
}
}
#endif
}
void GlkIO::setStyle(int style) {
switch (style) {
case NORMAL_STYLE:
glk_set_style(style_Normal);
break;
case EMPHASIZED_STYLE:
glk_set_style(style_Emphasized);
break;
case PREFORMATTED_STYLE:
glk_set_style(style_Preformatted);
break;
case ALERT_STYLE:
glk_set_style(style_Alert);
break;
case QUOTE_STYLE:
glk_set_style(style_BlockQuote);
break;
default:
break;
}
}
void GlkIO::statusLine(CONTEXT) {
uint glkWidth;
char line[100];
int pcol = col;
if (!statusLineOption || _saveSlot != -1 || glkStatusWin == nullptr)
return;
glk_set_window(glkStatusWin);
glk_window_clear(glkStatusWin);
glk_window_get_size(glkStatusWin, &glkWidth, nullptr);
onStatusLine = TRUE;
col = 1;
glk_window_move_cursor(glkStatusWin, 1, 0);
CALL1(sayInstance, where(HERO, /*TRUE*/ TRANSITIVE))
// TODO Add status message1 & 2 as author customizable messages
if (header->maximumScore > 0)
Common::sprintf_s(line, "Score %d(%d)/%d moves", current.score, (int)header->maximumScore, current.tick);
else
Common::sprintf_s(line, "%d moves", current.tick);
glk_window_move_cursor(glkStatusWin, glkWidth - strlen(line) - 1, 0);
glk_put_string(line);
needSpace = FALSE;
col = pcol;
onStatusLine = FALSE;
glk_set_window(glkMainWin);
}
/*======================================================================
readline()
Read a line from the user, with history and editing
*/
/* TODO - length of user buffer should be used */
bool GlkIO::readLine(CONTEXT, char *buffer, size_t maxLen) {
event_t event;
static bool readingCommands = FALSE;
static frefid_t commandFileRef;
static strid_t commandFile;
if (_saveSlot != -1) {
// Return a "restore" command
forcePrint("> ");
forcePrint("restore\n");
Common::strcpy_s(buffer, maxLen, "restore");
} else if (readingCommands) {
if (glk_get_line_stream(commandFile, buffer, maxLen) == 0) {
glk_stream_close(commandFile, nullptr);
readingCommands = FALSE;
} else {
glk_set_style(style_Input);
printf(buffer);
glk_set_style(style_Normal);
}
} else {
glk_request_line_event(glkMainWin, buffer, maxLen, 0);
do {
glk_select(&event);
if (shouldQuit())
LONG_JUMP0
switch (event.type) {
case evtype_Arrange:
R0CALL0(g_io->statusLine)
break;
default:
break;
}
} while (event.type != evtype_LineInput);
if (buffer[0] == '@') {
buffer[event.val1] = 0;
commandFileRef = glk_fileref_create_by_name(fileusage_InputRecord + fileusage_TextMode, &buffer[1], 0);
commandFile = glk_stream_open_file(commandFileRef, filemode_Read, 0);
if (commandFile != nullptr)
if (glk_get_line_stream(commandFile, buffer, maxLen) != 0) {
readingCommands = TRUE;
glk_set_style(style_Input);
printf(buffer);
glk_set_style(style_Normal);
}
} else
buffer[event.val1] = 0;
}
return TRUE;
}
Common::Error GlkIO::loadGame() {
if (_saveSlot != -1) {
int saveSlot = _saveSlot;
_saveSlot = -1;
return loadGameState(saveSlot);
} else {
return GlkAPI::loadGame();
}
}
} // End of namespace Alan3
} // End of namespace Glk

98
engines/glk/alan3/glkio.h Normal file
View File

@@ -0,0 +1,98 @@
/* 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_ALAN3_GLKIO
#define GLK_ALAN3_GLKIO
#include "glk/glk_api.h"
#include "glk/windows.h"
#include "glk/jumps.h"
namespace Glk {
namespace Alan3 {
class GlkIO : public GlkAPI {
private:
winid_t glkMainWin;
winid_t glkStatusWin;
schanid_t _soundChannel;
int _saveSlot;
public:
bool onStatusLine;
protected:
/**
* Does initialization
*/
bool initialize();
public:
/**
* Constructor
*/
GlkIO(OSystem *syst, const GlkGameDescription &gameDesc);
/**
* Print a string to the window
*/
void print(const char *fmt, ...);
/**
* Outputs a string to the window, even during startup
*/
void forcePrint(const char *str) {
glk_put_string(str);
}
void showImage(int image, int align);
void playSound(int sound);
void setStyle(int style);
void statusLine(CONTEXT);
bool readLine(CONTEXT, char *usrBuf, size_t maxLen);
void clear() {
glk_window_clear(glkMainWin);
}
void flowBreak() {
/* Make a new paragraph, i.e one empty line (one or two newlines). */
if (_saveSlot == -1 && glk_gestalt(gestalt_Graphics, 0) == 1)
glk_window_flow_break(glkMainWin);
}
/**
* If a savegame was selected to be loaded from the launcher, then load it.
* Otherwise, prompt the user for a savegame to load, and then load it
*/
Common::Error loadGame();
};
extern GlkIO *g_io;
#undef printf
#define printf g_io->print
} // End of namespace Alan3
} // End of namespace Glk
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,103 @@
/* 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_ALAN3_INSTANCE
#define GLK_ALAN3_INSTANCE
#include "common/serializer.h"
#include "glk/alan3/acode.h"
#include "glk/jumps.h"
#include "glk/alan3/types.h"
#include "glk/alan3/set.h"
namespace Glk {
namespace Alan3 {
/* Types: */
struct AdminEntry { /* Administrative data about instances */
Aint location;
AttributeEntry *attributes;
Abool alreadyDescribed;
Aint visitsCount;
Aint script;
Aint step;
Aint waitCount;
/**
* Save/Restore data
*/
void synchronize(Common::Serializer &s);
};
/* Data: */
extern InstanceEntry *instances; /* Instance table pointer */
extern AdminEntry *admin; /* Administrative data about instances */
extern AttributeEntry *attributes; /* Dynamic attribute values */
/* Functions: */
extern bool isA(int instance, int ancestor);
extern bool isAObject(int instance);
extern bool isAContainer(int instance);
extern bool isAActor(int instance);
extern bool isALocation(int instance);
extern bool isLiteral(int instance);
extern bool isANumeric(int instance);
extern bool isAString(int instance);
extern Aptr getInstanceAttribute(int instance, int attribute);
extern char *getInstanceStringAttribute(int instane, int attribute);
extern Set *getInstanceSetAttribute(int instance, int attribute);
extern void setInstanceAttribute(int instance, int atr, Aptr value);
extern void setInstanceStringAttribute(int instance, int attribute, char *string);
extern void setInstanceSetAttribute(int instance, int atr, Aptr set);
extern void say(CONTEXT, int instance);
extern void sayForm(CONTEXT, int instance, SayForm form);
extern void sayInstance(CONTEXT, int instance);
extern bool hasDescription(int instance);
extern bool isDescribable(int instance);
extern void describeAnything(CONTEXT, int instance);
extern void describeInstances(CONTEXT);
extern bool describe(CONTEXT, int instance);
extern int where(int instance, ATrans trans);
extern int positionOf(int instance);
extern int locationOf(int instance);
extern bool isAt(int instance, int other, ATrans trans);
extern bool isIn(int instance, int theContainer, ATrans trans);
extern bool isHere(int instance, ATrans trans);
extern bool isNearby(int instance, ATrans trans);
extern bool isNear(int instance, int other, ATrans trans);
extern bool isOpaque(int container);
extern void locate(CONTEXT, int instance, int whr);
} // End of namespace Alan3
} // End of namespace Glk
#endif

1431
engines/glk/alan3/inter.cpp Normal file

File diff suppressed because it is too large Load Diff

54
engines/glk/alan3/inter.h Normal file
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_ALAN3_INTER
#define GLK_ALAN3_INTER
/* The interpreter of Acode */
#include "glk/alan3/types.h"
#include "glk/alan3/stack.h"
#include "glk/jumps.h"
namespace Glk {
namespace Alan3 {
/* DATA: */
extern bool stopAtNextLine;
extern int currentLine;
extern int recursionDepth;
/* Global failure flag */
extern bool fail;
/* FUNCTIONS: */
extern void setInterpreterMock(void (*mock)(Aaddr adr));
extern void setInterpreterStack(Stack stack);
extern void interpret(CONTEXT, Aaddr adr);
extern Aword evaluate(CONTEXT, Aaddr adr);
} // End of namespace Alan3
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,62 @@
/* 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/alan3/lists.h"
#include "glk/alan3/syserr.h"
namespace Glk {
namespace Alan3 {
void initArray(void *array) {
implementationOfSetEndOfArray((Aword *)array);
}
/* How to know we are at end of a table or array, first Aword == EOD */
void implementationOfSetEndOfArray(Aword *adr) {
*adr = EOD;
}
bool implementationOfIsEndOfList(Aword *adr) {
return *adr == EOD;
}
int lengthOfArrayImplementation(void *array_of_any_type, int element_size_in_bytes) {
int length;
int element_size = element_size_in_bytes / sizeof(Aword);
Aword *array = (Aword *)array_of_any_type;
if (array == nullptr)
syserr("Taking length of NULL array");
for (length = 0; !isEndOfArray(&array[length * element_size]); length++)
;
return length;
}
void addElementImplementation(void *array_of_any_type, void *element, int element_size_in_bytes) {
Aword *array = (Aword *)array_of_any_type;
int length = lengthOfArray(array);
int element_size_in_words = element_size_in_bytes / sizeof(Aword);
memcpy(&array[length * element_size_in_words], element, element_size_in_bytes);
setEndOfArray(&array[(length + 1)*element_size_in_words]);
}
} // End of namespace Alan3
} // End of namespace Glk

49
engines/glk/alan3/lists.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_ALAN3_LISTS
#define GLK_ALAN3_LISTS
/* Various utility functions for handling lists and arrays */
#include "glk/alan3/acode.h"
#include "glk/alan3/types.h"
namespace Glk {
namespace Alan3 {
extern void initArray(void *array);
#define isEndOfArray(x) implementationOfIsEndOfList((Aword *) (x))
extern bool implementationOfIsEndOfList(Aword *adr);
#define setEndOfArray(x) implementationOfSetEndOfArray((Aword *) (x))
extern void implementationOfSetEndOfArray(Aword *adr);
#define lengthOfArray(array) lengthOfArrayImplementation((array), sizeof(*(array)))
extern int lengthOfArrayImplementation(void *array, int element_size_in_bytes);
#define addElement(array, element) addElementImplementation((array), (&element), sizeof(element))
extern void addElementImplementation(void *array_of_any_type, void *element_of_any_size, int element_size_in_bytes);
#endif
} // End of namespace Alan3
} // End of namespace Glk

View File

@@ -0,0 +1,80 @@
/* 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/alan3/literal.h"
#include "glk/alan3/types.h"
#include "glk/alan3/memory.h"
namespace Glk {
namespace Alan3 {
/* PUBLIC DATA */
int litCount = 0;
static LiteralEntry literalTable[100];
LiteralEntry *literals = literalTable;
/* PRIVATE TYPES & DATA */
/*+++++++++++++++++++++++++++++++++++++++++++++++++++*/
/*======================================================================*/
int instanceFromLiteral(int literalIndex) {
return literalIndex + header->instanceMax;
}
/*----------------------------------------------------------------------*/
void createIntegerLiteral(int integerValue) {
litCount++;
literals[litCount]._class = header->integerClassId;
literals[litCount].type = NUMERIC_LITERAL;
literals[litCount].value = integerValue;
}
/*----------------------------------------------------------------------*/
void createStringLiteral(char *unquotedString) {
litCount++;
literals[litCount]._class = header->stringClassId;
literals[litCount].type = STRING_LITERAL;
literals[litCount].value = toAptr(scumm_strdup(unquotedString));
}
/*----------------------------------------------------------------------*/
void freeLiterals() {
int i;
for (i = 0; i <= litCount; i++)
if (literals[i].type == STRING_LITERAL && literals[i].value != 0) {
deallocate((void *)fromAptr(literals[i].value));
}
litCount = 0;
}
/*======================================================================*/
int literalFromInstance(int instance) {
return instance - header->instanceMax;
}
} // End of namespace Alan3
} // End of namespace Glk

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_ALAN3_LITERAL
#define GLK_ALAN3_LITERAL
#include "glk/alan3/acode.h"
namespace Glk {
namespace Alan3 {
/* TYPES */
enum LiteralType {
NO_LITERAL, NUMERIC_LITERAL, STRING_LITERAL
};
struct LiteralEntry { /* LITERAL */
Aint _class; /* Class id of the literal type */
LiteralType type;
Aptr value;
};
/* DATA */
extern int litCount;
extern LiteralEntry *literals;
/* FUNCTIONS */
extern void createIntegerLiteral(int integerValue);
extern void createStringLiteral(char *unquotedString);
extern void freeLiterals(void);
extern int literalFromInstance(int instance);
extern int instanceFromLiteral(int literal);
} // End of namespace Alan3
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,131 @@
/* 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/alan3/location.h"
#include "glk/alan3/instance.h"
#include "glk/alan3/options.h"
#include "glk/alan3/word.h"
#include "glk/alan3/inter.h"
#include "glk/alan3/glkio.h"
#include "glk/alan3/lists.h"
#include "glk/alan3/checkentry.h"
#include "glk/alan3/debug.h"
#include "glk/alan3/memory.h"
#include "glk/alan3/dictionary.h"
#include "glk/alan3/output.h"
#include "glk/alan3/msg.h"
#include "glk/alan3/current.h"
namespace Glk {
namespace Alan3 {
/*----------------------------------------------------------------------*/
static void traceExit(CONTEXT, int location, int dir, const char *what) {
printf("\n<EXIT %s[%d] from ",
(char *)pointerTo(dictionary[playerWords[currentWordIndex - 1].code].string), dir);
CALL1(traceSay, location)
printf("[%d], %s:>\n", location, what);
}
/*======================================================================*/
void go(CONTEXT, int location, int dir) {
ExitEntry *theExit;
bool ok;
Aword oldloc;
theExit = (ExitEntry *) pointerTo(instances[location].exits);
if (instances[location].exits != 0) {
while (!isEndOfArray(theExit)) {
if (theExit->code == (uint)dir) {
ok = TRUE;
if (theExit->checks != 0) {
if (traceSectionOption)
CALL3(traceExit, location, dir, "Checking")
FUNC2(checksFailed, ok, theExit->checks, EXECUTE_CHECK_BODY_ON_FAIL)
ok = !ok;
}
if (ok) {
oldloc = location;
if (theExit->action != 0) {
if (traceSectionOption)
CALL3(traceExit, location, dir, "Executing")
CALL1(interpret, theExit->action)
}
/* Still at the same place? */
if (where(HERO, TRANSITIVE) == (int)oldloc) {
if (traceSectionOption)
CALL3(traceExit, location, dir, "Moving")
CALL2(locate, HERO, theExit->target)
}
return;
} else {
CALL1(error, NO_MSG)
}
}
theExit++;
}
}
CALL1(error, M_NO_WAY)
}
/*======================================================================*/
bool exitto(int to, int from) {
ExitEntry *theExit;
if (instances[from].exits == 0)
return FALSE; /* No exits */
for (theExit = (ExitEntry *) pointerTo(instances[from].exits); !isEndOfArray(theExit); theExit++)
if (theExit->target == (uint)to)
return TRUE;
return FALSE;
}
/*======================================================================*/
void look(CONTEXT) {
uint i;
/* Set describe flag for all objects and actors */
for (i = 1; i <= header->instanceMax; i++)
admin[i].alreadyDescribed = FALSE;
if (anyOutput)
para();
setSubHeaderStyle();
CALL1(sayInstance, current.location)
setNormalStyle();
newline();
capitalize = TRUE;
if (describe(context, current.location) && !context._break)
describeInstances(context);
}
} // End of namespace Alan3
} // End of namespace Glk

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/>.
*
*/
#ifndef GLK_ALAN3_LOCATION
#define GLK_ALAN3_LOCATION
#include "glk/alan3/types.h"
#include "glk/jumps.h"
namespace Glk {
namespace Alan3 {
extern bool exitto(int to, int from);
extern void go(CONTEXT, int location, int dir);
extern void look(CONTEXT);
} // End of namespace Alan3
} // End of namespace Glk
#endif

833
engines/glk/alan3/main.cpp Normal file
View File

@@ -0,0 +1,833 @@
/* 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/alan3/main.h"
#include "glk/alan3/alan_version.h"
#include "glk/alan3/class.h"
#include "glk/alan3/compatibility.h"
#include "glk/alan3/container.h"
#include "glk/alan3/current.h"
#include "glk/alan3/debug.h"
#include "glk/alan3/decode.h"
#include "glk/alan3/dictionary.h"
#include "glk/alan3/event.h"
#include "glk/alan3/exe.h"
#include "glk/alan3/glkio.h"
#include "glk/alan3/instance.h"
#include "glk/alan3/inter.h"
#include "glk/jumps.h"
#include "glk/alan3/lists.h"
#include "glk/alan3/literal.h"
#include "glk/alan3/location.h"
#include "glk/alan3/memory.h"
#include "glk/alan3/msg.h"
#include "glk/alan3/options.h"
#include "glk/alan3/output.h"
#include "glk/alan3/parse.h"
#include "glk/alan3/reverse.h"
#include "glk/alan3/rules.h"
#include "glk/alan3/scan.h"
#include "glk/alan3/score.h"
#include "glk/alan3/state.h"
#include "glk/alan3/syserr.h"
#include "glk/alan3/syntax.h"
#include "glk/alan3/utils.h"
namespace Glk {
namespace Alan3 {
/* PUBLIC DATA */
/* Amachine structures - Static */
VerbEntry *vrbs; /* Verb table pointer */
/* PRIVATE DATA */
#define STACKSIZE 100
/*----------------------------------------------------------------------*
*
* Event Handling
*
*----------------------------------------------------------------------*/
/*----------------------------------------------------------------------*/
static char *eventName(int event) {
return stringAt(events[event].id);
}
/*----------------------------------------------------------------------*/
static void runPendingEvents(CONTEXT) {
int i;
resetRules();
while (eventQueueTop != 0 && eventQueue[eventQueueTop - 1].after == 0) {
eventQueueTop--;
if (isALocation(eventQueue[eventQueueTop].where))
current.location = eventQueue[eventQueueTop].where;
else
current.location = where(eventQueue[eventQueueTop].where, TRANSITIVE);
if (traceSectionOption) {
printf("\n<EVENT %s[%d] (at ", eventName(eventQueue[eventQueueTop].event),
eventQueue[eventQueueTop].event);
CALL1(traceSay, current.location)
printf(" [%d]):>\n", current.location);
}
CALL1(interpret, events[eventQueue[eventQueueTop].event].code)
CALL1(evaluateRules, rules)
}
for (i = 0; i < eventQueueTop; i++)
eventQueue[i].after--;
}
/*----------------------------------------------------------------------*\
Main program and initialisation
\*----------------------------------------------------------------------*/
Common::SeekableReadStream *codfil;
/*----------------------------------------------------------------------
Calculate where to start calculating the CRC. Is different for
different versions. CRC is calculated from pre-beta2 memory start to
be compatible. If header size changes this should return beta2
header size for later versions.
*/
static int crcStart(const byte version[4]) {
/* Some earlier versions had a shorter header */
if (isPreAlpha5(version))
return sizeof(Pre3_0alpha5Header) / sizeof(Aword);
else if (isPreBeta2(version))
return sizeof(Pre3_0beta2Header) / sizeof(Aword);
else
return sizeof(ACodeHeader) / sizeof(Aword);
}
/*----------------------------------------------------------------------*/
static void readTemporaryHeader(CONTEXT, ACodeHeader *tmphdr) {
codfil->seek(0);
if (codfil->read(&tmphdr->tag[0], sizeof(ACodeHeader)) != sizeof(ACodeHeader) ||
strncmp((char *)tmphdr, "ALAN", 4) != 0)
playererr(context, "Not an Alan game file, does not start with \"ALAN\"");
}
/*----------------------------------------------------------------------*/
#ifdef SCUMM_LITTLE_ENDIAN
static void reverseMemory() {
if (debugOption || traceSectionOption || traceInstructionOption)
output("<Hmm, this is a little-endian machine, fixing byte ordering....");
reverseACD(); /* Reverse content of the ACD file */
if (debugOption || traceSectionOption || traceInstructionOption)
output("OK.>$n");
}
#endif
/*----------------------------------------------------------------------*/
static void setupHeader(ACodeHeader tmphdr) {
if (isPreBeta2(tmphdr.version)) {
header = (ACodeHeader *)duplicate(&memory[0], sizeof(ACodeHeader));
if (isPreAlpha5(tmphdr.version)) {
header->ifids = 0;
}
header->prompt = 0;
} else if (isPreBeta3(tmphdr.version)) {
header = (ACodeHeader *)pointerTo(0);
} else {
header = (ACodeHeader *)pointerTo(0);
}
}
/*----------------------------------------------------------------------*/
static void loadAndCheckMemory(ACodeHeader tmphdr, Aword crc, char err[]) {
int i;
/* No memory allocated yet? */
if (memory == nullptr) {
memory = (Aword *)allocate(tmphdr.size * sizeof(Aword));
}
memTop = tmphdr.size;
codfil->seek(0);
if (codfil->read(memory, sizeof(Aword) * memTop) != (sizeof(Aword) * memTop))
syserr("Could not read all ACD code.");
/* Calculate checksum */
for (i = crcStart(tmphdr.version); i < memTop; i++) {
crc += memory[i] & 0xff;
crc += (memory[i] >> 8) & 0xff;
crc += (memory[i] >> 16) & 0xff;
crc += (memory[i] >> 24) & 0xff;
}
if (crc != tmphdr.acdcrc) {
Common::sprintf_s(err, 100, "Checksum error in Acode (.a3c) file (0x%lx instead of 0x%lx).",
(unsigned long) crc, (unsigned long) tmphdr.acdcrc);
if (!ignoreErrorOption)
syserr(err);
else {
output("<WARNING! $$");
output(err);
output("$$ Ignored, proceed at your own risk.>$n");
}
}
}
/*----------------------------------------------------------------------*/
static const char *decodeState(int c) {
static char state[3] = "\0\0";
switch (c) {
case 0:
return ".";
case 'd':
return "dev";
case 'a':
return "alpha";
case 'b':
return "beta";
default:
state[0] = header->version[3];
return state;
}
}
/*======================================================================*/
char *decodedGameVersion(const byte version[]) {
static char str[100];
Common::sprintf_s(str, "%d.%d%s%d",
(int)version[3],
(int)version[2],
decodeState(version[0]),
(int)version[1]);
return str;
}
/*----------------------------------------------------------------------*/
static void incompatibleDevelopmentVersion(ACodeHeader *hdr) {
Common::String msg = Common::String::format("Incompatible version of ACODE program. "
"Development versions always require exact match. Game is %ld.%ld%s%ld, interpreter %ld.%ld%s%ld!",
(long)(hdr->version[0]),
(long)(hdr->version[1]),
decodeState(hdr->version[3]),
(long)(hdr->version[2]),
(long)alan.version.version,
(long)alan.version.revision,
alan.version.state,
(long)alan.version.correction);
apperr(msg.c_str());
}
/*----------------------------------------------------------------------*/
static void incompatibleVersion(ACodeHeader *hdr) {
Common::String msg = Common::String::format("Incompatible version of ACODE program. Game is %ld.%ld, interpreter %ld.%ld.",
(long)(hdr->version[0]),
(long)(hdr->version[1]),
(long)alan.version.version,
(long)alan.version.revision);
apperr(msg.c_str());
}
/*----------------------------------------------------------------------*/
static void alphaRunningLaterGame(char gameState) {
output("<WARNING! You are running an alpha interpreter, but the game is generated by a");
if (gameState == 'b')
output("beta");
else
output("release");
output("state compiler which was released later. This might cause the game to not work fully as intended. Look for an upgraded game file.>\n");
}
/*----------------------------------------------------------------------*/
static void nonDevelopmentRunningDevelopmentStateGame(const byte version[]) {
char errorMessage[200];
char versionString[100];
Common::strcpy_s(errorMessage, "Games generated by a development state compiler");
Common::sprintf_s(versionString, "(this game is v%d.%d.%d%s)", version[0], version[1],
version[2], decodeState(version[3]));
Common::strcat_s(errorMessage, versionString);
Common::strcat_s(errorMessage, "can only be run with a matching interpreter. Look for a game file generated with an alpha, beta or release state compiler.>\n");
apperr(errorMessage);
}
/*======================================================================*/
void checkVersion(ACodeHeader *hdr) {
/* Strategy for version matching is:
1) Development interpreters/games require exact match
2) Alpha, Beta and Release interpreters will not run development games
3) Alpha interpreters must warn if they run beta or release games
4) Beta interpreters may introduce changes which are not alpha compatible,
if the change is a strict addition (i.e. if not used will not affect
alpha interpreters, example is introduction of a new opcode if it is
done at the end of the list)
5) Release interpreters should run alpha and beta games without problems
NOTE that we are working with a non-reversed version string/word here.
*/
char interpreterVersion[4];
bool developmentVersion;
bool alphaVersion;
int compareLength;
char gameState = hdr->version[3];
/* Construct our own version */
interpreterVersion[0] = alan.version.version;
interpreterVersion[1] = alan.version.revision;
interpreterVersion[2] = alan.version.correction;
interpreterVersion[3] = alan.version.state[0];
/* Check version of .ACD file */
if (debugOption && !regressionTestOption) {
printf("<Version of '%s' is %d.%d%s%d!>\n",
g_vm->getFilename().c_str(),
(int)hdr->version[0],
(int)hdr->version[1],
decodeState(hdr->version[3]),
(int)hdr->version[2]);
newline();
}
/* Development version require exact match, else only 2 digit match */
developmentVersion = (strcmp(alan.version.state, "dev") == 0);
alphaVersion = (strcmp(alan.version.state, "alpha") == 0);
compareLength = (developmentVersion ? 3 : 2);
if (gameState == 'd' && !developmentVersion)
/* Development state game requires development state interpreter... */
nonDevelopmentRunningDevelopmentStateGame(hdr->version);
else {
/* Compatible if version, revision (and correction if dev state) match... */
if (memcmp(hdr->version, interpreterVersion, compareLength) != 0) {
/* Mismatch! */
if (!ignoreErrorOption) {
if (developmentVersion)
incompatibleDevelopmentVersion(hdr);
else
incompatibleVersion(hdr);
} else
output("<WARNING! Incompatible version of ACODE program.>\n");
} else if (developmentVersion && gameState != 'd')
/* ... unless interpreter is development and game not */
incompatibleDevelopmentVersion(hdr);
else if (alphaVersion && gameState != 'a') {
/* If interpreter is alpha version and the game is later, warn! */
alphaRunningLaterGame(gameState);
}
}
}
/*----------------------------------------------------------------------*/
static void load(CONTEXT) {
ACodeHeader tmphdr;
Aword crc = 0;
char err[100];
CALL1(readTemporaryHeader, &tmphdr)
checkVersion(&tmphdr);
/* Allocate and load memory */
#ifdef SCUMM_LITTLE_ENDIAN
reverseHdr(&tmphdr);
#endif
if (tmphdr.size <= sizeof(ACodeHeader) / sizeof(Aword))
syserr("Malformed game file. Too small.");
loadAndCheckMemory(tmphdr, crc, err);
#ifdef SCUMM_LITTLE_ENDIAN
reverseMemory();
#endif
setupHeader(tmphdr);
}
/*----------------------------------------------------------------------*/
static void checkDebug(CONTEXT) {
/* Make sure he can't debug if not allowed! */
if (!header->debug) {
if (debugOption | traceSectionOption | traceInstructionOption) {
printf("<Sorry, '%s' is not compiled for debug! Exiting.>\n", g_vm->getFilename().c_str());
CALL1(terminate, 0)
}
para();
debugOption = FALSE;
traceSectionOption = FALSE;
traceInstructionOption = FALSE;
tracePushOption = FALSE;
}
// If debugging, use no randomization
if (debugOption || regressionTestOption)
g_vm->setRandomNumberSeed(1);
}
/*----------------------------------------------------------------------*/
static void initStaticData(void) {
/* Dictionary */
dictionary = (DictionaryEntry *) pointerTo(header->dictionary);
/* Find out number of entries in dictionary */
for (dictionarySize = 0; !isEndOfArray(&dictionary[dictionarySize]); dictionarySize++);
/* Scores */
/* All addresses to tables indexed by ids are converted to pointers,
then adjusted to point to the (imaginary) element before the
actual table so that [0] does not exist. Instead indices goes
from 1 and we can use [1]. */
if (header->instanceTableAddress == 0)
syserr("Instance table pointer == 0");
instances = (InstanceEntry *) pointerTo(header->instanceTableAddress);
instances--; /* Back up one so that first is no. 1 */
if (header->classTableAddress == 0)
syserr("Class table pointer == 0");
classes = (ClassEntry *) pointerTo(header->classTableAddress);
classes--; /* Back up one so that first is no. 1 */
if (header->containerTableAddress != 0) {
containers = (ContainerEntry *) pointerTo(header->containerTableAddress);
containers--;
}
if (header->eventTableAddress != 0) {
events = (EventEntry *) pointerTo(header->eventTableAddress);
events--;
}
/* Scores, if already allocated, copy initial data */
if (scores == nullptr)
scores = (Aword *)duplicate((Aword *) pointerTo(header->scores), header->scoreCount * sizeof(Aword));
else
memcpy(scores, pointerTo(header->scores), header->scoreCount * sizeof(Aword));
if (literals == nullptr)
literals = (LiteralEntry *)allocate(sizeof(Aword) * (MAXPARAMS + 1));
stxs = (SyntaxEntry *) pointerTo(header->syntaxTableAddress);
vrbs = (VerbEntry *) pointerTo(header->verbTableAddress);
msgs = (MessageEntry *) pointerTo(header->messageTableAddress);
initRules(header->ruleTableAddress);
if (header->pack)
freq = (Aword *) pointerTo(header->freq);
}
/*----------------------------------------------------------------------*/
static void initStrings(void) {
StringInitEntry *init;
for (init = (StringInitEntry *) pointerTo(header->stringInitTable); !isEndOfArray(init); init++)
setInstanceAttribute(init->instanceCode, init->attributeCode, toAptr(getStringFromFile(init->fpos, init->len)));
}
/*----------------------------------------------------------------------*/
static Aint sizeOfAttributeData(void) {
uint i;
int size = 0;
for (i = 1; i <= header->instanceMax; i++) {
AttributeEntry *attribute = (AttributeEntry *)pointerTo(instances[i].initialAttributes);
while (!isEndOfArray(attribute)) {
size += AwordSizeOf(AttributeEntry);
attribute++;
}
size += 1; /* For EOD */
}
if (size != header->attributesAreaSize
&& (sizeof(AttributeHeaderEntry) == sizeof(AttributeEntry)))
syserr("Attribute area size calculated wrong.");
return size;
}
/*----------------------------------------------------------------------*/
static AttributeEntry *initializeAttributes(int awordSize) {
Aword *attributeArea = (Aword *)allocate(awordSize * sizeof(Aword));
Aword *currentAttributeArea = attributeArea;
uint i;
for (i = 1; i <= header->instanceMax; i++) {
AttributeHeaderEntry *originalAttribute = (AttributeHeaderEntry *)pointerTo(instances[i].initialAttributes);
admin[i].attributes = (AttributeEntry *)currentAttributeArea;
while (!isEndOfArray(originalAttribute)) {
((AttributeEntry *)currentAttributeArea)->code = originalAttribute->code;
((AttributeEntry *)currentAttributeArea)->value = originalAttribute->value;
((AttributeEntry *)currentAttributeArea)->id = originalAttribute->id;
currentAttributeArea += AwordSizeOf(AttributeEntry);
originalAttribute++;
}
*((Aword *)currentAttributeArea) = EOD;
currentAttributeArea += 1;
}
return (AttributeEntry *)attributeArea;
}
/*----------------------------------------------------------------------*/
static void initDynamicData(void) {
uint instanceId;
/* Allocate for administrative table */
admin = (AdminEntry *)allocate((header->instanceMax + 1) * sizeof(AdminEntry));
/* Create game state copy of attributes */
attributes = initializeAttributes(sizeOfAttributeData());
/* Initialise string & set attributes */
initStrings();
initSets((SetInitEntry *)pointerTo(header->setInitTable));
/* Set initial locations */
for (instanceId = 1; instanceId <= header->instanceMax; instanceId++)
admin[instanceId].location = instances[instanceId].initialLocation;
}
/*----------------------------------------------------------------------*/
static void runInheritedInitialize(CONTEXT, Aint theClass) {
if (theClass == 0) return;
CALL1(runInheritedInitialize, classes[theClass].parent)
if (classes[theClass].initialize)
interpret(context, classes[theClass].initialize);
}
/*----------------------------------------------------------------------*/
static void runInitialize(CONTEXT, Aint theInstance) {
CALL1(runInheritedInitialize, instances[theInstance].parent)
if (instances[theInstance].initialize != 0)
interpret(context, instances[theInstance].initialize);
}
/*----------------------------------------------------------------------*/
static void initializeInstances(CONTEXT) {
uint instanceId;
/* Set initial locations */
for (instanceId = 1; instanceId <= header->instanceMax; instanceId++) {
current.instance = instanceId;
CALL1(runInitialize, instanceId)
}
}
/*----------------------------------------------------------------------*/
static void start(CONTEXT) {
int startloc;
current.tick = 0;
current.location = startloc = where(HERO, TRANSITIVE);
current.actor = HERO;
current.score = 0;
CALL0(initializeInstances)
if (traceSectionOption)
printf("\n<START:>\n");
CALL1(interpret, header->start)
para();
if (where(HERO, TRANSITIVE) == startloc) {
if (traceSectionOption)
printf("<CURRENT LOCATION:>");
CALL0(look)
}
resetAndEvaluateRules(context, rules, header->version);
}
/*----------------------------------------------------------------------*/
static void openFiles(void) {
/* If logging open log file */
if (transcriptOption || logOption) {
startTranscript();
}
}
/*----------------------------------------------------------------------*/
static void init(CONTEXT) {
int i;
/* Initialise some status */
eventQueueTop = 0; /* No pending events */
initStaticData();
initDynamicData();
initParsing();
CALL0(checkDebug)
getPageSize();
/* Find first conjunction and use that for ',' handling */
for (i = 0; i < dictionarySize; i++)
if (isConjunction(i)) {
conjWord = i;
break;
}
/* Start the adventure */
if (debugOption) {
CALL3(debug, FALSE, 0, 0)
} else {
clear();
}
start(context);
}
/*----------------------------------------------------------------------*/
static bool traceActor(CONTEXT, int theActor) {
if (traceSectionOption) {
printf("\n<ACTOR ");
R0CALL1(traceSay, theActor)
printf("[%d]", theActor);
if (current.location != 0) {
printf(" (at ");
R0CALL1(traceSay, current.location)
} else
printf(" (nowhere");
printf("[%d])", current.location);
}
return traceSectionOption;
}
/*----------------------------------------------------------------------*/
static char *scriptName(int theActor, int theScript) {
ScriptEntry *scriptEntry = (ScriptEntry *)pointerTo(header->scriptTableAddress);
while (theScript > 1) {
scriptEntry++;
theScript--;
}
return (char *)pointerTo(scriptEntry->id);
}
/*----------------------------------------------------------------------*/
static void moveActor(CONTEXT, int theActor) {
ScriptEntry *scr;
StepEntry *step;
Aint previousInstance = current.instance;
bool flag;
if (context._break) {
// forfeit setjmp replacement destination
assert(context._label == "forfeit");
context.clear();
current.instance = previousInstance;
return;
}
current.actor = theActor;
current.instance = theActor;
current.location = where(theActor, TRANSITIVE);
if (theActor == (int)HERO) {
// Ask him!
CALL0(parse)
capitalize = TRUE;
fail = FALSE; // fail only aborts one actor
} else if (admin[theActor].script != 0) {
for (scr = (ScriptEntry *) pointerTo(header->scriptTableAddress); !isEndOfArray(scr); scr++) {
if (scr->code == admin[theActor].script) {
/* Find correct step in the list by indexing */
step = (StepEntry *) pointerTo(scr->steps);
step = (StepEntry *) &step[admin[theActor].step];
/* Now execute it, maybe. First check wait count */
if (admin[theActor].waitCount > 0) { /* Wait some more ? */
FUNC1(traceActor, flag, theActor)
if (flag)
printf(", SCRIPT %s[%ld], STEP %ld, Waiting another %ld turns>\n",
scriptName(theActor, admin[theActor].script),
(long)admin[theActor].script, (long)admin[theActor].step + 1,
(long)admin[theActor].waitCount);
admin[theActor].waitCount--;
break;
}
/* Then check possible expression to wait for */
if (step->exp != 0) {
FUNC1(traceActor, flag, theActor)
if (flag)
printf(", SCRIPT %s[%ld], STEP %ld, Evaluating:>\n",
scriptName(theActor, admin[theActor].script),
(long)admin[theActor].script, (long)admin[theActor].step + 1);
FUNC1(evaluate, flag, step->exp)
if (!flag)
break; /* Break loop, don't execute step*/
}
/* OK, so finally let him do his thing */
admin[theActor].step++; /* Increment step number before executing... */
if (!isEndOfArray(step + 1) && (step + 1)->after != 0) {
FUNC1(evaluate, admin[theActor].waitCount, (step + 1)->after)
}
FUNC1(traceActor, flag, theActor)
if (flag)
printf(", SCRIPT %s[%ld], STEP %ld, Executing:>\n",
scriptName(theActor, admin[theActor].script),
(long)admin[theActor].script,
(long)admin[theActor].step);
CALL1(interpret, step->stms)
step++;
/* ... so that we can see if he failed or is USEing another script now */
if (fail || (admin[theActor].step != 0 && isEndOfArray(step)))
/* No more steps in this script, so stop him */
admin[theActor].script = 0;
fail = FALSE; /* fail only aborts one actor */
break; /* We have executed a script so leave loop */
}
}
if (isEndOfArray(scr))
syserr("Unknown actor script.");
} else {
FUNC1(traceActor, flag, theActor)
if (flag) {
printf(", Idle>\n");
}
}
current.instance = previousInstance;
}
/*======================================================================*/
void run(void) {
Stack theStack = nullptr;
Context ctx;
openFiles();
load(ctx); // Load program
do {
ctx.clear();
if (ctx._break)
break;
if (theStack)
deleteStack(theStack);
theStack = createStack(STACKSIZE);
setInterpreterStack(theStack);
initStateStack();
// Initialise and start the adventure
init(ctx);
while (!g_vm->shouldQuit()) {
if (!(ctx._break && ctx._label == "forfeit")) {
if (ctx._break) {
assert(ctx._label.hasPrefix("return"));
if (ctx._label == "returnError") {
forgetGameState();
forceNewPlayerInput();
} else if (ctx._label == "returnUndo") {
forceNewPlayerInput();
}
ctx.clear();
} else {
if (debugOption)
debug(ctx, FALSE, 0, 0);
if (!ctx._break) {
if (stackDepth(theStack) != 0)
syserr("Stack is not empty in main loop");
if (!current.meta)
runPendingEvents(ctx);
}
}
recursionDepth = 0;
// Move all characters, hero first
rememberGameState();
current.meta = FALSE;
}
moveActor(ctx, header->theHero);
if (!ctx._break) {
if (gameStateChanged)
rememberCommands();
else
forgetGameState();
if (!current.meta) {
current.tick++;
// Remove this call? Since Eval is done up there after each event...
resetAndEvaluateRules(ctx, rules, header->version);
if (!ctx._break) {
// Then all the other actors...
for (uint i = 1; i <= header->instanceMax; i++) {
if (i != header->theHero && isAActor(i)) {
moveActor(ctx, i);
if (ctx._break)
break;
resetAndEvaluateRules(ctx, rules, header->version);
if (ctx._break)
break;
}
}
}
}
}
if (ctx._break && ctx._label == "restart")
break;
}
} while (!g_vm->shouldQuit() && ctx._label == "restart");
}
} // End of namespace Alan3
} // End of namespace Glk

44
engines/glk/alan3/main.h Normal file
View File

@@ -0,0 +1,44 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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_ALAN3_MAIN
#define GLK_ALAN3_MAIN
/* Header file for main unit of ARUN Alan System interpreter */
#include "common/stream.h"
#include "glk/alan3/types.h"
#include "glk/alan3/acode.h"
namespace Glk {
namespace Alan3 {
extern Common::SeekableReadStream *codfil;
extern VerbEntry *vrbs; // Verb table pointer
extern void run();
extern void usage();
} // End of namespace Alan3
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,115 @@
/* 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/alan3/memory.h"
#include "glk/alan3/types.h"
#include "glk/alan3/syserr.h"
namespace Glk {
namespace Alan3 {
/* PUBLIC DATA */
Aword *memory = nullptr;
static ACodeHeader dummyHeader; /* Dummy to use until memory allocated */
ACodeHeader *header = &dummyHeader;
int memTop = 0; /* Top of load memory */
/*======================================================================*/
void *allocate(unsigned long lengthInBytes) {
void *p = (void *)calloc((size_t)lengthInBytes, 1);
if (p == nullptr)
syserr("Out of memory.");
return p;
}
/*======================================================================*/
void deallocate(void *ptr) {
free(ptr);
}
/*======================================================================*/
void *duplicate(void *original, unsigned long len) {
void *p = allocate(len + 1);
memcpy(p, original, len);
return p;
}
typedef struct {
Aptr aptr;
void *voidp;
} PointerMapEntry;
static PointerMapEntry *pointerMap = nullptr;
static int pointerMapSize = 0;
static int nextAptr = 1;
/*======================================================================*/
void resetPointerMap(void) {
if (pointerMap != nullptr) free(pointerMap);
pointerMap = nullptr;
pointerMapSize = 0;
}
/*======================================================================*/
void *fromAptr(Aptr aptr) {
int index;
for (index = 0; index < pointerMapSize && pointerMap[index].aptr != aptr; index++)
;
if (index == pointerMapSize)
syserr("No pointerMap entry for Aptr");
return pointerMap[index].voidp;
}
/*======================================================================*/
Aptr toAptr(void *ptr) {
int index;
if (pointerMap == nullptr) {
pointerMap = (PointerMapEntry *)allocate(sizeof(PointerMapEntry));
pointerMapSize = 1;
}
for (index = 0; index < pointerMapSize && pointerMap[index].voidp != nullptr; index++)
;
if (index == pointerMapSize) {
pointerMap = (PointerMapEntry *)realloc(pointerMap, (index + 1) * sizeof(PointerMapEntry));
pointerMapSize++;
}
pointerMap[index].voidp = ptr;
pointerMap[index].aptr = nextAptr++;
return pointerMap[index].aptr;
}
} // End of namespace Alan3
} // End of namespace Glk

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_ALAN3_MEMORY
#define GLK_ALAN3_MEMORY
#include "glk/alan3/sysdep.h"
#include "glk/alan3/acode.h"
namespace Glk {
namespace Alan3 {
/* DATA */
extern Aword *memory;
extern ACodeHeader *header;
extern int memTop;
/* FUNCTIONS */
extern void *allocate(unsigned long lengthInBytes);
extern void *duplicate(void *original, unsigned long len);
extern void deallocate(void *ptr);
extern void resetPointerMap();
extern void *fromAptr(Aptr aptr);
extern Aptr toAptr(void *ptr);
} // End of namespace Alan3
} // End of namespace Glk
#endif

103
engines/glk/alan3/msg.cpp Normal file
View File

@@ -0,0 +1,103 @@
/* 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/alan3/msg.h"
#include "glk/alan3/memory.h"
#include "glk/alan3/inter.h"
#include "glk/alan3/exe.h"
#include "glk/alan3/lists.h"
namespace Glk {
namespace Alan3 {
/* PUBLIC DATA */
MessageEntry *msgs; /* Message table pointer */
/*======================================================================*/
void printMessage(MsgKind msg) { /* IN - message number */
Context ctx;
interpret(ctx, msgs[msg].stms);
}
static void (*errorHandler)(MsgKind msg) = nullptr;
/*======================================================================*/
void setErrorHandler(void (*handler)(MsgKind msg)) { /* IN - The error message number */
// N.B. The error handler must not return because the standard handler does not...
errorHandler = handler;
}
/*======================================================================*/
void error(CONTEXT, MsgKind msgno) { /* IN - The error message number */
if (errorHandler != nullptr)
errorHandler(msgno);
else {
/* Print an error message and longjmp to main loop. */
if (msgno != NO_MSG)
printMessage(msgno);
LONG_JUMP_LABEL("returnError");
}
}
/*======================================================================*/
void abortPlayerCommand(CONTEXT) {
error(context, NO_MSG);
}
/*======================================================================*/
void printMessageWithInstanceParameter(MsgKind message, int instanceId) {
ParameterArray parameters = newParameterArray();
addParameterForInstance(parameters, instanceId);
printMessageWithParameters(message, parameters);
freeParameterArray(parameters);
}
/*======================================================================*/
void printMessageUsing2InstanceParameters(MsgKind message, int instance1, int instance2) {
ParameterArray parameters = newParameterArray();
addParameterForInstance(parameters, instance1);
addParameterForInstance(parameters, instance2);
printMessageWithParameters(message, parameters);
freeParameterArray(parameters);
}
/*======================================================================*/
void printMessageWithParameters(MsgKind msg, Parameter *messageParameters) {
Parameter *savedParameters = newParameterArray();
Context ctx;
copyParameterArray(savedParameters, globalParameters);
copyParameterArray(globalParameters, messageParameters);
interpret(ctx, msgs[msg].stms);
copyParameterArray(globalParameters, savedParameters);
freeParameterArray(savedParameters);
}
} // End of namespace Alan3
} // End of namespace Glk

56
engines/glk/alan3/msg.h Normal file
View File

@@ -0,0 +1,56 @@
/* 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_ALAN3_MSG
#define GLK_ALAN3_MSG
#include "glk/alan3/acode.h"
#include "glk/jumps.h"
#include "glk/alan3/types.h"
#include "glk/alan3/params.h"
namespace Glk {
namespace Alan3 {
/* TYPES */
typedef struct MessageEntry { /* MESSAGE TABLE */
Aaddr stms; /* Address to statements*/
} MessageEntry;
/* DATA */
extern MessageEntry *msgs; /* Message table pointer */
/* FUNCTIONS */
extern void setErrorHandler(void (*handler)(MsgKind));
extern void abortPlayerCommand(CONTEXT);
extern void error(CONTEXT, MsgKind msg);
extern bool confirm(CONTEXT, MsgKind msgno);
extern void printMessage(MsgKind msg);
extern void printMessageWithParameters(MsgKind msg, Parameter *messageParameters);
extern void printMessageWithInstanceParameter(MsgKind message, int i);
extern void printMessageUsing2InstanceParameters(MsgKind message, int instance1, int instance2);
} // End of namespace Alan3
} // End of namespace Glk
#endif

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/>.
*
*/
namespace Glk {
namespace Alan3 {
bool verboseOption;
bool ignoreErrorOption;
bool debugOption;
bool traceSectionOption;
bool tracePushOption;
bool traceStackOption;
bool traceSourceOption;
bool traceInstructionOption;
bool transcriptOption;
bool logOption;
bool statusLineOption;
bool regressionTestOption;
} // End of namespace Alan3
} // End of namespace Glk

View File

@@ -0,0 +1,46 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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_ALAN3_OPTIONS
#define GLK_ALAN3_OPTIONS
#include "glk/alan3/types.h"
namespace Glk {
namespace Alan3 {
extern bool verboseOption;
extern bool ignoreErrorOption;
extern bool debugOption;
extern bool traceSectionOption;
extern bool tracePushOption;
extern bool traceStackOption;
extern bool traceSourceOption;
extern bool traceInstructionOption;
extern bool transcriptOption;
extern bool logOption;
extern bool statusLineOption;
extern bool regressionTestOption;
} // End of namespace Alan3
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,453 @@
/* 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 "common/stream.h"
#include "glk/alan3/glkio.h"
#include "glk/alan3/options.h"
#include "glk/alan3/output.h"
#include "glk/alan3/memory.h"
#include "glk/alan3/word.h"
#include "glk/alan3/lists.h"
#include "glk/alan3/syserr.h"
#include "glk/alan3/dictionary.h"
#include "glk/alan3/current.h"
#include "glk/alan3/msg.h"
#include "glk/alan3/sysdep.h"
#include "glk/alan3/instance.h"
namespace Glk {
namespace Alan3 {
/* PUBLIC DATA */
bool anyOutput;
bool capitalize;
bool needSpace;
bool skipSpace;
/* Screen formatting info */
int col, lin;
int pageLength, pageWidth;
/* Logfile */
strid_t logFile;
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/*
getPageSize()
Try to get the current page size from the system, else use the ones
from the header.
*/
void getPageSize(void) {
pageLength = 0;
pageWidth = 0;
}
/*----------------------------------------------------------------------*/
static int updateColumn(int currentColumn, const char *string) {
const char *newlinePosition = strrchr(string, '\n');
if (newlinePosition != nullptr)
return &string[strlen(string)] - newlinePosition;
else
return currentColumn + strlen(string);
}
/*======================================================================*/
void setSubHeaderStyle(void) {
g_io->glk_set_style(style_Subheader);
}
/*======================================================================*/
void setNormalStyle(void) {
g_io->glk_set_style(style_Normal);
}
/*======================================================================*/
void newline(void) {
printAndLog("\n");
col = 1;
needSpace = FALSE;
}
/*======================================================================*/
void para(void) {
g_io->flowBreak();
if (col != 1)
newline();
newline();
capitalize = TRUE;
}
/*======================================================================*/
void clear(void) {
g_io->clear();
}
/*----------------------------------------------------------------------*/
static void capitalizeFirst(Common::String &str) {
uint i = 0;
// Skip over space...
while (i < str.size() && isSpace(str[i])) i++;
if (i < str.size()) {
str.setChar(toUpper(str[i]), i);
capitalize = false;
}
}
/*======================================================================*/
void printAndLog(const char *string) {
static int column = 0;
char *stringCopy;
char *stringPart;
printf("%s", string);
if (!g_io->onStatusLine && transcriptOption) {
// TODO Is this assuming only 70-char wide windows for GLK?
if ((int)strlen(string) > 70 - column) {
stringCopy = scumm_strdup(string); /* Make sure we can write NULLs */
stringPart = stringCopy;
while ((int)strlen(stringPart) > 70 - column) {
int p;
for (p = 70 - column; p > 0 && !Common::isSpace((int)stringPart[p]); p--);
stringPart[p] = '\0';
g_io->glk_put_string_stream(logFile, stringPart);
g_io->glk_put_char_stream(logFile, '\n');
column = 0;
stringPart = &stringPart[p + 1];
}
g_io->glk_put_string_stream(logFile, stringPart);
column = updateColumn(column, stringPart);
free(stringCopy);
} else {
g_io->glk_put_string_stream(logFile, string);
column = updateColumn(column, string);
}
}
}
/*----------------------------------------------------------------------*/
static void justify(const char *str) {
Common::String tempStr(str);
if (capitalize)
capitalizeFirst(tempStr);
printAndLog(tempStr.c_str());
col = col + tempStr.size(); // Update column
}
/*----------------------------------------------------------------------*/
static void space(void) {
if (skipSpace)
skipSpace = FALSE;
else {
if (needSpace) {
printAndLog(" ");
col++;
}
}
needSpace = FALSE;
}
/*----------------------------------------------------------------------*/
static void sayPlayerWordsForParameter(int p) {
int i;
for (i = globalParameters[p].firstWord; i <= globalParameters[p].lastWord; i++) {
justify((char *)pointerTo(dictionary[playerWords[i].code].string));
if (i < globalParameters[p].lastWord)
justify(" ");
}
}
/*----------------------------------------------------------------------*/
static void sayParameter(CONTEXT, int p, int form) {
int i;
for (i = 0; i <= p; i++)
if (isEndOfArray(&globalParameters[i]))
apperr("Nonexistent parameter referenced.");
#ifdef ALWAYS_SAY_PARAMETERS_USING_PLAYER_WORDS
if (params[p].firstWord != EOD) /* Any words he used? */
/* Yes, so use them... */
sayPlayerWordsForParameter(p);
else
CALL2(sayForm(params[p].code, form)
#else
if (globalParameters[p].useWords) {
/* Ambiguous instance referenced, so use the words he used */
sayPlayerWordsForParameter(p);
} else {
CALL2(sayForm, globalParameters[p].instance, (SayForm)form)
}
#endif
}
/*----------------------------------------------------------------------
Print an expanded symbolic reference.
N = newline
I = indent on a new line
P = new paragraph
L = current location name
O = current object -> first parameter!
<n> = n:th parameter
+<n> = definite form of n:th parameter
0<n> = indefinite form of n:th parameter
!<n> = pronoun for the n:th parameter
V = current verb
A = current actor
T = tabulation
$ = no space needed after this, and don't capitalize
_ = interpret this as a single dollar, if in doubt or conflict with other symbols
str - The string starting with '$'
*/
static char *printSymbol(CONTEXT, char str[]) {
int advance = 2;
if (*str == '\0') printAndLog("$");
else switch (toLower(str[1])) {
case 'n':
newline();
needSpace = FALSE;
break;
case 'i':
newline();
printAndLog(" ");
col = 5;
needSpace = FALSE;
break;
case 'o':
space();
R0CALL2(sayParameter, 0, 0)
needSpace = TRUE; /* We did print something non-white */
break;
case '+':
case '0':
case '-':
case '!':
space();
if (Common::isDigit((int)str[2])) {
int form;
switch (str[1]) {
case '+':
form = SAY_DEFINITE;
break;
case '0':
form = SAY_INDEFINITE;
break;
case '-':
form = SAY_NEGATIVE;
break;
case '!':
form = SAY_PRONOUN;
break;
default:
form = SAY_SIMPLE;
break;
}
R0CALL2(sayParameter, str[2] - '1', form)
needSpace = TRUE;
}
advance = 3;
break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
space();
R0CALL2(sayParameter, str[1] - '1', SAY_SIMPLE)
needSpace = TRUE; /* We did print something non-white */
break;
case 'l':
space();
R0CALL1(say, current.location)
needSpace = TRUE; /* We did print something non-white */
break;
case 'a':
space();
R0CALL1(say, current.actor)
needSpace = TRUE; /* We did print something non-white */
break;
case 'v':
space();
justify((const char *)pointerTo(dictionary[verbWord].string));
needSpace = TRUE; /* We did print something non-white */
break;
case 'p':
para();
needSpace = FALSE;
break;
case 't': {
int i;
int spaces = 4 - (col - 1) % 4;
for (i = 0; i < spaces; i++) printAndLog(" ");
col = col + spaces;
needSpace = FALSE;
break;
}
case '$':
skipSpace = TRUE;
capitalize = FALSE;
break;
case '_':
advance = 2;
printAndLog("$");
break;
default:
advance = 1;
printAndLog("$");
break;
}
return &str[advance];
}
/*----------------------------------------------------------------------*/
static bool inhibitSpace(char *str) {
return str[0] != '\0' && str[0] == '$' && str[1] == '$';
}
/*----------------------------------------------------------------------*/
static bool isSpaceEquivalent(char str[]) {
if (str[0] == ' ')
return TRUE;
else
return strncmp(str, "$p", 2) == 0
|| strncmp(str, "$n", 2) == 0
|| strncmp(str, "$i", 2) == 0
|| strncmp(str, "$t", 2) == 0;
}
/*----------------------------------------------------------------------*/
static bool punctuationNext(char *str) {
const char *punctuation = strchr(".,!?", str[0]);
bool end = str[1] == '\0';
bool space = isSpaceEquivalent(&str[1]);
return (punctuation != nullptr && (end || space));
}
/*----------------------------------------------------------------------*/
static char lastCharOf(char *str) {
return str[strlen(str) - 1];
}
/*======================================================================*/
void output(const char *original) {
char ch;
char *str, *copy;
char *symptr;
Context ctx;
copy = scumm_strdup(original);
str = copy;
if (inhibitSpace(str) || punctuationNext(str))
needSpace = FALSE;
else
space(); /* Output space if needed (& not inhibited) */
/* Output string up to symbol and handle the symbol */
while ((symptr = strchr(str, '$')) != (char *) nullptr) {
ch = *symptr; /* Terminate before symbol */
*symptr = '\0';
if (strlen(str) > 0) {
skipSpace = FALSE; /* Only let skipSpace through if it is
last in the string */
if (lastCharOf(str) == ' ') {
str[strlen(str) - 1] = '\0'; /* Truncate space character */
justify(str); /* Output part before '$' */
needSpace = TRUE;
} else {
justify(str); /* Output part before '$' */
needSpace = FALSE;
}
}
*symptr = ch; /* restore '$' */
str = printSymbol(ctx, symptr); /* Print the symbolic reference and advance */
}
if (str[0] != 0) {
justify(str); /* Output trailing part */
skipSpace = FALSE;
if (lastCharOf(str) != ' ')
needSpace = TRUE;
}
if (needSpace)
capitalize = strchr("!?.", str[strlen(str) - 1]) != nullptr;
anyOutput = TRUE;
free(copy);
}
/*======================================================================*/
bool confirm(CONTEXT, MsgKind msgno) {
char buf[80];
bool flag;
/* This is a bit of a hack since we really want to compare the input,
it could be affirmative, but for now any input is NOT! */
printMessage(msgno);
R0FUNC2(g_io->readLine, flag, buf, 80)
if (!flag)
return TRUE;
col = 1;
return (buf[0] == '\0');
}
} // End of namespace Alan3
} // End of namespace Glk

View File

@@ -0,0 +1,56 @@
/* 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_ALAN3_OUTPUT
#define GLK_ALAN3_OUTPUT
#include "glk/alan3/types.h"
#include "glk/streams.h"
namespace Glk {
namespace Alan3 {
/* DATA */
extern int col, lin; // TODO Move to current.column & current.line?
extern int pageLength, pageWidth;
extern bool anyOutput;
extern bool needSpace;
extern bool capitalize;
extern bool skipSpace;
/* Log file */
extern strid_t logFile;
/* FUNCTIONS */
extern void getPageSize();
extern void setSubHeaderStyle(void);
extern void setNormalStyle(void);
extern void newline(void);
extern void para(void);
extern void clear(void);
extern void printAndLog(const char *string);
extern void output(const char *string);
} // End of namespace Alan3
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,102 @@
/* 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/alan3/parameter_position.h"
#include "glk/alan3/memory.h"
#include "glk/alan3/lists.h"
namespace Glk {
namespace Alan3 {
/*======================================================================*/
void deallocateParameterPositions(ParameterPosition *parameterPositions) {
int i;
for (i = 0; !parameterPositions[i].endOfList; i++) {
ParameterPosition *position = &parameterPositions[i];
freeParameterArray(position->parameters);
if (position->exceptions)
freeParameterArray(position->exceptions);
}
deallocate(parameterPositions);
}
/*======================================================================*/
void uncheckAllParameterPositions(ParameterPosition parameterPositions[]) {
int position;
for (position = 0; position < MAXPARAMS; position++) {
parameterPositions[position].checked = FALSE;
}
}
/*======================================================================*/
void copyParameterPositions(ParameterPosition originalParameterPositions[], ParameterPosition parameterPositions[]) {
int i;
for (i = 0; !originalParameterPositions[i].endOfList; i++)
parameterPositions[i] = originalParameterPositions[i];
parameterPositions[i].endOfList = TRUE;
}
/*======================================================================*/
bool equalParameterPositions(ParameterPosition parameterPositions1[], ParameterPosition parameterPositions2[]) {
int i;
for (i = 0; !parameterPositions1[i].endOfList; i++) {
if (parameterPositions2[i].endOfList)
return FALSE;
if (!equalParameterArrays(parameterPositions1[i].parameters, parameterPositions2[i].parameters))
return FALSE;
}
return parameterPositions2[i].endOfList;
}
/*======================================================================*/
int findMultipleParameterPosition(ParameterPosition parameterPositions[]) {
Aint parameterNumber;
for (parameterNumber = 0; !parameterPositions[parameterNumber].endOfList; parameterNumber++)
if (parameterPositions[parameterNumber].explicitMultiple)
return parameterNumber;
return -1;
}
/*======================================================================*/
void markExplicitMultiple(ParameterPosition parameterPositions[], Parameter parameters[]) {
int parameterCount;
for (parameterCount = 0; !parameterPositions[parameterCount].endOfList; parameterCount++)
if (parameterPositions[parameterCount].explicitMultiple)
parameters[parameterCount].instance = 0;
}
/*======================================================================*/
void convertPositionsToParameters(ParameterPosition parameterPositions[], Parameter parameters[]) {
ParameterPosition *position = parameterPositions;
clearParameterArray(parameters);
while (!position->endOfList) {
addParameterToParameterArray(parameters, &position->parameters[0]);
position++;
}
}
} // End of namespace Alan3
} // End of namespace Glk

View File

@@ -0,0 +1,76 @@
/* 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_ALAN3_PARAMETER_POSITION
#define GLK_ALAN3_PARAMETER_POSITION
/* ParameterPosition
Represents on position in the player input holding a parameter. That
position is filled with some words from the player, those words must
be disambiguated to one or more instances. There are three cases:
1) words presuming it would be a single instance (it
might actually not be) "the chair"
2) words indicating explicit mentioning of multiple instances, "the
book and the chair"
3) implicit multiple using "all" or "everything except the blue
ball"
For all those cases the position must be able to deliver the words,
possible explicit or implicit multiple, and the resulting set of
instances.
*/
#include "glk/alan3/acode.h"
#include "glk/alan3/types.h"
#include "glk/alan3/params.h"
namespace Glk {
namespace Alan3 {
/* Types: */
struct ParameterPosition {
bool endOfList;
bool explicitMultiple;
bool all;
bool them;
bool checked;
Aword flags;
Parameter *parameters;
Parameter *exceptions;
};
/* Functions: */
extern void deallocateParameterPositions(ParameterPosition *parameterPositions);
extern void uncheckAllParameterPositions(ParameterPosition parameterPositions[]);
extern void copyParameterPositions(ParameterPosition originalParameterPositions[], ParameterPosition parameterPositions[]);
extern bool equalParameterPositions(ParameterPosition parameterPositions1[], ParameterPosition parameterPositions2[]);
extern int findMultipleParameterPosition(ParameterPosition parameterPositions[]);
extern void markExplicitMultiple(ParameterPosition parameterPositions[], Parameter parameters[]);
extern void convertPositionsToParameters(ParameterPosition parameterPositions[], Parameter parameters[]);
} // End of namespace Alan3
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,323 @@
/* 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/alan3/params.h"
#include "glk/alan3/glkio.h"
#include "glk/alan3/lists.h"
#include "glk/alan3/literal.h"
#include "glk/alan3/memory.h"
#include "glk/alan3/syserr.h"
namespace Glk {
namespace Alan3 {
/* PUBLIC DATA */
Parameter *globalParameters = nullptr;
/*======================================================================*/
Parameter *newParameter(int id) {
Parameter *parameter = NEW(Parameter);
parameter->instance = id;
parameter->candidates = nullptr;
return parameter;
}
/*======================================================================*/
Parameter *newParameterArray(void) {
Parameter *newArray = (Parameter *)allocate((MAXINSTANCE + 1) * sizeof(Parameter));
setEndOfArray(newArray);
return newArray;
}
/*======================================================================*/
void freeParameterArray(ParameterArray arrayPointer) {
Parameter *p;
for (p = arrayPointer; !isEndOfArray(p); p++)
if (p->candidates != nullptr)
freeParameterArray(p->candidates);
deallocate(arrayPointer);
}
/*======================================================================*/
Parameter *ensureParameterArrayAllocated(ParameterArray currentArray) {
if (currentArray == nullptr)
return newParameterArray();
else {
clearParameterArray(currentArray);
return currentArray;
}
}
/*======================================================================*/
bool parameterArrayIsEmpty(ParameterArray array) {
return array == nullptr || lengthOfParameterArray(array) == 0;
}
/*======================================================================*/
void clearParameter(Parameter *parameter) {
Parameter *candidates = parameter->candidates;
memset(parameter, 0, sizeof(Parameter));
parameter->candidates = candidates;
if (parameter->candidates != nullptr)
clearParameterArray(parameter->candidates);
}
/*======================================================================*/
void setGlobalParameters(ParameterArray newParameters) {
if (globalParameters == nullptr)
globalParameters = newParameterArray();
copyParameterArray(globalParameters, newParameters);
}
/*======================================================================*/
Parameter *getGlobalParameters(void) {
if (globalParameters == nullptr)
globalParameters = newParameterArray();
return globalParameters;
}
/*======================================================================*/
Parameter *getGlobalParameter(int parameterIndex) {
return &globalParameters[parameterIndex];
}
/*======================================================================*/
Parameter *findEndOfParameterArray(Parameter *parameters) {
Parameter *parameter;
for (parameter = parameters; !isEndOfArray(parameter); parameter++);
return parameter;
}
/*======================================================================*/
/* A parameter position with code == 0 means this is a multiple position.
* We must loop over this position (and replace it by each present in the
* matched list)
*/
int findMultiplePosition(Parameter parameters[]) {
// TODO: this should look at the isAll and isExplicitMultiple flags instead
int multiplePosition;
for (multiplePosition = 0; !isEndOfArray(&parameters[multiplePosition]); multiplePosition++)
if (parameters[multiplePosition].instance == 0)
return multiplePosition;
return -1;
}
/*======================================================================*/
void compressParameterArray(Parameter theArray[]) {
int i, j;
for (i = 0, j = 0; !isEndOfArray(&theArray[j]); j++)
if (theArray[j].instance != 0)
theArray[i++] = theArray[j];
setEndOfArray(&theArray[i]);
}
/*======================================================================*/
int lengthOfParameterArray(Parameter theArray[]) {
int i = 0;
if (theArray == nullptr) return 0;
while (!isEndOfArray(&theArray[i]))
i++;
return i;
}
/*======================================================================*/
bool equalParameterArrays(Parameter parameters1[], Parameter parameters2[]) {
int i;
if ((parameters1 == nullptr) != (parameters2 == nullptr))
return FALSE;
if (parameters1 == nullptr) // Because then parameter2 is also NULL
return TRUE;
for (i = 0; !isEndOfArray(&parameters1[i]); i++) {
if (isEndOfArray(&parameters2[i])) return FALSE;
if (parameters1[i].instance != parameters2[i].instance) return FALSE;
}
return isEndOfArray(&parameters2[i]);
}
/*======================================================================*/
bool inParameterArray(Parameter theArray[], Aword theCode) {
int i;
for (i = 0; !isEndOfArray(&theArray[i]) && theArray[i].instance != theCode; i++);
return (theArray[i].instance == theCode);
}
/*======================================================================*/
void copyParameter(Parameter *to, Parameter *from) {
Parameter *toCandidates = to->candidates;
*to = *from;
if (from->candidates != nullptr) {
if (toCandidates == nullptr)
to->candidates = newParameterArray();
else
to->candidates = toCandidates;
copyParameterArray(to->candidates, from->candidates);
} else if (toCandidates != nullptr)
freeParameterArray(toCandidates);
}
/*======================================================================*/
void addParameterToParameterArray(ParameterArray theArray, Parameter *theParameter) {
if (theArray == nullptr) syserr("Adding to null parameter array");
uint i;
for (i = 0; !isEndOfArray(&theArray[i]) && i < MAXINSTANCE; i++)
;
if (isEndOfArray(&theArray[i])) {
copyParameter(&theArray[i], theParameter);
setEndOfArray(&theArray[i + 1]);
} else
syserr("Couldn't find end of ParameterArray");
}
/*======================================================================*/
void copyParameterArray(ParameterArray to, ParameterArray from) {
int i;
if (to == nullptr && from == nullptr) return;
if (to == nullptr)
syserr("Copying to null parameter array");
else {
clearParameterArray(to);
for (i = 0; !isEndOfArray(&from[i]); i++)
addParameterToParameterArray(to, &from[i]);
}
}
/*======================================================================*/
void subtractParameterArrays(Parameter theArray[], Parameter remove[]) {
int i;
if (remove == nullptr) return;
for (i = 0; !isEndOfArray(&theArray[i]); i++)
if (inParameterArray(remove, theArray[i].instance))
theArray[i].instance = 0; /* Mark empty */
compressParameterArray(theArray);
}
/*======================================================================*/
void clearParameterArray(Parameter theArray[]) {
Parameter *p = &theArray[0];
for (p = &theArray[0]; !isEndOfArray(p); p++)
clearParameter(p);
setEndOfArray(theArray);
}
/*======================================================================*/
void intersectParameterArrays(Parameter one[], Parameter other[]) {
int i, last = 0;
for (i = 0; !isEndOfArray(&one[i]); i++)
if (inParameterArray(other, one[i].instance))
one[last++] = one[i];
setEndOfArray(&one[last]);
}
/*======================================================================*/
void copyReferencesToParameterArray(Aint references[], Parameter parameterArray[]) {
int i;
for (i = 0; !isEndOfArray(&references[i]); i++) {
parameterArray[i].instance = references[i];
parameterArray[i].firstWord = EOD; /* Ensure that there is no word that can be used */
}
setEndOfArray(&parameterArray[i]);
}
/*======================================================================*/
void addParameterForInstance(Parameter *parameters, int instance) {
Parameter *parameter = findEndOfParameterArray(parameters);
parameter->instance = instance;
parameter->useWords = FALSE;
setEndOfArray(parameter + 1);
}
/*======================================================================*/
void addParameterForInteger(ParameterArray parameters, int value) {
Parameter *parameter = findEndOfParameterArray(parameters);
createIntegerLiteral(value);
parameter->instance = instanceFromLiteral(litCount);
parameter->useWords = FALSE;
setEndOfArray(parameter + 1);
}
/*======================================================================*/
void addParameterForString(Parameter *parameters, char *value) {
Parameter *parameter = findEndOfParameterArray(parameters);
createStringLiteral(value);
parameter->instance = instanceFromLiteral(litCount);
parameter->useWords = FALSE;
setEndOfArray(parameter + 1);
}
/*======================================================================*/
void printParameterArray(Parameter parameters[]) {
int i;
printf("[");
for (i = 0; !isEndOfArray(&parameters[i]); i++) {
printf("%d ", (int)parameters[i].instance);
}
printf("]\n");
}
} // End of namespace Alan3
} // 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_ALAN3_PARAMS
#define GLK_ALAN3_PARAMS
/* Various utility functions for handling parameters */
#include "glk/alan3/types.h"
#include "glk/alan3/acode.h"
namespace Glk {
namespace Alan3 {
/* TYPES */
struct Parameter { /* PARAMETER */
Aid instance; /* Instance code for the parameter (0=multiple) */
bool isLiteral;
bool isPronoun;
bool isThem;
bool useWords; /* Indicate to use words instead of instance code when saying */
int firstWord; /* Index to first word used by player */
int lastWord; /* d:o to last */
struct Parameter *candidates; /* Array of instances possibly matching this parameter depending on player input */
};
typedef Parameter *ParameterArray;
/* DATA */
extern Parameter *globalParameters;
/* FUNCTIONS */
/* Single Parameter: */
extern Parameter *newParameter(int instanceId);
extern void clearParameter(Parameter *parameter);
extern void copyParameter(Parameter *theCopy, Parameter *theOriginal);
/* ParameterArray: */
extern ParameterArray newParameterArray(void);
extern ParameterArray ensureParameterArrayAllocated(ParameterArray currentArray);
extern void freeParameterArray(Parameter *array);
extern bool parameterArrayIsEmpty(ParameterArray parameters);
extern void addParameterToParameterArray(ParameterArray theArray, Parameter *theParameter);
extern void addParameterForInstance(ParameterArray parameters, int instance);
extern void addParameterForInteger(ParameterArray parameters, int value);
extern void addParameterForString(ParameterArray parameters, char *value);
extern Parameter *findEndOfParameterArray(ParameterArray parameters);
extern void compressParameterArray(ParameterArray a);
extern int lengthOfParameterArray(ParameterArray a);
extern bool equalParameterArrays(ParameterArray parameters1, ParameterArray parameters2);
extern bool inParameterArray(ParameterArray l, Aword e);
extern void copyParameterArray(ParameterArray to, ParameterArray from);
extern void clearParameterArray(ParameterArray list);
extern void subtractParameterArrays(ParameterArray a, ParameterArray b);
extern void mergeParameterArrays(ParameterArray a, ParameterArray b);
extern void intersectParameterArrays(ParameterArray a, ParameterArray b);
extern void copyReferencesToParameterArray(Aint *references, ParameterArray parameters);
extern void printParameterArray(ParameterArray parameters);
extern int findMultiplePosition(ParameterArray parameters);
/* Global Parameters: */
extern void setGlobalParameters(ParameterArray parameters);
extern ParameterArray getGlobalParameters(void);
extern ParameterArray getGlobalParameter(int parameterIndex);
} // End of namespace Alan3
} // End of namespace Glk
#endif

1520
engines/glk/alan3/parse.cpp Normal file

File diff suppressed because it is too large Load Diff

42
engines/glk/alan3/parse.h Normal file
View File

@@ -0,0 +1,42 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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_ALAN3_PARSE
#define GLK_ALAN3_PARSE
/* Parse data for ALAN interpreter module. */
#include "glk/alan3/types.h"
#include "glk/alan3/params.h"
#include "glk/jumps.h"
namespace Glk {
namespace Alan3 {
/* FUNCTIONS */
extern void parse(CONTEXT);
extern void initParsing(void);
} // End of namespace Alan3
} // End of namespace Glk
#endif

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_ALAN3_RESOURCES
#define GLK_ALAN3_RESOURCES
#define IDC_STATIC (-1)
#define IDR_ARUN 25000
#define IDR_ABOUT 27000
#define IDD_ABOUT 26000
#define ID_MENU_RESTART 26001
#define ID_MENU_SAVE 26002
#define ID_MENU_RECORD 26003
#define ID_MENU_PLAYBACK 26004
#define ID_MENU_TRANSCRIPT 26005
#define ID_MENU_RESTORE 26006
#define ID_MENU_ABOUT 26007
#endif

View File

@@ -0,0 +1,655 @@
/* 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/alan3/types.h"
#include "glk/alan3/lists.h"
#include "glk/alan3/checkentry.h"
#include "glk/alan3/rules.h"
#include "glk/alan3/msg.h"
#include "glk/alan3/utils.h"
#include "glk/alan3/compatibility.h"
#include "glk/alan3/syserr.h"
#include "glk/alan3/memory.h"
namespace Glk {
namespace Alan3 {
extern Aword *memory;
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static Aaddr memorySize = 0;
static Aword *addressesDone = nullptr;
static int numberDone = 0;
static int doneSize = 0;
static bool alreadyDone(Aaddr address) {
int i;
if (address == 0) return TRUE;
/* Have we already done it? */
for (i = 0; i < numberDone; i++)
if (addressesDone[i] == address)
return TRUE;
if (doneSize == numberDone) {
doneSize += 100;
addressesDone = (Aword *)realloc(addressesDone, doneSize * sizeof(Aword));
}
addressesDone[numberDone] = address;
numberDone++;
return FALSE;
}
#define NATIVE(w) \
( (((Aword)((w)[3]) ) & 0x000000ff) \
| (((Aword)((w)[2]) << 8) & 0x0000ff00) \
| (((Aword)((w)[1]) << 16) & 0x00ff0000) \
| (((Aword)((w)[0]) << 24) & 0xff000000))
/*----------------------------------------------------------------------*/
Aword reversed(Aword w) { /* IN - The ACODE word to swap bytes of */
#ifdef TRYNATIVE
return NATIVE(&w);
#else
Aword s; /* The swapped ACODE word */
char *wp, *sp;
uint i;
wp = (char *) &w;
sp = (char *) &s;
for (i = 0; i < sizeof(Aword); i++)
sp[sizeof(Aword) - 1 - i] = wp[i];
return s;
#endif
}
void reverseWord(Aword *w) { /* IN - The ACODE word to reverse bytes in */
*w = reversed(*w);
}
void reverse(Aword *w) { /* IN - The ACODE word to reverse bytes in */
if (w < &memory[0] || w > &memory[memorySize])
syserr("Reversing address outside of memory");
reverseWord(w);
}
static void reverseTable(Aword adr, int elementSize) {
Aword *e = &memory[adr];
uint i;
if (elementSize < (int)sizeof(Aword) || elementSize % (int)sizeof(Aword) != 0)
syserr("***Wrong size in 'reverseTable()' ***");
if (adr == 0) return;
while (!isEndOfArray(e)) {
for (i = 0; i < elementSize / sizeof(Aword); i++) {
reverse(e);
e++;
}
}
}
static void reverseStms(Aword adr) {
Aword *e = &memory[adr];
if (!adr || alreadyDone(adr)) return;
while (TRUE) {
reverse(e);
if (*e == ((Aword)C_STMOP << 28 | (Aword)I_RETURN)) break;
e++;
}
}
static void reverseMsgs(Aword adr) {
MessageEntry *e = (MessageEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(MessageEntry));
while (!isEndOfArray(e)) {
reverseStms(e->stms);
e++;
}
}
}
static void reverseDictionary(Aword adr) {
DictionaryEntry *e = (DictionaryEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(DictionaryEntry));
while (!isEndOfArray(e)) {
if ((e->classBits & SYNONYM_BIT) == 0) { /* Do not do this for synonyms */
reverseTable(e->adjectiveRefs, sizeof(Aword));
reverseTable(e->nounRefs, sizeof(Aword));
reverseTable(e->pronounRefs, sizeof(Aword));
}
e++;
}
}
}
static void reverseChks(Aword adr) {
CheckEntry *e = (CheckEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(CheckEntry));
while (!isEndOfArray(e)) {
reverseStms(e->exp);
reverseStms(e->stms);
e++;
}
}
}
static void reverseAlts(Aword adr) {
AltEntry *e = (AltEntry *)&memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(AltEntry));
while (!isEndOfArray(e)) {
reverseChks(e->checks);
reverseStms(e->action);
e++;
}
}
}
static void reverseVerbs(Aword adr) {
VerbEntry *e = (VerbEntry *)&memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(VerbEntry));
while (!isEndOfArray(e)) {
reverseAlts(e->alts);
e++;
}
}
}
static void reverseSteps(Aword adr) {
StepEntry *e = (StepEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(StepEntry));
while (!isEndOfArray(e)) {
reverseStms(e->after);
reverseStms(e->exp);
reverseStms(e->stms);
e++;
}
}
}
static void reverseScrs(Aword adr) {
ScriptEntry *e = (ScriptEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(ScriptEntry));
while (!isEndOfArray(e)) {
reverseStms(e->description);
reverseSteps(e->steps);
e++;
}
}
}
static void reverseExits(Aword adr) {
ExitEntry *e = (ExitEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(ExitEntry));
while (!isEndOfArray(e)) {
reverseChks(e->checks);
reverseStms(e->action);
e++;
}
}
}
static void reverseClasses(Aword adr) {
ClassEntry *e = (ClassEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(ClassEntry));
while (!isEndOfArray(e)) {
reverseStms(e->name);
reverseStms(e->initialize);
reverseChks(e->descriptionChecks);
reverseStms(e->description);
reverseStms(e->entered);
reverseStms(e->definite.address);
reverseStms(e->indefinite.address);
reverseStms(e->negative.address);
reverseStms(e->mentioned);
reverseVerbs(e->verbs);
e++;
}
}
}
static void reverseInstances(Aword adr) {
InstanceEntry *e = (InstanceEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(InstanceEntry));
while (!isEndOfArray(e)) {
reverseStms(e->name);
reverseTable(e->initialAttributes, sizeof(AttributeHeaderEntry));
reverseStms(e->initialize);
reverseStms(e->definite.address);
reverseStms(e->indefinite.address);
reverseStms(e->negative.address);
reverseStms(e->mentioned);
reverseChks(e->checks);
reverseStms(e->description);
reverseVerbs(e->verbs);
reverseStms(e->entered);
reverseExits(e->exits);
e++;
}
}
}
static void reverseRestrictions(Aword adr) {
RestrictionEntry *e = (RestrictionEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(RestrictionEntry));
while (!isEndOfArray(e)) {
reverseStms(e->stms);
e++;
}
}
}
static void reverseElms(Aword adr) {
ElementEntry *e = (ElementEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(ElementEntry));
while (!isEndOfArray(e)) {
if ((uint)e->code == EOS) reverseRestrictions(e->next);
else reverseElms(e->next);
e++;
}
}
}
static void reverseSyntaxTableCurrent(Aword adr) {
SyntaxEntry *e = (SyntaxEntry *) &memory[adr];
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(SyntaxEntry));
while (!isEndOfArray(e)) {
reverseElms(e->elms);
reverseTable(e->parameterNameTable, sizeof(Aaddr));
e++;
}
}
}
static void reverseSyntaxTablePreBeta2(Aword adr) {
SyntaxEntryPreBeta2 *e = (SyntaxEntryPreBeta2 *) &memory[adr];
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(SyntaxEntryPreBeta2));
while (!isEndOfArray(e)) {
reverseElms(e->elms);
e++;
}
}
}
static void reverseSyntaxTable(Aword adr, byte version[]) {
if (!adr || alreadyDone(adr)) return;
if (isPreBeta2(version))
reverseSyntaxTablePreBeta2(adr);
else
reverseSyntaxTableCurrent(adr);
}
static void reverseParameterNames(Aaddr parameterMapAddress) {
Aaddr *e;
Aaddr adr;
adr = addressAfterTable(parameterMapAddress, sizeof(ParameterMapEntry));
reverse(&memory[adr]);
adr = memory[adr];
reverseTable(adr, sizeof(Aaddr));
e = (Aaddr *) &memory[adr];
while (!isEndOfArray(e)) {
reverseTable(*e, sizeof(Aaddr));
e++;
}
}
static void reverseParameterTable(Aword adr) {
ParameterMapEntry *e = (ParameterMapEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(ParameterMapEntry));
while (!isEndOfArray(e)) {
reverseTable(e->parameterMapping, sizeof(Aword));
e++;
}
}
}
static void reverseEvts(Aword adr) {
EventEntry *e = (EventEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(EventEntry));
while (!isEndOfArray(e)) {
reverseStms(e->code);
e++;
}
}
}
static void reverseLims(Aword adr) {
LimitEntry *e = (LimitEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(LimitEntry));
while (!isEndOfArray(e)) {
reverseStms(e->stms);
e++;
}
}
}
static void reverseContainers(Aword adr) {
ContainerEntry *e = (ContainerEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(ContainerEntry));
while (!isEndOfArray(e)) {
reverseLims(e->limits);
reverseStms(e->header);
reverseStms(e->empty);
reverseChks(e->extractChecks);
reverseStms(e->extractStatements);
e++;
}
}
}
static void reverseRuls(Aword adr) {
RuleEntry *e = (RuleEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(RuleEntry));
while (!isEndOfArray(e)) {
reverseStms(e->exp);
reverseStms(e->stms);
e++;
}
}
}
static void reverseSetInitTable(Aaddr adr) {
SetInitEntry *e = (SetInitEntry *)&memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(SetInitEntry));
while (!isEndOfArray(e)) {
reverseTable(e->setAddress, sizeof(Aword));
e++;
}
}
}
/*----------------------------------------------------------------------*/
static void reversePreAlpha5Header(Pre3_0alpha5Header *hdr) {
uint i;
/* Reverse all words in the header except the tag */
for (i = 1; i < sizeof(*hdr) / sizeof(Aword); i++)
reverseWord(&((Aword *)hdr)[i]);
}
/*----------------------------------------------------------------------*/
static void reversePreAlpha5() {
/* NOTE that the reversePreXXX() have different header definitions */
Pre3_0alpha5Header *hdr = (Pre3_0alpha5Header *)memory;
reversePreAlpha5Header(hdr);
memorySize = hdr->size;
reverseDictionary(hdr->dictionary);
reverseSyntaxTable(hdr->syntaxTableAddress, hdr->version);
reverseParameterTable(hdr->parameterMapAddress);
reverseVerbs(hdr->verbTableAddress);
reverseClasses(hdr->classTableAddress);
reverseInstances(hdr->instanceTableAddress);
reverseScrs(hdr->scriptTableAddress);
reverseContainers(hdr->containerTableAddress);
reverseEvts(hdr->eventTableAddress);
reverseRuls(hdr->ruleTableAddress);
reverseTable(hdr->stringInitTable, sizeof(StringInitEntry));
reverseSetInitTable(hdr->setInitTable);
reverseTable(hdr->sourceFileTable, sizeof(SourceFileEntry));
reverseTable(hdr->sourceLineTable, sizeof(SourceLineEntry));
reverseStms(hdr->start);
reverseMsgs(hdr->messageTableAddress);
reverseTable(hdr->scores, sizeof(Aword));
reverseTable(hdr->freq, sizeof(Aword));
}
/*----------------------------------------------------------------------*/
static void reversePreBeta2Header(Pre3_0beta2Header *hdr) {
uint i;
/* Reverse all words in the header except the tag */
for (i = 1; i < sizeof(*hdr) / sizeof(Aword); i++)
reverseWord(&((Aword *)hdr)[i]);
}
/*----------------------------------------------------------------------*/
static void reversePreBeta2() {
/* NOTE that the reversePreXXX() have different header definitions */
Pre3_0beta2Header *hdr = (Pre3_0beta2Header *)memory;
reversePreBeta2Header(hdr);
memorySize = hdr->size;
reverseDictionary(hdr->dictionary);
reverseSyntaxTable(hdr->syntaxTableAddress, hdr->version);
reverseParameterTable(hdr->parameterMapAddress);
reverseVerbs(hdr->verbTableAddress);
reverseClasses(hdr->classTableAddress);
reverseInstances(hdr->instanceTableAddress);
reverseScrs(hdr->scriptTableAddress);
reverseContainers(hdr->containerTableAddress);
reverseEvts(hdr->eventTableAddress);
reverseRuls(hdr->ruleTableAddress);
reverseTable(hdr->stringInitTable, sizeof(StringInitEntry));
reverseSetInitTable(hdr->setInitTable);
reverseTable(hdr->sourceFileTable, sizeof(SourceFileEntry));
reverseTable(hdr->sourceLineTable, sizeof(SourceLineEntry));
reverseStms(hdr->start);
reverseMsgs(hdr->messageTableAddress);
reverseTable(hdr->scores, sizeof(Aword));
reverseTable(hdr->freq, sizeof(Aword));
}
/*======================================================================*/
void reverseHdr(ACodeHeader *hdr) {
uint i;
/* Reverse all words in the header except the tag and the version marking */
for (i = 1; i < sizeof(*hdr) / sizeof(Aword); i++)
reverseWord(&((Aword *)hdr)[i]);
}
/*----------------------------------------------------------------------*/
static void reverseInstanceIdTable(ACodeHeader *hdr) {
reverseTable(hdr->instanceTableAddress + hdr->instanceMax * sizeof(InstanceEntry) / sizeof(Aword) + 1, sizeof(Aword));
}
/*----------------------------------------------------------------------*/
static void reverseNative() {
/* NOTE that the reversePreXXX() have different hdr definitions */
ACodeHeader *hdr = (ACodeHeader *)memory;
reverseHdr(hdr);
memorySize = hdr->size;
reverseDictionary(hdr->dictionary);
reverseSyntaxTable(hdr->syntaxTableAddress, hdr->version);
if (hdr->debug && !isPreBeta3(hdr->version))
reverseParameterNames(hdr->parameterMapAddress);
reverseParameterTable(hdr->parameterMapAddress);
reverseVerbs(hdr->verbTableAddress);
reverseClasses(hdr->classTableAddress);
reverseInstances(hdr->instanceTableAddress);
if (hdr->debug && !isPreBeta3(hdr->version))
reverseInstanceIdTable(hdr);
reverseScrs(hdr->scriptTableAddress);
reverseContainers(hdr->containerTableAddress);
reverseEvts(hdr->eventTableAddress);
reverseRuls(hdr->ruleTableAddress);
reverseTable(hdr->stringInitTable, sizeof(StringInitEntry));
reverseSetInitTable(hdr->setInitTable);
reverseTable(hdr->sourceFileTable, sizeof(SourceFileEntry));
reverseTable(hdr->sourceLineTable, sizeof(SourceLineEntry));
reverseStms(hdr->prompt);
reverseStms(hdr->start);
reverseMsgs(hdr->messageTableAddress);
reverseTable(hdr->scores, sizeof(Aword));
reverseTable(hdr->freq, sizeof(Aword));
}
/*======================================================================
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(void) {
ACodeHeader *hdr = (ACodeHeader *)memory;
byte version[4];
int i;
/* Make a copy of the version marking to reverse */
for (i = 0; i <= 3; i++)
version[i] = hdr->version[i];
reverseWord((Aword *)&version);
if (isPreAlpha5(version))
reversePreAlpha5();
else if (isPreBeta2(version))
reversePreBeta2();
else
reverseNative();
free(addressesDone);
}
} // End of namespace Alan3
} // End of namespace Glk

View File

@@ -0,0 +1,42 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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_ALAN3_REVERSE
#define GLK_ALAN3_REVERSE
/* Header file for reverse-module in Alan Interpreter */
#include "glk/alan3/types.h"
namespace Glk {
namespace Alan3 {
/* Functions: */
extern void reverseHdr(ACodeHeader *hdr);
extern void reverseACD(void);
extern void reverse(Aword *word);
extern Aword reversed(Aword word);
} // End of namespace Alan3
} // End of namespace Glk
#endif

263
engines/glk/alan3/rules.cpp Normal file
View File

@@ -0,0 +1,263 @@
/* 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/alan3/types.h"
#include "glk/alan3/rules.h"
#include "glk/alan3/lists.h"
#include "glk/alan3/inter.h"
#include "glk/alan3/debug.h"
#include "glk/alan3/current.h"
#include "glk/alan3/options.h"
#include "glk/alan3/compatibility.h"
#ifdef HAVE_GLK
#include "glk/alan3/glkio.h"
#endif
namespace Glk {
namespace Alan3 {
/* PUBLIC DATA: */
RuleEntry *rules; /* Rule table pointer */
bool anyRuleRun;
/* PRIVATE TYPES: */
typedef struct RulesAdmin {
bool lastEval;
bool alreadyRun;
} RulesAdmin;
/* PRIVATE DATA: */
static int ruleCount;
static RulesAdmin *rulesAdmin; /* Table for administration of the rules */
/*----------------------------------------------------------------------*/
static void clearRulesAdmin(int numRules) {
int r;
for (r = 0; r < numRules; r++) {
rulesAdmin[r].lastEval = FALSE;
rulesAdmin[r].alreadyRun = FALSE;
}
}
/*----------------------------------------------------------------------*/
static void initRulesAdmin(int numRules) {
int r;
rulesAdmin = (RulesAdmin *)allocate(numRules * sizeof(RulesAdmin) + sizeof(EOD));
for (r = 0; r < numRules; r++)
;
setEndOfArray(&rulesAdmin[r]);
}
/*======================================================================*/
void initRules(Aaddr ruleTableAddress) {
rules = (RuleEntry *) pointerTo(ruleTableAddress);
if (ruleCount == 0) { /* Not initiated */
for (ruleCount = 0; !isEndOfArray(&rules[ruleCount]); ruleCount++)
;
initRulesAdmin(ruleCount);
}
clearRulesAdmin(ruleCount);
}
/*----------------------------------------------------------------------*/
static void traceRuleStart(CONTEXT, int rule, const char *what) {
printf("\n<RULE %d", rule);
if (current.location != 0) {
printf(" (at ");
CALL1(traceSay, current.location)
} else
printf(" (nowhere");
printf("[%d]), %s", current.location, what);
}
static bool detailedTraceOn() {
return traceInstructionOption || traceSourceOption || tracePushOption || traceStackOption;
}
/*----------------------------------------------------------------------*/
static void traceRuleEvaluation(CONTEXT, int rule) {
if (traceSectionOption) {
if (detailedTraceOn()) {
CALL2(traceRuleStart, rule, "Evaluating:>")
if (!traceInstructionOption)
printf("\n");
} else {
CALL2(traceRuleStart, rule, "Evaluating to ")
}
}
}
/*----------------------------------------------------------------------*/
static void traceRuleResult(int rule, bool result) {
if (traceSectionOption) {
if (detailedTraceOn())
printf("<RULE %d %s%s", rule, "Evaluated to ", result ? ": true>\n" : ": false>\n");
else
printf(result ? "true" : "false");
}
}
/*----------------------------------------------------------------------*/
static void traceRuleExecution(CONTEXT, int rule) {
if (traceSectionOption) {
if (!traceInstructionOption && !traceSourceOption)
printf(", Executing:>\n");
else {
CALL2(traceRuleStart, rule, "Executing:>")
if (!traceInstructionOption)
printf("\n");
}
}
}
/*----------------------------------------------------------------------*/
static void evaluateRulesPreBeta2(CONTEXT) {
bool change = TRUE;
bool flag;
int i;
for (i = 1; !isEndOfArray(&rules[i - 1]); i++)
rules[i - 1].alreadyRun = FALSE;
while (change) {
change = FALSE;
for (i = 1; !isEndOfArray(&rules[i - 1]); i++)
if (!rules[i - 1].alreadyRun) {
CALL1(traceRuleEvaluation, i)
FUNC1(evaluate, flag, rules[i - 1].exp)
if (flag) {
change = TRUE;
rules[i - 1].alreadyRun = TRUE;
CALL1(traceRuleExecution, i)
CALL1(interpret, rules[i - 1].stms)
} else if (traceSectionOption && !traceInstructionOption)
printf(":>\n");
}
}
}
/*----------------------------------------------------------------------*/
/* This is how beta2 thought rules should be evaluated:
*/
static void evaluateRulesBeta2(CONTEXT) {
bool change = TRUE;
bool triggered;
int i;
for (i = 1; !isEndOfArray(&rules[i - 1]); i++)
rules[i - 1].alreadyRun = FALSE;
current.location = NOWHERE;
current.actor = 0;
while (change) {
change = FALSE;
for (i = 1; !isEndOfArray(&rules[i - 1]); i++)
if (!rules[i - 1].alreadyRun) {
CALL1(traceRuleEvaluation, i)
FUNC1(evaluate, triggered, rules[i - 1].exp)
if (triggered) {
if (rulesAdmin[i - 1].lastEval == false) {
change = TRUE;
rules[i - 1].alreadyRun = TRUE;
CALL1(traceRuleExecution, i)
CALL1(interpret, rules[i - 1].stms)
}
rulesAdmin[i - 1].lastEval = triggered;
} else {
rulesAdmin[i - 1].lastEval = false;
if (traceSectionOption && !traceInstructionOption)
printf(":>\n");
}
}
}
}
/*======================================================================*/
void resetRules() {
int i;
for (i = 1; !isEndOfArray(&rules[i - 1]); i++) {
rulesAdmin[i - 1].alreadyRun = FALSE;
}
}
/*======================================================================*/
void evaluateRules(CONTEXT, RuleEntry ruleList[]) {
bool change = TRUE;
bool evaluated_value;
int rule;
current.location = NOWHERE;
current.actor = 0;
while (change) {
change = FALSE;
for (rule = 1; !isEndOfArray(&ruleList[rule - 1]); rule++) {
CALL1(traceRuleEvaluation, rule)
FUNC1(evaluate, evaluated_value, ruleList[rule - 1].exp)
traceRuleResult(rule, evaluated_value);
if (evaluated_value == true && rulesAdmin[rule - 1].lastEval == false
&& !rulesAdmin[rule - 1].alreadyRun) {
change = TRUE;
CALL1(traceRuleExecution, rule)
CALL1(interpret, ruleList[rule - 1].stms)
rulesAdmin[rule - 1].alreadyRun = TRUE;
anyRuleRun = TRUE;
} else {
if (traceSectionOption && !(traceInstructionOption || traceSourceOption))
printf(":>\n");
}
rulesAdmin[rule - 1].lastEval = evaluated_value;
}
}
}
/*=======================================================================*/
void resetAndEvaluateRules(CONTEXT, RuleEntry ruleList[], const byte *version) {
if (isPreBeta2(version))
evaluateRulesPreBeta2(context);
else if (isPreBeta3(version))
evaluateRulesBeta2(context);
else {
resetRules();
evaluateRules(context, ruleList);
}
}
} // End of namespace Alan3
} // End of namespace Glk

46
engines/glk/alan3/rules.h Normal file
View File

@@ -0,0 +1,46 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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_ALAN3_RULES
#define GLK_ALAN3_RULES
/* Header file for rules handler in Alan interpreter */
#include "glk/jumps.h"
#include "glk/alan3/acode.h"
namespace Glk {
namespace Alan3 {
/* DATA */
extern RuleEntry *rules; /* Rule table pointer */
extern bool anyRuleRun; /* Did any rule run? */
/* FUNCTIONS */
extern void initRules(Aaddr rulesTableAddress);
extern void resetAndEvaluateRules(CONTEXT, RuleEntry rules[], const byte *version);
extern void resetRules(void);
extern void evaluateRules(CONTEXT, RuleEntry rules[]);
} // End of namespace Alan3
} // End of namespace Glk
#endif

158
engines/glk/alan3/save.cpp Normal file
View File

@@ -0,0 +1,158 @@
/* 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/alan3/save.h"
#include "glk/alan3/acode.h"
#include "glk/alan3/current.h"
#include "glk/alan3/event.h"
#include "glk/alan3/instance.h"
#include "glk/alan3/lists.h"
#include "glk/alan3/memory.h"
#include "glk/alan3/msg.h"
#include "glk/alan3/options.h"
#include "glk/alan3/score.h"
#include "glk/alan3/types.h"
namespace Glk {
namespace Alan3 {
static void saveGameInfo(Common::WriteStream *saveFile) {
saveFile->writeUint32BE(MKTAG('A', 'S', 'A', 'V'));
saveFile->write(header->version, 4);
saveFile->writeUint32LE(header->uid);
}
static void verifySaveFile(CONTEXT, Common::SeekableReadStream *saveFile) {
if (saveFile->readUint32BE() != MKTAG('A', 'S', 'A', 'V'))
error(context, M_NOTASAVEFILE);
}
static void verifyCompilerVersion(CONTEXT, Common::SeekableReadStream *saveFile) {
char savedVersion[4];
saveFile->read(&savedVersion, 4);
if (!ignoreErrorOption && memcmp(savedVersion, header->version, 4))
error(context, M_SAVEVERS);
}
static void verifyGameId(CONTEXT, Common::SeekableReadStream *saveFile) {
Aword savedUid = saveFile->readUint32LE();
if (!ignoreErrorOption && savedUid != header->uid)
error(context, M_SAVEVERS);
}
void syncGame(Common::Serializer &s) {
// Current values
current.synchronize(s);
// Attributes area
for (Aint i = 0; i < header->attributesAreaSize / 3; ++i)
attributes[i].synchronize(s);
// Admin data
for (uint i = 1; i <= header->instanceMax; i++)
admin[i].synchronize(s);
// Event queue
s.syncAsSint32LE(eventQueueTop);
for (int i = 0; i < eventQueueTop; ++i)
eventQueue[i].synchronize(s);
// Scores
for (Aint i = 0; i < header->scoreCount; ++i)
s.syncAsUint32LE(scores[i]);
// Strings
if (header->stringInitTable != 0)
for (StringInitEntry *initEntry = (StringInitEntry *)pointerTo(header->stringInitTable);
!isEndOfArray(initEntry); initEntry++) {
if (s.isSaving()) {
char *attr = (char *)getInstanceStringAttribute(initEntry->instanceCode, initEntry->attributeCode);
Aint length = strlen(attr) + 1;
s.syncAsUint32LE(length);
s.syncBytes((byte *)attr, length);
} else {
Aint length = 0;
s.syncAsUint32LE(length);
char *string = (char *)allocate(length + 1);
s.syncBytes((byte *)string, length);
setInstanceAttribute(initEntry->instanceCode, initEntry->attributeCode, toAptr(string));
}
}
// Sets
if (header->setInitTable != 0) {
for (SetInitEntry *initEntry = (SetInitEntry *)pointerTo(header->setInitTable);
!isEndOfArray(initEntry); initEntry++) {
if (s.isSaving()) {
Set *attr = (Set *)getInstanceSetAttribute(initEntry->instanceCode, initEntry->attributeCode);
s.syncAsUint32LE(attr->size);
for (int i = 0; i < attr->size; ++i)
s.syncAsUint32LE(attr->members[i]);
} else {
Aword setSize = 0, member = 0;
s.syncAsUint32BE(setSize);
Set *set = newSet(setSize);
for (uint i = 0; i < setSize; ++i) {
s.syncAsUint32LE(member);
addToSet(set, member);
}
setInstanceAttribute(initEntry->instanceCode, initEntry->attributeCode, toAptr(set));
}
}
}
}
void saveGame(Common::WriteStream *saveFile) {
// Save tag, version of interpreter, and unique id of game
saveGameInfo(saveFile);
// Save game data
Common::Serializer s(nullptr, saveFile);
syncGame(s);
}
bool restoreGame(Common::SeekableReadStream *saveFile) {
Context ctx;
verifySaveFile(ctx, saveFile);
if (ctx._break) return false;
// Verify version of compiler/interpreter of saved game with us
verifyCompilerVersion(ctx, saveFile);
if (ctx._break) return false;
// Verify unique id of game
verifyGameId(ctx, saveFile);
if (ctx._break) return false;
// Restore game data
Common::Serializer s(saveFile, nullptr);
syncGame(s);
return true;
}
} // End of namespace Alan3
} // End of namespace Glk

36
engines/glk/alan3/save.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_ALAN3_SAVE
#define GLK_ALAN3_SAVE
#include "common/stream.h"
namespace Glk {
namespace Alan3 {
extern void saveGame(Common::WriteStream *saveFile);
extern bool restoreGame(Common::SeekableReadStream *saveFile);
} // End of namespace Alan3
} // End of namespace Glk
#endif

243
engines/glk/alan3/scan.cpp Normal file
View File

@@ -0,0 +1,243 @@
/* 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/alan3/scan.h"
#include "glk/alan3/lists.h"
#include "glk/alan3/dictionary.h"
#include "glk/alan3/debug.h"
#include "glk/alan3/exe.h"
#include "glk/alan3/glkio.h"
#include "glk/alan3/inter.h"
#include "glk/alan3/literal.h"
#include "glk/alan3/memory.h"
#include "glk/alan3/msg.h"
#include "glk/alan3/options.h"
#include "glk/alan3/output.h"
#include "glk/alan3/params.h"
#include "glk/alan3/syserr.h"
#include "glk/alan3/word.h"
namespace Glk {
namespace Alan3 {
/* PUBLIC DATA */
bool continued = FALSE;
/* PRIVATE DATA */
static char buf[1000]; /* The input buffer */
static char isobuf[1000]; /* The input buffer in ISO */
static bool eol = TRUE; /* Looking at End of line? Yes, initially */
static char *token = nullptr;
/*======================================================================*/
void forceNewPlayerInput() {
setEndOfArray(&playerWords[currentWordIndex]);
}
/*----------------------------------------------------------------------*/
static void unknown(CONTEXT, char tok[]) {
char *str = scumm_strdup(tok);
Parameter *messageParameters = newParameterArray();
addParameterForString(messageParameters, str);
printMessageWithParameters(M_UNKNOWN_WORD, messageParameters);
deallocate(messageParameters);
free(str);
CALL0(abortPlayerCommand)
}
/*----------------------------------------------------------------------*/
static int number(char tok[]) {
int i;
(void)sscanf(tok, "%d", &i);
return i;
}
/*----------------------------------------------------------------------*/
static int lookup(CONTEXT, char wrd[]) {
int i;
for (i = 0; !isEndOfArray(&dictionary[i]); i++) {
if (compareStrings(wrd, (char *) pointerTo(dictionary[i].string)) == 0) {
return (i);
}
}
R0CALL1(unknown, wrd)
return (int)EOD;
}
/*----------------------------------------------------------------------*/
static bool isWordCharacter(int ch) {
return isISOLetter(ch) || Common::isDigit(ch) || ch == '\'' || ch == '-' || ch == '_';
}
/*----------------------------------------------------------------------*/
static char *gettoken(char *txtBuf) {
static char *marker;
static char oldch;
if (txtBuf == nullptr)
*marker = oldch;
else
marker = txtBuf;
while (*marker != '\0' && isSpace(*marker) && *marker != '\n')
marker++;
txtBuf = marker;
if (isISOLetter(*marker))
while (*marker && isWordCharacter(*marker))
marker++;
else if (Common::isDigit((int)*marker))
while (Common::isDigit((int)*marker))
marker++;
else if (*marker == '\"') {
marker++;
while (*marker != '\"')
marker++;
marker++;
} else if (*marker == '\0' || *marker == '\n' || *marker == ';')
return nullptr;
else
marker++;
oldch = *marker;
*marker = '\0';
return txtBuf;
}
/*----------------------------------------------------------------------*/
// TODO replace dependency to exe.c with injection of quitGame() and undo()
static void getLine(CONTEXT) {
para();
do {
CALL0(g_io->statusLine)
if (header->prompt) {
anyOutput = FALSE;
CALL1(interpret, header->prompt)
if (anyOutput)
printAndLog(" ");
needSpace = FALSE;
} else
printAndLog("> ");
bool flag;
FUNC2(g_io->readLine, flag, buf, 255);
if (!flag) {
newline();
CALL0(quitGame)
}
getPageSize();
anyOutput = FALSE;
if (transcriptOption || logOption) {
// TODO: Refactor out the logging to log.c?
g_io->glk_put_string_stream(logFile, buf);
g_io->glk_put_char_stream(logFile, '\n');
}
/* If the player input an empty command he forfeited his command */
if (strlen(buf) == 0) {
clearWordList(playerWords);
LONG_JUMP_LABEL("forfeit")
}
Common::strcpy_s(isobuf, buf);
token = gettoken(isobuf);
if (token != nullptr) {
if (strcmp("debug", token) == 0 && header->debug) {
debugOption = TRUE;
CALL3(debug, FALSE, 0, 0)
token = nullptr;
} else if (strcmp("undo", token) == 0) {
token = gettoken(nullptr);
if (token != nullptr) /* More tokens? */
CALL1(error, M_WHAT)
CALL0(undo)
}
}
} while (token == nullptr);
eol = FALSE;
}
/*======================================================================*/
void scan(CONTEXT) {
int i;
int w;
if (continued) {
/* Player used '.' to separate commands. Read next */
para();
token = gettoken(nullptr); /* Or did he just finish the command with a full stop? */
if (token == nullptr) {
CALL0(getLine)
}
continued = FALSE;
} else {
CALL0(getLine)
}
freeLiterals();
playerWords[0].code = 0; // TODO This means what?
i = 0;
do {
ensureSpaceForPlayerWords(i + 1);
playerWords[i].start = token;
playerWords[i].end = strchr(token, '\0');
if (isISOLetter(token[0])) {
FUNC1(lookup, w, token);
if (!isNoise(w))
playerWords[i++].code = w;
} else if (Common::isDigit((int)token[0]) || token[0] == '\"') {
if (Common::isDigit((int)token[0])) {
createIntegerLiteral(number(token));
} else {
char *unquotedString = scumm_strdup(token);
unquotedString[strlen(token) - 1] = '\0';
createStringLiteral(&unquotedString[1]);
free(unquotedString);
}
playerWords[i++].code = dictionarySize + litCount; /* Word outside dictionary = literal */
} else if (token[0] == ',') {
playerWords[i++].code = conjWord;
} else if (token[0] == '.') {
continued = TRUE;
setEndOfArray(&playerWords[i]);
eol = TRUE;
break;
} else
CALL1(unknown, token)
setEndOfArray(&playerWords[i]);
eol = (token = gettoken(nullptr)) == nullptr;
} while (!eol);
}
} // End of namespace Alan3
} // End of namespace Glk

45
engines/glk/alan3/scan.h Normal file
View File

@@ -0,0 +1,45 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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_ALAN3_SCAN
#define GLK_ALAN3_SCAN
/* Player input scanner for ALAN interpreter module. */
#include "glk/alan3/types.h"
#include "glk/jumps.h"
namespace Glk {
namespace Alan3 {
/* DATA */
extern bool continued;
/* FUNCTIONS */
extern void forceNewPlayerInput();
extern void scan(CONTEXT);
} // End of namespace Alan3
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,31 @@
/* 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/alan3/score.h"
namespace Glk {
namespace Alan3 {
/* PUBLIC DATA */
Aword *scores; // Score table pointer
} // End of namespace Alan3
} // End of namespace Glk

36
engines/glk/alan3/score.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_ALAN3_SCORE
#define GLK_ALAN3_SCORE
#include "glk/alan3/acode.h"
namespace Glk {
namespace Alan3 {
/* DATA */
extern Aword *scores;
} // End of namespace Alan3
} // End of namespace Glk
#endif

169
engines/glk/alan3/set.cpp Normal file
View File

@@ -0,0 +1,169 @@
/* 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/alan3/set.h"
#include "glk/alan3/lists.h"
#include "glk/alan3/syserr.h"
#include "glk/alan3/memory.h"
#include "glk/alan3/instance.h"
namespace Glk {
namespace Alan3 {
#define EXTENT 5
/*======================================================================*/
Set *newSet(int allocation) {
Set *theSet = NEW(Set);
if (allocation) {
theSet->members = (Aword *)allocate(allocation * sizeof(theSet->members[0]));
theSet->size = 0;
theSet->allocated = allocation;
}
return theSet;
}
/*======================================================================*/
void initSets(SetInitEntry *initTable) {
SetInitEntry *init;
int i;
for (init = initTable; !isEndOfArray(init); init++) {
Set *set = newSet(init->size);
Aword *member = (Aword *)pointerTo(init->setAddress);
for (i = 0; i < init->size; i++, member++)
addToSet(set, *member);
setInstanceAttribute(init->instanceCode, init->attributeCode, toAptr(set));
}
}
/*======================================================================*/
int setSize(Set *theSet) {
return theSet->size;
}
/*======================================================================*/
void clearSet(Set *theSet) {
theSet->size = 0;
}
/*======================================================================*/
Set *copySet(Set *theSet) {
Set *nset = newSet(theSet->size);
int i;
for (i = 1; i <= theSet->size; i++)
addToSet(nset, getSetMember(theSet, i));
return nset;
}
/*======================================================================*/
Aword getSetMember(Set *theSet, Aint theMember) {
if (theMember > theSet->size || theMember < 1)
apperr("Accessing nonexisting member in a set");
return theSet->members[theMember - 1];
}
/*======================================================================*/
bool inSet(Set *theSet, Aword member) {
int i;
for (i = 1; i <= theSet->size; i++)
if (getSetMember(theSet, i) == member)
return TRUE;
return FALSE;
}
/*=======================================================================*/
Set *setUnion(Set *set1, Set *set2) {
Set *theUnion = newSet(set1->size + set2->size);
int i;
for (i = 0; i < set1->size; i++)
addToSet(theUnion, set1->members[i]);
for (i = 0; i < set2->size; i++)
addToSet(theUnion, set2->members[i]);
return theUnion;
}
/*=======================================================================*/
void addToSet(Set *theSet, Aword newMember) {
if (inSet(theSet, newMember)) return;
if (theSet->size == theSet->allocated) {
theSet->allocated += EXTENT;
theSet->members = (Aword *)realloc(theSet->members, theSet->allocated * sizeof(theSet->members[0]));
}
theSet->members[theSet->size] = newMember;
theSet->size++;
}
/*=======================================================================*/
void removeFromSet(Set *theSet, Aword member) {
int i, j;
if (!inSet(theSet, member)) return;
for (i = 0; i < theSet->size; i++) {
if ((Aword)theSet->members[i] == member) {
for (j = i; j < theSet->size - 1; j++)
theSet->members[j] = theSet->members[j + 1];
theSet->size--;
break;
}
}
}
/*=======================================================================*/
bool equalSets(Set *set1, Set *set2) {
int i;
if (set1->size != set2->size) return FALSE;
for (i = 0; i < set1->size; i++) {
if (!inSet(set2, set1->members[i]))
return FALSE;
}
return TRUE;
}
/*======================================================================*/
void freeSet(Set *theSet) {
if (theSet != nullptr) {
if (theSet->members != nullptr)
deallocate(theSet->members);
deallocate(theSet);
}
}
} // End of namespace Alan3
} // End of namespace Glk

63
engines/glk/alan3/set.h Normal file
View File

@@ -0,0 +1,63 @@
/* 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_ALAN3_SET
#define GLK_ALAN3_SET
/* Abstract datatype Set for Alan interpreter
A set is implemented as a struct holding a size and a
dynamically allocated array of members. Members can be
integers or instance numbers. Attributes of Set type is
allocated and the pointer to it is used as the attribute
value. As members are only references, clearing a set can
simply be done by setting the size to zero.
*/
#include "glk/alan3/acode.h"
#include "glk/alan3/types.h"
namespace Glk {
namespace Alan3 {
struct Set {
int size;
int allocated;
Aword *members;
};
extern Set *newSet(int size);
extern void initSets(SetInitEntry *initTable);
extern int setSize(Set *theSet);
extern void clearSet(Set *theSet);
extern Set *copySet(Set *theSet);
extern Aword getSetMember(Set *theSet, Aint member);
extern bool inSet(Set *theSet, Aword member);
extern void addToSet(Set *theSet, Aword newMember);
extern void removeFromSet(Set *theSet, Aword member);
extern Set *setUnion(Set *theSet, Set *other);
extern bool equalSets(Set *theSet, Set *other);
extern void freeSet(Set *theSet);
} // End of namespace Alan3
} // End of namespace Glk
#endif

174
engines/glk/alan3/stack.cpp Normal file
View File

@@ -0,0 +1,174 @@
/* 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/alan3/stack.h"
#include "glk/alan3/glkio.h"
#include "glk/alan3/types.h"
#include "glk/alan3/memory.h"
#include "glk/alan3/options.h"
#include "glk/alan3/syserr.h"
namespace Glk {
namespace Alan3 {
/*======================================================================*/
Stack createStack(int size) {
StackStructure *theStack = NEW(StackStructure);
theStack->stack = (Aword *)allocate(size * sizeof(Aptr));
theStack->stackSize = size;
theStack->framePointer = -1;
return theStack;
}
/*======================================================================*/
void deleteStack(Stack theStack) {
if (theStack == nullptr)
syserr("deleting a NULL stack");
deallocate(theStack->stack);
deallocate(theStack);
}
/*======================================================================*/
int stackDepth(Stack theStack) {
return theStack->stackp;
}
/*======================================================================*/
void dumpStack(Stack theStack) {
int i;
if (theStack == nullptr)
syserr("NULL stack not supported anymore");
printf("[");
for (i = 0; i < theStack->stackp; i++)
printf("%ld ", (unsigned long) theStack->stack[i]);
printf("]");
if (!traceInstructionOption && !tracePushOption)
printf("\n");
}
/*======================================================================*/
void push(Stack theStack, Aptr i) {
if (theStack == nullptr)
syserr("NULL stack not supported anymore");
if (theStack->stackp == theStack->stackSize)
syserr("Out of stack space.");
theStack->stack[(theStack->stackp)++] = i;
}
/*======================================================================*/
Aptr pop(Stack theStack) {
if (theStack == nullptr)
syserr("NULL stack not supported anymore");
if (theStack->stackp == 0)
syserr("Stack underflow.");
return theStack->stack[--(theStack->stackp)];
}
/*======================================================================*/
Aptr top(Stack theStack) {
if (theStack == nullptr)
syserr("NULL stack not supported anymore");
return theStack->stack[theStack->stackp - 1];
}
/* The AMACHINE Block Frames */
/*======================================================================*/
void newFrame(Stack theStack, Aint noOfLocals) {
int n;
if (theStack == nullptr)
syserr("NULL stack not supported anymore");
push(theStack, theStack->framePointer);
theStack->framePointer = theStack->stackp;
for (n = 0; n < noOfLocals; n++)
push(theStack, 0);
}
/*======================================================================*/
/* Local variables are numbered 1 and up and stored on their index-1 */
Aptr getLocal(Stack theStack, Aint framesBelow, Aint variableNumber) {
int frame;
int frameCount;
if (variableNumber < 1)
syserr("Reading a non-existing block-local variable.");
if (theStack == nullptr)
syserr("NULL stack not supported anymore");
frame = theStack->framePointer;
if (framesBelow != 0)
for (frameCount = framesBelow; frameCount != 0; frameCount--)
frame = theStack->stack[frame - 1];
return theStack->stack[frame + variableNumber - 1];
}
/*======================================================================*/
void setLocal(Stack theStack, Aint framesBelow, Aint variableNumber, Aptr value) {
int frame;
int frameCount;
if (variableNumber < 1)
syserr("Writing a non-existing block-local variable.");
if (theStack == nullptr)
syserr("NULL stack not supported anymore");
frame = theStack->framePointer;
if (framesBelow != 0)
for (frameCount = framesBelow; frameCount != 0; frameCount--)
frame = theStack->stack[frame - 1];
theStack->stack[frame + variableNumber - 1] = value;
}
/*======================================================================*/
void endFrame(Stack theStack) {
if (theStack == nullptr)
syserr("NULL stack not supported anymore");
theStack->stackp = theStack->framePointer;
theStack->framePointer = pop(theStack);
}
} // End of namespace Alan3
} // End of namespace Glk

61
engines/glk/alan3/stack.h Normal file
View File

@@ -0,0 +1,61 @@
/* 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_ALAN3_STACK
#define GLK_ALAN3_STACK
/* Header file for stack handler in Alan interpreter */
#include "glk/alan3/acode.h"
namespace Glk {
namespace Alan3 {
struct StackStructure {
Aword *stack; // Array that can take Awords
int stackSize;
int stackp;
int framePointer;
};
typedef StackStructure *Stack;
/* FUNCTIONS: */
/* NB: The stack uses Aptr size elements since we need to be able to store pointers to allocated memory */
extern Stack createStack(int size);
extern void deleteStack(Stack stack);
extern void dumpStack(Stack theStack);
extern Aptr pop(Stack stack);
extern void push(Stack stack, Aptr item);
extern Aptr top(Stack theStack);
extern int stackDepth(Stack theStack);
extern void newFrame(Stack theStack, Aint noOfLocals);
extern void setLocal(Stack theStack, Aint blocksBelow, Aint variableNumber, Aptr value);
extern Aptr getLocal(Stack theStack, Aint level, Aint variable);
extern void endFrame(Stack theStack);
} // End of namespace Alan3
} // End of namespace Glk
#endif

357
engines/glk/alan3/state.cpp Normal file
View File

@@ -0,0 +1,357 @@
/* 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/alan3/state.h"
#include "glk/alan3/syserr.h"
#include "glk/alan3/current.h"
#include "glk/alan3/word.h"
#include "glk/alan3/state_stack.h"
#include "glk/alan3/instance.h"
#include "glk/alan3/attribute.h"
#include "glk/alan3/memory.h"
#include "glk/alan3/score.h"
#include "glk/alan3/event.h"
#include "glk/alan3/set.h"
namespace Glk {
namespace Alan3 {
/* PRIVATE TYPES */
/* Implementation of the abstract type typedef struct game_state GameState */
struct game_state {
/* Event queue */
EventQueueEntry *eventQueue;
int eventQueueTop; /* Event queue top pointer */
/* Scores */
int score;
Aword *scores; /* Score table pointer */
/* Instance data */
AdminEntry *admin; /* Administrative data about instances */
AttributeEntry *attributes; /* Attributes data area */
/* Sets and strings are dynamically allocated areas for which the
attribute is just a pointer to. So they are not catched by the
saving of attributes, instead they require special storage */
Set **sets; /* Array of set pointers */
char **strings; /* Array of string pointers */
};
/* PRIVATE DATA */
static GameState gameState; /* TODO: Make pointer, then we don't have to copy to stack, we can just use the pointer */
static StateStackP stateStack = nullptr;
static char *playerCommand;
/*----------------------------------------------------------------------*/
static int countStrings(void) {
StringInitEntry *entry;
int count = 0;
if (header->stringInitTable != 0)
for (entry = (StringInitEntry *)pointerTo(header->stringInitTable); * (Aword *)entry != EOD; entry++)
count++;
return (count);
}
/*----------------------------------------------------------------------*/
static void deallocateStrings(GameState *gState) {
int count = countStrings();
int i;
for (i = 0; i < count; i++)
deallocate(gState->strings[i]);
deallocate(gState->strings);
}
/*----------------------------------------------------------------------*/
static int countSets(void) {
SetInitEntry *entry;
int count = 0;
if (header->setInitTable != 0)
for (entry = (SetInitEntry *)pointerTo(header->setInitTable); * (Aword *)entry != EOD; entry++)
count++;
return (count);
}
/*----------------------------------------------------------------------*/
static void deallocateSets(GameState *gState) {
int count = countSets();
int i;
for (i = 0; i < count; i++)
freeSet(gState->sets[i]);
deallocate(gState->sets);
}
/*======================================================================*/
void deallocateGameState(GameState *gState) {
deallocate(gState->admin);
deallocate(gState->attributes);
if (gState->eventQueueTop > 0) {
deallocate(gState->eventQueue);
gState->eventQueue = nullptr;
}
if (gState->scores)
deallocate(gState->scores);
deallocateStrings(gState);
deallocateSets(gState);
memset(gState, 0, sizeof(GameState));
}
/*======================================================================*/
void forgetGameState(void) {
char *playerCmd;
popGameState(stateStack, &gameState, &playerCmd);
deallocateGameState(&gameState);
if (playerCmd != nullptr)
deallocate(playerCmd);
}
/*======================================================================*/
void initStateStack(void) {
if (stateStack != nullptr)
deleteStateStack(stateStack);
stateStack = createStateStack(sizeof(GameState));
}
/*======================================================================*/
void terminateStateStack(void) {
deleteStateStack(stateStack);
stateStack = nullptr;
}
/*======================================================================*/
bool anySavedState(void) {
return !stateStackIsEmpty(stateStack);
}
/*----------------------------------------------------------------------*/
static Set **collectSets(void) {
SetInitEntry *entry;
int count = countSets();
Set **sets;
int i;
if (count == 0) return nullptr;
sets = (Set **)allocate(count * sizeof(Set));
entry = (SetInitEntry *)pointerTo(header->setInitTable);
for (i = 0; i < count; i++)
sets[i] = getInstanceSetAttribute(entry[i].instanceCode, entry[i].attributeCode);
return sets;
}
/*----------------------------------------------------------------------*/
static char **collectStrings(void) {
StringInitEntry *entry;
int count = countStrings();
char **strings;
int i;
if (count == 0) return nullptr;
strings = (char **)allocate(count * sizeof(char *));
entry = (StringInitEntry *)pointerTo(header->stringInitTable);
for (i = 0; i < count; i++)
strings[i] = getInstanceStringAttribute(entry[i].instanceCode, entry[i].attributeCode);
return strings;
}
/*======================================================================*/
void rememberCommands(void) {
char *command = playerWordsAsCommandString();
attachPlayerCommandsToLastState(stateStack, command);
deallocate(command);
}
/*----------------------------------------------------------------------*/
static void collectEvents(void) {
gameState.eventQueueTop = eventQueueTop;
if (eventQueueTop > 0)
gameState.eventQueue = (EventQueueEntry *)duplicate(eventQueue, eventQueueTop * sizeof(EventQueueEntry));
}
/*----------------------------------------------------------------------*/
static void collectInstanceData(void) {
gameState.admin = (AdminEntry *)duplicate(admin, (header->instanceMax + 1) * sizeof(AdminEntry));
gameState.attributes = (AttributeEntry *)duplicate(attributes, header->attributesAreaSize * sizeof(Aword));
gameState.sets = collectSets();
gameState.strings = collectStrings();
}
/*----------------------------------------------------------------------*/
static void collectScores(void) {
gameState.score = current.score;
if (scores == nullptr)
gameState.scores = nullptr;
else
gameState.scores = (Aword *)duplicate(scores, header->scoreCount * sizeof(Aword));
}
/*======================================================================*/
void rememberGameState(void) {
collectEvents();
collectInstanceData();
collectScores();
if (stateStack == nullptr)
initStateStack();
pushGameState(stateStack, &gameState);
gameStateChanged = FALSE;
}
/*----------------------------------------------------------------------*/
static void freeCurrentSetAttributes(void) {
SetInitEntry *entry;
if (header->setInitTable == 0) return;
for (entry = (SetInitEntry *)pointerTo(header->setInitTable); * (Aword *)entry != EOD; entry++) {
Aptr attributeValue = getAttribute(admin[entry->instanceCode].attributes, entry->attributeCode);
freeSet((Set *)fromAptr(attributeValue));
}
}
/*----------------------------------------------------------------------*/
static void recallSets(Set **sets) {
SetInitEntry *entry;
int count = countSets();
int i;
if (header->setInitTable == 0) return;
entry = (SetInitEntry *)pointerTo(header->setInitTable);
for (i = 0; i < count; i++) {
setAttribute(admin[entry[i].instanceCode].attributes, entry[i].attributeCode, toAptr(sets[i]));
sets[i] = nullptr; /* Since we reuse the saved set, we need to clear the pointer */
}
}
/*----------------------------------------------------------------------*/
static void freeCurrentStringAttributes(void) {
StringInitEntry *entry;
if (header->stringInitTable == 0) return;
for (entry = (StringInitEntry *)pointerTo(header->stringInitTable); * (Aword *)entry != EOD; entry++) {
Aptr attributeValue = getAttribute(admin[entry->instanceCode].attributes, entry->attributeCode);
deallocate(fromAptr(attributeValue));
}
}
/*----------------------------------------------------------------------*/
static void recallStrings(char **strings) {
StringInitEntry *entry;
int count = countStrings();
int i;
if (header->stringInitTable == 0) return;
entry = (StringInitEntry *)pointerTo(header->stringInitTable);
for (i = 0; i < count; i++) {
setAttribute(admin[entry[i].instanceCode].attributes, entry[i].attributeCode, toAptr(strings[i]));
strings[i] = nullptr; /* Since we reuse the saved, we need to clear the state */
}
}
/*----------------------------------------------------------------------*/
static void recallEvents(void) {
eventQueueTop = gameState.eventQueueTop;
if (eventQueueTop > 0) {
memcpy(eventQueue, gameState.eventQueue,
(eventQueueTop + 1)*sizeof(EventQueueEntry));
}
}
/*----------------------------------------------------------------------*/
static void recallInstances(void) {
if (admin == nullptr)
syserr("admin[] == NULL in recallInstances()");
memcpy(admin, gameState.admin,
(header->instanceMax + 1)*sizeof(AdminEntry));
freeCurrentSetAttributes(); /* Need to free previous set values */
freeCurrentStringAttributes(); /* Need to free previous string values */
memcpy(attributes, gameState.attributes,
header->attributesAreaSize * sizeof(Aword));
recallSets(gameState.sets);
recallStrings(gameState.strings);
}
/*----------------------------------------------------------------------*/
static void recallScores(void) {
current.score = gameState.score;
memcpy(scores, gameState.scores, header->scoreCount * sizeof(Aword));
}
/*======================================================================*/
void recallGameState(void) {
popGameState(stateStack, &gameState, &playerCommand);
recallEvents();
recallInstances();
recallScores();
deallocateGameState(&gameState);
}
/*======================================================================*/
char *recreatePlayerCommand(void) {
return playerCommand;
}
} // End of namespace Alan3
} // End of namespace Glk

50
engines/glk/alan3/state.h Normal file
View File

@@ -0,0 +1,50 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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_ALAN3_STATE
#define GLK_ALAN3_STATE
/* Header file for instruction state and undo handling in Alan interpreter */
#include "glk/alan3/types.h"
namespace Glk {
namespace Alan3 {
/* DATA */
struct game_state;
typedef struct game_state GameState;
/* FUNCTIONS */
extern bool anySavedState(void);
extern void initStateStack(void);
extern void rememberGameState(void);
extern void forgetGameState(void);
extern void rememberCommands(void);
extern void recallGameState(void);
extern char *recreatePlayerCommand(void);
extern void terminateStateStack(void);
extern void deallocateGameState(GameState *gameState);
} // End of namespace Alan3
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,125 @@
/* 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/alan3/state_stack.h"
#include "glk/alan3/syserr.h"
#include "glk/alan3/memory.h"
#include "glk/alan3/state.h"
namespace Glk {
namespace Alan3 {
/* CONSTANTS: */
#define EXTENT 10
/* PRIVATE TYPES: */
struct StateStackStructure {
void **states;
char **commands;
int stackSize;
int stackPointer; /* Points above used stack, 0 initially */
int elementSize; /* Size of elements in the stack */
};
/*----------------------------------------------------------------------*/
static void *reallocate(void *from, int newSize) {
void *newArea = realloc(from, newSize * sizeof(void *));
if (newArea == nullptr)
syserr("Out of memory in 'reallocateStack()'");
return newArea;
}
/*======================================================================*/
StateStackP createStateStack(int elementSize) {
StateStackP stack = NEW(StateStackStructure);
stack->stackSize = 0;
stack->stackPointer = 0;
stack->elementSize = elementSize;
return stack;
}
/*======================================================================*/
void deleteStateStack(StateStackP stateStack) {
if (stateStack != nullptr) {
while (stateStack->stackPointer > 0) {
stateStack->stackPointer--;
deallocateGameState((GameState *)stateStack->states[stateStack->stackPointer]);
deallocate(stateStack->states[stateStack->stackPointer]);
deallocate(stateStack->commands[stateStack->stackPointer]);
}
if (stateStack->stackSize > 0) {
deallocate(stateStack->states);
deallocate(stateStack->commands);
}
deallocate(stateStack);
}
}
/*======================================================================*/
bool stateStackIsEmpty(StateStackP stateStack) {
return stateStack->stackPointer == 0;
}
/*----------------------------------------------------------------------*/
static void ensureSpaceForGameState(StateStackP stack) {
if (stack->stackPointer == stack->stackSize) {
stack->states = (void **)reallocate(stack->states, stack->stackSize + EXTENT);
stack->commands = (char **)reallocate(stack->commands, stack->stackSize + EXTENT);
stack->stackSize += EXTENT;
}
}
/*======================================================================*/
void pushGameState(StateStackP stateStack, void *gameState) {
void *element = allocate(stateStack->elementSize);
memcpy(element, gameState, stateStack->elementSize);
ensureSpaceForGameState(stateStack);
stateStack->commands[stateStack->stackPointer] = nullptr;
stateStack->states[stateStack->stackPointer++] = element;
}
/*======================================================================*/
void attachPlayerCommandsToLastState(StateStackP stateStack, char *playerCommands) {
stateStack->commands[stateStack->stackPointer - 1] = scumm_strdup(playerCommands);
}
/*======================================================================*/
void popGameState(StateStackP stateStack, void *gameState, char **playerCommand) {
if (stateStack->stackPointer == 0)
syserr("Popping GameState from empty stack");
else {
stateStack->stackPointer--;
memcpy(gameState, stateStack->states[stateStack->stackPointer], stateStack->elementSize);
deallocate(stateStack->states[stateStack->stackPointer]);
*playerCommand = stateStack->commands[stateStack->stackPointer];
}
}
} // End of namespace Alan3
} // End of namespace Glk

View File

@@ -0,0 +1,44 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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_ALAN3_STATE_STACK
#define GLK_ALAN3_STATE_STACK
#include "glk/alan3/types.h"
namespace Glk {
namespace Alan3 {
/* TYPES */
typedef struct StateStackStructure *StateStackP;
/* FUNCTIONS */
extern StateStackP createStateStack(int elementSize);
extern bool stateStackIsEmpty(StateStackP stateStack);
extern void pushGameState(StateStackP stateStack, void *state);
extern void popGameState(StateStackP stateStack, void *state, char **playerCommandPointer);
extern void attachPlayerCommandsToLastState(StateStackP stateStack, char *playerCommand);
extern void deleteStateStack(StateStackP stateStack);
} // End of namespace Alan3
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,94 @@
/* 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/alan3/syntax.h"
#include "glk/alan3/word.h"
#include "glk/alan3/msg.h"
#include "glk/alan3/lists.h"
#include "glk/alan3/compatibility.h"
namespace Glk {
namespace Alan3 {
/* PUBLIC DATA */
SyntaxEntry *stxs; /* Syntax table pointer */
/* PRIVATE TYPES & DATA */
/*+++++++++++++++++++++++++++++++++++++++++++++++++++*/
/*======================================================================*/
ElementEntry *elementTreeOf(SyntaxEntry *stx) {
return (ElementEntry *) pointerTo(stx->elms);
}
/*----------------------------------------------------------------------*/
static SyntaxEntry *findSyntaxEntryForPreBeta2(int verbCode, SyntaxEntry *foundStx) {
SyntaxEntryPreBeta2 *stx;
for (stx = (SyntaxEntryPreBeta2 *)stxs; !isEndOfArray(stx); stx++)
if (stx->code == verbCode) {
foundStx = (SyntaxEntry *)stx;
break;
}
return (foundStx);
}
/*----------------------------------------------------------------------*/
static SyntaxEntry *findSyntaxEntry(int verbCode) {
SyntaxEntry *stx;
for (stx = stxs; !isEndOfArray(stx); stx++)
if (stx->code == verbCode) {
return stx;
break;
}
return nullptr;
}
/*======================================================================*/
SyntaxEntry *findSyntaxTreeForVerb(CONTEXT, int verbCode) {
SyntaxEntry *foundStx = nullptr;
if (isPreBeta2(header->version)) {
foundStx = findSyntaxEntryForPreBeta2(verbCode, foundStx);
} else {
foundStx = findSyntaxEntry(verbCode);
}
if (foundStx == nullptr)
// No matching syntax
R0CALL1(error, M_WHAT)
return foundStx;
}
/*======================================================================*/
char *parameterNameInSyntax(int syntaxNumber, int parameterNumber) {
Aaddr adr = addressAfterTable(header->parameterMapAddress, sizeof(ParameterMapEntry));
Aaddr *syntaxParameterNameTable = (Aaddr *)pointerTo(memory[adr]);
Aaddr *parameterNameTable = (Aaddr *)pointerTo(syntaxParameterNameTable[syntaxNumber - 1]);
return stringAt(parameterNameTable[parameterNumber - 1]);
}
} // End of namespace Alan3
} // End of namespace Glk

View File

@@ -0,0 +1,44 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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_ALAN3_SYNTAX
#define GLK_ALAN3_SYNTAX
#include "glk/alan3/types.h"
#include "glk/jumps.h"
#include "glk/alan3/memory.h"
namespace Glk {
namespace Alan3 {
/* DATA */
extern SyntaxEntry *stxs; /* Syntax table pointer */
/* FUNCTIONS */
extern ElementEntry *elementTreeOf(SyntaxEntry *stx);
extern char *parameterNameInSyntax(int syntaxNumber, int parameterNumber);
extern SyntaxEntry *findSyntaxTreeForVerb(CONTEXT, int verbCode);
} // End of namespace Alan3
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,332 @@
/* 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/alan3/sysdep.h"
#include "glk/alan3/alan3.h"
#include "glk/alan3/glkio.h"
#include "glk/alan3/syserr.h"
namespace Glk {
namespace Alan3 {
/* 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 .A3C 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 const byte spaceCharacters[] = {
0x0A, /* linefeed */
0x20, /* space */
0xA0, /* non-breaking space */
0x00
};
static const byte lowerCaseCharacters[] = {
0x61, /* a */ 0x62, /* b */ 0x63, /* c */ 0x64, /* d */
0x65, /* e */ 0x66, /* f */ 0x67, /* g */ 0x68, /* h */
0x69, /* i */ 0x6A, /* j */ 0x6B, /* k */ 0x6C, /* l */
0x6D, /* m */ 0x6E, /* n */ 0x6F, /* o */ 0x70, /* p */
0x71, /* q */ 0x72, /* r */ 0x73, /* s */ 0x74, /* t */
0x75, /* u */ 0x76, /* v */ 0x77, /* w */ 0x78, /* x */
0x79, /* y */ 0x7A, /* z */ 0xDF, /* ss <small sharp s> */
0xE0, /* a grave */ 0xE1, /* a acute */
0xE2, /* a circumflex */ 0xE3, /* a tilde */
0xE4, /* a diaeresis */ 0xE5, /* a ring */
0xE6, /* ae */ 0xE7, /* c cedilla */
0xE8, /* e grave */ 0xE9, /* e acute */
0xEA, /* e circumflex */ 0xEB, /* e diaeresis */
0xEC, /* i grave */ 0xED, /* i acute */
0xEE, /* i circumflex */ 0xEF, /* i diaeresis */
0xF0, /* <small eth> */ 0xF1, /* n tilde */
0xF2, /* o grave */ 0xF3, /* o acute */
0xF4, /* o circumflex */ 0xF5, /* o tilde */
0xF6, /* o diaeresis */ 0xF8, /* o slash */
0xF9, /* u grave */ 0xFA, /* u acute */
0xFB, /* u circumflex */ 0xFC, /* u diaeresis */
0xFD, /* y acute */ 0xFE, /* <small thorn> */
0xFF, /* y diaeresis */ 0x00
};
/* FIXME: ss <small sharp s> and y diaeresis have no UC analogues
Are they really considered LC?
*/
static const byte upperCaseCharacters[] = {
0x41, /* A */ 0x42, /* B */ 0x43, /* C */ 0x44, /* D */
0x45, /* E */ 0x46, /* F */ 0x47, /* G */ 0x48, /* H */
0x49, /* I */ 0x4A, /* J */ 0x4B, /* K */ 0x4C, /* L */
0x4D, /* M */ 0x4E, /* N */ 0x4F, /* O */ 0x50, /* P */
0x51, /* Q */ 0x52, /* R */ 0x53, /* S */ 0x54, /* T */
0x55, /* U */ 0x56, /* V */ 0x57, /* W */ 0x58, /* X */
0x59, /* Y */ 0x5A, /* Z */
0xC0, /* A grave */ 0xC1, /* A acute */
0xC2, /* A circumflex */ 0xC3, /* A tilde */
0xC4, /* A diaeresis */ 0xC5, /* A ring */
0xC6, /* AE */ 0xC7, /* C cedilla */
0xC8, /* E grave */ 0xC9, /* E acute */
0xCA, /* E circumflex */ 0xCB, /* E diaeresis */
0xCC, /* I grave */ 0xCD, /* I acute */
0xCE, /* I circumflex */ 0xCF, /* I diaeresis */
0xD0, /* <capital eth> */ 0xD1, /* N tilde */
0xD2, /* O grave */ 0xD3, /* O acute */
0xD4, /* O circumflex */ 0xD5, /* O tilde */
0xD6, /* O diaeresis */ 0xD8, /* O slash */
0xD9, /* U grave */ 0xDA, /* U acute */
0xDB, /* U circumflex */ 0xDC, /* U diaeresis */
0xDD, /* Y acute */ 0xDE, /* <capital thorn> */
0x00
};
int isSpace(unsigned int c) {
return (c != '\0' && strchr((const char *)spaceCharacters, c) != nullptr);
}
int isLower(unsigned int c) {
return (c != '\0' && strchr((const char *)lowerCaseCharacters, c) != nullptr);
}
int isUpper(unsigned int c) {
return (c != '\0' && strchr((const char *)upperCaseCharacters, c) != nullptr);
}
int isLetter(unsigned int c) {
return (c != '\0' && (isLower(c) ? !0 : isUpper(c)));
}
int toLower(unsigned int c) {
return g_vm->glk_char_to_lower(c);
}
int toUpper(unsigned int c) {
return g_vm->glk_char_to_upper(c);
}
char *strlow(char str[]) {
char *s;
for (s = str; *s; s++)
*s = toLower(*s);
return (str);
}
char *strupp(char str[]) {
char *s;
for (s = str; *s; s++)
*s = toUpper(*s);
return (str);
}
/* The following work on ISO characters */
int isLowerCase(unsigned int c) {
uint i;
for (i = 0; i < strlen((const char *)lowerCaseCharacters); i++)
if (((unsigned int)lowerCaseCharacters[i]) == c) return 1;
return 0;
}
int isUpperCase(unsigned int c) {
uint i;
for (i = 0; i < strlen((const char *)upperCaseCharacters); i++)
if (upperCaseCharacters[i] == c) return 1;
return 0;
}
int isISOLetter(int c) {
return (isLowerCase(c) || isUpperCase(c));
}
char IsoToLowerCase(int c) {
return (isUpperCase(c) ? c + ('a' - 'A') : c);
}
char IsoToUpperCase(int c) {
return (isLowerCase(c) ? c - ('a' - 'A') : c);
}
char *stringLower(char str[]) {
char *s;
for (s = str; *s; s++)
*s = IsoToLowerCase(*s);
return (str);
}
char *stringUpper(char str[]) {
char *s;
for (s = str; *s; s++)
*s = IsoToUpperCase(*s);
return (str);
}
/*----------------------------------------------------------------------*/
int compareStrings(char *str1, char *str2) {
char *s1 = str1, *s2 = str2;
while (*s1 != '\0' && *s2 != '\0') {
if (IsoToLowerCase(*s1) < IsoToLowerCase(*s2)) return -1;
if (IsoToLowerCase(*s1) > IsoToLowerCase(*s2)) return 1;
s1++;
s2++;
}
return IsoToLowerCase(*s2) - IsoToLowerCase(*s1);
}
#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 const 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 const 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[], char original[]) {
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.
copy - Mapped string
original - string to convert
charset - the current character set
*/
void toNative(char copy[], char original[], int charset) {
toIso(copy, original, charset);
if (NATIVECHARSET != 0)
fromIso(copy, copy);
}
#endif
/*======================================================================*/
char *baseNameStart(char *fullPathName) {
const char *delimiters = "\\>]/:";
int i;
for (i = strlen(fullPathName) - 1; i > 0; i--)
if (strchr(delimiters, fullPathName[i]) != nullptr)
return &fullPathName[i + 1];
return (fullPathName);
}
} // End of namespace Alan3
} // End of namespace Glk

121
engines/glk/alan3/sysdep.h Normal file
View File

@@ -0,0 +1,121 @@
/* 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_ALAN3_SYSDEP
#define GLK_ALAN3_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 and version (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/util.h"
namespace Glk {
namespace Alan3 {
#define GLK
#define HAVE_GLK
/*----------------------------------------------------------------------
Below follows OS and compiler dependent settings. They should not be
changed except for introducing new sections when porting to new
environments.
*/
/***********************/
/* ISO character sets? */
/***********************/
/* Common case first */
#define ISO 1
#define NATIVECHARSET 0
#undef ISO
#define ISO 1
#undef NATIVECHARSET
#define NATIVECHARSET 0
/**************************/
/* Strings for file modes */
/**************************/
#define READ_MODE "rb"
#define WRITE_MODE "wb"
/****************/
/* don't need TERMIO */
#undef HAVE_TERMIO
/* don't need ANSI */
#undef HAVE_ANSI
#define USE_READLINE
/* Native character functions */
extern int isSpace(unsigned int c); /* IN - Native character to test */
extern int isLower(unsigned int c); /* IN - Native character to test */
extern int isUpper(unsigned int c); /* IN - Native character to test */
extern int isLetter(unsigned int c); /* IN - Native character to test */
extern int toLower(unsigned int c); /* IN - Native character to convert */
extern int toUpper(unsigned 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 IsoToLowerCase(int c); /* IN - ISO character to convert */
extern char IsoToUpperCase(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 */
extern int compareStrings(char str1[], char str2[]); /* Case-insensitive compare */
#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
extern char *baseNameStart(char *fullPathName);
} // End of namespace Alan3
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,103 @@
/* 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/alan3/syserr.h"
#include "glk/alan3/current.h"
#include "glk/alan3/debug.h"
#include "glk/alan3/glkio.h"
#include "glk/alan3/output.h"
#include "glk/alan3/utils.h"
#include "common/textconsole.h"
namespace Glk {
namespace Alan3 {
static void (*handler)(const char *);
/*----------------------------------------------------------------------*/
static void runtimeError(CONTEXT, const char *errorClassification, const char *errorDescription, const char *blurb) {
output("$n$nAs you enter the twilight zone of Adventures, you stumble \
and fall to your knees. In front of you, you can vaguely see the outlines \
of an Adventure that never was.$n$n");
output(errorClassification);
output(errorDescription);
newline();
if (current.sourceLine != 0) {
printf("At source line %d in '%s':\n", current.sourceLine, sourceFileName(current.sourceFile));
printf("%s", readSourceLine(current.sourceFile, current.sourceLine));
}
newline();
output(blurb);
terminate(context, 2);
}
static void runtimeError(const char *errorClassification, const char *errorDescription, const char *blurb) {
::error("%s%s %s", errorClassification, errorDescription, blurb);
}
/*======================================================================*/
void setSyserrHandler(void (*f)(const char *)) {
handler = f;
}
/*======================================================================*/
// TODO Make syserr() use ... as printf()
void syserr(const char *description) {
lin = 0;
if (handler == nullptr) {
const char *blurb = "<If you are the creator of this piece of Interactive Fiction, \
please help debug this Alan system error. Collect *all* the sources, and, if possible, an \
exact transcript of the commands that led to this error, in a zip-file and send \
it to support@alanif.se. Thank you!>";
runtimeError("SYSTEM ERROR: ", description, blurb);
} else
handler(description);
}
/*======================================================================*/
void apperr(const char *description) {
if (handler == nullptr) {
const char *blurb = "<If you are playing this piece of Interactive Fiction, \
please help the author to debug this programming error. Send an exact \
transcript of the commands that led to this error to the author. Thank you! \
If you *are* the author, then you have to figure this out before releasing the game.>";
runtimeError("APPLICATION ERROR: ", description, blurb);
} else
handler(description);
}
/*======================================================================*/
void playererr(CONTEXT, const char *description) {
if (handler == nullptr) {
const char *blurb = "<You have probably done something that is not exactly right.>";
runtimeError(context, "PLAYER ERROR: ", description, blurb);
} else
handler(description);
}
} // End of namespace Alan3
} // 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_ALAN3_SYSERR
#define GLK_ALAN3_SYSERR
/* Header file for syserr unit of ARUN Alan System interpreter */
#include "glk/jumps.h"
namespace Glk {
namespace Alan3 {
/* Functions: */
extern void syserr(const char *msg);
extern void apperr(const char *msg);
extern void playererr(CONTEXT, const char *msg);
extern void setSyserrHandler(void (*handler)(const char *));
} // End of namespace Alan3
} // End of namespace Glk
#endif

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/>.
*
*/
#include "glk/alan3/acode.h"
#include "glk/alan3/lists.h"
namespace Glk {
namespace Alan3 {
/*======================================================================*/
Aaddr addressAfterTable(Aaddr adr, int size) {
while (!isEndOfArray(&memory[adr])) {
adr += size / sizeof(Aword);
}
return adr + 1;
}
} // End of namespace Alan3
} // End of namespace Glk

75
engines/glk/alan3/types.h Normal file
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/>.
*
*/
#ifndef GLK_ALAN3_TYPES
#define GLK_ALAN3_TYPES
/* Header file for the Alan interpreter module. */
#include "glk/alan3/sysdep.h"
#include "glk/alan3/acode.h"
#include "glk/alan3/memory.h"
namespace Glk {
namespace Alan3 {
/* PREPROCESSOR */
#define FORWARD
#define NEW(type) ((type *)allocate(sizeof(type)))
/* CONSTANTS */
#define HERO (header->theHero)
#define ENTITY (header->entityClassId)
#define OBJECT (header->objectClassId)
#define LOCATION (header->locationClassId)
#define THING (header->thingClassId)
#define ACTOR (header->actorClassId)
#define MAXPARAMS (header->maxParameters)
#define MAXINSTANCE (header->instanceMax)
#define pointerTo(x) ((void *)&memory[x])
#define addressOf(x) ((((long)x)-((long)memory))/sizeof(Aword))
#define stringAt(x) ((char *)pointerTo(x))
#define ASIZE(x) (sizeof(x)/sizeof(Aword))
/* The various tables */
struct VerbEntry { /* VERB TABLE */
Aint code; /* Code for the verb */
Aaddr alts; /* Address to alternatives */
};
struct LimitEntry { /* LIMIT Type */
Aword atr; /* Attribute that limits */
Aword val; /* And the limiting value */
Aaddr stms; /* Statements if fail */
};
/* Functions: */
extern Aaddr addressAfterTable(Aaddr adr, int size);
} // End of namespace Alan3
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,97 @@
/* 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/alan3/utils.h"
#include "glk/alan3/alan_version.h"
#include "glk/alan3/glkio.h"
#include "glk/alan3/options.h"
#include "glk/alan3/memory.h"
#include "glk/alan3/output.h"
#include "glk/alan3/exe.h"
#include "glk/alan3/state.h"
#include "glk/alan3/lists.h"
#include "glk/alan3/fnmatch.h"
namespace Glk {
namespace Alan3 {
/*======================================================================
terminate()
Terminate the execution of the adventure, e.g. close windows,
return buffers...
*/
void terminate(CONTEXT, int code) {
newline();
terminateStateStack();
stopTranscript();
if (memory) {
deallocate(memory);
memory = nullptr;
}
g_io->glk_exit();
LONG_JUMP
}
/*======================================================================*/
void printVersion(int buildNumber) {
printf("Arun - Adventure Language Interpreter version %s", alan.version.string);
if (buildNumber != 0) printf("-%d", buildNumber);
printf(" (%s %s)", alan.date, alan.time);
}
/*======================================================================*/
void usage(const char *programName) {
printVersion(0);
printf("\n\nUsage:\n\n");
printf(" %s [<switches>] <adventure>\n\n", programName);
printf("where the possible optional switches are:\n");
g_io->glk_set_style(style_Preformatted);
printf(" -v verbose mode\n");
printf(" -l log transcript to a file\n");
printf(" -c log player commands to a file\n");
printf(" -n no Status Line\n");
printf(" -d enter debug mode\n");
printf(" -t[<n>] trace game execution, higher <n> gives more trace\n");
printf(" -i ignore version and checksum errors\n");
printf(" -r make regression test easier (don't timestamp, page break, randomize...)\n");
g_io->glk_set_style(style_Normal);
}
#ifndef FNM_CASEFOLD
#define FNM_CASEFOLD 0
#endif
/*======================================================================*/
bool match(const char *pattern, char *input) {
return fnmatch(pattern, input, FNM_CASEFOLD) == 0;
}
} // End of namespace Alan3
} // End of namespace Glk

42
engines/glk/alan3/utils.h Normal file
View File

@@ -0,0 +1,42 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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_ALAN3_UTILS
#define GLK_ALAN3_UTILS
/* Utility functions for the Alan interpreter */
#include "glk/alan3/types.h"
#include "glk/jumps.h"
namespace Glk {
namespace Alan3 {
/* FUNCTIONS: */
extern void terminate(CONTEXT, int code);
extern void usage(const char *programName);
extern void printVersion(int buildNumber);
extern bool match(const char *pattern, char *input);
} // End of namespace Alan3
} // 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_ALAN3_VERSION
#define GLK_ALAN3_VERSION
#include "common/scummsys.h"
namespace Glk {
namespace Alan3 {
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;
Version version;
};
} // End of namespace Alan3
} // End of namespace Glk
#endif

View File

@@ -0,0 +1,81 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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/alan3/word.h"
#include "glk/alan3/types.h"
#include "glk/alan3/memory.h"
#include "glk/alan3/syserr.h"
#include "glk/alan3/lists.h"
namespace Glk {
namespace Alan3 {
/* PUBLIC DATA */
/* List of parsed words, index into dictionary */
Word *playerWords = nullptr;
int currentWordIndex; /* An index into the list of playerWords */
int firstWord, lastWord; /* Index for the first and last words for this command */
/* Some variable for dynamically allocating the playerWords, which will happen in scan() */
static int playerWordsLength = 0;
#define PLAYER_WORDS_EXTENT 20
/* What did the user say? */
int verbWord; /* The word he used as a verb, dictionary index */
int verbWordCode; /* The code for that verb */
/* PRIVATE TYPES & DATA */
/*+++++++++++++++++++++++++++++++++++++++++++++++++++*/
void ensureSpaceForPlayerWords(int size) {
int newLength = playerWordsLength + PLAYER_WORDS_EXTENT;
if (playerWordsLength < size + 1) {
playerWords = (Word *)realloc(playerWords, newLength * sizeof(Word));
if (playerWords == nullptr)
syserr("Out of memory in 'ensureSpaceForPlayerWords()'");
playerWordsLength = newLength;
}
}
/*======================================================================*/
char *playerWordsAsCommandString(void) {
char *commandString;
int size = playerWords[lastWord].end - playerWords[firstWord].start;
commandString = (char *)allocate(size + 1);
strncpy(commandString, playerWords[firstWord].start, size);
commandString[size] = '\0';
return commandString;
}
/*======================================================================*/
void clearWordList(Word list[]) {
implementationOfSetEndOfArray((Aword *)list);
}
} // End of namespace Alan3
} // End of namespace Glk

55
engines/glk/alan3/word.h Normal file
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/>.
*
*/
#ifndef GLK_ALAN3_WORD
#define GLK_ALAN3_WORD
namespace Glk {
namespace Alan3 {
typedef struct WordEntry {
int code; /* The dictionary index for that word */
char *start; /* Where does it start */
char *end; /* .. and end */
} Word;
/* DATA */
extern Word *playerWords; /* List of Parsed Word */
extern int currentWordIndex; /* and an index into it */
extern int firstWord;
extern int lastWord;
extern int verbWord;
extern int verbWordCode;
/* FUNCTIONS */
extern void ensureSpaceForPlayerWords(int count);
extern char *playerWordsAsCommandString(void);
extern void clearWordList(Word *list);
} // End of namespace Alan3
} // End of namespace Glk
#endif