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