ai_instance.cpp

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

Generated on Mon May 11 15:48:01 2009 for OpenTTD by  doxygen 1.5.6