ai_instance.cpp

Go to the documentation of this file.
00001 /* $Id: ai_instance.cpp 15708 2009-03-14 01:32:04Z 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 "../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   ShowErrorMessage(INVALID_STRING_ID, STR_AI_PLEASE_REPORT_CRASH, 0, 0);
00259 }
00260 
00261 void AIInstance::GameLoop()
00262 {
00263   if (this->is_dead) return;
00264   if (this->engine->HasScriptCrashed()) {
00265     /* The script crashed during saving, kill it here. */
00266     this->Died();
00267     return;
00268   }
00269   this->controller->ticks++;
00270 
00271   if (this->suspend   < -1) this->suspend++; // Multiplayer suspend, increase up to -1.
00272   if (this->suspend   < 0)  return;          // Multiplayer suspend, wait for Continue().
00273   if (--this->suspend > 0)  return;          // Singleplayer suspend, decrease to 0.
00274 
00275   /* If there is a callback to call, call that first */
00276   if (this->callback != NULL) {
00277     try {
00278       this->callback(this);
00279     } catch (AI_VMSuspend e) {
00280       this->suspend  = e.GetSuspendTime();
00281       this->callback = e.GetSuspendCallback();
00282 
00283       return;
00284     }
00285   }
00286 
00287   this->suspend  = 0;
00288   this->callback = NULL;
00289 
00290   if (!this->is_started) {
00291     try {
00292       AIObject::SetAllowDoCommand(false);
00293       /* Run the constructor if it exists. Don't allow any DoCommands in it. */
00294       if (this->engine->MethodExists(*this->instance, "constructor")) {
00295         if (!this->engine->CallMethod(*this->instance, "constructor")) { this->Died(); return; }
00296       }
00297       if (!this->CallLoad()) { this->Died(); return; }
00298       AIObject::SetAllowDoCommand(true);
00299       /* Start the AI by calling Start() */
00300       if (!this->engine->CallMethod(*this->instance, "Start",  _settings_game.ai.ai_max_opcode_till_suspend) || !this->engine->IsSuspended()) this->Died();
00301     } catch (AI_VMSuspend e) {
00302       this->suspend  = e.GetSuspendTime();
00303       this->callback = e.GetSuspendCallback();
00304     }
00305 
00306     this->is_started = true;
00307     return;
00308   }
00309 
00310   /* Continue the VM */
00311   try {
00312     if (!this->engine->Resume(_settings_game.ai.ai_max_opcode_till_suspend)) this->Died();
00313   } catch (AI_VMSuspend e) {
00314     this->suspend  = e.GetSuspendTime();
00315     this->callback = e.GetSuspendCallback();
00316   }
00317 }
00318 
00319 void AIInstance::CollectGarbage()
00320 {
00321   if (this->is_started && !this->is_dead) this->engine->CollectGarbage();
00322 }
00323 
00324 /* static */ void AIInstance::DoCommandReturn(AIInstance *instance)
00325 {
00326   instance->engine->InsertResult(AIObject::GetLastCommandRes());
00327 }
00328 
00329 /* static */ void AIInstance::DoCommandReturnVehicleID(AIInstance *instance)
00330 {
00331   instance->engine->InsertResult(AIObject::GetNewVehicleID());
00332 }
00333 
00334 /* static */ void AIInstance::DoCommandReturnSignID(AIInstance *instance)
00335 {
00336   instance->engine->InsertResult(AIObject::GetNewSignID());
00337 }
00338 
00339 /* static */ void AIInstance::DoCommandReturnGroupID(AIInstance *instance)
00340 {
00341   instance->engine->InsertResult(AIObject::GetNewGroupID());
00342 }
00343 
00344 /* static */ AIStorage *AIInstance::GetStorage()
00345 {
00346   assert(IsValidCompanyID(_current_company) && !IsHumanCompany(_current_company));
00347   return GetCompany(_current_company)->ai_instance->storage;
00348 }
00349 
00350 /*
00351  * All data is stored in the following format:
00352  * First 1 byte indicating if there is a data blob at all.
00353  * 1 byte indicating the type of data.
00354  * The data itself, this differs per type:
00355  *  - integer: a binary representation of the integer (int32).
00356  *  - string:  First one byte with the string length, then a 0-terminated char
00357  *             array. The string can't be longer then 255 bytes (including
00358  *             terminating '\0').
00359  *  - array:   All data-elements of the array are saved recursive in this
00360  *             format, and ended with an element of the type
00361  *             SQSL_ARRAY_TABLE_END.
00362  *  - table:   All key/value pairs are saved in this format (first key 1, then
00363  *             value 1, then key 2, etc.). All keys and values can have an
00364  *             arbitrary type (as long as it is supported by the save function
00365  *             of course). The table is ended with an element of the type
00366  *             SQSL_ARRAY_TABLE_END.
00367  *  - bool:    A single byte with value 1 representing true and 0 false.
00368  *  - null:    No data.
00369  */
00370 
00372 enum SQSaveLoadType {
00373   SQSL_INT             = 0x00, 
00374   SQSL_STRING          = 0x01, 
00375   SQSL_ARRAY           = 0x02, 
00376   SQSL_TABLE           = 0x03, 
00377   SQSL_BOOL            = 0x04, 
00378   SQSL_NULL            = 0x05, 
00379   SQSL_ARRAY_TABLE_END = 0xFF, 
00380 };
00381 
00382 static byte _ai_sl_byte;
00383 
00384 static const SaveLoad _ai_byte[] = {
00385   SLEG_VAR(_ai_sl_byte, SLE_UINT8),
00386   SLE_END()
00387 };
00388 
00389 enum {
00390   AISAVE_MAX_DEPTH = 25, 
00391 };
00392 
00393 /* static */ bool AIInstance::SaveObject(HSQUIRRELVM vm, SQInteger index, int max_depth, bool test)
00394 {
00395   if (max_depth == 0) {
00396     AILog::Error("Savedata can only be nested to 25 deep. No data saved.");
00397     return false;
00398   }
00399 
00400   switch (sq_gettype(vm, index)) {
00401     case OT_INTEGER: {
00402       if (!test) {
00403         _ai_sl_byte = SQSL_INT;
00404         SlObject(NULL, _ai_byte);
00405       }
00406       SQInteger res;
00407       sq_getinteger(vm, index, &res);
00408       if (!test) {
00409         int value = (int)res;
00410         SlArray(&value, 1, SLE_INT32);
00411       }
00412       return true;
00413     }
00414 
00415     case OT_STRING: {
00416       if (!test) {
00417         _ai_sl_byte = SQSL_STRING;
00418         SlObject(NULL, _ai_byte);
00419       }
00420       const SQChar *res;
00421       sq_getstring(vm, index, &res);
00422       /* @bug if a string longer than 512 characters is given to FS2OTTD, the
00423        *  internal buffer overflows. */
00424       const char *buf = FS2OTTD(res);
00425       size_t len = strlen(buf) + 1;
00426       if (len >= 255) {
00427         AILog::Error("Maximum string length is 254 chars. No data saved.");
00428         return false;
00429       }
00430       if (!test) {
00431         _ai_sl_byte = (byte)len;
00432         SlObject(NULL, _ai_byte);
00433         SlArray((void*)buf, len, SLE_CHAR);
00434       }
00435       return true;
00436     }
00437 
00438     case OT_ARRAY: {
00439       if (!test) {
00440         _ai_sl_byte = SQSL_ARRAY;
00441         SlObject(NULL, _ai_byte);
00442       }
00443       sq_pushnull(vm);
00444       while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
00445         /* Store the value */
00446         bool res = SaveObject(vm, -1, max_depth - 1, test);
00447         sq_pop(vm, 2);
00448         if (!res) {
00449           sq_pop(vm, 1);
00450           return false;
00451         }
00452       }
00453       sq_pop(vm, 1);
00454       if (!test) {
00455         _ai_sl_byte = SQSL_ARRAY_TABLE_END;
00456         SlObject(NULL, _ai_byte);
00457       }
00458       return true;
00459     }
00460 
00461     case OT_TABLE: {
00462       if (!test) {
00463         _ai_sl_byte = SQSL_TABLE;
00464         SlObject(NULL, _ai_byte);
00465       }
00466       sq_pushnull(vm);
00467       while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
00468         /* Store the key + value */
00469         bool res = SaveObject(vm, -2, max_depth - 1, test) && SaveObject(vm, -1, max_depth - 1, test);
00470         sq_pop(vm, 2);
00471         if (!res) {
00472           sq_pop(vm, 1);
00473           return false;
00474         }
00475       }
00476       sq_pop(vm, 1);
00477       if (!test) {
00478         _ai_sl_byte = SQSL_ARRAY_TABLE_END;
00479         SlObject(NULL, _ai_byte);
00480       }
00481       return true;
00482     }
00483 
00484     case OT_BOOL: {
00485       if (!test) {
00486         _ai_sl_byte = SQSL_BOOL;
00487         SlObject(NULL, _ai_byte);
00488       }
00489       SQBool res;
00490       sq_getbool(vm, index, &res);
00491       if (!test) {
00492         _ai_sl_byte = res ? 1 : 0;
00493         SlObject(NULL, _ai_byte);
00494       }
00495       return true;
00496     }
00497 
00498     case OT_NULL: {
00499       if (!test) {
00500         _ai_sl_byte = SQSL_NULL;
00501         SlObject(NULL, _ai_byte);
00502       }
00503       return true;
00504     }
00505 
00506     default:
00507       AILog::Error("You tried to save an unsupported type. No data saved.");
00508       return false;
00509   }
00510 }
00511 
00512 /* static */ void AIInstance::SaveEmpty()
00513 {
00514   _ai_sl_byte = 0;
00515   SlObject(NULL, _ai_byte);
00516 }
00517 
00518 void AIInstance::Save()
00519 {
00520   /* Don't save data if the AI didn't start yet or if it crashed. */
00521   if (this->engine == NULL || this->engine->HasScriptCrashed()) {
00522     SaveEmpty();
00523     return;
00524   }
00525 
00526   HSQUIRRELVM vm = this->engine->GetVM();
00527   if (!this->is_started) {
00528     SQBool res;
00529     sq_getbool(vm, -1, &res);
00530     if (!res) {
00531       SaveEmpty();
00532       return;
00533     }
00534     /* Push the loaded savegame data to the top of the stack. */
00535     sq_push(vm, -2);
00536     _ai_sl_byte = 1;
00537     SlObject(NULL, _ai_byte);
00538     /* Save the data that was just loaded. */
00539     SaveObject(vm, -1, AISAVE_MAX_DEPTH, false);
00540     sq_poptop(vm);
00541   } else if (this->engine->MethodExists(*this->instance, "Save")) {
00542     HSQOBJECT savedata;
00543     /* We don't want to be interrupted during the save function. */
00544     bool backup_allow = AIObject::GetAllowDoCommand();
00545     AIObject::SetAllowDoCommand(false);
00546     if (!this->engine->CallMethod(*this->instance, "Save", &savedata)) {
00547       /* The script crashed in the Save function. We can't kill
00548        * it here, but do so in the next AI tick. */
00549       SaveEmpty();
00550       return;
00551     }
00552     AIObject::SetAllowDoCommand(backup_allow);
00553 
00554     if (!sq_istable(savedata)) {
00555       AILog::Error("Save function should return a table.");
00556       SaveEmpty();
00557       return;
00558     }
00559     sq_pushobject(vm, savedata);
00560     if (SaveObject(vm, -1, AISAVE_MAX_DEPTH, true)) {
00561       _ai_sl_byte = 1;
00562       SlObject(NULL, _ai_byte);
00563       SaveObject(vm, -1, AISAVE_MAX_DEPTH, false);
00564     } else {
00565       _ai_sl_byte = 0;
00566       SlObject(NULL, _ai_byte);
00567     }
00568     sq_pop(vm, 1);
00569   } else {
00570     AILog::Warning("Save function is not implemented");
00571     _ai_sl_byte = 0;
00572     SlObject(NULL, _ai_byte);
00573   }
00574 
00575 }
00576 
00577 /* static */ bool AIInstance::LoadObjects(HSQUIRRELVM vm)
00578 {
00579   SlObject(NULL, _ai_byte);
00580   switch (_ai_sl_byte) {
00581     case SQSL_INT: {
00582       int value;
00583       SlArray(&value, 1, SLE_INT32);
00584       if (vm != NULL) sq_pushinteger(vm, (SQInteger)value);
00585       return true;
00586     }
00587 
00588     case SQSL_STRING: {
00589       SlObject(NULL, _ai_byte);
00590       static char buf[256];
00591       SlArray(buf, _ai_sl_byte, SLE_CHAR);
00592       if (vm != NULL) sq_pushstring(vm, OTTD2FS(buf), -1);
00593       return true;
00594     }
00595 
00596     case SQSL_ARRAY: {
00597       if (vm != NULL) sq_newarray(vm, 0);
00598       while (LoadObjects(vm)) {
00599         if (vm != NULL) sq_arrayappend(vm, -2);
00600         /* The value is popped from the stack by squirrel. */
00601       }
00602       return true;
00603     }
00604 
00605     case SQSL_TABLE: {
00606       if (vm != NULL) sq_newtable(vm);
00607       while (LoadObjects(vm)) {
00608         LoadObjects(vm);
00609         if (vm != NULL) sq_rawset(vm, -3);
00610         /* The key (-2) and value (-1) are popped from the stack by squirrel. */
00611       }
00612       return true;
00613     }
00614 
00615     case SQSL_BOOL: {
00616       SlObject(NULL, _ai_byte);
00617       if (vm != NULL) sq_pushinteger(vm, (SQBool)(_ai_sl_byte != 0));
00618       return true;
00619     }
00620 
00621     case SQSL_NULL: {
00622       if (vm != NULL) sq_pushnull(vm);
00623       return true;
00624     }
00625 
00626     case SQSL_ARRAY_TABLE_END: {
00627       return false;
00628     }
00629 
00630     default: NOT_REACHED();
00631   }
00632 }
00633 
00634 /* static */ void AIInstance::LoadEmpty()
00635 {
00636   SlObject(NULL, _ai_byte);
00637   /* Check if there was anything saved at all. */
00638   if (_ai_sl_byte == 0) return;
00639 
00640   LoadObjects(NULL);
00641 }
00642 
00643 void AIInstance::Load(int version)
00644 {
00645   if (this->engine == NULL || version == -1) {
00646     LoadEmpty();
00647     return;
00648   }
00649   HSQUIRRELVM vm = this->engine->GetVM();
00650 
00651   SlObject(NULL, _ai_byte);
00652   /* Check if there was anything saved at all. */
00653   if (_ai_sl_byte == 0) return;
00654 
00655   /* First remove the value "false" since we have data to load. */
00656   sq_poptop(vm);
00657   sq_pushinteger(vm, version);
00658   LoadObjects(vm);
00659   sq_pushbool(vm, true);
00660 }
00661 
00662 bool AIInstance::CallLoad()
00663 {
00664   HSQUIRRELVM vm = this->engine->GetVM();
00665   /* Is there save data that we should load? */
00666   SQBool res;
00667   sq_getbool(vm, -1, &res);
00668   sq_poptop(vm);
00669   if (!res) return true;
00670 
00671   if (!this->engine->MethodExists(*this->instance, "Load")) {
00672     AILog::Warning("Loading failed: there was data for the AI to load, but the AI does not have a Load() function.");
00673 
00674     /* Pop the savegame data and version. */
00675     sq_pop(vm, 2);
00676     return true;
00677   }
00678 
00679   /* Go to the instance-root */
00680   sq_pushobject(vm, *this->instance);
00681   /* Find the function-name inside the script */
00682   sq_pushstring(vm, OTTD2FS("Load"), -1);
00683   /* Change the "Load" string in a function pointer */
00684   sq_get(vm, -2);
00685   /* Push the main instance as "this" object */
00686   sq_pushobject(vm, *this->instance);
00687   /* Push the version data and savegame data as arguments */
00688   sq_push(vm, -5);
00689   sq_push(vm, -5);
00690 
00691   /* Call the AI load function. sq_call removes the arguments (but not the
00692    * function pointer) from the stack. */
00693   if (SQ_FAILED(sq_call(vm, 3, SQFalse, SQFalse))) return false;
00694 
00695   /* Pop 1) The version, 2) the savegame data, 3) the object instance, 4) the function pointer. */
00696   sq_pop(vm, 4);
00697   return true;
00698 }

Generated on Sun Mar 15 22:49:44 2009 for openttd by  doxygen 1.5.6