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