00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "../stdafx.h"
00013 #include "../debug.h"
00014 #include "../saveload/saveload.h"
00015 #include "../gui.h"
00016
00017 #include <squirrel.h>
00018 #include "../script/squirrel.hpp"
00019 #include "../script/squirrel_helper.hpp"
00020 #include "../script/squirrel_class.hpp"
00021
00022 #include "ai_config.hpp"
00023 #include "ai_storage.hpp"
00024 #include "ai_instance.hpp"
00025 #include "ai_gui.hpp"
00026
00027
00028
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_basestation.hpp.sq"
00034 #include "api/ai_bridge.hpp.sq"
00035 #include "api/ai_bridgelist.hpp.sq"
00036 #include "api/ai_cargo.hpp.sq"
00037 #include "api/ai_cargolist.hpp.sq"
00038 #include "api/ai_company.hpp.sq"
00039 #include "api/ai_controller.hpp.sq"
00040 #include "api/ai_date.hpp.sq"
00041 #include "api/ai_depotlist.hpp.sq"
00042 #include "api/ai_engine.hpp.sq"
00043 #include "api/ai_enginelist.hpp.sq"
00044 #include "api/ai_error.hpp.sq"
00045 #include "api/ai_event.hpp.sq"
00046 #include "api/ai_event_types.hpp.sq"
00047 #include "api/ai_execmode.hpp.sq"
00048 #include "api/ai_gamesettings.hpp.sq"
00049 #include "api/ai_group.hpp.sq"
00050 #include "api/ai_grouplist.hpp.sq"
00051 #include "api/ai_industry.hpp.sq"
00052 #include "api/ai_industrylist.hpp.sq"
00053 #include "api/ai_industrytype.hpp.sq"
00054 #include "api/ai_industrytypelist.hpp.sq"
00055 #include "api/ai_list.hpp.sq"
00056 #include "api/ai_log.hpp.sq"
00057 #include "api/ai_map.hpp.sq"
00058 #include "api/ai_marine.hpp.sq"
00059 #include "api/ai_order.hpp.sq"
00060 #include "api/ai_rail.hpp.sq"
00061 #include "api/ai_railtypelist.hpp.sq"
00062 #include "api/ai_road.hpp.sq"
00063 #include "api/ai_sign.hpp.sq"
00064 #include "api/ai_signlist.hpp.sq"
00065 #include "api/ai_station.hpp.sq"
00066 #include "api/ai_stationlist.hpp.sq"
00067 #include "api/ai_subsidy.hpp.sq"
00068 #include "api/ai_subsidylist.hpp.sq"
00069 #include "api/ai_testmode.hpp.sq"
00070 #include "api/ai_tile.hpp.sq"
00071 #include "api/ai_tilelist.hpp.sq"
00072 #include "api/ai_town.hpp.sq"
00073 #include "api/ai_townlist.hpp.sq"
00074 #include "api/ai_tunnel.hpp.sq"
00075 #include "api/ai_vehicle.hpp.sq"
00076 #include "api/ai_vehiclelist.hpp.sq"
00077 #include "api/ai_waypoint.hpp.sq"
00078 #include "api/ai_waypointlist.hpp.sq"
00079
00080 #include "../company_base.h"
00081 #include "../fileio_func.h"
00082
00083 AIStorage::~AIStorage()
00084 {
00085
00086 if (event_data != NULL) AIEventController::FreeEventPointer();
00087 if (log_data != NULL) AILog::FreeLogPointer();
00088 }
00089
00090 static void PrintFunc(bool error_msg, const SQChar *message)
00091 {
00092
00093 AIController::Print(error_msg, SQ2OTTD(message));
00094 }
00095
00096 AIInstance::AIInstance(AIInfo *info) :
00097 controller(NULL),
00098 storage(NULL),
00099 engine(NULL),
00100 instance(NULL),
00101 is_started(false),
00102 is_dead(false),
00103 is_save_data_on_stack(false),
00104 suspend(0),
00105 callback(NULL)
00106 {
00107
00108 Company::Get(_current_company)->ai_instance = this;
00109
00110 this->controller = new AIController();
00111 this->storage = new AIStorage();
00112 this->engine = new Squirrel();
00113 this->engine->SetPrintFunction(&PrintFunc);
00114
00115
00116 this->engine->AddMethod("import", &AILibrary::Import, 4, ".ssi");
00117
00118
00119 SQAIController_Register(this->engine);
00120
00121
00122 this->RegisterAPI();
00123
00124 if (!this->LoadCompatibilityScripts(info->GetAPIVersion())) {
00125 this->Died();
00126 return;
00127 }
00128
00129 try {
00130 AIObject::SetAllowDoCommand(false);
00131
00132 const char *main_script = info->GetMainScript();
00133 if (strcmp(main_script, "%_dummy") == 0) {
00134 extern void AI_CreateAIDummy(HSQUIRRELVM vm);
00135 AI_CreateAIDummy(this->engine->GetVM());
00136 } else if (!this->engine->LoadScript(main_script) || this->engine->IsSuspended()) {
00137 if (this->engine->IsSuspended()) AILog::Error("This AI took too long to load script. AI is not started.");
00138 this->Died();
00139 return;
00140 }
00141
00142
00143 this->instance = MallocT<SQObject>(1);
00144 if (!this->engine->CreateClassInstance(info->GetInstanceName(), this->controller, this->instance)) {
00145 this->Died();
00146 return;
00147 }
00148 AIObject::SetAllowDoCommand(true);
00149 } catch (AI_FatalError e) {
00150 this->is_dead = true;
00151 this->engine->ThrowError(e.GetErrorMessage());
00152 this->engine->ResumeError();
00153 this->Died();
00154 }
00155 }
00156
00157 AIInstance::~AIInstance()
00158 {
00159 if (instance != NULL) this->engine->ReleaseObject(this->instance);
00160 if (engine != NULL) delete this->engine;
00161 delete this->storage;
00162 delete this->controller;
00163 free(this->instance);
00164 }
00165
00166 void AIInstance::RegisterAPI()
00167 {
00168
00169 squirrel_register_std(this->engine);
00170 SQAIAbstractList_Register(this->engine);
00171 SQAIAccounting_Register(this->engine);
00172 SQAIAirport_Register(this->engine);
00173 SQAIBase_Register(this->engine);
00174 SQAIBaseStation_Register(this->engine);
00175 SQAIBridge_Register(this->engine);
00176 SQAIBridgeList_Register(this->engine);
00177 SQAIBridgeList_Length_Register(this->engine);
00178 SQAICargo_Register(this->engine);
00179 SQAICargoList_Register(this->engine);
00180 SQAICargoList_IndustryAccepting_Register(this->engine);
00181 SQAICargoList_IndustryProducing_Register(this->engine);
00182 SQAICompany_Register(this->engine);
00183 SQAIDate_Register(this->engine);
00184 SQAIDepotList_Register(this->engine);
00185 SQAIEngine_Register(this->engine);
00186 SQAIEngineList_Register(this->engine);
00187 SQAIError_Register(this->engine);
00188 SQAIEvent_Register(this->engine);
00189 SQAIEventCompanyAskMerger_Register(this->engine);
00190 SQAIEventCompanyBankrupt_Register(this->engine);
00191 SQAIEventCompanyInTrouble_Register(this->engine);
00192 SQAIEventCompanyMerger_Register(this->engine);
00193 SQAIEventCompanyNew_Register(this->engine);
00194 SQAIEventController_Register(this->engine);
00195 SQAIEventDisasterZeppelinerCleared_Register(this->engine);
00196 SQAIEventDisasterZeppelinerCrashed_Register(this->engine);
00197 SQAIEventEngineAvailable_Register(this->engine);
00198 SQAIEventEnginePreview_Register(this->engine);
00199 SQAIEventIndustryClose_Register(this->engine);
00200 SQAIEventIndustryOpen_Register(this->engine);
00201 SQAIEventStationFirstVehicle_Register(this->engine);
00202 SQAIEventSubsidyAwarded_Register(this->engine);
00203 SQAIEventSubsidyExpired_Register(this->engine);
00204 SQAIEventSubsidyOffer_Register(this->engine);
00205 SQAIEventSubsidyOfferExpired_Register(this->engine);
00206 SQAIEventVehicleCrashed_Register(this->engine);
00207 SQAIEventVehicleLost_Register(this->engine);
00208 SQAIEventVehicleUnprofitable_Register(this->engine);
00209 SQAIEventVehicleWaitingInDepot_Register(this->engine);
00210 SQAIExecMode_Register(this->engine);
00211 SQAIGameSettings_Register(this->engine);
00212 SQAIGroup_Register(this->engine);
00213 SQAIGroupList_Register(this->engine);
00214 SQAIIndustry_Register(this->engine);
00215 SQAIIndustryList_Register(this->engine);
00216 SQAIIndustryList_CargoAccepting_Register(this->engine);
00217 SQAIIndustryList_CargoProducing_Register(this->engine);
00218 SQAIIndustryType_Register(this->engine);
00219 SQAIIndustryTypeList_Register(this->engine);
00220 SQAIList_Register(this->engine);
00221 SQAILog_Register(this->engine);
00222 SQAIMap_Register(this->engine);
00223 SQAIMarine_Register(this->engine);
00224 SQAIOrder_Register(this->engine);
00225 SQAIRail_Register(this->engine);
00226 SQAIRailTypeList_Register(this->engine);
00227 SQAIRoad_Register(this->engine);
00228 SQAISign_Register(this->engine);
00229 SQAISignList_Register(this->engine);
00230 SQAIStation_Register(this->engine);
00231 SQAIStationList_Register(this->engine);
00232 SQAIStationList_Vehicle_Register(this->engine);
00233 SQAISubsidy_Register(this->engine);
00234 SQAISubsidyList_Register(this->engine);
00235 SQAITestMode_Register(this->engine);
00236 SQAITile_Register(this->engine);
00237 SQAITileList_Register(this->engine);
00238 SQAITileList_IndustryAccepting_Register(this->engine);
00239 SQAITileList_IndustryProducing_Register(this->engine);
00240 SQAITileList_StationType_Register(this->engine);
00241 SQAITown_Register(this->engine);
00242 SQAITownList_Register(this->engine);
00243 SQAITunnel_Register(this->engine);
00244 SQAIVehicle_Register(this->engine);
00245 SQAIVehicleList_Register(this->engine);
00246 SQAIVehicleList_DefaultGroup_Register(this->engine);
00247 SQAIVehicleList_Depot_Register(this->engine);
00248 SQAIVehicleList_Group_Register(this->engine);
00249 SQAIVehicleList_SharedOrders_Register(this->engine);
00250 SQAIVehicleList_Station_Register(this->engine);
00251 SQAIWaypoint_Register(this->engine);
00252 SQAIWaypointList_Register(this->engine);
00253 SQAIWaypointList_Vehicle_Register(this->engine);
00254
00255 this->engine->SetGlobalPointer(this->engine);
00256 }
00257
00258 bool AIInstance::LoadCompatibilityScripts(const char *api_version)
00259 {
00260 char script_name[32];
00261 seprintf(script_name, lastof(script_name), "compat_%s.nut", api_version);
00262 char buf[MAX_PATH];
00263 Searchpath sp;
00264 FOR_ALL_SEARCHPATHS(sp) {
00265 FioAppendDirectory(buf, MAX_PATH, sp, AI_DIR);
00266 ttd_strlcat(buf, script_name, MAX_PATH);
00267 if (!FileExists(buf)) continue;
00268
00269 if (this->engine->LoadScript(buf)) return true;
00270
00271 AILog::Error("Failed to load API compatibility script");
00272 DEBUG(ai, 0, "Error compiling / running API compatibility script: %s", buf);
00273 return false;
00274 }
00275
00276 AILog::Warning("API compatibility script not found");
00277 return true;
00278 }
00279
00280 void AIInstance::Continue()
00281 {
00282 assert(this->suspend < 0);
00283 this->suspend = -this->suspend - 1;
00284 }
00285
00286 void AIInstance::Died()
00287 {
00288 DEBUG(ai, 0, "The AI died unexpectedly.");
00289 this->is_dead = true;
00290
00291 if (this->instance != NULL) this->engine->ReleaseObject(this->instance);
00292 delete this->engine;
00293 this->instance = NULL;
00294 this->engine = NULL;
00295
00296 ShowAIDebugWindow(_current_company);
00297
00298 const AIInfo *info = AIConfig::GetConfig(_current_company)->GetInfo();
00299 if (info != NULL) {
00300 ShowErrorMessage(STR_ERROR_AI_PLEASE_REPORT_CRASH, INVALID_STRING_ID, 0, 0);
00301
00302 if (info->GetURL() != NULL) {
00303 AILog::Info("Please report the error to the following URL:");
00304 AILog::Info(info->GetURL());
00305 }
00306 }
00307 }
00308
00309 void AIInstance::GameLoop()
00310 {
00311 if (this->IsDead()) return;
00312 if (this->engine->HasScriptCrashed()) {
00313
00314 this->Died();
00315 return;
00316 }
00317 this->controller->ticks++;
00318
00319 if (this->suspend < -1) this->suspend++;
00320 if (this->suspend < 0) return;
00321 if (--this->suspend > 0) return;
00322
00323
00324 if (this->callback != NULL) {
00325 if (this->is_save_data_on_stack) {
00326 sq_poptop(this->engine->GetVM());
00327 this->is_save_data_on_stack = false;
00328 }
00329 try {
00330 this->callback(this);
00331 } catch (AI_VMSuspend e) {
00332 this->suspend = e.GetSuspendTime();
00333 this->callback = e.GetSuspendCallback();
00334
00335 return;
00336 }
00337 }
00338
00339 this->suspend = 0;
00340 this->callback = NULL;
00341
00342 if (!this->is_started) {
00343 try {
00344 AIObject::SetAllowDoCommand(false);
00345
00346 if (this->engine->MethodExists(*this->instance, "constructor")) {
00347 if (!this->engine->CallMethod(*this->instance, "constructor", 100000) || this->engine->IsSuspended()) {
00348 if (this->engine->IsSuspended()) AILog::Error("This AI took too long to initialize. AI is not started.");
00349 this->Died();
00350 return;
00351 }
00352 }
00353 if (!this->CallLoad() || this->engine->IsSuspended()) {
00354 if (this->engine->IsSuspended()) AILog::Error("This AI took too long in the Load function. AI is not started.");
00355 this->Died();
00356 return;
00357 }
00358 AIObject::SetAllowDoCommand(true);
00359
00360 if (!this->engine->CallMethod(*this->instance, "Start", _settings_game.ai.ai_max_opcode_till_suspend) || !this->engine->IsSuspended()) this->Died();
00361 } catch (AI_VMSuspend e) {
00362 this->suspend = e.GetSuspendTime();
00363 this->callback = e.GetSuspendCallback();
00364 } catch (AI_FatalError e) {
00365 this->is_dead = true;
00366 this->engine->ThrowError(e.GetErrorMessage());
00367 this->engine->ResumeError();
00368 this->Died();
00369 }
00370
00371 this->is_started = true;
00372 return;
00373 }
00374 if (this->is_save_data_on_stack) {
00375 sq_poptop(this->engine->GetVM());
00376 this->is_save_data_on_stack = false;
00377 }
00378
00379
00380 try {
00381 if (!this->engine->Resume(_settings_game.ai.ai_max_opcode_till_suspend)) this->Died();
00382 } catch (AI_VMSuspend e) {
00383 this->suspend = e.GetSuspendTime();
00384 this->callback = e.GetSuspendCallback();
00385 } catch (AI_FatalError e) {
00386 this->is_dead = true;
00387 this->engine->ThrowError(e.GetErrorMessage());
00388 this->engine->ResumeError();
00389 this->Died();
00390 }
00391 }
00392
00393 void AIInstance::CollectGarbage() const
00394 {
00395 if (this->is_started && !this->IsDead()) this->engine->CollectGarbage();
00396 }
00397
00398 void AIInstance::DoCommandReturn(AIInstance *instance)
00399 {
00400 instance->engine->InsertResult(AIObject::GetLastCommandRes());
00401 }
00402
00403 void AIInstance::DoCommandReturnVehicleID(AIInstance *instance)
00404 {
00405 instance->engine->InsertResult(AIObject::GetNewVehicleID());
00406 }
00407
00408 void AIInstance::DoCommandReturnSignID(AIInstance *instance)
00409 {
00410 instance->engine->InsertResult(AIObject::GetNewSignID());
00411 }
00412
00413 void AIInstance::DoCommandReturnGroupID(AIInstance *instance)
00414 {
00415 instance->engine->InsertResult(AIObject::GetNewGroupID());
00416 }
00417
00418 AIStorage *AIInstance::GetStorage()
00419 {
00420 assert(Company::IsValidAiID(_current_company));
00421 return Company::Get(_current_company)->ai_instance->storage;
00422 }
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00446 enum SQSaveLoadType {
00447 SQSL_INT = 0x00,
00448 SQSL_STRING = 0x01,
00449 SQSL_ARRAY = 0x02,
00450 SQSL_TABLE = 0x03,
00451 SQSL_BOOL = 0x04,
00452 SQSL_NULL = 0x05,
00453 SQSL_ARRAY_TABLE_END = 0xFF,
00454 };
00455
00456 static byte _ai_sl_byte;
00457
00458 static const SaveLoad _ai_byte[] = {
00459 SLEG_VAR(_ai_sl_byte, SLE_UINT8),
00460 SLE_END()
00461 };
00462
00463 enum {
00464 AISAVE_MAX_DEPTH = 25,
00465 };
00466
00467 bool AIInstance::SaveObject(HSQUIRRELVM vm, SQInteger index, int max_depth, bool test)
00468 {
00469 if (max_depth == 0) {
00470 AILog::Error("Savedata can only be nested to 25 deep. No data saved.");
00471 return false;
00472 }
00473
00474 switch (sq_gettype(vm, index)) {
00475 case OT_INTEGER: {
00476 if (!test) {
00477 _ai_sl_byte = SQSL_INT;
00478 SlObject(NULL, _ai_byte);
00479 }
00480 SQInteger res;
00481 sq_getinteger(vm, index, &res);
00482 if (!test) {
00483 int value = (int)res;
00484 SlArray(&value, 1, SLE_INT32);
00485 }
00486 return true;
00487 }
00488
00489 case OT_STRING: {
00490 if (!test) {
00491 _ai_sl_byte = SQSL_STRING;
00492 SlObject(NULL, _ai_byte);
00493 }
00494 const SQChar *res;
00495 sq_getstring(vm, index, &res);
00496
00497
00498 const char *buf = SQ2OTTD(res);
00499 size_t len = strlen(buf) + 1;
00500 if (len >= 255) {
00501 AILog::Error("Maximum string length is 254 chars. No data saved.");
00502 return false;
00503 }
00504 if (!test) {
00505 _ai_sl_byte = (byte)len;
00506 SlObject(NULL, _ai_byte);
00507 SlArray((void*)buf, len, SLE_CHAR);
00508 }
00509 return true;
00510 }
00511
00512 case OT_ARRAY: {
00513 if (!test) {
00514 _ai_sl_byte = SQSL_ARRAY;
00515 SlObject(NULL, _ai_byte);
00516 }
00517 sq_pushnull(vm);
00518 while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
00519
00520 bool res = SaveObject(vm, -1, max_depth - 1, test);
00521 sq_pop(vm, 2);
00522 if (!res) {
00523 sq_pop(vm, 1);
00524 return false;
00525 }
00526 }
00527 sq_pop(vm, 1);
00528 if (!test) {
00529 _ai_sl_byte = SQSL_ARRAY_TABLE_END;
00530 SlObject(NULL, _ai_byte);
00531 }
00532 return true;
00533 }
00534
00535 case OT_TABLE: {
00536 if (!test) {
00537 _ai_sl_byte = SQSL_TABLE;
00538 SlObject(NULL, _ai_byte);
00539 }
00540 sq_pushnull(vm);
00541 while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
00542
00543 bool res = SaveObject(vm, -2, max_depth - 1, test) && SaveObject(vm, -1, max_depth - 1, test);
00544 sq_pop(vm, 2);
00545 if (!res) {
00546 sq_pop(vm, 1);
00547 return false;
00548 }
00549 }
00550 sq_pop(vm, 1);
00551 if (!test) {
00552 _ai_sl_byte = SQSL_ARRAY_TABLE_END;
00553 SlObject(NULL, _ai_byte);
00554 }
00555 return true;
00556 }
00557
00558 case OT_BOOL: {
00559 if (!test) {
00560 _ai_sl_byte = SQSL_BOOL;
00561 SlObject(NULL, _ai_byte);
00562 }
00563 SQBool res;
00564 sq_getbool(vm, index, &res);
00565 if (!test) {
00566 _ai_sl_byte = res ? 1 : 0;
00567 SlObject(NULL, _ai_byte);
00568 }
00569 return true;
00570 }
00571
00572 case OT_NULL: {
00573 if (!test) {
00574 _ai_sl_byte = SQSL_NULL;
00575 SlObject(NULL, _ai_byte);
00576 }
00577 return true;
00578 }
00579
00580 default:
00581 AILog::Error("You tried to save an unsupported type. No data saved.");
00582 return false;
00583 }
00584 }
00585
00586 void AIInstance::SaveEmpty()
00587 {
00588 _ai_sl_byte = 0;
00589 SlObject(NULL, _ai_byte);
00590 }
00591
00592 void AIInstance::Save()
00593 {
00594
00595 if (this->engine == NULL || this->engine->HasScriptCrashed()) {
00596 SaveEmpty();
00597 return;
00598 }
00599
00600 HSQUIRRELVM vm = this->engine->GetVM();
00601 if (this->is_save_data_on_stack) {
00602 _ai_sl_byte = 1;
00603 SlObject(NULL, _ai_byte);
00604
00605 SaveObject(vm, -1, AISAVE_MAX_DEPTH, false);
00606 } else if (!this->is_started) {
00607 SaveEmpty();
00608 return;
00609 } else if (this->engine->MethodExists(*this->instance, "Save")) {
00610 HSQOBJECT savedata;
00611
00612 bool backup_allow = AIObject::GetAllowDoCommand();
00613 AIObject::SetAllowDoCommand(false);
00614 try {
00615 if (!this->engine->CallMethod(*this->instance, "Save", &savedata)) {
00616
00617
00618 SaveEmpty();
00619 this->engine->CrashOccurred();
00620 return;
00621 }
00622 } catch (AI_FatalError e) {
00623
00624
00625 this->is_dead = true;
00626 this->engine->ThrowError(e.GetErrorMessage());
00627 this->engine->ResumeError();
00628 SaveEmpty();
00629
00630
00631 this->is_dead = false;
00632 this->engine->CrashOccurred();
00633 return;
00634 }
00635 AIObject::SetAllowDoCommand(backup_allow);
00636
00637 if (!sq_istable(savedata)) {
00638 AILog::Error("Save function should return a table.");
00639 SaveEmpty();
00640 this->engine->CrashOccurred();
00641 return;
00642 }
00643 sq_pushobject(vm, savedata);
00644 if (SaveObject(vm, -1, AISAVE_MAX_DEPTH, true)) {
00645 _ai_sl_byte = 1;
00646 SlObject(NULL, _ai_byte);
00647 SaveObject(vm, -1, AISAVE_MAX_DEPTH, false);
00648 this->is_save_data_on_stack = true;
00649 } else {
00650 SaveEmpty();
00651 this->engine->CrashOccurred();
00652 }
00653 } else {
00654 AILog::Warning("Save function is not implemented");
00655 _ai_sl_byte = 0;
00656 SlObject(NULL, _ai_byte);
00657 }
00658
00659 }
00660
00661 bool AIInstance::LoadObjects(HSQUIRRELVM vm)
00662 {
00663 SlObject(NULL, _ai_byte);
00664 switch (_ai_sl_byte) {
00665 case SQSL_INT: {
00666 int value;
00667 SlArray(&value, 1, SLE_INT32);
00668 if (vm != NULL) sq_pushinteger(vm, (SQInteger)value);
00669 return true;
00670 }
00671
00672 case SQSL_STRING: {
00673 SlObject(NULL, _ai_byte);
00674 static char buf[256];
00675 SlArray(buf, _ai_sl_byte, SLE_CHAR);
00676 if (vm != NULL) sq_pushstring(vm, OTTD2SQ(buf), -1);
00677 return true;
00678 }
00679
00680 case SQSL_ARRAY: {
00681 if (vm != NULL) sq_newarray(vm, 0);
00682 while (LoadObjects(vm)) {
00683 if (vm != NULL) sq_arrayappend(vm, -2);
00684
00685 }
00686 return true;
00687 }
00688
00689 case SQSL_TABLE: {
00690 if (vm != NULL) sq_newtable(vm);
00691 while (LoadObjects(vm)) {
00692 LoadObjects(vm);
00693 if (vm != NULL) sq_rawset(vm, -3);
00694
00695 }
00696 return true;
00697 }
00698
00699 case SQSL_BOOL: {
00700 SlObject(NULL, _ai_byte);
00701 if (vm != NULL) sq_pushinteger(vm, (SQBool)(_ai_sl_byte != 0));
00702 return true;
00703 }
00704
00705 case SQSL_NULL: {
00706 if (vm != NULL) sq_pushnull(vm);
00707 return true;
00708 }
00709
00710 case SQSL_ARRAY_TABLE_END: {
00711 return false;
00712 }
00713
00714 default: NOT_REACHED();
00715 }
00716 }
00717
00718 void AIInstance::LoadEmpty()
00719 {
00720 SlObject(NULL, _ai_byte);
00721
00722 if (_ai_sl_byte == 0) return;
00723
00724 LoadObjects(NULL);
00725 }
00726
00727 void AIInstance::Load(int version)
00728 {
00729 if (this->engine == NULL || version == -1) {
00730 LoadEmpty();
00731 return;
00732 }
00733 HSQUIRRELVM vm = this->engine->GetVM();
00734
00735 SlObject(NULL, _ai_byte);
00736
00737 if (_ai_sl_byte == 0) return;
00738
00739 sq_pushinteger(vm, version);
00740 LoadObjects(vm);
00741 this->is_save_data_on_stack = true;
00742 }
00743
00744 bool AIInstance::CallLoad()
00745 {
00746 HSQUIRRELVM vm = this->engine->GetVM();
00747
00748 if (!this->is_save_data_on_stack) return true;
00749
00750 this->is_save_data_on_stack = false;
00751
00752 if (!this->engine->MethodExists(*this->instance, "Load")) {
00753 AILog::Warning("Loading failed: there was data for the AI to load, but the AI does not have a Load() function.");
00754
00755
00756 sq_pop(vm, 2);
00757 return true;
00758 }
00759
00760
00761 sq_pushobject(vm, *this->instance);
00762
00763 sq_pushstring(vm, OTTD2SQ("Load"), -1);
00764
00765 sq_get(vm, -2);
00766
00767 sq_pushobject(vm, *this->instance);
00768
00769 sq_push(vm, -5);
00770 sq_push(vm, -5);
00771
00772
00773
00774 if (SQ_FAILED(sq_call(vm, 3, SQFalse, SQFalse, 100000))) return false;
00775
00776
00777 sq_pop(vm, 4);
00778 return true;
00779 }