# script_instance.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 "../debug.h"
    00014 #include "../saveload/saveload.h"
    00015
    00016 #include "../script/squirrel_class.hpp"
    00017
    00018 #include "script_fatalerror.hpp"
    00019 #include "script_storage.hpp"
    00020 #include "script_info.hpp"
    00021 #include "script_instance.hpp"
    00022
    00023 #include "api/script_controller.hpp"
    00024 #include "api/script_error.hpp"
    00025 #include "api/script_event.hpp"
    00026 #include "api/script_log.hpp"
    00027
    00028 #include "../company_base.h"
    00029 #include "../company_func.h"
    00030 #include "../fileio_func.h"
    00031
    00032 ScriptStorage::~ScriptStorage()
    00033 {
    00034   /* Free our pointers */
    00035   if (event_data != NULL) ScriptEventController::FreeEventPointer();
    00036   if (log_data != NULL) ScriptLog::FreeLogPointer();
    00037 }
    00038
    00044 static void PrintFunc(bool error_msg, const SQChar *message)
    00045 {
    00046   /* Convert to OpenTTD internal capable string */
    00047   ScriptController::Print(error_msg, SQ2OTTD(message));
    00048 }
    00049
    00050 ScriptInstance::ScriptInstance(const char *APIName) :
    00051   engine(NULL),
    00052   controller(NULL),
    00053   storage(NULL),
    00054   instance(NULL),
    00055   is_started(false),
    00056   is_dead(false),
    00057   is_save_data_on_stack(false),
    00058   suspend(0),
    00059   is_paused(false),
    00060   callback(NULL)
    00061 {
    00062   this->storage = new ScriptStorage();
    00063   this->engine  = new Squirrel(APIName);
    00064   this->engine->SetPrintFunction(&PrintFunc);
    00065 }
    00066
    00067 void ScriptInstance::Initialize(const char *main_script, const char *instance_name, CompanyID company)
    00068 {
    00069   ScriptObject::ActiveInstance active(this);
    00070
    00071   this->controller = new ScriptController(company);
    00072
    00073   /* Register the API functions and classes */
    00074   this->engine->SetGlobalPointer(this->engine);
    00075   this->RegisterAPI();
    00076
    00077   try {
    00078     ScriptObject::SetAllowDoCommand(false);
    00079     /* Load and execute the script for this script */
    00080     if (strcmp(main_script, "%_dummy") == 0) {
    00081       this->LoadDummyScript();
    00082     } else if (!this->engine->LoadScript(main_script) || this->engine->IsSuspended()) {
    00083       if (this->engine->IsSuspended()) ScriptLog::Error("This script took too long to load script. AI is not started.");
    00084       this->Died();
    00085       return;
    00086     }
    00087
    00088     /* Create the main-class */
    00089     this->instance = MallocT<SQObject>(1);
    00090     if (!this->engine->CreateClassInstance(instance_name, this->controller, this->instance)) {
    00091       this->Died();
    00092       return;
    00093     }
    00094     ScriptObject::SetAllowDoCommand(true);
    00095   } catch (Script_FatalError e) {
    00096     this->is_dead = true;
    00097     this->engine->ThrowError(e.GetErrorMessage());
    00098     this->engine->ResumeError();
    00099     this->Died();
    00100   }
    00101 }
    00102
    00103 void ScriptInstance::RegisterAPI()
    00104 {
    00105   extern void squirrel_register_std(Squirrel *engine);
    00106   squirrel_register_std(this->engine);
    00107 }
    00108
    00109 bool ScriptInstance::LoadCompatibilityScripts(const char *api_version, Subdirectory dir)
    00110 {
    00111   char script_name[32];
    00112   seprintf(script_name, lastof(script_name), "compat_%s.nut", api_version);
    00113   char buf[MAX_PATH];
    00114   Searchpath sp;
    00115   FOR_ALL_SEARCHPATHS(sp) {
    00116     FioAppendDirectory(buf, MAX_PATH, sp, dir);
    00117     ttd_strlcat(buf, script_name, MAX_PATH);
    00118     if (!FileExists(buf)) continue;
    00119
    00120     if (this->engine->LoadScript(buf)) return true;
    00121
    00122     ScriptLog::Error("Failed to load API compatibility script");
    00123     DEBUG(script, 0, "Error compiling / running API compatibility script: %s", buf);
    00124     return false;
    00125   }
    00126
    00127   ScriptLog::Warning("API compatibility script not found");
    00128   return true;
    00129 }
    00130
    00131 ScriptInstance::~ScriptInstance()
    00132 {
    00133   ScriptObject::ActiveInstance active(this);
    00134
    00135   if (instance != NULL) this->engine->ReleaseObject(this->instance);
    00136   if (engine != NULL) delete this->engine;
    00137   delete this->storage;
    00138   delete this->controller;
    00139   free(this->instance);
    00140 }
    00141
    00142 void ScriptInstance::Continue()
    00143 {
    00144   assert(this->suspend < 0);
    00145   this->suspend = -this->suspend - 1;
    00146 }
    00147
    00148 void ScriptInstance::Died()
    00149 {
    00150   DEBUG(script, 0, "The script died unexpectedly.");
    00151   this->is_dead = true;
    00152
    00153   if (this->instance != NULL) this->engine->ReleaseObject(this->instance);
    00154   delete this->engine;
    00155   this->instance = NULL;
    00156   this->engine = NULL;
    00157 }
    00158
    00159 void ScriptInstance::GameLoop()
    00160 {
    00161   ScriptObject::ActiveInstance active(this);
    00162
    00163   if (this->IsDead()) return;
    00164   if (this->engine->HasScriptCrashed()) {
    00165     /* The script crashed during saving, kill it here. */
    00166     this->Died();
    00167     return;
    00168   }
    00169   if (this->is_paused) return;
    00170   this->controller->ticks++;
    00171
    00172   if (this->suspend   < -1) this->suspend++; // Multiplayer suspend, increase up to -1.
    00173   if (this->suspend   < 0)  return;          // Multiplayer suspend, wait for Continue().
    00174   if (--this->suspend > 0)  return;          // Singleplayer suspend, decrease to 0.
    00175
    00176   _current_company = ScriptObject::GetCompany();
    00177
    00178   /* If there is a callback to call, call that first */
    00179   if (this->callback != NULL) {
    00180     if (this->is_save_data_on_stack) {
    00181       sq_poptop(this->engine->GetVM());
    00182       this->is_save_data_on_stack = false;
    00183     }
    00184     try {
    00185       this->callback(this);
    00186     } catch (Script_Suspend e) {
    00187       this->suspend  = e.GetSuspendTime();
    00188       this->callback = e.GetSuspendCallback();
    00189
    00190       return;
    00191     }
    00192   }
    00193
    00194   this->suspend  = 0;
    00195   this->callback = NULL;
    00196
    00197   if (!this->is_started) {
    00198     try {
    00199       ScriptObject::SetAllowDoCommand(false);
    00200       /* Run the constructor if it exists. Don't allow any DoCommands in it. */
    00201       if (this->engine->MethodExists(*this->instance, "constructor")) {
    00202         if (!this->engine->CallMethod(*this->instance, "constructor", MAX_CONSTRUCTOR_OPS) || this->engine->IsSuspended()) {
    00203           if (this->engine->IsSuspended()) ScriptLog::Error("This script took too long to initialize. Script is not started.");
    00204           this->Died();
    00205           return;
    00206         }
    00207       }
    00208       if (!this->CallLoad() || this->engine->IsSuspended()) {
    00209         if (this->engine->IsSuspended()) ScriptLog::Error("This script took too long in the Load function. Script is not started.");
    00210         this->Died();
    00211         return;
    00212       }
    00213       ScriptObject::SetAllowDoCommand(true);
    00214       /* Start the script by calling Start() */
    00215       if (!this->engine->CallMethod(*this->instance, "Start",  _settings_game.script.script_max_opcode_till_suspend) || !this->engine->IsSuspended()) this->Died();
    00216     } catch (Script_Suspend e) {
    00217       this->suspend  = e.GetSuspendTime();
    00218       this->callback = e.GetSuspendCallback();
    00219     } catch (Script_FatalError e) {
    00220       this->is_dead = true;
    00221       this->engine->ThrowError(e.GetErrorMessage());
    00222       this->engine->ResumeError();
    00223       this->Died();
    00224     }
    00225
    00226     this->is_started = true;
    00227     return;
    00228   }
    00229   if (this->is_save_data_on_stack) {
    00230     sq_poptop(this->engine->GetVM());
    00231     this->is_save_data_on_stack = false;
    00232   }
    00233
    00234   /* Continue the VM */
    00235   try {
    00236     if (!this->engine->Resume(_settings_game.script.script_max_opcode_till_suspend)) this->Died();
    00237   } catch (Script_Suspend e) {
    00238     this->suspend  = e.GetSuspendTime();
    00239     this->callback = e.GetSuspendCallback();
    00240   } catch (Script_FatalError e) {
    00241     this->is_dead = true;
    00242     this->engine->ThrowError(e.GetErrorMessage());
    00243     this->engine->ResumeError();
    00244     this->Died();
    00245   }
    00246 }
    00247
    00248 void ScriptInstance::CollectGarbage() const
    00249 {
    00250   if (this->is_started && !this->IsDead()) this->engine->CollectGarbage();
    00251 }
    00252
    00253 /* static */ void ScriptInstance::DoCommandReturn(ScriptInstance *instance)
    00254 {
    00255   instance->engine->InsertResult(ScriptObject::GetLastCommandRes());
    00256 }
    00257
    00258 /* static */ void ScriptInstance::DoCommandReturnVehicleID(ScriptInstance *instance)
    00259 {
    00260   instance->engine->InsertResult(ScriptObject::GetNewVehicleID());
    00261 }
    00262
    00263 /* static */ void ScriptInstance::DoCommandReturnSignID(ScriptInstance *instance)
    00264 {
    00265   instance->engine->InsertResult(ScriptObject::GetNewSignID());
    00266 }
    00267
    00268 /* static */ void ScriptInstance::DoCommandReturnGroupID(ScriptInstance *instance)
    00269 {
    00270   instance->engine->InsertResult(ScriptObject::GetNewGroupID());
    00271 }
    00272
    00273 /* static */ void ScriptInstance::DoCommandReturnGoalID(ScriptInstance *instance)
    00274 {
    00275   instance->engine->InsertResult(ScriptObject::GetNewGoalID());
    00276 }
    00277
    00278 ScriptStorage *ScriptInstance::GetStorage()
    00279 {
    00280   return this->storage;
    00281 }
    00282
    00283 void *ScriptInstance::GetLogPointer()
    00284 {
    00285   ScriptObject::ActiveInstance active(this);
    00286
    00287   return ScriptObject::GetLogPointer();
    00288 }
    00289
    00290 /*
    00291  * All data is stored in the following format:
    00292  * First 1 byte indicating if there is a data blob at all.
    00293  * 1 byte indicating the type of data.
    00294  * The data itself, this differs per type:
    00295  *  - integer: a binary representation of the integer (int32).
    00296  *  - string:  First one byte with the string length, then a 0-terminated char
    00297  *             array. The string can't be longer than 255 bytes (including
    00298  *             terminating '\0').
    00299  *  - array:   All data-elements of the array are saved recursive in this
    00300  *             format, and ended with an element of the type
    00301  *             SQSL_ARRAY_TABLE_END.
    00302  *  - table:   All key/value pairs are saved in this format (first key 1, then
    00303  *             value 1, then key 2, etc.). All keys and values can have an
    00304  *             arbitrary type (as long as it is supported by the save function
    00305  *             of course). The table is ended with an element of the type
    00306  *             SQSL_ARRAY_TABLE_END.
    00307  *  - bool:    A single byte with value 1 representing true and 0 false.
    00308  *  - null:    No data.
    00309  */
    00310
    00312 enum SQSaveLoadType {
    00313   SQSL_INT             = 0x00,
    00314   SQSL_STRING          = 0x01,
    00315   SQSL_ARRAY           = 0x02,
    00316   SQSL_TABLE           = 0x03,
    00317   SQSL_BOOL            = 0x04,
    00318   SQSL_NULL            = 0x05,
    00319   SQSL_ARRAY_TABLE_END = 0xFF,
    00320 };
    00321
    00322 static byte _script_sl_byte;
    00323
    00325 static const SaveLoad _script_byte[] = {
    00326   SLEG_VAR(_script_sl_byte, SLE_UINT8),
    00327   SLE_END()
    00328 };
    00329
    00330 /* static */ bool ScriptInstance::SaveObject(HSQUIRRELVM vm, SQInteger index, int max_depth, bool test)
    00331 {
    00332   if (max_depth == 0) {
    00333     ScriptLog::Error("Savedata can only be nested to 25 deep. No data saved."); // SQUIRREL_MAX_DEPTH = 25
    00334     return false;
    00335   }
    00336
    00337   switch (sq_gettype(vm, index)) {
    00338     case OT_INTEGER: {
    00339       if (!test) {
    00340         _script_sl_byte = SQSL_INT;
    00341         SlObject(NULL, _script_byte);
    00342       }
    00343       SQInteger res;
    00344       sq_getinteger(vm, index, &res);
    00345       if (!test) {
    00346         int value = (int)res;
    00347         SlArray(&value, 1, SLE_INT32);
    00348       }
    00349       return true;
    00350     }
    00351
    00352     case OT_STRING: {
    00353       if (!test) {
    00354         _script_sl_byte = SQSL_STRING;
    00355         SlObject(NULL, _script_byte);
    00356       }
    00357       const SQChar *res;
    00358       sq_getstring(vm, index, &res);
    00359       /* @bug if a string longer than 512 characters is given to SQ2OTTD, the
    00360        *  internal buffer overflows. */
    00361       const char *buf = SQ2OTTD(res);
    00362       size_t len = strlen(buf) + 1;
    00363       if (len >= 255) {
    00364         ScriptLog::Error("Maximum string length is 254 chars. No data saved.");
    00365         return false;
    00366       }
    00367       if (!test) {
    00368         _script_sl_byte = (byte)len;
    00369         SlObject(NULL, _script_byte);
    00370         SlArray(const_cast<char *>(buf), len, SLE_CHAR);
    00371       }
    00372       return true;
    00373     }
    00374
    00375     case OT_ARRAY: {
    00376       if (!test) {
    00377         _script_sl_byte = SQSL_ARRAY;
    00378         SlObject(NULL, _script_byte);
    00379       }
    00380       sq_pushnull(vm);
    00381       while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
    00382         /* Store the value */
    00383         bool res = SaveObject(vm, -1, max_depth - 1, test);
    00384         sq_pop(vm, 2);
    00385         if (!res) {
    00386           sq_pop(vm, 1);
    00387           return false;
    00388         }
    00389       }
    00390       sq_pop(vm, 1);
    00391       if (!test) {
    00392         _script_sl_byte = SQSL_ARRAY_TABLE_END;
    00393         SlObject(NULL, _script_byte);
    00394       }
    00395       return true;
    00396     }
    00397
    00398     case OT_TABLE: {
    00399       if (!test) {
    00400         _script_sl_byte = SQSL_TABLE;
    00401         SlObject(NULL, _script_byte);
    00402       }
    00403       sq_pushnull(vm);
    00404       while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
    00405         /* Store the key + value */
    00406         bool res = SaveObject(vm, -2, max_depth - 1, test) && SaveObject(vm, -1, max_depth - 1, test);
    00407         sq_pop(vm, 2);
    00408         if (!res) {
    00409           sq_pop(vm, 1);
    00410           return false;
    00411         }
    00412       }
    00413       sq_pop(vm, 1);
    00414       if (!test) {
    00415         _script_sl_byte = SQSL_ARRAY_TABLE_END;
    00416         SlObject(NULL, _script_byte);
    00417       }
    00418       return true;
    00419     }
    00420
    00421     case OT_BOOL: {
    00422       if (!test) {
    00423         _script_sl_byte = SQSL_BOOL;
    00424         SlObject(NULL, _script_byte);
    00425       }
    00426       SQBool res;
    00427       sq_getbool(vm, index, &res);
    00428       if (!test) {
    00429         _script_sl_byte = res ? 1 : 0;
    00430         SlObject(NULL, _script_byte);
    00431       }
    00432       return true;
    00433     }
    00434
    00435     case OT_NULL: {
    00436       if (!test) {
    00437         _script_sl_byte = SQSL_NULL;
    00438         SlObject(NULL, _script_byte);
    00439       }
    00440       return true;
    00441     }
    00442
    00443     default:
    00444       ScriptLog::Error("You tried to save an unsupported type. No data saved.");
    00445       return false;
    00446   }
    00447 }
    00448
    00449 /* static */ void ScriptInstance::SaveEmpty()
    00450 {
    00451   _script_sl_byte = 0;
    00452   SlObject(NULL, _script_byte);
    00453 }
    00454
    00455 void ScriptInstance::Save()
    00456 {
    00457   ScriptObject::ActiveInstance active(this);
    00458
    00459   /* Don't save data if the script didn't start yet or if it crashed. */
    00460   if (this->engine == NULL || this->engine->HasScriptCrashed()) {
    00461     SaveEmpty();
    00462     return;
    00463   }
    00464
    00465   HSQUIRRELVM vm = this->engine->GetVM();
    00466   if (this->is_save_data_on_stack) {
    00467     _script_sl_byte = 1;
    00468     SlObject(NULL, _script_byte);
    00469     /* Save the data that was just loaded. */
    00470     SaveObject(vm, -1, SQUIRREL_MAX_DEPTH, false);
    00471   } else if (!this->is_started) {
    00472     SaveEmpty();
    00473     return;
    00474   } else if (this->engine->MethodExists(*this->instance, "Save")) {
    00475     HSQOBJECT savedata;
    00476     /* We don't want to be interrupted during the save function. */
    00477     bool backup_allow = ScriptObject::GetAllowDoCommand();
    00478     ScriptObject::SetAllowDoCommand(false);
    00479     try {
    00480       if (!this->engine->CallMethod(*this->instance, "Save", &savedata, MAX_SL_OPS)) {
    00481         /* The script crashed in the Save function. We can't kill
    00482          * it here, but do so in the next script tick. */
    00483         SaveEmpty();
    00484         this->engine->CrashOccurred();
    00485         return;
    00486       }
    00487     } catch (Script_FatalError e) {
    00488       /* If we don't mark the script as dead here cleaning up the squirrel
    00489        * stack could throw Script_FatalError again. */
    00490       this->is_dead = true;
    00491       this->engine->ThrowError(e.GetErrorMessage());
    00492       this->engine->ResumeError();
    00493       SaveEmpty();
    00494       /* We can't kill the script here, so mark it as crashed (not dead) and
    00495        * kill it in the next script tick. */
    00496       this->is_dead = false;
    00497       this->engine->CrashOccurred();
    00498       return;
    00499     }
    00500     ScriptObject::SetAllowDoCommand(backup_allow);
    00501
    00502     if (!sq_istable(savedata)) {
    00503       ScriptLog::Error(this->engine->IsSuspended() ? "This script took too long to Save." : "Save function should return a table.");
    00504       SaveEmpty();
    00505       this->engine->CrashOccurred();
    00506       return;
    00507     }
    00508     sq_pushobject(vm, savedata);
    00509     if (SaveObject(vm, -1, SQUIRREL_MAX_DEPTH, true)) {
    00510       _script_sl_byte = 1;
    00511       SlObject(NULL, _script_byte);
    00512       SaveObject(vm, -1, SQUIRREL_MAX_DEPTH, false);
    00513       this->is_save_data_on_stack = true;
    00514     } else {
    00515       SaveEmpty();
    00516       this->engine->CrashOccurred();
    00517     }
    00518   } else {
    00519     ScriptLog::Warning("Save function is not implemented");
    00520     _script_sl_byte = 0;
    00521     SlObject(NULL, _script_byte);
    00522   }
    00523 }
    00524
    00525 void ScriptInstance::Pause()
    00526 {
    00527   /* Suspend script. */
    00528   HSQUIRRELVM vm = this->engine->GetVM();
    00529   Squirrel::DecreaseOps(vm, _settings_game.script.script_max_opcode_till_suspend);
    00530
    00531   this->is_paused = true;
    00532 }
    00533
    00534 void ScriptInstance::Unpause()
    00535 {
    00536   this->is_paused = false;
    00537 }
    00538
    00539 bool ScriptInstance::IsPaused()
    00540 {
    00541   return this->is_paused;
    00542 }
    00543
    00544 /* static */ bool ScriptInstance::LoadObjects(HSQUIRRELVM vm)
    00545 {
    00546   SlObject(NULL, _script_byte);
    00547   switch (_script_sl_byte) {
    00548     case SQSL_INT: {
    00549       int value;
    00550       SlArray(&value, 1, SLE_INT32);
    00551       if (vm != NULL) sq_pushinteger(vm, (SQInteger)value);
    00552       return true;
    00553     }
    00554
    00555     case SQSL_STRING: {
    00556       SlObject(NULL, _script_byte);
    00557       static char buf[256];
    00558       SlArray(buf, _script_sl_byte, SLE_CHAR);
    00559       if (vm != NULL) sq_pushstring(vm, OTTD2SQ(buf), -1);
    00560       return true;
    00561     }
    00562
    00563     case SQSL_ARRAY: {
    00564       if (vm != NULL) sq_newarray(vm, 0);
    00565       while (LoadObjects(vm)) {
    00566         if (vm != NULL) sq_arrayappend(vm, -2);
    00567         /* The value is popped from the stack by squirrel. */
    00568       }
    00569       return true;
    00570     }
    00571
    00572     case SQSL_TABLE: {
    00573       if (vm != NULL) sq_newtable(vm);
    00574       while (LoadObjects(vm)) {
    00575         LoadObjects(vm);
    00576         if (vm != NULL) sq_rawset(vm, -3);
    00577         /* The key (-2) and value (-1) are popped from the stack by squirrel. */
    00578       }
    00579       return true;
    00580     }
    00581
    00582     case SQSL_BOOL: {
    00583       SlObject(NULL, _script_byte);
    00584       if (vm != NULL) sq_pushinteger(vm, (SQBool)(_script_sl_byte != 0));
    00585       return true;
    00586     }
    00587
    00588     case SQSL_NULL: {
    00589       if (vm != NULL) sq_pushnull(vm);
    00590       return true;
    00591     }
    00592
    00593     case SQSL_ARRAY_TABLE_END: {
    00594       return false;
    00595     }
    00596
    00597     default: NOT_REACHED();
    00598   }
    00599 }
    00600
    00601 /* static */ void ScriptInstance::LoadEmpty()
    00602 {
    00603   SlObject(NULL, _script_byte);
    00604   /* Check if there was anything saved at all. */
    00605   if (_script_sl_byte == 0) return;
    00606
    00607   LoadObjects(NULL);
    00608 }
    00609
    00610 void ScriptInstance::Load(int version)
    00611 {
    00612   ScriptObject::ActiveInstance active(this);
    00613
    00614   if (this->engine == NULL || version == -1) {
    00615     LoadEmpty();
    00616     return;
    00617   }
    00618   HSQUIRRELVM vm = this->engine->GetVM();
    00619
    00620   SlObject(NULL, _script_byte);
    00621   /* Check if there was anything saved at all. */
    00622   if (_script_sl_byte == 0) return;
    00623
    00624   sq_pushinteger(vm, version);
    00625   LoadObjects(vm);
    00626   this->is_save_data_on_stack = true;
    00627 }
    00628
    00629 bool ScriptInstance::CallLoad()
    00630 {
    00631   HSQUIRRELVM vm = this->engine->GetVM();
    00632   /* Is there save data that we should load? */
    00633   if (!this->is_save_data_on_stack) return true;
    00634   /* Whatever happens, after CallLoad the savegame data is removed from the stack. */
    00635   this->is_save_data_on_stack = false;
    00636
    00637   if (!this->engine->MethodExists(*this->instance, "Load")) {
    00638     ScriptLog::Warning("Loading failed: there was data for the script to load, but the script does not have a Load() function.");
    00639
    00640     /* Pop the savegame data and version. */
    00641     sq_pop(vm, 2);
    00642     return true;
    00643   }
    00644
    00645   /* Go to the instance-root */
    00646   sq_pushobject(vm, *this->instance);
    00647   /* Find the function-name inside the script */
    00648   sq_pushstring(vm, OTTD2SQ("Load"), -1);
    00649   /* Change the "Load" string in a function pointer */
    00650   sq_get(vm, -2);
    00651   /* Push the main instance as "this" object */
    00652   sq_pushobject(vm, *this->instance);
    00653   /* Push the version data and savegame data as arguments */
    00654   sq_push(vm, -5);
    00655   sq_push(vm, -5);
    00656
    00657   /* Call the script load function. sq_call removes the arguments (but not the
    00658    * function pointer) from the stack. */
    00659   if (SQ_FAILED(sq_call(vm, 3, SQFalse, SQFalse, MAX_SL_OPS))) return false;
    00660
    00661   /* Pop 1) The version, 2) the savegame data, 3) the object instance, 4) the function pointer. */
    00662   sq_pop(vm, 4);
    00663   return true;
    00664 }
    00665
    00666 SQInteger ScriptInstance::GetOpsTillSuspend()
    00667 {
    00668   return this->engine->GetOpsTillSuspend();
    00669 }
    00670
    00671 void ScriptInstance::DoCommandCallback(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
    00672 {
    00673   ScriptObject::ActiveInstance active(this);
    00674
    00675   ScriptObject::SetLastCommandRes(result.Succeeded());
    00676
    00677   if (result.Failed()) {
    00678     ScriptObject::SetLastError(ScriptError::StringToError(result.GetErrorMessage()));
    00679   } else {
    00680     ScriptObject::IncreaseDoCommandCosts(result.GetCost());
    00681     ScriptObject::SetLastCost(result.GetCost());
    00682   }
    00683 }
    00684
    00685 void ScriptInstance::InsertEvent(class ScriptEvent *event)
    00686 {
    00687   ScriptObject::ActiveInstance active(this);
    00688
    00689   ScriptEventController::InsertEvent(event);
    00690 }