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