# ai_instance.cpp

Go to the documentation of this file.

    00001 /* $Id: ai_instance.cpp 18862 2010-01-18 15:41:38Z 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 #include "../gui.h"
    00016
    00017 #include <squirrel.h>
    00018 #include "../script/squirrel.hpp"
    00019 #include "../script/squirrel_helper.hpp"
    00020 #include "../script/squirrel_class.hpp"
    00021
    00022 #include "ai_config.hpp"
    00023 #include "ai_storage.hpp"
    00024 #include "ai_instance.hpp"
    00025 #include "ai_gui.hpp"
    00026
    00027 /* Convert all AI related classes to Squirrel data.
    00028  * Note: this line a marker in squirrel_export.sh. Do not change! */
    00029 #include "api/ai_abstractlist.hpp.sq"
    00030 #include "api/ai_accounting.hpp.sq"
    00031 #include "api/ai_airport.hpp.sq"
    00032 #include "api/ai_base.hpp.sq"
    00033 #include "api/ai_basestation.hpp.sq"
    00034 #include "api/ai_bridge.hpp.sq"
    00035 #include "api/ai_bridgelist.hpp.sq"
    00036 #include "api/ai_cargo.hpp.sq"
    00037 #include "api/ai_cargolist.hpp.sq"
    00038 #include "api/ai_company.hpp.sq"
    00039 #include "api/ai_controller.hpp.sq"
    00040 #include "api/ai_date.hpp.sq"
    00041 #include "api/ai_depotlist.hpp.sq"
    00042 #include "api/ai_engine.hpp.sq"
    00043 #include "api/ai_enginelist.hpp.sq"
    00044 #include "api/ai_error.hpp.sq"
    00045 #include "api/ai_event.hpp.sq"
    00046 #include "api/ai_event_types.hpp.sq"
    00047 #include "api/ai_execmode.hpp.sq"
    00048 #include "api/ai_gamesettings.hpp.sq"
    00049 #include "api/ai_group.hpp.sq"
    00050 #include "api/ai_grouplist.hpp.sq"
    00051 #include "api/ai_industry.hpp.sq"
    00052 #include "api/ai_industrylist.hpp.sq"
    00053 #include "api/ai_industrytype.hpp.sq"
    00054 #include "api/ai_industrytypelist.hpp.sq"
    00055 #include "api/ai_list.hpp.sq"
    00056 #include "api/ai_log.hpp.sq"
    00057 #include "api/ai_map.hpp.sq"
    00058 #include "api/ai_marine.hpp.sq"
    00059 #include "api/ai_order.hpp.sq"
    00060 #include "api/ai_rail.hpp.sq"
    00061 #include "api/ai_railtypelist.hpp.sq"
    00062 #include "api/ai_road.hpp.sq"
    00063 #include "api/ai_sign.hpp.sq"
    00064 #include "api/ai_signlist.hpp.sq"
    00065 #include "api/ai_station.hpp.sq"
    00066 #include "api/ai_stationlist.hpp.sq"
    00067 #include "api/ai_subsidy.hpp.sq"
    00068 #include "api/ai_subsidylist.hpp.sq"
    00069 #include "api/ai_testmode.hpp.sq"
    00070 #include "api/ai_tile.hpp.sq"
    00071 #include "api/ai_tilelist.hpp.sq"
    00072 #include "api/ai_town.hpp.sq"
    00073 #include "api/ai_townlist.hpp.sq"
    00074 #include "api/ai_tunnel.hpp.sq"
    00075 #include "api/ai_vehicle.hpp.sq"
    00076 #include "api/ai_vehiclelist.hpp.sq"
    00077 #include "api/ai_waypoint.hpp.sq"
    00078 #include "api/ai_waypointlist.hpp.sq"
    00079
    00080 #include "../company_base.h"
    00081 #include "../fileio_func.h"
    00082
    00083 AIStorage::~AIStorage()
    00084 {
    00085   /* Free our pointers */
    00086   if (event_data != NULL) AIEventController::FreeEventPointer();
    00087   if (log_data != NULL) AILog::FreeLogPointer();
    00088 }
    00089
    00090 static void PrintFunc(bool error_msg, const SQChar *message)
    00091 {
    00092   /* Convert to OpenTTD internal capable string */
    00093   AIController::Print(error_msg, SQ2OTTD(message));
    00094 }
    00095
    00096 AIInstance::AIInstance(AIInfo *info) :
    00097   controller(NULL),
    00098   storage(NULL),
    00099   engine(NULL),
    00100   instance(NULL),
    00101   is_started(false),
    00102   is_dead(false),
    00103   is_save_data_on_stack(false),
    00104   suspend(0),
    00105   callback(NULL)
    00106 {
    00107   /* Set the instance already, so we can use AIObject::Set commands */
    00108   Company::Get(_current_company)->ai_instance = this;
    00109
    00110   this->controller = new AIController();
    00111   this->storage    = new AIStorage();
    00112   this->engine     = new Squirrel();
    00113   this->engine->SetPrintFunction(&PrintFunc);
    00114
    00115   /* The import method is available at a very early stage */
    00116   this->engine->AddMethod("import", &AILibrary::Import, 4, ".ssi");
    00117
    00118   /* Register the AIController */
    00119   SQAIController_Register(this->engine);
    00120
    00121   /* Register the API functions and classes */
    00122   this->RegisterAPI();
    00123
    00124   if (!this->LoadCompatibilityScripts(info->GetAPIVersion())) {
    00125     this->Died();
    00126     return;
    00127   }
    00128
    00129   try {
    00130     AIObject::SetAllowDoCommand(false);
    00131     /* Load and execute the script for this AI */
    00132     const char *main_script = info->GetMainScript();
    00133     if (strcmp(main_script, "%_dummy") == 0) {
    00134       extern void AI_CreateAIDummy(HSQUIRRELVM vm);
    00135       AI_CreateAIDummy(this->engine->GetVM());
    00136     } else if (!this->engine->LoadScript(main_script) || this->engine->IsSuspended()) {
    00137       if (this->engine->IsSuspended()) AILog::Error("This AI took too long to load script. AI is not started.");
    00138       this->Died();
    00139       return;
    00140     }
    00141
    00142     /* Create the main-class */
    00143     this->instance = MallocT<SQObject>(1);
    00144     if (!this->engine->CreateClassInstance(info->GetInstanceName(), this->controller, this->instance)) {
    00145       this->Died();
    00146       return;
    00147     }
    00148     AIObject::SetAllowDoCommand(true);
    00149   } catch (AI_FatalError e) {
    00150     this->is_dead = true;
    00151     this->engine->ThrowError(e.GetErrorMessage());
    00152     this->engine->ResumeError();
    00153     this->Died();
    00154   }
    00155 }
    00156
    00157 AIInstance::~AIInstance()
    00158 {
    00159   if (instance != NULL) this->engine->ReleaseObject(this->instance);
    00160   if (engine != NULL) delete this->engine;
    00161   delete this->storage;
    00162   delete this->controller;
    00163   free(this->instance);
    00164 }
    00165
    00166 void AIInstance::RegisterAPI()
    00167 {
    00168 /* Register all classes */
    00169   squirrel_register_std(this->engine);
    00170   SQAIAbstractList_Register(this->engine);
    00171   SQAIAccounting_Register(this->engine);
    00172   SQAIAirport_Register(this->engine);
    00173   SQAIBase_Register(this->engine);
    00174   SQAIBaseStation_Register(this->engine);
    00175   SQAIBridge_Register(this->engine);
    00176   SQAIBridgeList_Register(this->engine);
    00177   SQAIBridgeList_Length_Register(this->engine);
    00178   SQAICargo_Register(this->engine);
    00179   SQAICargoList_Register(this->engine);
    00180   SQAICargoList_IndustryAccepting_Register(this->engine);
    00181   SQAICargoList_IndustryProducing_Register(this->engine);
    00182   SQAICompany_Register(this->engine);
    00183   SQAIDate_Register(this->engine);
    00184   SQAIDepotList_Register(this->engine);
    00185   SQAIEngine_Register(this->engine);
    00186   SQAIEngineList_Register(this->engine);
    00187   SQAIError_Register(this->engine);
    00188   SQAIEvent_Register(this->engine);
    00189   SQAIEventCompanyAskMerger_Register(this->engine);
    00190   SQAIEventCompanyBankrupt_Register(this->engine);
    00191   SQAIEventCompanyInTrouble_Register(this->engine);
    00192   SQAIEventCompanyMerger_Register(this->engine);
    00193   SQAIEventCompanyNew_Register(this->engine);
    00194   SQAIEventController_Register(this->engine);
    00195   SQAIEventDisasterZeppelinerCleared_Register(this->engine);
    00196   SQAIEventDisasterZeppelinerCrashed_Register(this->engine);
    00197   SQAIEventEngineAvailable_Register(this->engine);
    00198   SQAIEventEnginePreview_Register(this->engine);
    00199   SQAIEventIndustryClose_Register(this->engine);
    00200   SQAIEventIndustryOpen_Register(this->engine);
    00201   SQAIEventStationFirstVehicle_Register(this->engine);
    00202   SQAIEventSubsidyAwarded_Register(this->engine);
    00203   SQAIEventSubsidyExpired_Register(this->engine);
    00204   SQAIEventSubsidyOffer_Register(this->engine);
    00205   SQAIEventSubsidyOfferExpired_Register(this->engine);
    00206   SQAIEventVehicleCrashed_Register(this->engine);
    00207   SQAIEventVehicleLost_Register(this->engine);
    00208   SQAIEventVehicleUnprofitable_Register(this->engine);
    00209   SQAIEventVehicleWaitingInDepot_Register(this->engine);
    00210   SQAIExecMode_Register(this->engine);
    00211   SQAIGameSettings_Register(this->engine);
    00212   SQAIGroup_Register(this->engine);
    00213   SQAIGroupList_Register(this->engine);
    00214   SQAIIndustry_Register(this->engine);
    00215   SQAIIndustryList_Register(this->engine);
    00216   SQAIIndustryList_CargoAccepting_Register(this->engine);
    00217   SQAIIndustryList_CargoProducing_Register(this->engine);
    00218   SQAIIndustryType_Register(this->engine);
    00219   SQAIIndustryTypeList_Register(this->engine);
    00220   SQAIList_Register(this->engine);
    00221   SQAILog_Register(this->engine);
    00222   SQAIMap_Register(this->engine);
    00223   SQAIMarine_Register(this->engine);
    00224   SQAIOrder_Register(this->engine);
    00225   SQAIRail_Register(this->engine);
    00226   SQAIRailTypeList_Register(this->engine);
    00227   SQAIRoad_Register(this->engine);
    00228   SQAISign_Register(this->engine);
    00229   SQAISignList_Register(this->engine);
    00230   SQAIStation_Register(this->engine);
    00231   SQAIStationList_Register(this->engine);
    00232   SQAIStationList_Vehicle_Register(this->engine);
    00233   SQAISubsidy_Register(this->engine);
    00234   SQAISubsidyList_Register(this->engine);
    00235   SQAITestMode_Register(this->engine);
    00236   SQAITile_Register(this->engine);
    00237   SQAITileList_Register(this->engine);
    00238   SQAITileList_IndustryAccepting_Register(this->engine);
    00239   SQAITileList_IndustryProducing_Register(this->engine);
    00240   SQAITileList_StationType_Register(this->engine);
    00241   SQAITown_Register(this->engine);
    00242   SQAITownList_Register(this->engine);
    00243   SQAITunnel_Register(this->engine);
    00244   SQAIVehicle_Register(this->engine);
    00245   SQAIVehicleList_Register(this->engine);
    00246   SQAIVehicleList_DefaultGroup_Register(this->engine);
    00247   SQAIVehicleList_Depot_Register(this->engine);
    00248   SQAIVehicleList_Group_Register(this->engine);
    00249   SQAIVehicleList_SharedOrders_Register(this->engine);
    00250   SQAIVehicleList_Station_Register(this->engine);
    00251   SQAIWaypoint_Register(this->engine);
    00252   SQAIWaypointList_Register(this->engine);
    00253   SQAIWaypointList_Vehicle_Register(this->engine);
    00254
    00255   this->engine->SetGlobalPointer(this->engine);
    00256 }
    00257
    00258 bool AIInstance::LoadCompatibilityScripts(const char *api_version)
    00259 {
    00260   char script_name[32];
    00261   seprintf(script_name, lastof(script_name), "compat_%s.nut", api_version);
    00262   char buf[MAX_PATH];
    00263   Searchpath sp;
    00264   FOR_ALL_SEARCHPATHS(sp) {
    00265     FioAppendDirectory(buf, MAX_PATH, sp, AI_DIR);
    00266     ttd_strlcat(buf, script_name, MAX_PATH);
    00267     if (!FileExists(buf)) continue;
    00268
    00269     if (this->engine->LoadScript(buf)) return true;
    00270
    00271     AILog::Error("Failed to load API compatibility script");
    00272     DEBUG(ai, 0, "Error compiling / running API compatibility script: %s", buf);
    00273     return false;
    00274   }
    00275
    00276   AILog::Warning("API compatibility script not found");
    00277   return true;
    00278 }
    00279
    00280 void AIInstance::Continue()
    00281 {
    00282   assert(this->suspend < 0);
    00283   this->suspend = -this->suspend - 1;
    00284 }
    00285
    00286 void AIInstance::Died()
    00287 {
    00288   DEBUG(ai, 0, "The AI died unexpectedly.");
    00289   this->is_dead = true;
    00290
    00291   if (this->instance != NULL) this->engine->ReleaseObject(this->instance);
    00292   delete this->engine;
    00293   this->instance = NULL;
    00294   this->engine = NULL;
    00295
    00296   ShowAIDebugWindow(_current_company);
    00297
    00298   const AIInfo *info = AIConfig::GetConfig(_current_company)->GetInfo();
    00299   if (info != NULL) {
    00300     ShowErrorMessage(STR_ERROR_AI_PLEASE_REPORT_CRASH, INVALID_STRING_ID, 0, 0);
    00301
    00302     if (info->GetURL() != NULL) {
    00303       AILog::Info("Please report the error to the following URL:");
    00304       AILog::Info(info->GetURL());
    00305     }
    00306   }
    00307 }
    00308
    00309 void AIInstance::GameLoop()
    00310 {
    00311   if (this->IsDead()) return;
    00312   if (this->engine->HasScriptCrashed()) {
    00313     /* The script crashed during saving, kill it here. */
    00314     this->Died();
    00315     return;
    00316   }
    00317   this->controller->ticks++;
    00318
    00319   if (this->suspend   < -1) this->suspend++; // Multiplayer suspend, increase up to -1.
    00320   if (this->suspend   < 0)  return;          // Multiplayer suspend, wait for Continue().
    00321   if (--this->suspend > 0)  return;          // Singleplayer suspend, decrease to 0.
    00322
    00323   /* If there is a callback to call, call that first */
    00324   if (this->callback != NULL) {
    00325     if (this->is_save_data_on_stack) {
    00326       sq_poptop(this->engine->GetVM());
    00327       this->is_save_data_on_stack = false;
    00328     }
    00329     try {
    00330       this->callback(this);
    00331     } catch (AI_VMSuspend e) {
    00332       this->suspend  = e.GetSuspendTime();
    00333       this->callback = e.GetSuspendCallback();
    00334
    00335       return;
    00336     }
    00337   }
    00338
    00339   this->suspend  = 0;
    00340   this->callback = NULL;
    00341
    00342   if (!this->is_started) {
    00343     try {
    00344       AIObject::SetAllowDoCommand(false);
    00345       /* Run the constructor if it exists. Don't allow any DoCommands in it. */
    00346       if (this->engine->MethodExists(*this->instance, "constructor")) {
    00347         if (!this->engine->CallMethod(*this->instance, "constructor", 100000) || this->engine->IsSuspended()) {
    00348           if (this->engine->IsSuspended()) AILog::Error("This AI took too long to initialize. AI is not started.");
    00349           this->Died();
    00350           return;
    00351         }
    00352       }
    00353       if (!this->CallLoad() || this->engine->IsSuspended()) {
    00354         if (this->engine->IsSuspended()) AILog::Error("This AI took too long in the Load function. AI is not started.");
    00355         this->Died();
    00356         return;
    00357       }
    00358       AIObject::SetAllowDoCommand(true);
    00359       /* Start the AI by calling Start() */
    00360       if (!this->engine->CallMethod(*this->instance, "Start",  _settings_game.ai.ai_max_opcode_till_suspend) || !this->engine->IsSuspended()) this->Died();
    00361     } catch (AI_VMSuspend e) {
    00362       this->suspend  = e.GetSuspendTime();
    00363       this->callback = e.GetSuspendCallback();
    00364     } catch (AI_FatalError e) {
    00365       this->is_dead = true;
    00366       this->engine->ThrowError(e.GetErrorMessage());
    00367       this->engine->ResumeError();
    00368       this->Died();
    00369     }
    00370
    00371     this->is_started = true;
    00372     return;
    00373   }
    00374   if (this->is_save_data_on_stack) {
    00375     sq_poptop(this->engine->GetVM());
    00376     this->is_save_data_on_stack = false;
    00377   }
    00378
    00379   /* Continue the VM */
    00380   try {
    00381     if (!this->engine->Resume(_settings_game.ai.ai_max_opcode_till_suspend)) this->Died();
    00382   } catch (AI_VMSuspend e) {
    00383     this->suspend  = e.GetSuspendTime();
    00384     this->callback = e.GetSuspendCallback();
    00385   } catch (AI_FatalError e) {
    00386     this->is_dead = true;
    00387     this->engine->ThrowError(e.GetErrorMessage());
    00388     this->engine->ResumeError();
    00389     this->Died();
    00390   }
    00391 }
    00392
    00393 void AIInstance::CollectGarbage() const
    00394 {
    00395   if (this->is_started && !this->IsDead()) this->engine->CollectGarbage();
    00396 }
    00397
    00398 /* static */ void AIInstance::DoCommandReturn(AIInstance *instance)
    00399 {
    00400   instance->engine->InsertResult(AIObject::GetLastCommandRes());
    00401 }
    00402
    00403 /* static */ void AIInstance::DoCommandReturnVehicleID(AIInstance *instance)
    00404 {
    00405   instance->engine->InsertResult(AIObject::GetNewVehicleID());
    00406 }
    00407
    00408 /* static */ void AIInstance::DoCommandReturnSignID(AIInstance *instance)
    00409 {
    00410   instance->engine->InsertResult(AIObject::GetNewSignID());
    00411 }
    00412
    00413 /* static */ void AIInstance::DoCommandReturnGroupID(AIInstance *instance)
    00414 {
    00415   instance->engine->InsertResult(AIObject::GetNewGroupID());
    00416 }
    00417
    00418 /* static */ AIStorage *AIInstance::GetStorage()
    00419 {
    00420   assert(Company::IsValidAiID(_current_company));
    00421   return Company::Get(_current_company)->ai_instance->storage;
    00422 }
    00423
    00424 /*
    00425  * All data is stored in the following format:
    00426  * First 1 byte indicating if there is a data blob at all.
    00427  * 1 byte indicating the type of data.
    00428  * The data itself, this differs per type:
    00429  *  - integer: a binary representation of the integer (int32).
    00430  *  - string:  First one byte with the string length, then a 0-terminated char
    00431  *             array. The string can't be longer then 255 bytes (including
    00432  *             terminating '\0').
    00433  *  - array:   All data-elements of the array are saved recursive in this
    00434  *             format, and ended with an element of the type
    00435  *             SQSL_ARRAY_TABLE_END.
    00436  *  - table:   All key/value pairs are saved in this format (first key 1, then
    00437  *             value 1, then key 2, etc.). All keys and values can have an
    00438  *             arbitrary type (as long as it is supported by the save function
    00439  *             of course). The table is ended with an element of the type
    00440  *             SQSL_ARRAY_TABLE_END.
    00441  *  - bool:    A single byte with value 1 representing true and 0 false.
    00442  *  - null:    No data.
    00443  */
    00444
    00446 enum SQSaveLoadType {
    00447   SQSL_INT             = 0x00,
    00448   SQSL_STRING          = 0x01,
    00449   SQSL_ARRAY           = 0x02,
    00450   SQSL_TABLE           = 0x03,
    00451   SQSL_BOOL            = 0x04,
    00452   SQSL_NULL            = 0x05,
    00453   SQSL_ARRAY_TABLE_END = 0xFF,
    00454 };
    00455
    00456 static byte _ai_sl_byte;
    00457
    00458 static const SaveLoad _ai_byte[] = {
    00459   SLEG_VAR(_ai_sl_byte, SLE_UINT8),
    00460   SLE_END()
    00461 };
    00462
    00463 enum {
    00464   AISAVE_MAX_DEPTH = 25,
    00465 };
    00466
    00467 /* static */ bool AIInstance::SaveObject(HSQUIRRELVM vm, SQInteger index, int max_depth, bool test)
    00468 {
    00469   if (max_depth == 0) {
    00470     AILog::Error("Savedata can only be nested to 25 deep. No data saved.");
    00471     return false;
    00472   }
    00473
    00474   switch (sq_gettype(vm, index)) {
    00475     case OT_INTEGER: {
    00476       if (!test) {
    00477         _ai_sl_byte = SQSL_INT;
    00478         SlObject(NULL, _ai_byte);
    00479       }
    00480       SQInteger res;
    00481       sq_getinteger(vm, index, &res);
    00482       if (!test) {
    00483         int value = (int)res;
    00484         SlArray(&value, 1, SLE_INT32);
    00485       }
    00486       return true;
    00487     }
    00488
    00489     case OT_STRING: {
    00490       if (!test) {
    00491         _ai_sl_byte = SQSL_STRING;
    00492         SlObject(NULL, _ai_byte);
    00493       }
    00494       const SQChar *res;
    00495       sq_getstring(vm, index, &res);
    00496       /* @bug if a string longer than 512 characters is given to SQ2OTTD, the
    00497        *  internal buffer overflows. */
    00498       const char *buf = SQ2OTTD(res);
    00499       size_t len = strlen(buf) + 1;
    00500       if (len >= 255) {
    00501         AILog::Error("Maximum string length is 254 chars. No data saved.");
    00502         return false;
    00503       }
    00504       if (!test) {
    00505         _ai_sl_byte = (byte)len;
    00506         SlObject(NULL, _ai_byte);
    00507         SlArray((void*)buf, len, SLE_CHAR);
    00508       }
    00509       return true;
    00510     }
    00511
    00512     case OT_ARRAY: {
    00513       if (!test) {
    00514         _ai_sl_byte = SQSL_ARRAY;
    00515         SlObject(NULL, _ai_byte);
    00516       }
    00517       sq_pushnull(vm);
    00518       while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
    00519         /* Store the value */
    00520         bool res = SaveObject(vm, -1, max_depth - 1, test);
    00521         sq_pop(vm, 2);
    00522         if (!res) {
    00523           sq_pop(vm, 1);
    00524           return false;
    00525         }
    00526       }
    00527       sq_pop(vm, 1);
    00528       if (!test) {
    00529         _ai_sl_byte = SQSL_ARRAY_TABLE_END;
    00530         SlObject(NULL, _ai_byte);
    00531       }
    00532       return true;
    00533     }
    00534
    00535     case OT_TABLE: {
    00536       if (!test) {
    00537         _ai_sl_byte = SQSL_TABLE;
    00538         SlObject(NULL, _ai_byte);
    00539       }
    00540       sq_pushnull(vm);
    00541       while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
    00542         /* Store the key + value */
    00543         bool res = SaveObject(vm, -2, max_depth - 1, test) && SaveObject(vm, -1, max_depth - 1, test);
    00544         sq_pop(vm, 2);
    00545         if (!res) {
    00546           sq_pop(vm, 1);
    00547           return false;
    00548         }
    00549       }
    00550       sq_pop(vm, 1);
    00551       if (!test) {
    00552         _ai_sl_byte = SQSL_ARRAY_TABLE_END;
    00553         SlObject(NULL, _ai_byte);
    00554       }
    00555       return true;
    00556     }
    00557
    00558     case OT_BOOL: {
    00559       if (!test) {
    00560         _ai_sl_byte = SQSL_BOOL;
    00561         SlObject(NULL, _ai_byte);
    00562       }
    00563       SQBool res;
    00564       sq_getbool(vm, index, &res);
    00565       if (!test) {
    00566         _ai_sl_byte = res ? 1 : 0;
    00567         SlObject(NULL, _ai_byte);
    00568       }
    00569       return true;
    00570     }
    00571
    00572     case OT_NULL: {
    00573       if (!test) {
    00574         _ai_sl_byte = SQSL_NULL;
    00575         SlObject(NULL, _ai_byte);
    00576       }
    00577       return true;
    00578     }
    00579
    00580     default:
    00581       AILog::Error("You tried to save an unsupported type. No data saved.");
    00582       return false;
    00583   }
    00584 }
    00585
    00586 /* static */ void AIInstance::SaveEmpty()
    00587 {
    00588   _ai_sl_byte = 0;
    00589   SlObject(NULL, _ai_byte);
    00590 }
    00591
    00592 void AIInstance::Save()
    00593 {
    00594   /* Don't save data if the AI didn't start yet or if it crashed. */
    00595   if (this->engine == NULL || this->engine->HasScriptCrashed()) {
    00596     SaveEmpty();
    00597     return;
    00598   }
    00599
    00600   HSQUIRRELVM vm = this->engine->GetVM();
    00601   if (this->is_save_data_on_stack) {
    00602     _ai_sl_byte = 1;
    00603     SlObject(NULL, _ai_byte);
    00604     /* Save the data that was just loaded. */
    00605     SaveObject(vm, -1, AISAVE_MAX_DEPTH, false);
    00606   } else if (!this->is_started) {
    00607     SaveEmpty();
    00608     return;
    00609   } else if (this->engine->MethodExists(*this->instance, "Save")) {
    00610     HSQOBJECT savedata;
    00611     /* We don't want to be interrupted during the save function. */
    00612     bool backup_allow = AIObject::GetAllowDoCommand();
    00613     AIObject::SetAllowDoCommand(false);
    00614     try {
    00615       if (!this->engine->CallMethod(*this->instance, "Save", &savedata)) {
    00616         /* The script crashed in the Save function. We can't kill
    00617          * it here, but do so in the next AI tick. */
    00618         SaveEmpty();
    00619         this->engine->CrashOccurred();
    00620         return;
    00621       }
    00622     } catch (AI_FatalError e) {
    00623       /* If we don't mark the AI as dead here cleaning up the squirrel
    00624        * stack could throw AI_FatalError again. */
    00625       this->is_dead = true;
    00626       this->engine->ThrowError(e.GetErrorMessage());
    00627       this->engine->ResumeError();
    00628       SaveEmpty();
    00629       /* We can't kill the AI here, so mark it as crashed (not dead) and
    00630        * kill it in the next AI tick. */
    00631       this->is_dead = false;
    00632       this->engine->CrashOccurred();
    00633       return;
    00634     }
    00635     AIObject::SetAllowDoCommand(backup_allow);
    00636
    00637     if (!sq_istable(savedata)) {
    00638       AILog::Error("Save function should return a table.");
    00639       SaveEmpty();
    00640       this->engine->CrashOccurred();
    00641       return;
    00642     }
    00643     sq_pushobject(vm, savedata);
    00644     if (SaveObject(vm, -1, AISAVE_MAX_DEPTH, true)) {
    00645       _ai_sl_byte = 1;
    00646       SlObject(NULL, _ai_byte);
    00647       SaveObject(vm, -1, AISAVE_MAX_DEPTH, false);
    00648       this->is_save_data_on_stack = true;
    00649     } else {
    00650       SaveEmpty();
    00651       this->engine->CrashOccurred();
    00652     }
    00653   } else {
    00654     AILog::Warning("Save function is not implemented");
    00655     _ai_sl_byte = 0;
    00656     SlObject(NULL, _ai_byte);
    00657   }
    00658
    00659 }
    00660
    00661 /* static */ bool AIInstance::LoadObjects(HSQUIRRELVM vm)
    00662 {
    00663   SlObject(NULL, _ai_byte);
    00664   switch (_ai_sl_byte) {
    00665     case SQSL_INT: {
    00666       int value;
    00667       SlArray(&value, 1, SLE_INT32);
    00668       if (vm != NULL) sq_pushinteger(vm, (SQInteger)value);
    00669       return true;
    00670     }
    00671
    00672     case SQSL_STRING: {
    00673       SlObject(NULL, _ai_byte);
    00674       static char buf[256];
    00675       SlArray(buf, _ai_sl_byte, SLE_CHAR);
    00676       if (vm != NULL) sq_pushstring(vm, OTTD2SQ(buf), -1);
    00677       return true;
    00678     }
    00679
    00680     case SQSL_ARRAY: {
    00681       if (vm != NULL) sq_newarray(vm, 0);
    00682       while (LoadObjects(vm)) {
    00683         if (vm != NULL) sq_arrayappend(vm, -2);
    00684         /* The value is popped from the stack by squirrel. */
    00685       }
    00686       return true;
    00687     }
    00688
    00689     case SQSL_TABLE: {
    00690       if (vm != NULL) sq_newtable(vm);
    00691       while (LoadObjects(vm)) {
    00692         LoadObjects(vm);
    00693         if (vm != NULL) sq_rawset(vm, -3);
    00694         /* The key (-2) and value (-1) are popped from the stack by squirrel. */
    00695       }
    00696       return true;
    00697     }
    00698
    00699     case SQSL_BOOL: {
    00700       SlObject(NULL, _ai_byte);
    00701       if (vm != NULL) sq_pushinteger(vm, (SQBool)(_ai_sl_byte != 0));
    00702       return true;
    00703     }
    00704
    00705     case SQSL_NULL: {
    00706       if (vm != NULL) sq_pushnull(vm);
    00707       return true;
    00708     }
    00709
    00710     case SQSL_ARRAY_TABLE_END: {
    00711       return false;
    00712     }
    00713
    00714     default: NOT_REACHED();
    00715   }
    00716 }
    00717
    00718 /* static */ void AIInstance::LoadEmpty()
    00719 {
    00720   SlObject(NULL, _ai_byte);
    00721   /* Check if there was anything saved at all. */
    00722   if (_ai_sl_byte == 0) return;
    00723
    00724   LoadObjects(NULL);
    00725 }
    00726
    00727 void AIInstance::Load(int version)
    00728 {
    00729   if (this->engine == NULL || version == -1) {
    00730     LoadEmpty();
    00731     return;
    00732   }
    00733   HSQUIRRELVM vm = this->engine->GetVM();
    00734
    00735   SlObject(NULL, _ai_byte);
    00736   /* Check if there was anything saved at all. */
    00737   if (_ai_sl_byte == 0) return;
    00738
    00739   sq_pushinteger(vm, version);
    00740   LoadObjects(vm);
    00741   this->is_save_data_on_stack = true;
    00742 }
    00743
    00744 bool AIInstance::CallLoad()
    00745 {
    00746   HSQUIRRELVM vm = this->engine->GetVM();
    00747   /* Is there save data that we should load? */
    00748   if (!this->is_save_data_on_stack) return true;
    00749   /* Whatever happens, after CallLoad the savegame data is removed from the stack. */
    00750   this->is_save_data_on_stack = false;
    00751
    00752   if (!this->engine->MethodExists(*this->instance, "Load")) {
    00753     AILog::Warning("Loading failed: there was data for the AI to load, but the AI does not have a Load() function.");
    00754
    00755     /* Pop the savegame data and version. */
    00756     sq_pop(vm, 2);
    00757     return true;
    00758   }
    00759
    00760   /* Go to the instance-root */
    00761   sq_pushobject(vm, *this->instance);
    00762   /* Find the function-name inside the script */
    00763   sq_pushstring(vm, OTTD2SQ("Load"), -1);
    00764   /* Change the "Load" string in a function pointer */
    00765   sq_get(vm, -2);
    00766   /* Push the main instance as "this" object */
    00767   sq_pushobject(vm, *this->instance);
    00768   /* Push the version data and savegame data as arguments */
    00769   sq_push(vm, -5);
    00770   sq_push(vm, -5);
    00771
    00772   /* Call the AI load function. sq_call removes the arguments (but not the
    00773    * function pointer) from the stack. */
    00774   if (SQ_FAILED(sq_call(vm, 3, SQFalse, SQFalse, 100000))) return false;
    00775
    00776   /* Pop 1) The version, 2) the savegame data, 3) the object instance, 4) the function pointer. */
    00777   sq_pop(vm, 4);
    00778   return true;
    00779 }