aboutsummaryrefslogtreecommitdiff
path: root/engines/glk
diff options
context:
space:
mode:
authorPaul Gilbert2019-06-08 11:18:11 -0700
committerPaul Gilbert2019-06-09 15:00:46 -0700
commitda434f29522d7ee36f33c1b0bd95d9cc03cc5093 (patch)
treec771caea1a973ed56e5bda7cba2bf00cf10f3ec8 /engines/glk
parentb84e9a3dff91480f5d0356dc289c6bae5690c656 (diff)
downloadscummvm-rg350-da434f29522d7ee36f33c1b0bd95d9cc03cc5093.tar.gz
scummvm-rg350-da434f29522d7ee36f33c1b0bd95d9cc03cc5093.tar.bz2
scummvm-rg350-da434f29522d7ee36f33c1b0bd95d9cc03cc5093.zip
GLK: ADVSYS: Adding game data access methods
Diffstat (limited to 'engines/glk')
-rw-r--r--engines/glk/advsys/definitions.h2
-rw-r--r--engines/glk/advsys/game.cpp174
-rw-r--r--engines/glk/advsys/game.h166
3 files changed, 329 insertions, 13 deletions
diff --git a/engines/glk/advsys/definitions.h b/engines/glk/advsys/definitions.h
index 6a02a66a6b..8c96a9ea0a 100644
--- a/engines/glk/advsys/definitions.h
+++ b/engines/glk/advsys/definitions.h
@@ -26,7 +26,7 @@
namespace Glk {
namespace AdvSys {
-
+#define NIL 0
} // End of namespace AdvSys
} // End of namespace Glk
diff --git a/engines/glk/advsys/game.cpp b/engines/glk/advsys/game.cpp
index 69dc6e4bbc..938c85fe51 100644
--- a/engines/glk/advsys/game.cpp
+++ b/engines/glk/advsys/game.cpp
@@ -21,6 +21,7 @@
*/
#include "glk/advsys/game.h"
+#include "glk/advsys/definitions.h"
#include "common/memstream.h"
namespace Glk {
@@ -79,6 +80,23 @@ bool Header::init(Common::ReadStream &s) {
/*--------------------------------------------------------------------------*/
#define MAX_VERSION 102
+#define WORD_SIZE 6
+
+/**
+ * Property flags
+ */
+enum PropertyFlag {
+ P_CLASS = 0x8000
+};
+
+/**
+ * Link fields
+ */
+enum LinkField {
+ L_DATA = 0,
+ L_NEXT = 2,
+ L_SIZE = 4
+};
bool Game::init(Common::SeekableReadStream &s) {
// Load the header
@@ -121,6 +139,9 @@ bool Game::init(Common::SeekableReadStream &s) {
void Game::restart(Common::SeekableReadStream& s) {
s.seek(_residentOffset + _saveAreaOffset);
s.read(_saveArea, _saveSize);
+ decrypt(_saveArea, _saveSize);
+
+ setVariable(V_OCOUNT, _objectCount);
}
void Game::saveGameData(Common::WriteStream& ws) {
@@ -131,15 +152,160 @@ void Game::loadGameData(Common::ReadStream& rs) {
rs.read(_saveArea, _saveSize);
}
-void Game::setVariable(uint variableNum, int value) {
- assert(variableNum < _variableCount);
- WRITE_LE_UINT16(_variableTable + variableNum * 2, value);
+int Game::findWord(const Common::String &word) const {
+ // Limit the word to the maximum allowable size
+ Common::String w(word.c_str(), word.c_str() + WORD_SIZE);
+
+ // Iterate over the dictionary for the word
+ for (int idx = 1; idx <= _wordCount; ++idx) {
+ int wordOffset = READ_LE_UINT16(_wordTable + idx * 2);
+ if (w == (const char*)_residentBase + wordOffset + 2)
+ return READ_LE_UINT16(_residentBase + wordOffset);
+ }
+
+ return NIL;
+}
+
+bool Game::match(int obj, int noun, int* adjectives) {
+ if (!hasNoun(obj, noun))
+ return false;
+
+ for (int* adjPtr = adjectives; *adjPtr; ++adjPtr) {
+ if (!hasAdjective(obj, *adjPtr))
+ return false;
+ }
+
+ return true;
}
-int Game::getVariable(uint variableNum) {
+int Game::checkVerb(int* verbs) {
+ // Iterate through the actions
+ for (int idx = 1; idx <= _actionCount; ++idx) {
+ if (hasVerb(idx, verbs))
+ return idx;
+ }
+
+ return NIL;
+}
+
+int Game::findAction(int* verbs, int preposition, int flag) {
+ // Iterate through the actions
+ for (int idx = 1; idx <= _actionCount; ++idx) {
+ if ((preposition && !hasPreposition(idx, preposition)) || !hasVerb(idx, verbs))
+ continue;
+
+ int mask = ~getActionByte(idx, A_MASK);
+ if ((flag & mask) == (getActionByte(idx, A_FLAG) & mask))
+ return idx;
+ }
+
+ return NIL;
+}
+
+int Game::getObjectProperty(int obj, int prop) {
+ int field;
+
+ for (; obj; obj = getObjectField(obj, O_CLASS)) {
+ if ((field = findProperty(obj, prop)) != 0)
+ return getObjectField(obj, field);
+ }
+
+ return NIL;
+}
+
+void Game::setObjectProperty(int obj, int prop, int val) {
+ int field;
+
+ for (; obj; obj = getObjectField(obj, O_CLASS)) {
+ if ((field = findProperty(obj, prop)) != 0)
+ return setObjectField(obj, field, val);
+ }
+}
+
+int Game::getObjectLocation(int obj) const {
+ if (obj < 1 || obj > _objectCount)
+ error("Invalid object number %d", obj);
+
+ return READ_LE_UINT16(_objectTable + obj * 2);
+}
+
+int Game::getActionLocation(int action) const {
+ if (action < 1 || action >= _actionCount)
+ error("Invalid action number %d", action);
+
+ return READ_LE_UINT16(_actionTable + action * 2);
+}
+
+int Game::getVariable(int variableNum) {
assert(variableNum < _variableCount);
return READ_LE_UINT16(_variableTable + variableNum * 2);
}
+void Game::setVariable(int variableNum, int value) {
+ assert(variableNum < _variableCount);
+ WRITE_LE_UINT16(_variableTable + variableNum * 2, value);
+}
+
+int Game::findProperty(int obj, int prop) const {
+ int nProp = getObjectField(obj, O_NPROPERTIES);
+
+ for (int idx = 0, p = 0; idx < nProp; ++idx, p += 4) {
+ if ((getObjectField(obj, O_PROPERTIES + p) & ~P_CLASS) == prop)
+ return O_PROPERTIES + p + 2;
+ }
+
+ return NIL;
+}
+
+bool Game::hasNoun(int obj, int noun) const {
+ for (; obj; obj = getObjectField(obj, O_CLASS)) {
+ if (inList(getObjectField(obj, O_NOUNS), noun))
+ return true;
+ }
+
+ return false;
+}
+
+bool Game::hasAdjective(int obj, int adjective) const {
+ for (; obj; obj = getObjectField(obj, O_CLASS)) {
+ if (inList(getObjectField(obj, O_ADJECTIVES), adjective))
+ return true;
+ }
+
+ return false;
+}
+
+bool Game::hasVerb(int act, int* verbs) const {
+ // Get the list of verbs
+ int link = getActionField(act, A_VERBS);
+
+ // Look for the verb
+ for (; link; link = readWord(link + L_NEXT)) {
+ int* verb = verbs;
+ int word = readWord(link + L_DATA);
+
+ for (; *verb && word; link = readWord(link + L_NEXT)) {
+ if (*verb != readWord(word + L_DATA))
+ break;
+
+ ++verb;
+ }
+
+ if (!*verb && !word)
+ return true;
+ }
+
+ return true;
+}
+
+bool Game::inList(int link, int word) const {
+ for (; link; link = readWord(link + L_NEXT)) {
+ if (word == readWord(link + L_DATA))
+ return true;
+ }
+
+ return false;
+}
+
} // End of namespace AdvSys
} // End of namespace Glk
diff --git a/engines/glk/advsys/game.h b/engines/glk/advsys/game.h
index 1c7222df8f..bd125f2373 100644
--- a/engines/glk/advsys/game.h
+++ b/engines/glk/advsys/game.h
@@ -30,6 +30,30 @@ namespace Glk {
namespace AdvSys {
/**
+ * Actions
+ */
+enum Action {
+ A_VERBS = 0,
+ A_PREPOSITIONS = 2,
+ A_FLAG = 4,
+ A_MASK = 5,
+ A_CODE = 6,
+ A_SIZE = 8
+};
+
+/**
+ * Object fields
+ */
+enum ObjectField {
+ O_CLASS = 0,
+ O_NOUNS = 2,
+ O_ADJECTIVES = 4,
+ O_NPROPERTIES = 6,
+ O_PROPERTIES = 8,
+ O_SIZE = 8
+};
+
+/**
* Built-in variables
*/
enum Variable {
@@ -106,13 +130,45 @@ public:
* Game abstraction class
*/
class Game : public Header {
+private:
+ /**
+ * Find an object property field
+ */
+ int findProperty(int obj, int prop) const;
+
+ /**
+ * Returns true if an object has a given noun
+ */
+ bool hasNoun(int obj, int noun) const;
+
+ /**
+ * Returns true if an object has a given adjective
+ */
+ bool hasAdjective(int obj, int adjective) const;
+
+ /**
+ * Returns true if an action has a given verb
+ */
+ bool hasVerb(int act, int* verbs) const;
+
+ /**
+ * Returns true if an action is in a given list
+ */
+ bool hasPreposition(int act, int preposition) const {
+ return inList(getActionField(act, A_PREPOSITIONS), preposition);
+ }
+
+ /**
+ * Check if a word is in an element of a given list
+ */
+ bool inList(int link, int word) const;
public:
Common::Array<byte> _data;
- uint _residentOffset;
- uint _wordCount;
- uint _objectCount;
- uint _actionCount;
- uint _variableCount;
+ int _residentOffset;
+ int _wordCount;
+ int _objectCount;
+ int _actionCount;
+ int _variableCount;
byte* _residentBase;
byte* _wordTable;
@@ -153,14 +209,108 @@ public:
void loadGameData(Common::ReadStream& rs);
/**
- * Set a variable value
+ * Find a word in the dictionary
+ */
+ int findWord(const Common::String& word) const;
+
+ /**
+ * Return a word's type
+ */
+ int getWordType(int word) const { return _wordTypeTable[word]; }
+
+ /**
+ * Match an object against a name and list of adjectives
+ */
+ bool match(int obj, int noun, int* adjectives);
+
+ /**
+ * Check to see if this is a valid verb
+ */
+ int checkVerb(int* verbs);
+
+ /**
+ * Find an action matching a given description
+ */
+ int findAction(int* verbs, int preposition, int flag);
+
+ /**
+ * Get an object property
*/
- void setVariable(uint variableNum, int value);
+ int getObjectProperty(int obj, int prop);
+
+ /**
+ * Sets an object property
+ */
+ void setObjectProperty(int obj, int prop, int val);
+
+ /**
+ * Gets a field from an object
+ */
+ int getObjectField(int obj, int offset) const {
+ return READ_LE_UINT16(_residentBase + getObjectLocation(obj) + offset);
+ }
+
+ /**
+ * Sets a field in an object
+ */
+ void setObjectField(int obj, int offset, int val) {
+ WRITE_LE_UINT16(_residentBase + getObjectLocation(obj) + offset, val);
+ }
+
+ /**
+ * Gets a field from an action
+ */
+ int getActionField(int action, int offset) const {
+ return READ_LE_UINT16(_residentBase + getActionLocation(action) + offset);
+ }
+
+ /**
+ * Gets a byte field from an action
+ */
+ int getActionByte(int action, int offset) const {
+ return _residentBase[getActionLocation(action) + offset];
+ }
+
+ /**
+ * Gets the offset of an object from the object table
+ */
+ int getObjectLocation(int obj) const;
+
+ /**
+ * Gets the offset of an action from the action table
+ */
+ int getActionLocation(int action) const;
/**
* Get a variable value
*/
- int getVariable(uint variableNum);
+ int getVariable(int variableNum);
+
+ /**
+ * Set a variable value
+ */
+ void setVariable(int variableNum, int value);
+
+ /**
+ * Gets a code byte
+ */
+ int getCodeByte(int offset) const {
+ return _codeSpace[offset];
+ }
+
+ /**
+ * Read a word
+ */
+ int readWord(int offset) const {
+ return READ_LE_UINT16(_residentBase + offset);
+ }
+
+ /**
+ * Write a word
+ */
+ void writeWord(int offset, int val) {
+ WRITE_LE_UINT16(_residentBase + offset, val);
+ }
};
} // End of namespace AdvSys