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 SQAIEventVehicleCrashed_Register(this->engine);
00213 SQAIEventVehicleLost_Register(this->engine);
00214 SQAIEventVehicleUnprofitable_Register(this->engine);
00215 SQAIEventVehicleWaitingInDepot_Register(this->engine);
00216 SQAIExecMode_Register(this->engine);
00217 SQAIGameSettings_Register(this->engine);
00218 SQAIGroup_Register(this->engine);
00219 SQAIGroupList_Register(this->engine);
00220 SQAIIndustry_Register(this->engine);
00221 SQAIIndustryList_Register(this->engine);
00222 SQAIIndustryList_CargoAccepting_Register(this->engine);
00223 SQAIIndustryList_CargoProducing_Register(this->engine);
00224 SQAIIndustryType_Register(this->engine);
00225 SQAIIndustryTypeList_Register(this->engine);
00226 SQAILog_Register(this->engine);
00227 SQAIMap_Register(this->engine);
00228 SQAIMarine_Register(this->engine);
00229 SQAIOrder_Register(this->engine);
00230 SQAIRail_Register(this->engine);
00231 SQAIRailTypeList_Register(this->engine);
00232 SQAIRoad_Register(this->engine);
00233 SQAISign_Register(this->engine);
00234 SQAISignList_Register(this->engine);
00235 SQAIStation_Register(this->engine);
00236 SQAIStationList_Register(this->engine);
00237 SQAIStationList_Vehicle_Register(this->engine);
00238 SQAISubsidy_Register(this->engine);
00239 SQAISubsidyList_Register(this->engine);
00240 SQAITestMode_Register(this->engine);
00241 SQAITile_Register(this->engine);
00242 SQAITileList_Register(this->engine);
00243 SQAITileList_IndustryAccepting_Register(this->engine);
00244 SQAITileList_IndustryProducing_Register(this->engine);
00245 SQAITileList_StationType_Register(this->engine);
00246 SQAITown_Register(this->engine);
00247 SQAITownList_Register(this->engine);
00248 SQAITunnel_Register(this->engine);
00249 SQAIVehicle_Register(this->engine);
00250 SQAIVehicleList_Register(this->engine);
00251 SQAIVehicleList_DefaultGroup_Register(this->engine);
00252 SQAIVehicleList_Depot_Register(this->engine);
00253 SQAIVehicleList_Group_Register(this->engine);
00254 SQAIVehicleList_SharedOrders_Register(this->engine);
00255 SQAIVehicleList_Station_Register(this->engine);
00256 SQAIWaypoint_Register(this->engine);
00257 SQAIWaypointList_Register(this->engine);
00258 SQAIWaypointList_Vehicle_Register(this->engine);
00259
00260 this->engine->SetGlobalPointer(this->engine);
00261 }
00262
00263 bool AIInstance::LoadCompatibilityScripts(const char *api_version)
00264 {
00265 char script_name[32];
00266 seprintf(script_name, lastof(script_name), "compat_%s.nut", api_version);
00267 char buf[MAX_PATH];
00268 Searchpath sp;
00269 FOR_ALL_SEARCHPATHS(sp) {
00270 FioAppendDirectory(buf, MAX_PATH, sp, AI_DIR);
00271 ttd_strlcat(buf, script_name, MAX_PATH);
00272 if (!FileExists(buf)) continue;
00273
00274 if (this->engine->LoadScript(buf)) return true;
00275
00276 AILog::Error("Failed to load API compatibility script");
00277 DEBUG(ai, 0, "Error compiling / running API compatibility script: %s", buf);
00278 return false;
00279 }
00280
00281 AILog::Warning("API compatibility script not found");
00282 return true;
00283 }
00284
00285 void AIInstance::Continue()
00286 {
00287 assert(this->suspend < 0);
00288 this->suspend = -this->suspend - 1;
00289 }
00290
00291 void AIInstance::Died()
00292 {
00293 DEBUG(ai, 0, "The AI died unexpectedly.");
00294 this->is_dead = true;
00295
00296 if (this->instance != NULL) this->engine->ReleaseObject(this->instance);
00297 delete this->engine;
00298 this->instance = NULL;
00299 this->engine = NULL;
00300
00301 ShowAIDebugWindow(_current_company);
00302
00303 const AIInfo *info = AIConfig::GetConfig(_current_company)->GetInfo();
00304 if (info != NULL) {
00305 ShowErrorMessage(STR_ERROR_AI_PLEASE_REPORT_CRASH, INVALID_STRING_ID, WL_WARNING);
00306
00307 if (info->GetURL() != NULL) {
00308 AILog::Info("Please report the error to the following URL:");
00309 AILog::Info(info->GetURL());
00310 }
00311 }
00312 }
00313
00314 void AIInstance::GameLoop()
00315 {
00316 if (this->IsDead()) return;
00317 if (this->engine->HasScriptCrashed()) {
00318
00319 this->Died();
00320 return;
00321 }
00322 this->controller->ticks++;
00323
00324 if (this->suspend < -1) this->suspend++;
00325 if (this->suspend < 0) return;
00326 if (--this->suspend > 0) return;
00327
00328
00329 if (this->callback != NULL) {
00330 if (this->is_save_data_on_stack) {
00331 sq_poptop(this->engine->GetVM());
00332 this->is_save_data_on_stack = false;
00333 }
00334 try {
00335 this->callback(this);
00336 } catch (AI_VMSuspend e) {
00337 this->suspend = e.GetSuspendTime();
00338 this->callback = e.GetSuspendCallback();
00339
00340 return;
00341 }
00342 }
00343
00344 this->suspend = 0;
00345 this->callback = NULL;
00346
00347 if (!this->is_started) {
00348 try {
00349 AIObject::SetAllowDoCommand(false);
00350
00351 if (this->engine->MethodExists(*this->instance, "constructor")) {
00352 if (!this->engine->CallMethod(*this->instance, "constructor", MAX_CONSTRUCTOR_OPS) || this->engine->IsSuspended()) {
00353 if (this->engine->IsSuspended()) AILog::Error("This AI took too long to initialize. AI is not started.");
00354 this->Died();
00355 return;
00356 }
00357 }
00358 if (!this->CallLoad() || this->engine->IsSuspended()) {
00359 if (this->engine->IsSuspended()) AILog::Error("This AI took too long in the Load function. AI is not started.");
00360 this->Died();
00361 return;
00362 }
00363 AIObject::SetAllowDoCommand(true);
00364
00365 if (!this->engine->CallMethod(*this->instance, "Start", _settings_game.ai.ai_max_opcode_till_suspend) || !this->engine->IsSuspended()) this->Died();
00366 } catch (AI_VMSuspend e) {
00367 this->suspend = e.GetSuspendTime();
00368 this->callback = e.GetSuspendCallback();
00369 } catch (AI_FatalError e) {
00370 this->is_dead = true;
00371 this->engine->ThrowError(e.GetErrorMessage());
00372 this->engine->ResumeError();
00373 this->Died();
00374 }
00375
00376 this->is_started = true;
00377 return;
00378 }
00379 if (this->is_save_data_on_stack) {
00380 sq_poptop(this->engine->GetVM());
00381 this->is_save_data_on_stack = false;
00382 }
00383
00384
00385 try {
00386 if (!this->engine->Resume(_settings_game.ai.ai_max_opcode_till_suspend)) this->Died();
00387 } catch (AI_VMSuspend e) {
00388 this->suspend = e.GetSuspendTime();
00389 this->callback = e.GetSuspendCallback();
00390 } catch (AI_FatalError e) {
00391 this->is_dead = true;
00392 this->engine->ThrowError(e.GetErrorMessage());
00393 this->engine->ResumeError();
00394 this->Died();
00395 }
00396 }
00397
00398 void AIInstance::CollectGarbage() const
00399 {
00400 if (this->is_started && !this->IsDead()) this->engine->CollectGarbage();
00401 }
00402
00403 void AIInstance::DoCommandReturn(AIInstance *instance)
00404 {
00405 instance->engine->InsertResult(AIObject::GetLastCommandRes());
00406 }
00407
00408 void AIInstance::DoCommandReturnVehicleID(AIInstance *instance)
00409 {
00410 instance->engine->InsertResult(AIObject::GetNewVehicleID());
00411 }
00412
00413 void AIInstance::DoCommandReturnSignID(AIInstance *instance)
00414 {
00415 instance->engine->InsertResult(AIObject::GetNewSignID());
00416 }
00417
00418 void AIInstance::DoCommandReturnGroupID(AIInstance *instance)
00419 {
00420 instance->engine->InsertResult(AIObject::GetNewGroupID());
00421 }
00422
00423 AIStorage *AIInstance::GetStorage()
00424 {
00425 assert(Company::IsValidAiID(_current_company));
00426 return Company::Get(_current_company)->ai_instance->storage;
00427 }
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00451 enum SQSaveLoadType {
00452 SQSL_INT = 0x00,
00453 SQSL_STRING = 0x01,
00454 SQSL_ARRAY = 0x02,
00455 SQSL_TABLE = 0x03,
00456 SQSL_BOOL = 0x04,
00457 SQSL_NULL = 0x05,
00458 SQSL_ARRAY_TABLE_END = 0xFF,
00459 };
00460
00461 static byte _ai_sl_byte;
00462
00464 static const SaveLoad _ai_byte[] = {
00465 SLEG_VAR(_ai_sl_byte, SLE_UINT8),
00466 SLE_END()
00467 };
00468
00469 static const uint AISAVE_MAX_DEPTH = 25;
00470
00471 bool AIInstance::SaveObject(HSQUIRRELVM vm, SQInteger index, int max_depth, bool test)
00472 {
00473 if (max_depth == 0) {
00474 AILog::Error("Savedata can only be nested to 25 deep. No data saved.");
00475 return false;
00476 }
00477
00478 switch (sq_gettype(vm, index)) {
00479 case OT_INTEGER: {
00480 if (!test) {
00481 _ai_sl_byte = SQSL_INT;
00482 SlObject(NULL, _ai_byte);
00483 }
00484 SQInteger res;
00485 sq_getinteger(vm, index, &res);
00486 if (!test) {
00487 int value = (int)res;
00488 SlArray(&value, 1, SLE_INT32);
00489 }
00490 return true;
00491 }
00492
00493 case OT_STRING: {
00494 if (!test) {
00495 _ai_sl_byte = SQSL_STRING;
00496 SlObject(NULL, _ai_byte);
00497 }
00498 const SQChar *res;
00499 sq_getstring(vm, index, &res);
00500
00501
00502 const char *buf = SQ2OTTD(res);
00503 size_t len = strlen(buf) + 1;
00504 if (len >= 255) {
00505 AILog::Error("Maximum string length is 254 chars. No data saved.");
00506 return false;
00507 }
00508 if (!test) {
00509 _ai_sl_byte = (byte)len;
00510 SlObject(NULL, _ai_byte);
00511 SlArray((void*)buf, len, SLE_CHAR);
00512 }
00513 return true;
00514 }
00515
00516 case OT_ARRAY: {
00517 if (!test) {
00518 _ai_sl_byte = SQSL_ARRAY;
00519 SlObject(NULL, _ai_byte);
00520 }
00521 sq_pushnull(vm);
00522 while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
00523
00524 bool res = SaveObject(vm, -1, max_depth - 1, test);
00525 sq_pop(vm, 2);
00526 if (!res) {
00527 sq_pop(vm, 1);
00528 return false;
00529 }
00530 }
00531 sq_pop(vm, 1);
00532 if (!test) {
00533 _ai_sl_byte = SQSL_ARRAY_TABLE_END;
00534 SlObject(NULL, _ai_byte);
00535 }
00536 return true;
00537 }
00538
00539 case OT_TABLE: {
00540 if (!test) {
00541 _ai_sl_byte = SQSL_TABLE;
00542 SlObject(NULL, _ai_byte);
00543 }
00544 sq_pushnull(vm);
00545 while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
00546
00547 bool res = SaveObject(vm, -2, max_depth - 1, test) && SaveObject(vm, -1, max_depth - 1, test);
00548 sq_pop(vm, 2);
00549 if (!res) {
00550 sq_pop(vm, 1);
00551 return false;
00552 }
00553 }
00554 sq_pop(vm, 1);
00555 if (!test) {
00556 _ai_sl_byte = SQSL_ARRAY_TABLE_END;
00557 SlObject(NULL, _ai_byte);
00558 }
00559 return true;
00560 }
00561
00562 case OT_BOOL: {
00563 if (!test) {
00564 _ai_sl_byte = SQSL_BOOL;
00565 SlObject(NULL, _ai_byte);
00566 }
00567 SQBool res;
00568 sq_getbool(vm, index, &res);
00569 if (!test) {
00570 _ai_sl_byte = res ? 1 : 0;
00571 SlObject(NULL, _ai_byte);
00572 }
00573 return true;
00574 }
00575
00576 case OT_NULL: {
00577 if (!test) {
00578 _ai_sl_byte = SQSL_NULL;
00579 SlObject(NULL, _ai_byte);
00580 }
00581 return true;
00582 }
00583
00584 default:
00585 AILog::Error("You tried to save an unsupported type. No data saved.");
00586 return false;
00587 }
00588 }
00589
00590 void AIInstance::SaveEmpty()
00591 {
00592 _ai_sl_byte = 0;
00593 SlObject(NULL, _ai_byte);
00594 }
00595
00596 void AIInstance::Save()
00597 {
00598
00599 if (this->engine == NULL || this->engine->HasScriptCrashed()) {
00600 SaveEmpty();
00601 return;
00602 }
00603
00604 HSQUIRRELVM vm = this->engine->GetVM();
00605 if (this->is_save_data_on_stack) {
00606 _ai_sl_byte = 1;
00607 SlObject(NULL, _ai_byte);
00608
00609 SaveObject(vm, -1, AISAVE_MAX_DEPTH, false);
00610 } else if (!this->is_started) {
00611 SaveEmpty();
00612 return;
00613 } else if (this->engine->MethodExists(*this->instance, "Save")) {
00614 HSQOBJECT savedata;
00615
00616 bool backup_allow = AIObject::GetAllowDoCommand();
00617 AIObject::SetAllowDoCommand(false);
00618 try {
00619 if (!this->engine->CallMethod(*this->instance, "Save", &savedata, MAX_SL_OPS)) {
00620
00621
00622 SaveEmpty();
00623 this->engine->CrashOccurred();
00624 return;
00625 }
00626 } catch (AI_FatalError e) {
00627
00628
00629 this->is_dead = true;
00630 this->engine->ThrowError(e.GetErrorMessage());
00631 this->engine->ResumeError();
00632 SaveEmpty();
00633
00634
00635 this->is_dead = false;
00636 this->engine->CrashOccurred();
00637 return;
00638 }
00639 AIObject::SetAllowDoCommand(backup_allow);
00640
00641 if (!sq_istable(savedata)) {
00642 AILog::Error(this->engine->IsSuspended() ? "This AI took too long to Save." : "Save function should return a table.");
00643 SaveEmpty();
00644 this->engine->CrashOccurred();
00645 return;
00646 }
00647 sq_pushobject(vm, savedata);
00648 if (SaveObject(vm, -1, AISAVE_MAX_DEPTH, true)) {
00649 _ai_sl_byte = 1;
00650 SlObject(NULL, _ai_byte);
00651 SaveObject(vm, -1, AISAVE_MAX_DEPTH, false);
00652 this->is_save_data_on_stack = true;
00653 } else {
00654 SaveEmpty();
00655 this->engine->CrashOccurred();
00656 }
00657 } else {
00658 AILog::Warning("Save function is not implemented");
00659 _ai_sl_byte = 0;
00660 SlObject(NULL, _ai_byte);
00661 }
00662
00663 }
00664
00665 void AIInstance::Suspend()
00666 {
00667 HSQUIRRELVM vm = this->engine->GetVM();
00668 Squirrel::DecreaseOps(vm, _settings_game.ai.ai_max_opcode_till_suspend);
00669 }
00670
00671 bool AIInstance::LoadObjects(HSQUIRRELVM vm)
00672 {
00673 SlObject(NULL, _ai_byte);
00674 switch (_ai_sl_byte) {
00675 case SQSL_INT: {
00676 int value;
00677 SlArray(&value, 1, SLE_INT32);
00678 if (vm != NULL) sq_pushinteger(vm, (SQInteger)value);
00679 return true;
00680 }
00681
00682 case SQSL_STRING: {
00683 SlObject(NULL, _ai_byte);
00684 static char buf[256];
00685 SlArray(buf, _ai_sl_byte, SLE_CHAR);
00686 if (vm != NULL) sq_pushstring(vm, OTTD2SQ(buf), -1);
00687 return true;
00688 }
00689
00690 case SQSL_ARRAY: {
00691 if (vm != NULL) sq_newarray(vm, 0);
00692 while (LoadObjects(vm)) {
00693 if (vm != NULL) sq_arrayappend(vm, -2);
00694
00695 }
00696 return true;
00697 }
00698
00699 case SQSL_TABLE: {
00700 if (vm != NULL) sq_newtable(vm);
00701 while (LoadObjects(vm)) {
00702 LoadObjects(vm);
00703 if (vm != NULL) sq_rawset(vm, -3);
00704
00705 }
00706 return true;
00707 }
00708
00709 case SQSL_BOOL: {
00710 SlObject(NULL, _ai_byte);
00711 if (vm != NULL) sq_pushinteger(vm, (SQBool)(_ai_sl_byte != 0));
00712 return true;
00713 }
00714
00715 case SQSL_NULL: {
00716 if (vm != NULL) sq_pushnull(vm);
00717 return true;
00718 }
00719
00720 case SQSL_ARRAY_TABLE_END: {
00721 return false;
00722 }
00723
00724 default: NOT_REACHED();
00725 }
00726 }
00727
00728 void AIInstance::LoadEmpty()
00729 {
00730 SlObject(NULL, _ai_byte);
00731
00732 if (_ai_sl_byte == 0) return;
00733
00734 LoadObjects(NULL);
00735 }
00736
00737 void AIInstance::Load(int version)
00738 {
00739 if (this->engine == NULL || version == -1) {
00740 LoadEmpty();
00741 return;
00742 }
00743 HSQUIRRELVM vm = this->engine->GetVM();
00744
00745 SlObject(NULL, _ai_byte);
00746
00747 if (_ai_sl_byte == 0) return;
00748
00749 sq_pushinteger(vm, version);
00750 LoadObjects(vm);
00751 this->is_save_data_on_stack = true;
00752 }
00753
00754 bool AIInstance::CallLoad()
00755 {
00756 HSQUIRRELVM vm = this->engine->GetVM();
00757
00758 if (!this->is_save_data_on_stack) return true;
00759
00760 this->is_save_data_on_stack = false;
00761
00762 if (!this->engine->MethodExists(*this->instance, "Load")) {
00763 AILog::Warning("Loading failed: there was data for the AI to load, but the AI does not have a Load() function.");
00764
00765
00766 sq_pop(vm, 2);
00767 return true;
00768 }
00769
00770
00771 sq_pushobject(vm, *this->instance);
00772
00773 sq_pushstring(vm, OTTD2SQ("Load"), -1);
00774
00775 sq_get(vm, -2);
00776
00777 sq_pushobject(vm, *this->instance);
00778
00779 sq_push(vm, -5);
00780 sq_push(vm, -5);
00781
00782
00783
00784 if (SQ_FAILED(sq_call(vm, 3, SQFalse, SQFalse, MAX_SL_OPS))) return false;
00785
00786
00787 sq_pop(vm, 4);
00788 return true;
00789 }