(svn r28004) -Update from Eints:
[openttd.git] / src / script / api / script_controller.cpp
bloba42c8ede9b11e7ec74ad207954ae0f53b56276c5
1 /* $Id$ */
3 /*
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/>.
8 */
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.");
41 if (ticks <= 0) {
42 ScriptLog::Warning("Sleep() value should be > 0. Assuming value 1.");
43 ticks = 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) :
74 ticks(0),
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++) {
83 free((*iter).second);
84 free((*iter).first);
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);
122 if (lib == NULL) {
123 char error[1024];
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 */
129 HSQOBJECT parent;
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));
137 } else {
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)) {
149 char error[1024];
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);
155 sq_pop(vm, 1);
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))) {
168 char error[1024];
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);
172 HSQOBJECT obj;
173 sq_getstackobj(vm, -1, &obj);
174 sq_pop(vm, 3);
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);
184 sq_pop(vm, 1);
186 return obj;