1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 #ifndef GLK_ADVSYS_GAME 24 #define GLK_ADVSYS_GAME 25 26 #include "common/array.h" 27 #include "common/stream.h" 28 29 namespace Glk { 30 namespace AdvSys { 31 32 #define NIL 0 33 #define MESSAGE_CACHE_SIZE 8 34 #define MESSAGE_BLOCK_SIZE 512 35 36 /** 37 * Actions 38 */ 39 enum Action { 40 A_VERBS = 0, 41 A_PREPOSITIONS = 2, 42 A_FLAG = 4, 43 A_MASK = 5, 44 A_CODE = 6, 45 A_SIZE = 8 46 }; 47 48 /** 49 * Word types 50 */ 51 enum WordType { 52 WT_UNKNOWN = 0, 53 WT_VERB = 1, 54 WT_NOUN = 2, 55 WT_ADJECTIVE = 3, 56 WT_PREPOSITION = 4, 57 WT_CONJUNCTION = 5, 58 WT_ARTICLE = 6 59 }; 60 61 /** 62 * Object fields 63 */ 64 enum ObjectField { 65 O_CLASS = 0, 66 O_NOUNS = 2, 67 O_ADJECTIVES = 4, 68 O_NPROPERTIES = 6, 69 O_PROPERTIES = 8, 70 O_SIZE = 8 71 }; 72 73 /** 74 * Built-in variables 75 */ 76 enum Variable { 77 V_ACTOR = 1, ///< Actor noun phrase number 78 V_ACTION = 2, ///< Action from phrase 79 V_DOBJECT = 3, ///< First direct object noun phrase number 80 V_NDOBJECTS = 4, ///< Number of direct object noun phrases 81 V_IOBJECT = 5, ///< Indirect object noun phrase number 82 V_OCOUNT = 6 ///< Total object count 83 }; 84 85 /** 86 * Data decryption 87 */ 88 class Decrypter { 89 public: 90 /** 91 * Decrypt a data block 92 */ 93 static void decrypt(byte *data, size_t size); 94 }; 95 96 /** 97 * AdvSys game header 98 */ 99 class Header : public Decrypter { 100 public: 101 bool _valid; ///< Signals whether header is valid 102 size_t _size; ///< Resident size in bytes 103 uint _headerVersion; ///< Header structure version 104 Common::String _name; ///< Adventure name 105 uint _version; ///< Adventure version 106 uint _wordTableOffset; ///< Word table offset 107 uint _wordTypeTableOffset; ///< Word type table offset 108 uint _objectTableOffset; ///< Object table offset 109 uint _actionTableOffset; ///< Action table offset 110 uint _variableTableOffset; ///< Variable table offset 111 uint _dataSpaceOffset; ///< Data space offset 112 uint _codeSpaceOffset; ///< Code space offset 113 uint _dataBlockOffset; ///< First data block offset 114 uint _messageBlockOffset; ///< First message block offset 115 uint _initCodeOffset; ///< Initialization code offset 116 uint _updateCodeOffset; ///< Update code offset 117 uint _beforeOffset; ///< Code offset before verb handler 118 uint _afterOffset; ///< Code offset after verb handler 119 uint _errorHandlerOffset; ///< Error handler code offset 120 uint _saveAreaOffset; ///< Save area offset 121 uint _saveSize; ///< Save area size 122 public: 123 /** 124 * Constructor 125 */ Header()126 Header() : _valid(false), _size(0), _headerVersion(0), _version(0), _wordTableOffset(0), 127 _wordTypeTableOffset(0), _objectTableOffset(0), _actionTableOffset(0), _variableTableOffset(0), 128 _dataSpaceOffset(0), _codeSpaceOffset(0), _dataBlockOffset(0), _messageBlockOffset(0), 129 _initCodeOffset(0), _updateCodeOffset(0), _beforeOffset(0), _afterOffset(0), 130 _errorHandlerOffset(0), _saveAreaOffset(0), _saveSize(0) { 131 } 132 133 /** 134 * Constructor 135 */ Header(Common::SeekableReadStream * s)136 Header(Common::SeekableReadStream *s) { 137 init(s); 138 } 139 140 /** 141 * init the header 142 */ 143 bool init(Common::SeekableReadStream *s); 144 }; 145 146 /** 147 * Game abstraction class 148 */ 149 class Game : public Header { 150 struct CacheEntry { 151 int _blockNum; 152 char _data[MESSAGE_BLOCK_SIZE]; 153 154 /** 155 * Constructor 156 */ CacheEntryCacheEntry157 CacheEntry() : _blockNum(-1) { 158 Common::fill(&_data[0], &_data[MESSAGE_BLOCK_SIZE], '\0'); 159 } 160 }; 161 private: 162 bool _restartFlag; 163 Common::SeekableReadStream *_stream; 164 Common::Array<CacheEntry *> _msgCache; 165 int _msgBlockNum, _msgBlockOffset; 166 private: 167 /** 168 * Find an object property field 169 */ 170 int findProperty(int obj, int prop) const; 171 172 /** 173 * Returns true if an action has a given verb 174 */ 175 bool hasVerb(int act, const Common::Array<int> &verbs) const; 176 177 /** 178 * Returns true if an action is in a given list 179 */ hasPreposition(int act,int preposition)180 bool hasPreposition(int act, int preposition) const { 181 return inList(getActionField(act, A_PREPOSITIONS), preposition); 182 } 183 184 /** 185 * Check if a word is in an element of a given list 186 */ 187 bool inList(int link, int word) const; 188 189 /** 190 * Reads in a message block from the game file 191 */ 192 void readMsgBlock(); 193 194 /** 195 * Read the next character for a string 196 */ 197 char readMsgChar(); 198 protected: 199 /** 200 * Returns true if an object has a given noun 201 */ 202 bool hasNoun(int obj, int noun) const; 203 204 /** 205 * Returns true if an object has a given adjective 206 */ 207 bool hasAdjective(int obj, int adjective) const; 208 public: 209 Common::Array<byte> _data; 210 int _residentOffset; 211 int _wordCount; 212 int _objectCount; 213 int _actionCount; 214 int _variableCount; 215 216 byte *_wordTable; 217 byte *_wordTypeTable; 218 byte *_objectTable; 219 byte *_actionTable; 220 byte *_variableTable; 221 byte *_saveArea; 222 byte *_dataSpace; 223 byte *_codeSpace; 224 public: 225 /** 226 * Constructor 227 */ 228 Game(); 229 230 /** 231 * Destructor 232 */ 233 ~Game(); 234 235 /** 236 * init data for the game 237 */ 238 bool init(Common::SeekableReadStream *s); 239 240 /** 241 * Restore savegame data from the game to it's initial state 242 */ 243 void restart(); 244 245 /** 246 * Returns true if the game is restarting, and resets the flag 247 */ 248 bool shouldRestart(); 249 250 /** 251 * Save the game data to a savegame 252 */ 253 void saveGameData(Common::WriteStream &ws); 254 255 /** 256 * Restore the game data from a savegame 257 */ 258 void loadGameData(Common::ReadStream &rs); 259 260 /** 261 * Find a word in the dictionary 262 */ 263 int findWord(const Common::String &word) const; 264 265 /** 266 * Return a word's type 267 */ getWordType(int word)268 WordType getWordType(int word) const { 269 return (WordType)_wordTypeTable[word]; 270 } 271 272 /** 273 * Check to see if this is a valid verb 274 */ 275 int checkVerb(const Common::Array<int> &verbs); 276 277 /** 278 * Find an action matching a given description 279 */ 280 int findAction(const Common::Array<int> &verbs, int preposition, int flag); 281 282 /** 283 * Get an object property 284 */ 285 int getObjectProperty(int obj, int prop); 286 287 /** 288 * Sets an object property 289 */ 290 int setObjectProperty(int obj, int prop, int val); 291 292 /** 293 * Gets a field from an object 294 */ getObjectField(int obj,int offset)295 int getObjectField(int obj, int offset) const { 296 return READ_LE_UINT16(_dataSpace + getObjectLocation(obj) + offset); 297 } 298 299 /** 300 * Sets a field in an object 301 */ setObjectField(int obj,int offset,int val)302 int setObjectField(int obj, int offset, int val) { 303 WRITE_LE_UINT16(_dataSpace + getObjectLocation(obj) + offset, val); 304 return val; 305 } 306 307 /** 308 * Gets a field from an action 309 */ getActionField(int action,int offset)310 int getActionField(int action, int offset) const { 311 return READ_LE_UINT16(_dataSpace + getActionLocation(action) + offset); 312 } 313 314 /** 315 * Gets a byte field from an action 316 */ getActionByte(int action,int offset)317 int getActionByte(int action, int offset) const { 318 return _dataSpace[getActionLocation(action) + offset]; 319 } 320 321 /** 322 * Gets the offset of an object from the object table 323 */ 324 int getObjectLocation(int obj) const; 325 326 /** 327 * Gets the offset of an action from the action table 328 */ 329 int getActionLocation(int action) const; 330 331 /** 332 * Get a variable value 333 */ 334 int getVariable(int variableNum); 335 336 /** 337 * Set a variable value 338 */ 339 void setVariable(int variableNum, int value); 340 341 /** 342 * Gets a code byte 343 */ getCodeByte(int offset)344 int getCodeByte(int offset) const { 345 return _codeSpace[offset]; 346 } 347 348 /** 349 * Gets a code byte 350 */ getCodeWord(int offset)351 int getCodeWord(int offset) const { 352 return READ_LE_UINT16(_codeSpace + offset); 353 } 354 355 /** 356 * Read a word 357 */ readWord(int offset)358 int readWord(int offset) const { 359 return READ_LE_UINT16(_dataSpace + offset); 360 } 361 362 /** 363 * Write a word 364 */ writeWord(int offset,int val)365 void writeWord(int offset, int val) { 366 WRITE_LE_UINT16(_dataSpace + offset, val); 367 } 368 369 /** 370 * Read a string from the messages section 371 */ 372 Common::String readString(int msg); 373 }; 374 375 } // End of namespace AdvSys 376 } // End of namespace Glk 377 378 #endif 379