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