# ai_instance.cpp

Go to the documentation of this file.

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