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 ULTIMA4_GAME_SCRIPT_H
24 #define ULTIMA4_GAME_SCRIPT_H
25 
26 #include "ultima/ultima4/core/types.h"
27 #include "ultima/shared/conf/xml_node.h"
28 #include "common/file.h"
29 
30 namespace Ultima {
31 namespace Ultima4 {
32 
33 /**
34  * An xml-scripting class. It loads and runs xml scripts that
35  * take information and interact with the game environment itself.
36  * Currently, it is mainly useful for writing vendor code; however,
37  * it should be possible to write scripts for other parts of the
38  * game.
39  *
40  * @todo
41  * <ul>
42  *      <li>Strip vendor-specific code from the language</li>
43  *      <li>Fill in some of the missing integration with the game</li>
44  * </ul>
45  */
46 class Script {
47 public:
48 	/**
49 	 * A class that provides information to a script.  It is designed to
50 	 * translate qualifiers and identifiers in a script to another value.
51 	 * Each provider is assigned a qualifier that the script uses to
52 	 * select a provider.  The provider then uses the rest of the information
53 	 * to translate the information to something useful.
54 	 */
55 	class Provider {
56 	public:
~Provider()57 		virtual ~Provider() {}
58 		virtual Common::String translate(Std::vector<Common::String> &parts) = 0;
59 	};
60 
61 private:
62 	/**
63 	 * A class that represents a script variable
64 	 */
65 	class Variable {
66 	public:
67 		Variable();
68 		Variable(const Common::String &v);
69 		Variable(const int &v);
70 
71 		int    &getInt();
72 		Common::String &getString();
73 
74 		void    setValue(const int &v);
75 		void    setValue(const Common::String &v);
76 		void    unset();
77 
78 		bool    isInt() const;
79 		bool    isString() const;
80 		bool    isSet() const;
81 
82 	private:
83 		int _iVal;
84 		Common::String _sVal;
85 		bool _set;
86 	};
87 
88 public:
89 	/**
90 	 * A script return code
91 	 */
92 	enum ReturnCode {
93 		RET_OK,
94 		RET_REDIRECTED,
95 		RET_STOP
96 	};
97 
98 	/**
99 	 * The current state of the script
100 	 */
101 	enum State {
102 		STATE_UNLOADED,
103 		STATE_NORMAL,
104 		STATE_DONE,
105 		STATE_INPUT
106 	};
107 
108 	/**
109 	 * The type of input the script is requesting
110 	 */
111 	enum InputType {
112 		INPUT_CHOICE,
113 		INPUT_NUMBER,
114 		INPUT_STRING,
115 		INPUT_DIRECTION,
116 		INPUT_PLAYER,
117 		INPUT_KEYPRESS
118 	};
119 
120 	/**
121 	 * The action that the script is taking
122 	 */
123 	enum Action {
124 		ACTION_SET_CONTEXT,
125 		ACTION_UNSET_CONTEXT,
126 		ACTION_END,
127 		ACTION_REDIRECT,
128 		ACTION_WAIT_FOR_KEY,
129 		ACTION_WAIT,
130 		ACTION_STOP,
131 		ACTION_INCLUDE,
132 		ACTION_FOR_LOOP,
133 		ACTION_RANDOM,
134 		ACTION_MOVE,
135 		ACTION_SLEEP,
136 		ACTION_CURSOR,
137 		ACTION_PAY,
138 		ACTION_IF,
139 		ACTION_INPUT,
140 		ACTION_ADD,
141 		ACTION_LOSE,
142 		ACTION_HEAL,
143 		ACTION_CAST_SPELL,
144 		ACTION_DAMAGE,
145 		ACTION_KARMA,
146 		ACTION_MUSIC,
147 		ACTION_SET_VARIABLE,
148 		ACTION_ZTATS
149 	};
150 
151 	/**
152 	 * Constructs a script object
153 	 */
154 	Script();
155 	~Script();
156 
157 	/**
158 	 * Adds an information provider for the script
159 	 */
160 	void addProvider(const Common::String &name, Provider *p);
161 
162 	/**
163 	 * Loads the vendor script
164 	 */
165 	bool load(const Common::String &filename, const Common::String &baseId, const Common::String &subNodeName = "", const Common::String &subNodeId = "");
166 
167 	/**
168 	 * Unloads the script
169 	 */
170 	void unload();
171 
172 	/**
173 	 * Runs a script after it's been loaded
174 	 */
175 	void run(const Common::String &script);
176 
177 	/**
178 	 * Executes the subscript 'script' of the main script
179 	 */
180 	ReturnCode execute(Shared::XMLNode *script, Shared::XMLNode *currentItem = nullptr, Common::String *output = nullptr);
181 
182 	/**
183 	 * Continues the script from where it left off, or where the last script indicated
184 	 */
185 	void _continue();
186 
187 	/**
188 	 * Set and retrieve property values
189 	 */
190 	void resetState();
191 	void setState(State state);
192 	State getState();
193 
194 	void setTarget(const Common::String &val);
195 	void setChoices(const Common::String &val);
196 	void setVar(const Common::String &name, const Common::String &val);
197 	void setVar(const Common::String &name, int val);
198 	void unsetVar(const Common::String &name);
199 
200 	Common::String getTarget();
201 	InputType getInputType();
202 	Common::String getInputName();
203 	Common::String getChoices();
204 	int getInputMaxLen();
205 
206 private:
207 	/**
208 	 * Translates a script Common::String with dynamic variables
209 	 */
210 	void translate(Common::String *script);
211 
212 	/**
213 	 * Finds a subscript of script 'node'
214 	 */
215 	Shared::XMLNode *find(Shared::XMLNode *node, const Common::String &script, const Common::String &choice = "", bool _default = false);
216 
217 	/**
218 	 * Gets a property as Common::String from the script, and
219 	 * translates it using scriptTranslate.
220 	 */
221 	Common::String getPropAsStr(Std::list<Shared::XMLNode *> &nodes, const Common::String &prop, bool recursive);
222 
223 	Common::String getPropAsStr(Shared::XMLNode *node, const Common::String &prop, bool recursive = false);
224 
225 	/**
226 	 * Gets a property as int from the script
227 	 */
228 	int getPropAsInt(Std::list<Shared::XMLNode *> &nodes, const Common::String &prop, bool recursive);
229 
230 	int getPropAsInt(Shared::XMLNode *node, const Common::String &prop, bool recursive = false);
231 
232 	/**
233 	 * Gets the content of a script node
234 	 */
235 	Common::String getContent(Shared::XMLNode *node);
236 
237 	/*
238 	 * Action Functions
239 	 */
240 	/**
241 	 * Sets a new translation context for the script
242 	 */
243 	ReturnCode pushContext(Shared::XMLNode *script, Shared::XMLNode *current);
244 
245 	/**
246 	 * Removes a node from the translation context
247 	 */
248 	ReturnCode popContext(Shared::XMLNode *script, Shared::XMLNode *current);
249 
250 	/**
251 	 * End script execution
252 	 */
253 	ReturnCode end(Shared::XMLNode *script, Shared::XMLNode *current);
254 
255 	/**
256 	 * Wait for keypress from the user
257 	 */
258 	ReturnCode waitForKeypress(Shared::XMLNode *script, Shared::XMLNode *current);
259 
260 	/**
261 	 * Redirects script execution to another script
262 	 */
263 	ReturnCode redirect(Shared::XMLNode *script, Shared::XMLNode *current);
264 
265 	/**
266 	 * Includes a script to be executed
267 	 */
268 	ReturnCode include(Shared::XMLNode *script, Shared::XMLNode *current);
269 
270 	/**
271 	 * Waits a given number of milliseconds before continuing execution
272 	 */
273 	ReturnCode wait(Shared::XMLNode *script, Shared::XMLNode *current);
274 
275 	/**
276 	 * Executes a 'for' loop script
277 	 */
278 	ReturnCode forLoop(Shared::XMLNode *script, Shared::XMLNode *current);
279 
280 	/**
281 	 * Randomely executes script code
282 	 */
283 	ReturnCode randomScript(Shared::XMLNode *script, Shared::XMLNode *current);
284 
285 	/**
286 	 * Moves the player's current position
287 	 */
288 	ReturnCode move(Shared::XMLNode *script, Shared::XMLNode *current);
289 
290 	/**
291 	 * Puts the player to sleep. Useful when coding inn scripts
292 	 */
293 	ReturnCode sleep(Shared::XMLNode *script, Shared::XMLNode *current);
294 
295 	/**
296 	 * Enables/Disables the keyboard cursor
297 	 */
298 	ReturnCode cursor(Shared::XMLNode *script, Shared::XMLNode *current);
299 
300 	/**
301 	 * Pay gold to someone
302 	 */
303 	ReturnCode pay(Shared::XMLNode *script, Shared::XMLNode *current);
304 
305 	/**
306 	 * Perform a limited 'if' statement
307 	 */
308 	ReturnCode _if(Shared::XMLNode *script, Shared::XMLNode *current);
309 
310 	/**
311 	 * Get input from the player
312 	 */
313 	ReturnCode input(Shared::XMLNode *script, Shared::XMLNode *current);
314 
315 	/**
316 	 * Add item to inventory
317 	 */
318 	ReturnCode add(Shared::XMLNode *script, Shared::XMLNode *current);
319 
320 	/**
321 	 * Lose item
322 	 */
323 	ReturnCode lose(Shared::XMLNode *script, Shared::XMLNode *current);
324 
325 	/**
326 	 * Heals a party member
327 	 */
328 	ReturnCode heal(Shared::XMLNode *script, Shared::XMLNode *current);
329 
330 	/**
331 	 * Performs all of the visual/audio effects of casting a spell
332 	 */
333 	ReturnCode castSpell(Shared::XMLNode *script, Shared::XMLNode *current);
334 
335 	/**
336 	 * Apply damage to a player
337 	 */
338 	ReturnCode damage(Shared::XMLNode *script, Shared::XMLNode *current);
339 
340 	/**
341 	 * Apply karma changes based on the action taken
342 	 */
343 	ReturnCode karma(Shared::XMLNode *script, Shared::XMLNode *current);
344 
345 	/**
346 	 * Set the currently playing music
347 	 */
348 	ReturnCode music(Shared::XMLNode *script, Shared::XMLNode *current);
349 
350 	/**
351 	 * Sets a variable
352 	 */
353 	ReturnCode setVar(Shared::XMLNode *script, Shared::XMLNode *current);
354 
355 	/**
356 	 * Display a different ztats screen
357 	 */
358 	ReturnCode ztats(Shared::XMLNode *script, Shared::XMLNode *current);
359 
360 	/*
361 	 * Math and comparison functions
362 	 */
363 
364 	 /**
365 	  * Parses a math Common::String's children into results so
366 	  * there is only 1 equation remaining.
367 	  *
368 	  * ie. <math>5*<math>6/3</math></math>
369 	  */
370 	void mathParseChildren(Shared::XMLNode *math, Common::String *result);
371 
372 	/**
373 	 * Takes a simple equation Common::String and returns the value
374 	 */
375 	int mathValue(const Common::String &str);
376 
377 	/**
378 	 * Performs simple math operations in the script
379 	 */
380 	int math(int lval, int rval, Common::String &op);
381 
382 	/**
383 	 * Parses a Common::String into left integer value, right integer value,
384 	 * and operator. Returns false if the Common::String is not a valid
385 	 * math equation
386 	 */
387 	bool mathParse(const Common::String &str, int *lval, int *rval, Common::String *op);
388 
389 	/**
390 	 * Parses a Common::String containing an operator (+, -, *, /, etc.) into 3 parts,
391 	 * left, right, and operator.
392 	 */
393 	void parseOperation(const Common::String &str, Common::String *lval, Common::String *rval, Common::String *op);
394 
395 	/**
396 	 * Does a boolean comparison on a Common::String (math or Common::String),
397 	 * fails if the Common::String doesn't contain a valid comparison
398 	 */
399 	bool compare(const Common::String &str);
400 
401 	/**
402 	 * Parses a function into its name and contents
403 	 */
404 	void funcParse(const Common::String &str, Common::String *funcName, Common::String *contents);
405 
406 	/*
407 	 * Static variables
408 	 */
409 private:
410 	typedef Std::map<Common::String, Action> ActionMap;
411 	ActionMap _actionMap;
412 
413 private:
414 	void removeCurrentVariable(const Common::String &name);
415 	Shared::XMLNode *_vendorScriptDoc;
416 	Shared::XMLNode *_scriptNode;
417 	bool _debug;
418 
419 	State _state;                    /**< The state the script is in */
420 	Shared::XMLNode *_currentScript;       /**< The currently running script */
421 	Shared::XMLNode *_currentItem;         /**< The current position in the script */
422 	Std::list<Shared::XMLNode *> _translationContext;  /**< A list of nodes that make up our translation context */
423 	Common::String _target;                  /**< The name of a target script */
424 	InputType _inputType;            /**< The type of input required */
425 	Common::String _inputName;               /**< The variable in which to place the input (by default, "input") */
426 	int _inputMaxLen;                /**< The maximum length allowed for input */
427 
428 	Common::String _nounName;                /**< The name that identifies a node name of noun nodes */
429 	Common::String _idPropName;              /**< The name of the property that uniquely identifies a noun node
430 										 and is used to find a new translation context */
431 
432 	Common::String _choices;
433 	int _iterator;
434 
435 	Std::map<Common::String, Variable *> _variables;
436 	Std::map<Common::String, Provider *> _providers;
437 };
438 
439 } // End of namespace Ultima4
440 } // End of namespace Ultima
441 
442 #endif
443