script_controller.cpp

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * 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.
00006  * 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.
00007  * 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/>.
00008  */
00009 
00012 #include "../../stdafx.h"
00013 #include "../../string_func.h"
00014 #include "../../script/squirrel.hpp"
00015 #include "../../rev.h"
00016 
00017 #include "script_controller.hpp"
00018 #include "../script_fatalerror.hpp"
00019 #include "../script_info.hpp"
00020 #include "../script_instance.hpp"
00021 #include "../script_suspend.hpp"
00022 #include "script_log.hpp"
00023 
00024 /* static */ void ScriptController::SetCommandDelay(int ticks)
00025 {
00026   if (ticks <= 0) return;
00027   ScriptObject::SetDoCommandDelay(ticks);
00028 }
00029 
00030 /* static */ void ScriptController::Sleep(int ticks)
00031 {
00032   if (!ScriptObject::CanSuspend()) {
00033     throw Script_FatalError("You are not allowed to call Sleep in your constructor, Save(), Load(), and any valuator.");
00034   }
00035 
00036   if (ticks <= 0) {
00037     ScriptLog::Warning("Sleep() value should be > 0. Assuming value 1.");
00038     ticks = 1;
00039   }
00040 
00041   throw Script_Suspend(ticks, NULL);
00042 }
00043 
00044 /* static */ void ScriptController::Print(bool error_msg, const char *message)
00045 {
00046   ScriptLog::Log(error_msg ? ScriptLog::LOG_SQ_ERROR : ScriptLog::LOG_SQ_INFO, message);
00047 }
00048 
00049 ScriptController::ScriptController() :
00050   ticks(0),
00051   loaded_library_count(0)
00052 {
00053 }
00054 
00055 ScriptController::~ScriptController()
00056 {
00057   for (LoadedLibraryList::iterator iter = this->loaded_library.begin(); iter != this->loaded_library.end(); iter++) {
00058     free((*iter).second);
00059     free((*iter).first);
00060   }
00061 
00062   this->loaded_library.clear();
00063 }
00064 
00065 /* static */ uint ScriptController::GetTick()
00066 {
00067   return ScriptObject::GetActiveInstance()->GetController()->ticks;
00068 }
00069 
00070 /* static */ int ScriptController::GetOpsTillSuspend()
00071 {
00072   return ScriptObject::GetActiveInstance()->GetOpsTillSuspend();
00073 }
00074 
00075 /* static */ int ScriptController::GetSetting(const char *name)
00076 {
00077   return ScriptObject::GetActiveInstance()->GetSetting(name);
00078 }
00079 
00080 /* static */ uint ScriptController::GetVersion()
00081 {
00082   return _openttd_newgrf_version;
00083 }
00084 
00085 /* static */ HSQOBJECT ScriptController::Import(const char *library, const char *class_name, int version)
00086 {
00087   ScriptController *controller = ScriptObject::GetActiveInstance()->GetController();
00088   Squirrel *engine = ScriptObject::GetActiveInstance()->engine;
00089   HSQUIRRELVM vm = engine->GetVM();
00090 
00091   /* Internally we store libraries as 'library.version' */
00092   char library_name[1024];
00093   snprintf(library_name, sizeof(library_name), "%s.%d", library, version);
00094   strtolower(library_name);
00095 
00096   ScriptInfo *lib = ScriptObject::GetActiveInstance()->FindLibrary(library, version);
00097   if (lib == NULL) {
00098     char error[1024];
00099     snprintf(error, sizeof(error), "couldn't find library '%s' with version %d", library, version);
00100     throw sq_throwerror(vm, OTTD2SQ(error));
00101   }
00102 
00103   /* Get the current table/class we belong to */
00104   HSQOBJECT parent;
00105   sq_getstackobj(vm, 1, &parent);
00106 
00107   char fake_class[1024];
00108 
00109   LoadedLibraryList::iterator iter = controller->loaded_library.find(library_name);
00110   if (iter != controller->loaded_library.end()) {
00111     ttd_strlcpy(fake_class, (*iter).second, sizeof(fake_class));
00112   } else {
00113     int next_number = ++controller->loaded_library_count;
00114 
00115     /* Create a new fake internal name */
00116     snprintf(fake_class, sizeof(fake_class), "_internalNA%d", next_number);
00117 
00118     /* Load the library in a 'fake' namespace, so we can link it to the name the user requested */
00119     sq_pushroottable(vm);
00120     sq_pushstring(vm, OTTD2SQ(fake_class), -1);
00121     sq_newclass(vm, SQFalse);
00122     /* Load the library */
00123     if (!engine->LoadScript(vm, lib->GetMainScript(), false)) {
00124       char error[1024];
00125       snprintf(error, sizeof(error), "there was a compile error when importing '%s' version %d", library, version);
00126       throw sq_throwerror(vm, OTTD2SQ(error));
00127     }
00128     /* Create the fake class */
00129     sq_newslot(vm, -3, SQFalse);
00130     sq_pop(vm, 1);
00131 
00132     controller->loaded_library[strdup(library_name)] = strdup(fake_class);
00133   }
00134 
00135   /* Find the real class inside the fake class (like 'sets.Vector') */
00136   sq_pushroottable(vm);
00137   sq_pushstring(vm, OTTD2SQ(fake_class), -1);
00138   if (SQ_FAILED(sq_get(vm, -2))) {
00139     throw sq_throwerror(vm, _SC("internal error assigning library class"));
00140   }
00141   sq_pushstring(vm, OTTD2SQ(lib->GetInstanceName()), -1);
00142   if (SQ_FAILED(sq_get(vm, -2))) {
00143     char error[1024];
00144     snprintf(error, sizeof(error), "unable to find class '%s' in the library '%s' version %d", lib->GetInstanceName(), library, version);
00145     throw sq_throwerror(vm, OTTD2SQ(error));
00146   }
00147   HSQOBJECT obj;
00148   sq_getstackobj(vm, -1, &obj);
00149   sq_pop(vm, 3);
00150 
00151   if (StrEmpty(class_name)) return obj;
00152 
00153   /* Now link the name the user wanted to our 'fake' class */
00154   sq_pushobject(vm, parent);
00155   sq_pushstring(vm, OTTD2SQ(class_name), -1);
00156   sq_pushobject(vm, obj);
00157   sq_newclass(vm, SQTrue);
00158   sq_newslot(vm, -3, SQFalse);
00159   sq_pop(vm, 1);
00160 
00161   return obj;
00162 }