/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef GLK_ADVSYS_GAME #define GLK_ADVSYS_GAME #include "common/array.h" #include "common/stream.h" namespace Glk { namespace AdvSys { #define NIL 0 #define MESSAGE_CACHE_SIZE 8 #define MESSAGE_BLOCK_SIZE 512 /** * Actions */ enum Action { A_VERBS = 0, A_PREPOSITIONS = 2, A_FLAG = 4, A_MASK = 5, A_CODE = 6, A_SIZE = 8 }; /** * Word types */ enum WordType { WT_UNKNOWN = 0, WT_VERB = 1, WT_NOUN = 2, WT_ADJECTIVE = 3, WT_PREPOSITION = 4, WT_CONJUNCTION = 5, WT_ARTICLE = 6 }; /** * 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 { V_ACTOR = 1, ///< Actor noun phrase number V_ACTION = 2, ///< Action from phrase V_DOBJECT = 3, ///< First direct object noun phrase number V_NDOBJECTS = 4, ///< Number of direct object noun phrases V_IOBJECT = 5, ///< Indirect object noun phrase number V_OCOUNT = 6 ///< Total object count }; /** * Data decryption */ class Decrypter { public: /** * Decrypt a data block */ static void decrypt(byte *data, size_t size); }; /** * AdvSys game header */ class Header : public Decrypter { public: bool _valid; ///< Signals whether header is valid size_t _size; ///< Resident size in bytes uint _headerVersion; ///< Header structure version Common::String _name; ///< Adventure name uint _version; ///< Adventure version uint _wordTableOffset; ///< Word table offset uint _wordTypeTableOffset; ///< Word type table offset uint _objectTableOffset; ///< Object table offset uint _actionTableOffset; ///< Action table offset uint _variableTableOffset; ///< Variable table offset uint _dataSpaceOffset; ///< Data space offset uint _codeSpaceOffset; ///< Code space offset uint _dataBlockOffset; ///< First data block offset uint _messageBlockOffset; ///< First message block offset uint _initCodeOffset; ///< Initialization code offset uint _updateCodeOffset; ///< Update code offset uint _beforeOffset; ///< Code offset before verb handler uint _afterOffset; ///< Code offset after verb handler uint _errorHandlerOffset; ///< Error handler code offset uint _saveAreaOffset; ///< Save area offset uint _saveSize; ///< Save area size public: /** * Constructor */ Header() : _valid(false), _size(0), _headerVersion(0), _version(0), _wordTableOffset(0), _wordTypeTableOffset(0), _objectTableOffset(0), _actionTableOffset(0), _variableTableOffset(0), _dataSpaceOffset(0), _codeSpaceOffset(0), _dataBlockOffset(0), _messageBlockOffset(0), _initCodeOffset(0), _updateCodeOffset(0), _beforeOffset(0), _afterOffset(0), _errorHandlerOffset(0), _saveAreaOffset(0), _saveSize(0) { } /** * Constructor */ Header(Common::SeekableReadStream *s) { init(s); } /** * init the header */ bool init(Common::SeekableReadStream *s); }; /** * Game abstraction class */ class Game : public Header { struct CacheEntry { int _blockNum; char _data[MESSAGE_BLOCK_SIZE]; /** * Constructor */ CacheEntry() : _blockNum(-1) { Common::fill(&_data[0], &_data[MESSAGE_BLOCK_SIZE], '\0'); } }; private: bool _restartFlag; Common::SeekableReadStream *_stream; Common::Array _msgCache; int _msgBlockNum, _msgBlockOffset; private: /** * Find an object property field */ int findProperty(int obj, int prop) const; /** * Returns true if an action has a given verb */ bool hasVerb(int act, const Common::Array &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; /** * Reads in a message block from the game file */ void readMsgBlock(); /** * Read the next character for a string */ char readMsgChar(); protected: /** * 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; public: Common::Array _data; int _residentOffset; int _wordCount; int _objectCount; int _actionCount; int _variableCount; byte *_wordTable; byte *_wordTypeTable; byte *_objectTable; byte *_actionTable; byte *_variableTable; byte *_saveArea; byte *_dataSpace; byte *_codeSpace; public: /** * Constructor */ Game(); /** * Destructor */ ~Game(); /** * init data for the game */ bool init(Common::SeekableReadStream *s); /** * Restore savegame data from the game to it's initial state */ void restart(); /** * Returns true if the game is restarting, and resets the flag */ bool shouldRestart(); /** * Save the game data to a savegame */ void saveGameData(Common::WriteStream &ws); /** * Restore the game data from a savegame */ void loadGameData(Common::ReadStream &rs); /** * Find a word in the dictionary */ int findWord(const Common::String &word) const; /** * Return a word's type */ WordType getWordType(int word) const { return (WordType)_wordTypeTable[word]; } /** * Check to see if this is a valid verb */ int checkVerb(const Common::Array &verbs); /** * Find an action matching a given description */ int findAction(const Common::Array &verbs, int preposition, int flag); /** * Get an object property */ int getObjectProperty(int obj, int prop); /** * Sets an object property */ int setObjectProperty(int obj, int prop, int val); /** * Gets a field from an object */ int getObjectField(int obj, int offset) const { return READ_LE_UINT16(_dataSpace + getObjectLocation(obj) + offset); } /** * Sets a field in an object */ int setObjectField(int obj, int offset, int val) { WRITE_LE_UINT16(_dataSpace + getObjectLocation(obj) + offset, val); return val; } /** * Gets a field from an action */ int getActionField(int action, int offset) const { return READ_LE_UINT16(_dataSpace + getActionLocation(action) + offset); } /** * Gets a byte field from an action */ int getActionByte(int action, int offset) const { return _dataSpace[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(int variableNum); /** * Set a variable value */ void setVariable(int variableNum, int value); /** * Gets a code byte */ int getCodeByte(int offset) const { return _codeSpace[offset]; } /** * Gets a code byte */ int getCodeWord(int offset) const { return READ_LE_UINT16(_codeSpace + offset); } /** * Read a word */ int readWord(int offset) const { return READ_LE_UINT16(_dataSpace + offset); } /** * Write a word */ void writeWord(int offset, int val) { WRITE_LE_UINT16(_dataSpace + offset, val); } /** * Read a string from the messages section */ Common::String readString(int msg); }; } // End of namespace AdvSys } // End of namespace Glk #endif