ai_instance.cpp

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

Generated on Mon Mar 9 23:33:45 2009 for openttd by  doxygen 1.5.6