ai_instance.cpp

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

Generated on Mon Mar 23 00:25:17 2009 for OpenTTD by  doxygen 1.5.6