/* * This file is part of OpenTTD. * OpenTTD 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, version 2. * OpenTTD 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 OpenTTD. If not, see . */ /** @file script_controller.hpp The controller of the script. */ #ifndef SCRIPT_CONTROLLER_HPP #define SCRIPT_CONTROLLER_HPP #include "script_types.hpp" #include "../../core/string_compare_type.hpp" #include /** * The Controller, the class each Script should extend. It creates the Script, * makes sure the logic kicks in correctly, and that #GetTick() has a valid * value. * * When starting a new game, or when loading a game, OpenTTD tries to match a * script that matches to the specified version as close as possible. It tries * (from first to last, stopping as soon as the attempt succeeds) * * - load the latest version of the same script that supports loading data from * the saved version (the version of saved data must be equal or greater * than ScriptInfo::MinVersionToLoad), * - load the latest version of the same script (ignoring version requirements), * - (for AIs) load a random AI, and finally * - (for AIs) load the dummy AI. * * After determining the script to use, starting it is done as follows * * - An instance is constructed of the class derived from ScriptController * (class name is retrieved from ScriptInfo::CreateInstance). * - If there is script data available in the loaded game and if the data is * loadable according to ScriptInfo::MinVersionToLoad, #Load is called with the * data from the loaded game. * - Finally, #Start is called to start execution of the script. * * See also https://wiki.openttd.org/en/Development/Script/Save%20and%20Load for more details. * * @api ai game */ class ScriptController { friend class AIScanner; friend class ScriptInstance; public: /** * Initializer of the ScriptController. * @param company The company this Script is normally serving. */ ScriptController(CompanyID company); /** * Destructor of the ScriptController. */ ~ScriptController(); /** * This function is called to start your script. Your script starts here. If you * return from this function, your script dies, so make sure that doesn't * happen. * @note Cannot be called from within your script. */ void Start(); #ifdef DOXYGEN_API /** * Save the state of the script. * * By implementing this function, you can store some data inside the savegame. * The function should return a table with the information you want to store. * You can only store: * * - integers, * - strings, * - arrays (max. 25 levels deep), * - tables (max. 25 levels deep), * - booleans, and * - nulls. * * In particular, instances of classes can't be saved including * ScriptList. Such a list should be converted to an array or table on * save and converted back on load. * * The function is called as soon as the user saves the game, * independently of other activities of the script. The script is not * notified of the call. To avoid race-conditions between #Save and the * other script code, change variables directly after a #Sleep, it is * very unlikely, to get interrupted at that point in the execution. * See also https://wiki.openttd.org/en/Development/Script/Save%20and%20Load for more details. * * @note No other information is saved than the table returned by #Save. * For example all pending events are lost as soon as the game is loaded. * * @return Data of the script that should be stored in the save game. */ SquirrelTable Save(); /** * Load saved data just before calling #Start. * The function is only called when there is data to load. * @param version Version number of the script that created the \a data. * @param data Data that was saved (return value of #Save). */ void Load(int version, SquirrelTable data); #endif /* DOXYGEN_API */ /** * Find at which tick your script currently is. * @return returns the current tick. */ static uint GetTick(); /** * Get the number of operations the script may still execute this tick. * @return The amount of operations left to execute. * @note This number can go negative when certain uninteruptable * operations are executed. The amount of operations that you go * over the limit will be deducted from the next tick you would * be allowed to run. */ static int GetOpsTillSuspend(); /** * Get the value of one of your settings you set via info.nut. * @param name The name of the setting. * @return the value for the setting, or -1 if the setting is not known. */ static int GetSetting(const char *name); /** * Get the OpenTTD version of this executable. The version is formatted * with the bits having the following meaning: * 24-31 major version + 16. * 20-23 minor version. * 19 1 if it is a release, 0 if it is not. * 0-18 revision number; 0 when the revision is unknown. * You have to subtract 16 from the major version to get the correct * value. * * Prior to OpenTTD 12, the bits have the following meaning: * 28-31 major version. * 24-27 minor version. * 20-23 build. * 19 1 if it is a release, 0 if it is not. * 0-18 revision number; 0 when the revision is unknown. * * @return The version in newgrf format. */ static uint GetVersion(); /** * Change the minimum amount of time the script should be put in suspend mode * when you execute a command. Normally in SP this is 1, and in MP it is * what ever delay the server has been programmed to delay commands * (normally between 1 and 5). To give a more 'real' effect to your script, * you can control that number here. * @param ticks The minimum amount of ticks to wait. * @pre Ticks should be positive. Too big values will influence performance of the script. * @note If the number is lower than the MP setting, the MP setting wins. */ static void SetCommandDelay(int ticks); /** * Sleep for X ticks. The code continues after this line when the X script ticks * are passed. Mind that an script tick is different from in-game ticks and * differ per script speed. * @param ticks the ticks to wait * @pre ticks > 0. * @post the value of GetTick() will be changed exactly 'ticks' in value after * calling this. */ static void Sleep(int ticks); /** * Break execution of the script when script developer tools are active. For * other users, nothing will happen when you call this function. To resume * the script, you have to click on the continue button in the AI debug * window. It is not recommended to leave calls to this function in scripts * that you publish or upload to bananas. * @param message to print in the AI debug window when the break occurs. * @note gui.ai_developer_tools setting must be enabled or the break is * ignored. */ static void Break(const char* message); /** * When Squirrel triggers a print, this function is called. * Squirrel calls this when 'print' is used, or when the script made an error. * @param error_msg If true, it is a Squirrel error message. * @param message The message Squirrel logged. * @note Use ScriptLog.Info/Warning/Error instead of 'print'. */ static void Print(bool error_msg, const char *message); /** * Import a library. * @param library The name of the library to import. The name should be composed as ScriptInfo::GetCategory() + "." + * ScriptInfo::CreateInstance(). * @param class_name Under which name you want it to be available (or "" if you just want the returning object). * @param version Which version you want specifically. * @return The loaded library object. If class_name is set, it is also available (under the scope of the import) under that name. * @note This command can be called from the global space, and does not need an instance. */ static HSQOBJECT Import(const char *library, const char *class_name, int version); private: typedef std::map LoadedLibraryList; ///< The type for loaded libraries. uint ticks; ///< The amount of ticks we're sleeping. LoadedLibraryList loaded_library; ///< The libraries we loaded. int loaded_library_count; ///< The amount of libraries. /** * Register all classes that are known inside the script API. */ void RegisterClasses(); }; #endif /* SCRIPT_CONTROLLER_HPP */