ai_instance.cpp

Go to the documentation of this file.
00001 /* $Id: ai_instance.cpp 16835 2009-07-15 20:29:45Z 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_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_bridge.hpp.sq"
00034 #include "api/ai_bridgelist.hpp.sq"
00035 #include "api/ai_cargo.hpp.sq"
00036 #include "api/ai_cargolist.hpp.sq"
00037 #include "api/ai_company.hpp.sq"
00038 #include "api/ai_controller.hpp.sq"
00039 #include "api/ai_date.hpp.sq"
00040 #include "api/ai_depotlist.hpp.sq"
00041 #include "api/ai_engine.hpp.sq"
00042 #include "api/ai_enginelist.hpp.sq"
00043 #include "api/ai_error.hpp.sq"
00044 #include "api/ai_event.hpp.sq"
00045 #include "api/ai_event_types.hpp.sq"
00046 #include "api/ai_execmode.hpp.sq"
00047 #include "api/ai_gamesettings.hpp.sq"
00048 #include "api/ai_group.hpp.sq"
00049 #include "api/ai_grouplist.hpp.sq"
00050 #include "api/ai_industry.hpp.sq"
00051 #include "api/ai_industrylist.hpp.sq"
00052 #include "api/ai_industrytype.hpp.sq"
00053 #include "api/ai_industrytypelist.hpp.sq"
00054 #include "api/ai_list.hpp.sq"
00055 #include "api/ai_log.hpp.sq"
00056 #include "api/ai_map.hpp.sq"
00057 #include "api/ai_marine.hpp.sq"
00058 #include "api/ai_order.hpp.sq"
00059 #include "api/ai_rail.hpp.sq"
00060 #include "api/ai_railtypelist.hpp.sq"
00061 #include "api/ai_road.hpp.sq"
00062 #include "api/ai_sign.hpp.sq"
00063 #include "api/ai_signlist.hpp.sq"
00064 #include "api/ai_station.hpp.sq"
00065 #include "api/ai_stationlist.hpp.sq"
00066 #include "api/ai_subsidy.hpp.sq"
00067 #include "api/ai_subsidylist.hpp.sq"
00068 #include "api/ai_testmode.hpp.sq"
00069 #include "api/ai_tile.hpp.sq"
00070 #include "api/ai_tilelist.hpp.sq"
00071 #include "api/ai_town.hpp.sq"
00072 #include "api/ai_townlist.hpp.sq"
00073 #include "api/ai_tunnel.hpp.sq"
00074 #include "api/ai_vehicle.hpp.sq"
00075 #include "api/ai_vehiclelist.hpp.sq"
00076 #include "api/ai_waypoint.hpp.sq"
00077 #include "api/ai_waypointlist.hpp.sq"
00078 
00079 #undef DEFINE_SCRIPT_FILES
00080 
00081 /* static */ AIInstance *AIInstance::current_instance = NULL;
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, FS2OTTD(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   GetCompany(_current_company)->ai_instance = this;
00109   AIInstance::current_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   /* Load and execute the script for this AI */
00123   const char *main_script = info->GetMainScript();
00124   if (strcmp(main_script, "%_dummy") == 0) {
00125     extern void AI_CreateAIDummy(HSQUIRRELVM vm);
00126     AI_CreateAIDummy(this->engine->GetVM());
00127   } else if (!this->engine->LoadScript(main_script)) {
00128     this->Died();
00129     return;
00130   }
00131 
00132   /* Create the main-class */
00133   this->instance = MallocT<SQObject>(1);
00134   if (!this->engine->CreateClassInstance(info->GetInstanceName(), this->controller, this->instance)) {
00135     this->Died();
00136     return;
00137   }
00138 
00139   /* Register the API functions and classes */
00140   this->RegisterAPI();
00141 }
00142 
00143 AIInstance::~AIInstance()
00144 {
00145   if (instance != NULL) this->engine->ReleaseObject(this->instance);
00146   if (engine != NULL) delete this->engine;
00147   delete this->storage;
00148   delete this->controller;
00149   free(this->instance);
00150 }
00151 
00152 void AIInstance::RegisterAPI()
00153 {
00154 /* Register all classes */
00155   squirrel_register_std(this->engine);
00156   SQAIAbstractList_Register(this->engine);
00157   SQAIAccounting_Register(this->engine);
00158   SQAIAirport_Register(this->engine);
00159   SQAIBase_Register(this->engine);
00160   SQAIBridge_Register(this->engine);
00161   SQAIBridgeList_Register(this->engine);
00162   SQAIBridgeList_Length_Register(this->engine);
00163   SQAICargo_Register(this->engine);
00164   SQAICargoList_Register(this->engine);
00165   SQAICargoList_IndustryAccepting_Register(this->engine);
00166   SQAICargoList_IndustryProducing_Register(this->engine);
00167   SQAICompany_Register(this->engine);
00168   SQAIDate_Register(this->engine);
00169   SQAIDepotList_Register(this->engine);
00170   SQAIEngine_Register(this->engine);
00171   SQAIEngineList_Register(this->engine);
00172   SQAIError_Register(this->engine);
00173   SQAIEvent_Register(this->engine);
00174   SQAIEventCompanyBankrupt_Register(this->engine);
00175   SQAIEventCompanyInTrouble_Register(this->engine);
00176   SQAIEventCompanyMerger_Register(this->engine);
00177   SQAIEventCompanyNew_Register(this->engine);
00178   SQAIEventController_Register(this->engine);
00179   SQAIEventDisasterZeppelinerCleared_Register(this->engine);
00180   SQAIEventDisasterZeppelinerCrashed_Register(this->engine);
00181   SQAIEventEngineAvailable_Register(this->engine);
00182   SQAIEventEnginePreview_Register(this->engine);
00183   SQAIEventIndustryClose_Register(this->engine);
00184   SQAIEventIndustryOpen_Register(this->engine);
00185   SQAIEventStationFirstVehicle_Register(this->engine);
00186   SQAIEventSubsidyAwarded_Register(this->engine);
00187   SQAIEventSubsidyExpired_Register(this->engine);
00188   SQAIEventSubsidyOffer_Register(this->engine);
00189   SQAIEventSubsidyOfferExpired_Register(this->engine);
00190   SQAIEventVehicleCrashed_Register(this->engine);
00191   SQAIEventVehicleLost_Register(this->engine);
00192   SQAIEventVehicleUnprofitable_Register(this->engine);
00193   SQAIEventVehicleWaitingInDepot_Register(this->engine);
00194   SQAIExecMode_Register(this->engine);
00195   SQAIGameSettings_Register(this->engine);
00196   SQAIGroup_Register(this->engine);
00197   SQAIGroupList_Register(this->engine);
00198   SQAIIndustry_Register(this->engine);
00199   SQAIIndustryList_Register(this->engine);
00200   SQAIIndustryList_CargoAccepting_Register(this->engine);
00201   SQAIIndustryList_CargoProducing_Register(this->engine);
00202   SQAIIndustryType_Register(this->engine);
00203   SQAIIndustryTypeList_Register(this->engine);
00204   SQAIList_Register(this->engine);
00205   SQAILog_Register(this->engine);
00206   SQAIMap_Register(this->engine);
00207   SQAIMarine_Register(this->engine);
00208   SQAIOrder_Register(this->engine);
00209   SQAIRail_Register(this->engine);
00210   SQAIRailTypeList_Register(this->engine);
00211   SQAIRoad_Register(this->engine);
00212   SQAISign_Register(this->engine);
00213   SQAISignList_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 
00259   const AIInfo *info = AIConfig::GetConfig(_current_company)->GetInfo();
00260   if (info != NULL) {
00261     ShowErrorMessage(INVALID_STRING_ID, STR_AI_PLEASE_REPORT_CRASH, 0, 0);
00262 
00263     if (info->GetURL() != NULL) {
00264       AILog::Info("Please report the error to the following URL:");
00265       AILog::Info(info->GetURL());
00266     }
00267   }
00268 }
00269 
00270 void AIInstance::GameLoop()
00271 {
00272   if (this->is_dead) return;
00273   if (this->engine->HasScriptCrashed()) {
00274     /* The script crashed during saving, kill it here. */
00275     this->Died();
00276     return;
00277   }
00278   this->controller->ticks++;
00279 
00280   if (this->suspend   < -1) this->suspend++; // Multiplayer suspend, increase up to -1.
00281   if (this->suspend   < 0)  return;          // Multiplayer suspend, wait for Continue().
00282   if (--this->suspend > 0)  return;          // Singleplayer suspend, decrease to 0.
00283 
00284   /* If there is a callback to call, call that first */
00285   if (this->callback != NULL) {
00286     if (this->is_save_data_on_stack) {
00287       sq_poptop(this->engine->GetVM());
00288       this->is_save_data_on_stack = false;
00289     }
00290     try {
00291       this->callback(this);
00292     } catch (AI_VMSuspend e) {
00293       this->suspend  = e.GetSuspendTime();
00294       this->callback = e.GetSuspendCallback();
00295 
00296       return;
00297     }
00298   }
00299 
00300   this->suspend  = 0;
00301   this->callback = NULL;
00302 
00303   if (!this->is_started) {
00304     try {
00305       AIObject::SetAllowDoCommand(false);
00306       /* Run the constructor if it exists. Don't allow any DoCommands in it. */
00307       if (this->engine->MethodExists(*this->instance, "constructor")) {
00308         if (!this->engine->CallMethod(*this->instance, "constructor", 100000) || this->engine->IsSuspended()) {
00309           if (this->engine->IsSuspended()) AILog::Error("This AI took too long to initialize. AI is not started.");
00310           this->Died();
00311           return;
00312         }
00313       }
00314       if (!this->CallLoad() || this->engine->IsSuspended()) {
00315         if (this->engine->IsSuspended()) AILog::Error("This AI took too long in the Load function. AI is not started.");
00316         this->Died();
00317         return;
00318       }
00319       AIObject::SetAllowDoCommand(true);
00320       /* Start the AI by calling Start() */
00321       if (!this->engine->CallMethod(*this->instance, "Start",  _settings_game.ai.ai_max_opcode_till_suspend) || !this->engine->IsSuspended()) this->Died();
00322     } catch (AI_VMSuspend e) {
00323       this->suspend  = e.GetSuspendTime();
00324       this->callback = e.GetSuspendCallback();
00325     }
00326 
00327     this->is_started = true;
00328     return;
00329   }
00330   if (this->is_save_data_on_stack) {
00331     sq_poptop(this->engine->GetVM());
00332     this->is_save_data_on_stack = false;
00333   }
00334 
00335   /* Continue the VM */
00336   try {
00337     if (!this->engine->Resume(_settings_game.ai.ai_max_opcode_till_suspend)) this->Died();
00338   } catch (AI_VMSuspend e) {
00339     this->suspend  = e.GetSuspendTime();
00340     this->callback = e.GetSuspendCallback();
00341   }
00342 }
00343 
00344 void AIInstance::CollectGarbage()
00345 {
00346   if (this->is_started && !this->is_dead) this->engine->CollectGarbage();
00347 }
00348 
00349 /* static */ void AIInstance::DoCommandReturn(AIInstance *instance)
00350 {
00351   instance->engine->InsertResult(AIObject::GetLastCommandRes());
00352 }
00353 
00354 /* static */ void AIInstance::DoCommandReturnVehicleID(AIInstance *instance)
00355 {
00356   instance->engine->InsertResult(AIObject::GetNewVehicleID());
00357 }
00358 
00359 /* static */ void AIInstance::DoCommandReturnSignID(AIInstance *instance)
00360 {
00361   instance->engine->InsertResult(AIObject::GetNewSignID());
00362 }
00363 
00364 /* static */ void AIInstance::DoCommandReturnGroupID(AIInstance *instance)
00365 {
00366   instance->engine->InsertResult(AIObject::GetNewGroupID());
00367 }
00368 
00369 /* static */ AIStorage *AIInstance::GetStorage()
00370 {
00371   assert(IsValidCompanyID(_current_company) && !IsHumanCompany(_current_company));
00372   return GetCompany(_current_company)->ai_instance->storage;
00373 }
00374 
00375 /*
00376  * All data is stored in the following format:
00377  * First 1 byte indicating if there is a data blob at all.
00378  * 1 byte indicating the type of data.
00379  * The data itself, this differs per type:
00380  *  - integer: a binary representation of the integer (int32).
00381  *  - string:  First one byte with the string length, then a 0-terminated char
00382  *             array. The string can't be longer then 255 bytes (including
00383  *             terminating '\0').
00384  *  - array:   All data-elements of the array are saved recursive in this
00385  *             format, and ended with an element of the type
00386  *             SQSL_ARRAY_TABLE_END.
00387  *  - table:   All key/value pairs are saved in this format (first key 1, then
00388  *             value 1, then key 2, etc.). All keys and values can have an
00389  *             arbitrary type (as long as it is supported by the save function
00390  *             of course). The table is ended with an element of the type
00391  *             SQSL_ARRAY_TABLE_END.
00392  *  - bool:    A single byte with value 1 representing true and 0 false.
00393  *  - null:    No data.
00394  */
00395 
00397 enum SQSaveLoadType {
00398   SQSL_INT             = 0x00, 
00399   SQSL_STRING          = 0x01, 
00400   SQSL_ARRAY           = 0x02, 
00401   SQSL_TABLE           = 0x03, 
00402   SQSL_BOOL            = 0x04, 
00403   SQSL_NULL            = 0x05, 
00404   SQSL_ARRAY_TABLE_END = 0xFF, 
00405 };
00406 
00407 static byte _ai_sl_byte;
00408 
00409 static const SaveLoad _ai_byte[] = {
00410   SLEG_VAR(_ai_sl_byte, SLE_UINT8),
00411   SLE_END()
00412 };
00413 
00414 enum {
00415   AISAVE_MAX_DEPTH = 25, 
00416 };
00417 
00418 /* static */ bool AIInstance::SaveObject(HSQUIRRELVM vm, SQInteger index, int max_depth, bool test)
00419 {
00420   if (max_depth == 0) {
00421     AILog::Error("Savedata can only be nested to 25 deep. No data saved.");
00422     return false;
00423   }
00424 
00425   switch (sq_gettype(vm, index)) {
00426     case OT_INTEGER: {
00427       if (!test) {
00428         _ai_sl_byte = SQSL_INT;
00429         SlObject(NULL, _ai_byte);
00430       }
00431       SQInteger res;
00432       sq_getinteger(vm, index, &res);
00433       if (!test) {
00434         int value = (int)res;
00435         SlArray(&value, 1, SLE_INT32);
00436       }
00437       return true;
00438     }
00439 
00440     case OT_STRING: {
00441       if (!test) {
00442         _ai_sl_byte = SQSL_STRING;
00443         SlObject(NULL, _ai_byte);
00444       }
00445       const SQChar *res;
00446       sq_getstring(vm, index, &res);
00447       /* @bug if a string longer than 512 characters is given to FS2OTTD, the
00448        *  internal buffer overflows. */
00449       const char *buf = FS2OTTD(res);
00450       size_t len = strlen(buf) + 1;
00451       if (len >= 255) {
00452         AILog::Error("Maximum string length is 254 chars. No data saved.");
00453         return false;
00454       }
00455       if (!test) {
00456         _ai_sl_byte = (byte)len;
00457         SlObject(NULL, _ai_byte);
00458         SlArray((void*)buf, len, SLE_CHAR);
00459       }
00460       return true;
00461     }
00462 
00463     case OT_ARRAY: {
00464       if (!test) {
00465         _ai_sl_byte = SQSL_ARRAY;
00466         SlObject(NULL, _ai_byte);
00467       }
00468       sq_pushnull(vm);
00469       while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
00470         /* Store the value */
00471         bool res = 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_TABLE: {
00487       if (!test) {
00488         _ai_sl_byte = SQSL_TABLE;
00489         SlObject(NULL, _ai_byte);
00490       }
00491       sq_pushnull(vm);
00492       while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
00493         /* Store the key + value */
00494         bool res = SaveObject(vm, -2, max_depth - 1, test) && SaveObject(vm, -1, max_depth - 1, test);
00495         sq_pop(vm, 2);
00496         if (!res) {
00497           sq_pop(vm, 1);
00498           return false;
00499         }
00500       }
00501       sq_pop(vm, 1);
00502       if (!test) {
00503         _ai_sl_byte = SQSL_ARRAY_TABLE_END;
00504         SlObject(NULL, _ai_byte);
00505       }
00506       return true;
00507     }
00508 
00509     case OT_BOOL: {
00510       if (!test) {
00511         _ai_sl_byte = SQSL_BOOL;
00512         SlObject(NULL, _ai_byte);
00513       }
00514       SQBool res;
00515       sq_getbool(vm, index, &res);
00516       if (!test) {
00517         _ai_sl_byte = res ? 1 : 0;
00518         SlObject(NULL, _ai_byte);
00519       }
00520       return true;
00521     }
00522 
00523     case OT_NULL: {
00524       if (!test) {
00525         _ai_sl_byte = SQSL_NULL;
00526         SlObject(NULL, _ai_byte);
00527       }
00528       return true;
00529     }
00530 
00531     default:
00532       AILog::Error("You tried to save an unsupported type. No data saved.");
00533       return false;
00534   }
00535 }
00536 
00537 /* static */ void AIInstance::SaveEmpty()
00538 {
00539   _ai_sl_byte = 0;
00540   SlObject(NULL, _ai_byte);
00541 }
00542 
00543 void AIInstance::Save()
00544 {
00545   /* Don't save data if the AI didn't start yet or if it crashed. */
00546   if (this->engine == NULL || this->engine->HasScriptCrashed()) {
00547     SaveEmpty();
00548     return;
00549   }
00550 
00551   HSQUIRRELVM vm = this->engine->GetVM();
00552   if (this->is_save_data_on_stack) {
00553     _ai_sl_byte = 1;
00554     SlObject(NULL, _ai_byte);
00555     /* Save the data that was just loaded. */
00556     SaveObject(vm, -1, AISAVE_MAX_DEPTH, false);
00557   } else if (!this->is_started) {
00558     SaveEmpty();
00559     return;
00560   } else if (this->engine->MethodExists(*this->instance, "Save")) {
00561     HSQOBJECT savedata;
00562     /* We don't want to be interrupted during the save function. */
00563     bool backup_allow = AIObject::GetAllowDoCommand();
00564     AIObject::SetAllowDoCommand(false);
00565     if (!this->engine->CallMethod(*this->instance, "Save", &savedata)) {
00566       /* The script crashed in the Save function. We can't kill
00567        * it here, but do so in the next AI tick. */
00568       SaveEmpty();
00569       return;
00570     }
00571     AIObject::SetAllowDoCommand(backup_allow);
00572 
00573     if (!sq_istable(savedata)) {
00574       AILog::Error("Save function should return a table.");
00575       SaveEmpty();
00576       this->engine->CrashOccurred();
00577       return;
00578     }
00579     sq_pushobject(vm, savedata);
00580     if (SaveObject(vm, -1, AISAVE_MAX_DEPTH, true)) {
00581       _ai_sl_byte = 1;
00582       SlObject(NULL, _ai_byte);
00583       SaveObject(vm, -1, AISAVE_MAX_DEPTH, false);
00584       this->is_save_data_on_stack = true;
00585     } else {
00586       SaveEmpty();
00587       this->engine->CrashOccurred();
00588     }
00589   } else {
00590     AILog::Warning("Save function is not implemented");
00591     _ai_sl_byte = 0;
00592     SlObject(NULL, _ai_byte);
00593   }
00594 
00595 }
00596 
00597 /* static */ bool AIInstance::LoadObjects(HSQUIRRELVM vm)
00598 {
00599   SlObject(NULL, _ai_byte);
00600   switch (_ai_sl_byte) {
00601     case SQSL_INT: {
00602       int value;
00603       SlArray(&value, 1, SLE_INT32);
00604       if (vm != NULL) sq_pushinteger(vm, (SQInteger)value);
00605       return true;
00606     }
00607 
00608     case SQSL_STRING: {
00609       SlObject(NULL, _ai_byte);
00610       static char buf[256];
00611       SlArray(buf, _ai_sl_byte, SLE_CHAR);
00612       if (vm != NULL) sq_pushstring(vm, OTTD2FS(buf), -1);
00613       return true;
00614     }
00615 
00616     case SQSL_ARRAY: {
00617       if (vm != NULL) sq_newarray(vm, 0);
00618       while (LoadObjects(vm)) {
00619         if (vm != NULL) sq_arrayappend(vm, -2);
00620         /* The value is popped from the stack by squirrel. */
00621       }
00622       return true;
00623     }
00624 
00625     case SQSL_TABLE: {
00626       if (vm != NULL) sq_newtable(vm);
00627       while (LoadObjects(vm)) {
00628         LoadObjects(vm);
00629         if (vm != NULL) sq_rawset(vm, -3);
00630         /* The key (-2) and value (-1) are popped from the stack by squirrel. */
00631       }
00632       return true;
00633     }
00634 
00635     case SQSL_BOOL: {
00636       SlObject(NULL, _ai_byte);
00637       if (vm != NULL) sq_pushinteger(vm, (SQBool)(_ai_sl_byte != 0));
00638       return true;
00639     }
00640 
00641     case SQSL_NULL: {
00642       if (vm != NULL) sq_pushnull(vm);
00643       return true;
00644     }
00645 
00646     case SQSL_ARRAY_TABLE_END: {
00647       return false;
00648     }
00649 
00650     default: NOT_REACHED();
00651   }
00652 }
00653 
00654 /* static */ void AIInstance::LoadEmpty()
00655 {
00656   SlObject(NULL, _ai_byte);
00657   /* Check if there was anything saved at all. */
00658   if (_ai_sl_byte == 0) return;
00659 
00660   LoadObjects(NULL);
00661 }
00662 
00663 void AIInstance::Load(int version)
00664 {
00665   if (this->engine == NULL || version == -1) {
00666     LoadEmpty();
00667     return;
00668   }
00669   HSQUIRRELVM vm = this->engine->GetVM();
00670 
00671   SlObject(NULL, _ai_byte);
00672   /* Check if there was anything saved at all. */
00673   if (_ai_sl_byte == 0) return;
00674 
00675   sq_pushinteger(vm, version);
00676   LoadObjects(vm);
00677   this->is_save_data_on_stack = true;
00678 }
00679 
00680 bool AIInstance::CallLoad()
00681 {
00682   HSQUIRRELVM vm = this->engine->GetVM();
00683   /* Is there save data that we should load? */
00684   if (!this->is_save_data_on_stack) return true;
00685   /* Whatever happens, after CallLoad the savegame data is removed from the stack. */
00686   this->is_save_data_on_stack = false;
00687 
00688   if (!this->engine->MethodExists(*this->instance, "Load")) {
00689     AILog::Warning("Loading failed: there was data for the AI to load, but the AI does not have a Load() function.");
00690 
00691     /* Pop the savegame data and version. */
00692     sq_pop(vm, 2);
00693     return true;
00694   }
00695 
00696   /* Go to the instance-root */
00697   sq_pushobject(vm, *this->instance);
00698   /* Find the function-name inside the script */
00699   sq_pushstring(vm, OTTD2FS("Load"), -1);
00700   /* Change the "Load" string in a function pointer */
00701   sq_get(vm, -2);
00702   /* Push the main instance as "this" object */
00703   sq_pushobject(vm, *this->instance);
00704   /* Push the version data and savegame data as arguments */
00705   sq_push(vm, -5);
00706   sq_push(vm, -5);
00707 
00708   /* Call the AI load function. sq_call removes the arguments (but not the
00709    * function pointer) from the stack. */
00710   if (SQ_FAILED(sq_call(vm, 3, SQFalse, SQFalse, 100000))) return false;
00711 
00712   /* Pop 1) The version, 2) the savegame data, 3) the object instance, 4) the function pointer. */
00713   sq_pop(vm, 4);
00714   return true;
00715 }

Generated on Tue Jul 21 18:48:21 2009 for OpenTTD by  doxygen 1.5.6