# script_instance.cpp

Go to the documentation of this file.

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