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