ai_instance.cpp

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

Generated on Mon Feb 16 23:12:05 2009 for openttd by  doxygen 1.5.6