# ai_instance.cpp

Go to the documentation of this file.

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