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