/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef ULTIMA4_GAME_SCRIPT_H #define ULTIMA4_GAME_SCRIPT_H #include "ultima/ultima4/core/types.h" #include "ultima/shared/conf/xml_node.h" #include "ultima/shared/std/containers.h" #include "common/file.h" #include "common/list.h" namespace Ultima { namespace Ultima4 { /** * An xml-scripting class. It loads and runs xml scripts that * take information and interact with the game environment itself. * Currently, it is mainly useful for writing vendor code; however, * it should be possible to write scripts for other parts of the * game. * * @todo * */ class Script { public: /** * A class that provides information to a script. It is designed to * translate qualifiers and identifiers in a script to another value. * Each provider is assigned a qualifier that the script uses to * select a provider. The provider then uses the rest of the information * to translate the information to something useful. */ class Provider { public: virtual ~Provider() {} virtual Common::String translate(Std::vector &parts) = 0; }; private: /** * A class that represents a script variable */ class Variable { public: Variable(); Variable(const Common::String &v); Variable(const int &v); int &getInt(); Common::String &getString(); void setValue(const int &v); void setValue(const Common::String &v); void unset(); bool isInt() const; bool isString() const; bool isSet() const; private: int _iVal; Common::String _sVal; bool _set; }; public: /** * A script return code */ enum ReturnCode { RET_OK, RET_REDIRECTED, RET_STOP }; /** * The current state of the script */ enum State { STATE_UNLOADED, STATE_NORMAL, STATE_DONE, STATE_INPUT }; /** * The type of input the script is requesting */ enum InputType { INPUT_CHOICE, INPUT_NUMBER, INPUT_STRING, INPUT_DIRECTION, INPUT_PLAYER, INPUT_KEYPRESS }; /** * The action that the script is taking */ enum Action { ACTION_SET_CONTEXT, ACTION_UNSET_CONTEXT, ACTION_END, ACTION_REDIRECT, ACTION_WAIT_FOR_KEY, ACTION_WAIT, ACTION_STOP, ACTION_INCLUDE, ACTION_FOR_LOOP, ACTION_RANDOM, ACTION_MOVE, ACTION_SLEEP, ACTION_CURSOR, ACTION_PAY, ACTION_IF, ACTION_INPUT, ACTION_ADD, ACTION_LOSE, ACTION_HEAL, ACTION_CAST_SPELL, ACTION_DAMAGE, ACTION_KARMA, ACTION_MUSIC, ACTION_SET_VARIABLE, ACTION_ZTATS }; /** * Constructs a script object */ Script(); ~Script(); /** * Adds an information provider for the script */ void addProvider(const Common::String &name, Provider *p); /** * Loads the vendor script */ bool load(const Common::String &filename, const Common::String &baseId, const Common::String &subNodeName = "", const Common::String &subNodeId = ""); /** * Unloads the script */ void unload(); /** * Runs a script after it's been loaded */ void run(const Common::String &script); /** * Executes the subscript 'script' of the main script */ ReturnCode execute(Shared::XMLNode *script, Shared::XMLNode *currentItem = nullptr, Common::String *output = nullptr); /** * Continues the script from where it left off, or where the last script indicated */ void _continue(); /** * Set and retrieve property values */ void resetState(); void setState(State state); State getState(); void setTarget(const Common::String &val); void setChoices(const Common::String &val); void setVar(const Common::String &name, const Common::String &val); void setVar(const Common::String &name, int val); void unsetVar(const Common::String &name); Common::String getTarget(); InputType getInputType(); Common::String getInputName(); Common::String getChoices(); int getInputMaxLen(); private: /** * Translates a script Common::String with dynamic variables */ void translate(Common::String *script); /** * Finds a subscript of script 'node' */ Shared::XMLNode *find(Shared::XMLNode *node, const Common::String &script, const Common::String &choice = "", bool _default = false); /** * Gets a property as Common::String from the script, and * translates it using scriptTranslate. */ Common::String getPropAsStr(Common::List &nodes, const Common::String &prop, bool recursive); Common::String getPropAsStr(Shared::XMLNode *node, const Common::String &prop, bool recursive = false); /** * Gets a property as int from the script */ int getPropAsInt(Common::List &nodes, const Common::String &prop, bool recursive); int getPropAsInt(Shared::XMLNode *node, const Common::String &prop, bool recursive = false); /** * Gets the content of a script node */ Common::String getContent(Shared::XMLNode *node); /* * Action Functions */ /** * Sets a new translation context for the script */ ReturnCode pushContext(Shared::XMLNode *script, Shared::XMLNode *current); /** * Removes a node from the translation context */ ReturnCode popContext(Shared::XMLNode *script, Shared::XMLNode *current); /** * End script execution */ ReturnCode end(Shared::XMLNode *script, Shared::XMLNode *current); /** * Wait for keypress from the user */ ReturnCode waitForKeypress(Shared::XMLNode *script, Shared::XMLNode *current); /** * Redirects script execution to another script */ ReturnCode redirect(Shared::XMLNode *script, Shared::XMLNode *current); /** * Includes a script to be executed */ ReturnCode include(Shared::XMLNode *script, Shared::XMLNode *current); /** * Waits a given number of milliseconds before continuing execution */ ReturnCode wait(Shared::XMLNode *script, Shared::XMLNode *current); /** * Executes a 'for' loop script */ ReturnCode forLoop(Shared::XMLNode *script, Shared::XMLNode *current); /** * Randomely executes script code */ ReturnCode randomScript(Shared::XMLNode *script, Shared::XMLNode *current); /** * Moves the player's current position */ ReturnCode move(Shared::XMLNode *script, Shared::XMLNode *current); /** * Puts the player to sleep. Useful when coding inn scripts */ ReturnCode sleep(Shared::XMLNode *script, Shared::XMLNode *current); /** * Enables/Disables the keyboard cursor */ ReturnCode cursor(Shared::XMLNode *script, Shared::XMLNode *current); /** * Pay gold to someone */ ReturnCode pay(Shared::XMLNode *script, Shared::XMLNode *current); /** * Perform a limited 'if' statement */ ReturnCode _if(Shared::XMLNode *script, Shared::XMLNode *current); /** * Get input from the player */ ReturnCode input(Shared::XMLNode *script, Shared::XMLNode *current); /** * Add item to inventory */ ReturnCode add(Shared::XMLNode *script, Shared::XMLNode *current); /** * Lose item */ ReturnCode lose(Shared::XMLNode *script, Shared::XMLNode *current); /** * Heals a party member */ ReturnCode heal(Shared::XMLNode *script, Shared::XMLNode *current); /** * Performs all of the visual/audio effects of casting a spell */ ReturnCode castSpell(Shared::XMLNode *script, Shared::XMLNode *current); /** * Apply damage to a player */ ReturnCode damage(Shared::XMLNode *script, Shared::XMLNode *current); /** * Apply karma changes based on the action taken */ ReturnCode karma(Shared::XMLNode *script, Shared::XMLNode *current); /** * Set the currently playing music */ ReturnCode music(Shared::XMLNode *script, Shared::XMLNode *current); /** * Sets a variable */ ReturnCode setVar(Shared::XMLNode *script, Shared::XMLNode *current); /** * Display a different ztats screen */ ReturnCode ztats(Shared::XMLNode *script, Shared::XMLNode *current); /* * Math and comparison functions */ /** * Parses a math Common::String's children into results so * there is only 1 equation remaining. * * ie. 5*6/3 */ void mathParseChildren(Shared::XMLNode *math, Common::String *result); /** * Takes a simple equation Common::String and returns the value */ int mathValue(const Common::String &str); /** * Performs simple math operations in the script */ int math(int lval, int rval, Common::String &op); /** * Parses a Common::String into left integer value, right integer value, * and operator. Returns false if the Common::String is not a valid * math equation */ bool mathParse(const Common::String &str, int *lval, int *rval, Common::String *op); /** * Parses a Common::String containing an operator (+, -, *, /, etc.) into 3 parts, * left, right, and operator. */ void parseOperation(const Common::String &str, Common::String *lval, Common::String *rval, Common::String *op); /** * Does a boolean comparison on a Common::String (math or Common::String), * fails if the Common::String doesn't contain a valid comparison */ bool compare(const Common::String &str); /** * Parses a function into its name and contents */ void funcParse(const Common::String &str, Common::String *funcName, Common::String *contents); /* * Static variables */ private: typedef Common::HashMap ActionMap; ActionMap _actionMap; private: void removeCurrentVariable(const Common::String &name); Shared::XMLNode *_vendorScriptDoc; Shared::XMLNode *_scriptNode; bool _debug; State _state; /**< The state the script is in */ Shared::XMLNode *_currentScript; /**< The currently running script */ Shared::XMLNode *_currentItem; /**< The current position in the script */ Common::List _translationContext; /**< A list of nodes that make up our translation context */ Common::String _target; /**< The name of a target script */ InputType _inputType; /**< The type of input required */ Common::String _inputName; /**< The variable in which to place the input (by default, "input") */ int _inputMaxLen; /**< The maximum length allowed for input */ Common::String _nounName; /**< The name that identifies a node name of noun nodes */ Common::String _idPropName; /**< The name of the property that uniquely identifies a noun node and is used to find a new translation context */ Common::String _choices; int _iterator; Common::HashMap _variables; Common::HashMap _providers; }; } // End of namespace Ultima4 } // End of namespace Ultima #endif