Update: Translations from eints
[openttd-github.git] / src / script / api / script_object.cpp
blob637d662125f4c26eb844ca35e6ad5e65158d85c0
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_object.cpp Implementation of ScriptObject. */
10 #include "../../stdafx.h"
11 #include "../../script/squirrel.hpp"
12 #include "../../company_func.h"
13 #include "../../company_base.h"
14 #include "../../network/network.h"
15 #include "../../genworld.h"
16 #include "../../string_func.h"
17 #include "../../strings_func.h"
18 #include "../../command_func.h"
20 #include "../script_storage.hpp"
21 #include "../script_instance.hpp"
22 #include "../script_fatalerror.hpp"
23 #include "script_error.hpp"
24 #include "../../debug.h"
26 #include "../../safeguards.h"
28 /**
29 * Get the storage associated with the current ScriptInstance.
30 * @return The storage.
32 static ScriptStorage *GetStorage()
34 return ScriptObject::GetActiveInstance()->GetStorage();
38 /* static */ ScriptInstance *ScriptObject::ActiveInstance::active = nullptr;
40 ScriptObject::ActiveInstance::ActiveInstance(ScriptInstance *instance) : alc_scope(instance->engine)
42 this->last_active = ScriptObject::ActiveInstance::active;
43 ScriptObject::ActiveInstance::active = instance;
46 ScriptObject::ActiveInstance::~ActiveInstance()
48 ScriptObject::ActiveInstance::active = this->last_active;
51 /* static */ ScriptInstance *ScriptObject::GetActiveInstance()
53 assert(ScriptObject::ActiveInstance::active != nullptr);
54 return ScriptObject::ActiveInstance::active;
58 /* static */ void ScriptObject::SetDoCommandDelay(uint ticks)
60 assert(ticks > 0);
61 GetStorage()->delay = ticks;
64 /* static */ uint ScriptObject::GetDoCommandDelay()
66 return GetStorage()->delay;
69 /* static */ void ScriptObject::SetDoCommandMode(ScriptModeProc *proc, ScriptObject *instance)
71 GetStorage()->mode = proc;
72 GetStorage()->mode_instance = instance;
75 /* static */ ScriptModeProc *ScriptObject::GetDoCommandMode()
77 return GetStorage()->mode;
80 /* static */ ScriptObject *ScriptObject::GetDoCommandModeInstance()
82 return GetStorage()->mode_instance;
85 /* static */ void ScriptObject::SetDoCommandAsyncMode(ScriptAsyncModeProc *proc, ScriptObject *instance)
87 GetStorage()->async_mode = proc;
88 GetStorage()->async_mode_instance = instance;
91 /* static */ ScriptAsyncModeProc *ScriptObject::GetDoCommandAsyncMode()
93 return GetStorage()->async_mode;
96 /* static */ ScriptObject *ScriptObject::GetDoCommandAsyncModeInstance()
98 return GetStorage()->async_mode_instance;
101 /* static */ void ScriptObject::SetLastCommand(const CommandDataBuffer &data, Commands cmd)
103 ScriptStorage *s = GetStorage();
104 Debug(script, 6, "SetLastCommand company={:02d} cmd={} data={}", s->root_company, cmd, FormatArrayAsHex(data));
105 s->last_data = data;
106 s->last_cmd = cmd;
109 /* static */ bool ScriptObject::CheckLastCommand(const CommandDataBuffer &data, Commands cmd)
111 ScriptStorage *s = GetStorage();
112 Debug(script, 6, "CheckLastCommand company={:02d} cmd={} data={}", s->root_company, cmd, FormatArrayAsHex(data));
113 if (s->last_cmd != cmd) return false;
114 if (s->last_data != data) return false;
115 return true;
118 /* static */ void ScriptObject::SetDoCommandCosts(Money value)
120 GetStorage()->costs = CommandCost(INVALID_EXPENSES, value); // Expense type is never read.
123 /* static */ void ScriptObject::IncreaseDoCommandCosts(Money value)
125 GetStorage()->costs.AddCost(value);
128 /* static */ Money ScriptObject::GetDoCommandCosts()
130 return GetStorage()->costs.GetCost();
133 /* static */ void ScriptObject::SetLastError(ScriptErrorType last_error)
135 GetStorage()->last_error = last_error;
138 /* static */ ScriptErrorType ScriptObject::GetLastError()
140 return GetStorage()->last_error;
143 /* static */ void ScriptObject::SetLastCost(Money last_cost)
145 GetStorage()->last_cost = last_cost;
148 /* static */ Money ScriptObject::GetLastCost()
150 return GetStorage()->last_cost;
153 /* static */ void ScriptObject::SetRoadType(RoadType road_type)
155 GetStorage()->road_type = road_type;
158 /* static */ RoadType ScriptObject::GetRoadType()
160 return GetStorage()->road_type;
163 /* static */ void ScriptObject::SetRailType(RailType rail_type)
165 GetStorage()->rail_type = rail_type;
168 /* static */ RailType ScriptObject::GetRailType()
170 return GetStorage()->rail_type;
173 /* static */ void ScriptObject::SetLastCommandRes(bool res)
175 GetStorage()->last_command_res = res;
178 /* static */ bool ScriptObject::GetLastCommandRes()
180 return GetStorage()->last_command_res;
183 /* static */ void ScriptObject::SetLastCommandResData(CommandDataBuffer data)
185 GetStorage()->last_cmd_ret = std::move(data);
188 /* static */ const CommandDataBuffer &ScriptObject::GetLastCommandResData()
190 return GetStorage()->last_cmd_ret;
193 /* static */ void ScriptObject::SetAllowDoCommand(bool allow)
195 GetStorage()->allow_do_command = allow;
198 /* static */ bool ScriptObject::GetAllowDoCommand()
200 return GetStorage()->allow_do_command;
203 /* static */ void ScriptObject::SetCompany(CompanyID company)
205 if (GetStorage()->root_company == INVALID_OWNER) GetStorage()->root_company = company;
206 GetStorage()->company = company;
208 _current_company = company;
211 /* static */ CompanyID ScriptObject::GetCompany()
213 return GetStorage()->company;
216 /* static */ CompanyID ScriptObject::GetRootCompany()
218 return GetStorage()->root_company;
221 /* static */ bool ScriptObject::CanSuspend()
223 Squirrel *squirrel = ScriptObject::GetActiveInstance()->engine;
224 return GetStorage()->allow_do_command && squirrel->CanSuspend();
227 /* static */ void *&ScriptObject::GetEventPointer()
229 return GetStorage()->event_data;
232 /* static */ ScriptLogTypes::LogData &ScriptObject::GetLogData()
234 return GetStorage()->log_data;
237 /* static */ std::string ScriptObject::GetString(StringID string)
239 return ::StrMakeValid(::GetString(string));
242 /* static */ void ScriptObject::SetCallbackVariable(int index, int value)
244 if (static_cast<size_t>(index) >= GetStorage()->callback_value.size()) GetStorage()->callback_value.resize(index + 1);
245 GetStorage()->callback_value[index] = value;
248 /* static */ int ScriptObject::GetCallbackVariable(int index)
250 return GetStorage()->callback_value[index];
253 /* static */ CommandCallbackData *ScriptObject::GetDoCommandCallback()
255 return ScriptObject::GetActiveInstance()->GetDoCommandCallback();
258 std::tuple<bool, bool, bool, bool> ScriptObject::DoCommandPrep()
260 if (!ScriptObject::CanSuspend()) {
261 throw Script_FatalError("You are not allowed to execute any DoCommand (even indirect) in your constructor, Save(), Load(), and any valuator.");
264 /* Are we only interested in the estimate costs? */
265 bool estimate_only = GetDoCommandMode() != nullptr && !GetDoCommandMode()();
267 /* Should the command be executed asynchronously? */
268 bool asynchronous = GetDoCommandAsyncMode() != nullptr && GetDoCommandAsyncMode()();
270 bool networking = _networking && !_generating_world;
272 if (!ScriptCompanyMode::IsDeity() && !ScriptCompanyMode::IsValid()) {
273 ScriptObject::SetLastError(ScriptError::ERR_PRECONDITION_INVALID_COMPANY);
274 return { true, estimate_only, asynchronous, networking };
277 return { false, estimate_only, asynchronous, networking };
280 bool ScriptObject::DoCommandProcessResult(const CommandCost &res, Script_SuspendCallbackProc *callback, bool estimate_only, bool asynchronous)
282 /* Set the default callback to return a true/false result of the DoCommand */
283 if (callback == nullptr) callback = &ScriptInstance::DoCommandReturn;
285 /* We failed; set the error and bail out */
286 if (res.Failed()) {
287 SetLastError(ScriptError::StringToError(res.GetErrorMessage()));
288 return false;
291 /* No error, then clear it. */
292 SetLastError(ScriptError::ERR_NONE);
294 /* Estimates, update the cost for the estimate and be done */
295 if (estimate_only) {
296 IncreaseDoCommandCosts(res.GetCost());
297 return true;
300 /* Costs of this operation. */
301 SetLastCost(res.GetCost());
302 SetLastCommandRes(true);
304 if (_generating_world || asynchronous) {
305 IncreaseDoCommandCosts(res.GetCost());
306 if (!_generating_world) {
307 /* Charge a nominal fee for asynchronously executed commands */
308 Squirrel *engine = ScriptObject::GetActiveInstance()->engine;
309 Squirrel::DecreaseOps(engine->GetVM(), 100);
311 if (callback != nullptr) {
312 /* Insert return value into to stack and throw a control code that
313 * the return value in the stack should be used. */
314 callback(GetActiveInstance());
315 throw SQInteger(1);
317 return true;
318 } else if (_networking) {
319 /* Suspend the script till the command is really executed. */
320 throw Script_Suspend(-(int)GetDoCommandDelay(), callback);
321 } else {
322 IncreaseDoCommandCosts(res.GetCost());
324 /* Suspend the script player for 1+ ticks, so it simulates multiplayer. This
325 * both avoids confusion when a developer launched the script in a
326 * multiplayer game, but also gives time for the GUI and human player
327 * to interact with the game. */
328 throw Script_Suspend(GetDoCommandDelay(), callback);
331 NOT_REACHED();
335 /* static */ Randomizer ScriptObject::random_states[OWNER_END];
337 Randomizer &ScriptObject::GetRandomizer(Owner owner)
339 return ScriptObject::random_states[owner];
342 void ScriptObject::InitializeRandomizers()
344 Randomizer random = _random;
345 for (Owner owner = OWNER_BEGIN; owner < OWNER_END; owner++) {
346 ScriptObject::GetRandomizer(owner).SetSeed(random.Next());