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 ZVISION_SCRIPT_MANAGER_H
24 #define ZVISION_SCRIPT_MANAGER_H
25 
26 #include "zvision/scripting/puzzle.h"
27 #include "zvision/scripting/control.h"
28 #include "zvision/scripting/scripting_effect.h"
29 
30 #include "common/hashmap.h"
31 #include "common/queue.h"
32 #include "common/events.h"
33 
34 namespace Common {
35 class String;
36 class SeekableReadStream;
37 }
38 
39 namespace ZVision {
40 
41 class ZVision;
42 
43 enum StateKey {
44 	StateKey_World = 3,
45 	StateKey_Room  = 4,
46 	StateKey_Node  = 5,
47 	StateKey_View  = 6,
48 	StateKey_ViewPos = 7,
49 	StateKey_KeyPress = 8,
50 	StateKey_InventoryItem = 9,
51 	StateKey_LMouse = 10,
52 	StateKey_NotSet = 11, // This key doesn't set
53 	StateKey_Rounds = 12,
54 	StateKey_Venus = 13,
55 	StateKey_RMouse = 18,
56 	StateKey_MenuState = 19,
57 	StateKey_RestoreFlag = 20,
58 	StateKey_Quitting = 39,
59 	StateKey_LastWorld = 40,
60 	StateKey_LastRoom = 41,
61 	StateKey_LastNode = 42,
62 	StateKey_LastView = 43,
63 	StateKey_LastViewPos = 44,
64 	StateKey_Menu_LastWorld = 45,
65 	StateKey_Menu_LastRoom = 46,
66 	StateKey_Menu_LastNode = 47,
67 	StateKey_Menu_LastView = 48,
68 	StateKey_Menu_LastViewPos = 49,
69 	StateKey_KbdRotateSpeed = 50,
70 	StateKey_Subtitles = 51,
71 	StateKey_StreamSkipKey = 52,
72 	StateKey_RotateSpeed = 53,
73 	StateKey_Volume = 56,
74 	StateKey_Qsound = 57,
75 	StateKey_VenusEnable = 58,
76 	StateKey_HighQuality = 59,
77 	StateKey_VideoLineSkip = 65,
78 	StateKey_Platform = 66,
79 	StateKey_InstallLevel = 67,
80 	StateKey_CountryCode = 68,
81 	StateKey_CPU = 69,
82 	StateKey_MovieCursor = 70,
83 	StateKey_NoTurnAnim = 71,
84 	StateKey_WIN958 = 72,
85 	StateKey_ShowErrorDlg = 73,
86 	StateKey_DebugCheats = 74,
87 	StateKey_JapanFonts = 75,
88 	StateKey_ExecScopeStyle = 76,
89 	StateKey_Brightness = 77,
90 	StateKey_MPEGMovies = 78,
91 	StateKey_EF9_R = 91,
92 	StateKey_EF9_G = 92,
93 	StateKey_EF9_B = 93,
94 	StateKey_EF9_Speed = 94,
95 	StateKey_Inv_Cnt_Slot = 100,
96 	StateKey_Inv_1_Slot = 101,
97 	StateKey_Inv_49_Slot = 149,
98 	// ZGI only
99 	StateKey_Inv_TotalSlots = 150,
100 	StateKey_Inv_StartSlot = 151,
101 	StateKey_Spell_1 = 191,
102 	StateKey_Active_Spell = 205,
103 	StateKey_Reversed_Spellbooc = 206
104 };
105 
106 struct Location {
LocationLocation107 	Location() : world('g'), room('a'), node('r'), view('y'), offset(0) {}
108 
109 	char world;
110 	char room;
111 	char node;
112 	char view;
113 	uint32 offset;
114 };
115 
116 inline bool operator==(const Location& lhs, const Location& rhs) {
117 	return (
118 		lhs.world == rhs.world &&
119 		lhs.room == rhs.room &&
120 		lhs.node == rhs.node &&
121 		lhs.view == rhs.view
122 	);
123 }
124 
125 inline bool operator==(const Location& lhs, const char* rhs) {
126 	Common::String lhsStr = Common::String::format("%c%c%c%c", lhs.world, lhs.room, lhs.node, lhs.view);
127 	return lhsStr == rhs;
128 }
129 
130 inline bool operator!=(const Location& lhs, const Location& rhs) {
131 	return !(lhs == rhs);
132 }
133 
134 inline bool operator!=(const Location& lhs, const char* rhs) {
135 	return !(lhs == rhs);
136 }
137 
138 typedef Common::List<Puzzle *> PuzzleList;
139 typedef Common::Queue<Puzzle *> PuzzleQueue;
140 typedef Common::List<Control *> ControlList;
141 typedef Common::HashMap<uint32, int32> StateMap;
142 typedef Common::List<ScriptingEffect *> SideFXList;
143 typedef Common::List<Common::Event> EventList;
144 
145 class ScriptManager {
146 public:
147 	ScriptManager(ZVision *engine);
148 	~ScriptManager();
149 
150 private:
151 	ZVision *_engine;
152 
153 	struct ScriptScope {
154 		uint32 procCount;
155 
156 		PuzzleList *scopeQueue; // For adding puzzles to queue
157 		PuzzleList *execQueue;  // Switch to it when execute
158 		PuzzleList privQueueOne;
159 		PuzzleList privQueueTwo;
160 
161 		PuzzleList  puzzles;
162 		ControlList controls;
163 	};
164 
165 	struct PuzzleRef {
166 		Puzzle *puz;
167 		ScriptScope *scope;
168 	};
169 
170 	typedef Common::HashMap<uint32, Common::Array<PuzzleRef> > PuzzleMap;
171 
172 	/**
173 	 * Holds the global state variable. Do NOT directly modify this. Use the accessors and
174 	 * mutators getStateValue() and setStateValue(). This ensures that Puzzles that reference a
175 	 * particular state key are checked after the key is modified.
176 	 */
177 	StateMap _globalState;
178 	/** Holds execute flags */
179 	StateMap _globalStateFlags;
180 	/** References _globalState keys to Puzzles */
181 	PuzzleMap _referenceTable;
182 	/** Holds the currently active controls */
183 	ControlList *_activeControls;
184 
185 	EventList _controlEvents;
186 
187 	ScriptScope universe;
188 	ScriptScope world;
189 	ScriptScope room;
190 	ScriptScope nodeview;
191 
192 	/** Holds the currently active timers, musics, other */
193 	SideFXList _activeSideFx;
194 
195 	Location _currentLocation;
196 	Location _nextLocation;
197 	int _changeLocationDelayCycles;
198 
199 	uint32 _currentlyFocusedControl;
200 
201 public:
202 	void initialize();
203 	void update(uint deltaTimeMillis);
204 	void queuePuzzles(uint32 key);
205 
206 	int getStateValue(uint32 key);
207 	void setStateValue(uint32 key, int value);
208 
209 	uint getStateFlag(uint32 key);
210 	void setStateFlag(uint32 key, uint value);
211 	void unsetStateFlag(uint32 key, uint value);
212 
213 	void addControl(Control *control);
214 	Control *getControl(uint32 key);
215 
216 	void enableControl(uint32 key);
217 	void disableControl(uint32 key);
218 
219 	void focusControl(uint32 key);
220 	// Only change focus control without call focus/unfocus.
221 	void setFocusControlKey(uint32 key);
222 
223 	void addSideFX(ScriptingEffect *fx);
224 	ScriptingEffect *getSideFX(uint32 key);
225 	void deleteSideFx(uint32 key);
226 	void stopSideFx(uint32 key);
227 	void killSideFx(uint32 key);
228 	void killSideFxType(ScriptingEffect::ScriptingEffectType type);
229 
230 	void addEvent(Common::Event);
231 	void flushEvent(Common::EventType type);
232 
233 	/**
234 	 * Called when LeftMouse is pushed.
235 	 *
236 	 * @param screenSpacePos             The position of the mouse in screen space
237 	 * @param backgroundImageSpacePos    The position of the mouse in background image space
238 	 */
239 	void onMouseDown(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos);
240 	/**
241 	 * Called when LeftMouse is lifted.
242 	 *
243 	 * @param screenSpacePos             The position of the mouse in screen space
244 	 * @param backgroundImageSpacePos    The position of the mouse in background image space
245 	 */
246 	void onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos);
247 	/**
248 	 * Called on every MouseMove.
249 	 *
250 	 * @param screenSpacePos             The position of the mouse in screen space
251 	 * @param backgroundImageSpacePos    The position of the mouse in background image space
252 	 * @return                           Was the cursor changed?
253 	 */
254 	bool onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos);
255 	/**
256 	 * Called when a key is pressed.
257 	 *
258 	 * @param keycode    The key that was pressed
259 	 */
260 	void onKeyDown(Common::KeyState keyState);
261 	/**
262 	 * Called when a key is released.
263 	 *
264 	 * @param keycode    The key that was pressed
265 	 */
266 	void onKeyUp(Common::KeyState keyState);
267 
268 	/** Mark next location */
269 	void changeLocation(char world, char room, char node, char view, uint32 offset);
270 	void changeLocation(const Location &_newLocation);
271 
272 	void serialize(Common::WriteStream *stream);
273 	void deserialize(Common::SeekableReadStream *stream);
274 
275 	Location getCurrentLocation() const;
276 	Location getLastLocation();
277 	Location getLastMenuLocation();
278 
279 	/**
280 	 * Removes any line comments using '#' as a sequence start.
281 	 * Then removes any trailing and leading 'whitespace' using String::trim()
282 	 * Note: String::trim uses isspace() to determine what is whitespace and what is not.
283 	 *
284 	 * @param string    The string to modify. It is modified in place
285 	 */
286 	void trimCommentsAndWhiteSpace(Common::String *string) const;
287 
288 private:
289 	void referenceTableAddPuzzle(uint32 key, PuzzleRef ref);
290 	void addPuzzlesToReferenceTable(ScriptScope &scope);
291 	void updateNodes(uint deltaTimeMillis);
292 	void updateControls(uint deltaTimeMillis);
293 	bool checkPuzzleCriteria(Puzzle *puzzle, uint counter);
294 	void cleanStateTable();
295 	void cleanScriptScope(ScriptScope &scope);
296 	bool execScope(ScriptScope &scope);
297 
298 	/** Perform change location */
299 	void ChangeLocationReal(bool isLoading);
300 
301 	int8 inventoryGetCount();
302 	void inventorySetCount(int8 cnt);
303 	int16 inventoryGetItem(int8 id);
304 	void inventorySetItem(int8 id, int16 item);
305 
306 	void setStateFlagSilent(uint32 key, uint value);
307 	void setStateValueSilent(uint32 key, int value);
308 
309 public:
310 	void inventoryAdd(int16 item);
311 	void inventoryDrop(int16 item);
312 	void inventoryCycle();
313 
314 private:
315 	/**
316 	 * Parses a script file into triggers and events
317 	 *
318 	 * @param fileName    Name of the .scr file
319 	 * @param isGlobal    Are the puzzles included in the file global (true). AKA, the won't be purged during location changes
320 	 */
321 	void parseScrFile(const Common::String &fileName, ScriptScope &scope);
322 
323 	/**
324 	 * Parses the stream into a Puzzle object
325 	 * Helper method for parseScrFile.
326 	 *
327 	 * @param puzzle    The object to store what is parsed
328 	 * @param stream    Scr file stream
329 	 */
330 	void parsePuzzle(Puzzle *puzzle, Common::SeekableReadStream &stream);
331 
332 	/**
333 	 * Parses the stream into a Criteria object
334 	 * Helper method for parsePuzzle.
335 	 *
336 	 * @param criteria    Pointer to the Criteria object to fill
337 	 * @param stream      Scr file stream
338 	 * @param key         Puzzle key (for workarounds)
339 	 * @return            Whether any criteria were read
340 	 */
341 	bool parseCriteria(Common::SeekableReadStream &stream, Common::List<Common::List<Puzzle::CriteriaEntry> > &criteriaList, uint32 key) const;
342 
343 	/**
344 	 * Parses the stream into a ResultAction objects
345 	 * Helper method for parsePuzzle.
346 	 *
347 	 * @param stream        Scr file stream
348 	 * @param actionList    The list where the results will be added
349 	 * @return              Created Results object
350 	 */
351 	void parseResults(Common::SeekableReadStream &stream, Common::List<ResultAction *> &actionList) const;
352 
353 	/**
354 	 * Helper method for parsePuzzle. Parses the stream into a bitwise or of the StateFlags enum
355 	 *
356 	 * @param stream    Scr file stream
357 	 * @return          Bitwise OR of all the flags set within the puzzle
358 	 */
359 	uint parseFlags(Common::SeekableReadStream &stream) const;
360 
361 	/**
362 	 * Helper method for parseScrFile. Parses the stream into a Control object
363 	 *
364 	 * @param line      The line initially read
365 	 * @param stream    Scr file stream
366 	 */
367 	Control *parseControl(Common::String &line, Common::SeekableReadStream &stream);
368 };
369 
370 class ValueSlot {
371 public:
372 	ValueSlot(ScriptManager *scriptManager, const char *slotValue);
373 	int16 getValue();
374 private:
375 	int16 value;
376 	bool slot;
377 	ScriptManager *_scriptManager;
378 };
379 
380 } // End of namespace ZVision
381 
382 #endif
383