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