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