Update: Translations from eints
[openttd-github.git] / src / script / api / script_controller.cpp
blob2ffbf46730f5ec50b77670d811e65702f2924748
1 /*
2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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 <http://www.gnu.org/licenses/>.
6 */
8 /** @file script_controller.cpp Implementation of ScriptControler. */
10 #include "../../stdafx.h"
11 #include "../../string_func.h"
12 #include "../../script/squirrel.hpp"
13 #include "../../rev.h"
15 #include "script_controller.hpp"
16 #include "script_error.hpp"
17 #include "../script_fatalerror.hpp"
18 #include "../script_info.hpp"
19 #include "../script_instance.hpp"
20 #include "script_log.hpp"
21 #include "../script_gui.h"
22 #include "../../settings_type.h"
23 #include "../../network/network.h"
24 #include "../../misc_cmd.h"
26 #include "../../safeguards.h"
28 /* static */ void ScriptController::SetCommandDelay(int ticks)
30 if (ticks <= 0) return;
31 ScriptObject::SetDoCommandDelay(ticks);
34 /* static */ void ScriptController::Sleep(int ticks)
36 if (!ScriptObject::CanSuspend()) {
37 throw Script_FatalError("You are not allowed to call Sleep in your constructor, Save(), Load(), and any valuator.");
40 if (ticks <= 0) {
41 ScriptLog::Warning("Sleep() value should be > 0. Assuming value 1.");
42 ticks = 1;
45 throw Script_Suspend(ticks, nullptr);
48 /* static */ void ScriptController::Break(const std::string &message)
50 if (_network_dedicated || !_settings_client.gui.ai_developer_tools) return;
52 ScriptObject::GetActiveInstance()->Pause();
54 ScriptLog::Log(ScriptLogTypes::LOG_SQ_ERROR, fmt::format("Break: {}", message));
56 /* Inform script developer that their script has been paused and
57 * needs manual action to continue. */
58 ShowScriptDebugWindow(ScriptObject::GetRootCompany());
60 if ((_pause_mode & PM_PAUSED_NORMAL) == PM_UNPAUSED) {
61 ScriptObject::Command<CMD_PAUSE>::Do(PM_PAUSED_NORMAL, true);
65 /* static */ void ScriptController::Print(bool error_msg, const std::string &message)
67 ScriptLog::Log(error_msg ? ScriptLogTypes::LOG_SQ_ERROR : ScriptLogTypes::LOG_SQ_INFO, message);
70 ScriptController::ScriptController(CompanyID company) :
71 ticks(0),
72 loaded_library_count(0)
74 ScriptObject::SetCompany(company);
77 /* static */ uint ScriptController::GetTick()
79 return ScriptObject::GetActiveInstance()->GetController()->ticks;
82 /* static */ int ScriptController::GetOpsTillSuspend()
84 return ScriptObject::GetActiveInstance()->GetOpsTillSuspend();
87 /* static */ int ScriptController::GetSetting(const std::string &name)
89 return ScriptObject::GetActiveInstance()->GetSetting(name);
92 /* static */ uint ScriptController::GetVersion()
94 return _openttd_newgrf_version;
97 /* static */ HSQOBJECT ScriptController::Import(const std::string &library, const std::string &class_name, int version)
99 ScriptController *controller = ScriptObject::GetActiveInstance()->GetController();
100 Squirrel *engine = ScriptObject::GetActiveInstance()->engine;
101 HSQUIRRELVM vm = engine->GetVM();
103 ScriptInfo *lib = ScriptObject::GetActiveInstance()->FindLibrary(library, version);
104 if (lib == nullptr) {
105 throw sq_throwerror(vm, fmt::format("couldn't find library '{}' with version {}", library, version));
108 /* Internally we store libraries as 'library.version' */
109 std::string library_name = fmt::format("{}.{}", library, version);
111 /* Get the current table/class we belong to */
112 HSQOBJECT parent;
113 sq_getstackobj(vm, 1, &parent);
115 std::string fake_class;
117 LoadedLibraryList::iterator it = controller->loaded_library.find(library_name);
118 if (it != controller->loaded_library.end()) {
119 fake_class = (*it).second;
120 } else {
121 int next_number = ++controller->loaded_library_count;
123 /* Create a new fake internal name */
124 fake_class = fmt::format("_internalNA{}", next_number);
126 /* Load the library in a 'fake' namespace, so we can link it to the name the user requested */
127 sq_pushroottable(vm);
128 sq_pushstring(vm, fake_class, -1);
129 sq_newclass(vm, SQFalse);
130 /* Load the library */
131 if (!engine->LoadScript(vm, lib->GetMainScript(), false)) {
132 throw sq_throwerror(vm, fmt::format("there was a compile error when importing '{}' version {}", library, version));
134 /* Create the fake class */
135 sq_newslot(vm, -3, SQFalse);
136 sq_pop(vm, 1);
138 controller->loaded_library[library_name] = fake_class;
141 /* Find the real class inside the fake class (like 'sets.Vector') */
142 sq_pushroottable(vm);
143 sq_pushstring(vm, fake_class, -1);
144 if (SQ_FAILED(sq_get(vm, -2))) {
145 throw sq_throwerror(vm, "internal error assigning library class");
147 sq_pushstring(vm, lib->GetInstanceName(), -1);
148 if (SQ_FAILED(sq_get(vm, -2))) {
149 throw sq_throwerror(vm, fmt::format("unable to find class '{}' in the library '{}' version {}", lib->GetInstanceName(), library, version));
151 HSQOBJECT obj;
152 sq_getstackobj(vm, -1, &obj);
153 sq_pop(vm, 3);
155 if (class_name.empty()) return obj;
157 /* Now link the name the user wanted to our 'fake' class */
158 sq_pushobject(vm, parent);
159 sq_pushstring(vm, class_name, -1);
160 sq_pushobject(vm, obj);
161 sq_newclass(vm, SQTrue);
162 sq_newslot(vm, -3, SQFalse);
163 sq_pop(vm, 1);
165 return obj;