4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
10 /** @file script_controller.cpp Implementation of ScriptControler. */
12 #include "../../stdafx.h"
13 #include "../../string_func.h"
14 #include "../../script/squirrel.hpp"
15 #include "../../rev.h"
17 #include "script_controller.hpp"
18 #include "script_error.hpp"
19 #include "../script_fatalerror.hpp"
20 #include "../script_info.hpp"
21 #include "../script_instance.hpp"
22 #include "script_log.hpp"
23 #include "../../ai/ai_gui.hpp"
24 #include "../../settings_type.h"
25 #include "../../network/network.h"
27 #include "../../safeguards.h"
29 /* static */ void ScriptController::SetCommandDelay(int ticks
)
31 if (ticks
<= 0) return;
32 ScriptObject::SetDoCommandDelay(ticks
);
35 /* static */ void ScriptController::Sleep(int ticks
)
37 if (!ScriptObject::CanSuspend()) {
38 throw Script_FatalError("You are not allowed to call Sleep in your constructor, Save(), Load(), and any valuator.");
42 ScriptLog::Warning("Sleep() value should be > 0. Assuming value 1.");
46 throw Script_Suspend(ticks
, NULL
);
49 /* static */ void ScriptController::Break(const char* message
)
51 if (_network_dedicated
|| !_settings_client
.gui
.ai_developer_tools
) return;
53 ScriptObject::GetActiveInstance()->Pause();
55 char log_message
[1024];
56 seprintf(log_message
, lastof(log_message
), "Break: %s", message
);
57 ScriptLog::Log(ScriptLog::LOG_SQ_ERROR
, log_message
);
59 /* Inform script developer that his script has been paused and
60 * needs manual action to continue. */
61 ShowAIDebugWindow(ScriptObject::GetRootCompany());
63 if ((_pause_mode
& PM_PAUSED_NORMAL
) == PM_UNPAUSED
) {
64 ScriptObject::DoCommand(0, PM_PAUSED_NORMAL
, 1, CMD_PAUSE
);
68 /* static */ void ScriptController::Print(bool error_msg
, const char *message
)
70 ScriptLog::Log(error_msg
? ScriptLog::LOG_SQ_ERROR
: ScriptLog::LOG_SQ_INFO
, message
);
73 ScriptController::ScriptController(CompanyID company
) :
75 loaded_library_count(0)
77 ScriptObject::SetCompany(company
);
80 ScriptController::~ScriptController()
82 for (LoadedLibraryList::iterator iter
= this->loaded_library
.begin(); iter
!= this->loaded_library
.end(); iter
++) {
87 this->loaded_library
.clear();
90 /* static */ uint
ScriptController::GetTick()
92 return ScriptObject::GetActiveInstance()->GetController()->ticks
;
95 /* static */ int ScriptController::GetOpsTillSuspend()
97 return ScriptObject::GetActiveInstance()->GetOpsTillSuspend();
100 /* static */ int ScriptController::GetSetting(const char *name
)
102 return ScriptObject::GetActiveInstance()->GetSetting(name
);
105 /* static */ uint
ScriptController::GetVersion()
107 return _openttd_newgrf_version
;
110 /* static */ HSQOBJECT
ScriptController::Import(const char *library
, const char *class_name
, int version
)
112 ScriptController
*controller
= ScriptObject::GetActiveInstance()->GetController();
113 Squirrel
*engine
= ScriptObject::GetActiveInstance()->engine
;
114 HSQUIRRELVM vm
= engine
->GetVM();
116 /* Internally we store libraries as 'library.version' */
117 char library_name
[1024];
118 seprintf(library_name
, lastof(library_name
), "%s.%d", library
, version
);
119 strtolower(library_name
);
121 ScriptInfo
*lib
= ScriptObject::GetActiveInstance()->FindLibrary(library
, version
);
124 seprintf(error
, lastof(error
), "couldn't find library '%s' with version %d", library
, version
);
125 throw sq_throwerror(vm
, error
);
128 /* Get the current table/class we belong to */
130 sq_getstackobj(vm
, 1, &parent
);
132 char fake_class
[1024];
134 LoadedLibraryList::iterator iter
= controller
->loaded_library
.find(library_name
);
135 if (iter
!= controller
->loaded_library
.end()) {
136 strecpy(fake_class
, (*iter
).second
, lastof(fake_class
));
138 int next_number
= ++controller
->loaded_library_count
;
140 /* Create a new fake internal name */
141 seprintf(fake_class
, lastof(fake_class
), "_internalNA%d", next_number
);
143 /* Load the library in a 'fake' namespace, so we can link it to the name the user requested */
144 sq_pushroottable(vm
);
145 sq_pushstring(vm
, fake_class
, -1);
146 sq_newclass(vm
, SQFalse
);
147 /* Load the library */
148 if (!engine
->LoadScript(vm
, lib
->GetMainScript(), false)) {
150 seprintf(error
, lastof(error
), "there was a compile error when importing '%s' version %d", library
, version
);
151 throw sq_throwerror(vm
, error
);
153 /* Create the fake class */
154 sq_newslot(vm
, -3, SQFalse
);
157 controller
->loaded_library
[stredup(library_name
)] = stredup(fake_class
);
160 /* Find the real class inside the fake class (like 'sets.Vector') */
161 sq_pushroottable(vm
);
162 sq_pushstring(vm
, fake_class
, -1);
163 if (SQ_FAILED(sq_get(vm
, -2))) {
164 throw sq_throwerror(vm
, "internal error assigning library class");
166 sq_pushstring(vm
, lib
->GetInstanceName(), -1);
167 if (SQ_FAILED(sq_get(vm
, -2))) {
169 seprintf(error
, lastof(error
), "unable to find class '%s' in the library '%s' version %d", lib
->GetInstanceName(), library
, version
);
170 throw sq_throwerror(vm
, error
);
173 sq_getstackobj(vm
, -1, &obj
);
176 if (StrEmpty(class_name
)) return obj
;
178 /* Now link the name the user wanted to our 'fake' class */
179 sq_pushobject(vm
, parent
);
180 sq_pushstring(vm
, class_name
, -1);
181 sq_pushobject(vm
, obj
);
182 sq_newclass(vm
, SQTrue
);
183 sq_newslot(vm
, -3, SQFalse
);