diff options
author | Paul Gilbert | 2019-06-08 11:18:11 -0700 |
---|---|---|
committer | Paul Gilbert | 2019-06-09 15:00:46 -0700 |
commit | da434f29522d7ee36f33c1b0bd95d9cc03cc5093 (patch) | |
tree | c771caea1a973ed56e5bda7cba2bf00cf10f3ec8 /engines/glk | |
parent | b84e9a3dff91480f5d0356dc289c6bae5690c656 (diff) | |
download | scummvm-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.h | 2 | ||||
-rw-r--r-- | engines/glk/advsys/game.cpp | 174 | ||||
-rw-r--r-- | engines/glk/advsys/game.h | 166 |
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 |