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 }