118
119
/* Register the AIController */
119
120
SQAIController_Register(this->engine);
121
/* Load and execute the script for this AI */
122
const char *main_script = info->GetMainScript();
123
if (strcmp(main_script, "%_dummy") == 0) {
124
extern void AI_CreateAIDummy(HSQUIRRELVM vm);
125
AI_CreateAIDummy(this->engine->GetVM());
126
} else if (!this->engine->LoadScript(main_script)) {
131
/* Create the main-class */
132
this->instance = MallocT<SQObject>(1);
133
if (!this->engine->CreateClassInstance(info->GetInstanceName(), this->controller, this->instance)) {
138
122
/* Register the API functions and classes */
139
123
this->RegisterAPI();
141
/* The topmost stack item is true if there is data from a savegame
142
* and false otherwise. */
143
sq_pushbool(this->engine->vm, false);
126
AIObject::SetAllowDoCommand(false);
127
/* Load and execute the script for this AI */
128
const char *main_script = info->GetMainScript();
129
if (strcmp(main_script, "%_dummy") == 0) {
130
extern void AI_CreateAIDummy(HSQUIRRELVM vm);
131
AI_CreateAIDummy(this->engine->GetVM());
132
} else if (!this->engine->LoadScript(main_script) || this->engine->IsSuspended()) {
133
if (this->engine->IsSuspended()) AILog::Error("This AI took too long to load script. AI is not started.");
138
/* Create the main-class */
139
this->instance = MallocT<SQObject>(1);
140
if (!this->engine->CreateClassInstance(info->GetInstanceName(), this->controller, this->instance)) {
144
AIObject::SetAllowDoCommand(true);
145
} catch (AI_FatalError e) {
146
this->is_dead = true;
147
this->engine->ThrowError(e.GetErrorMessage());
148
this->engine->ResumeError();
146
153
AIInstance::~AIInstance()
273
280
void AIInstance::GameLoop()
275
if (this->is_dead) return;
282
if (this->IsDead()) return;
276
283
if (this->engine->HasScriptCrashed()) {
277
284
/* The script crashed during saving, kill it here. */
287
294
/* If there is a callback to call, call that first */
288
295
if (this->callback != NULL) {
296
if (this->is_save_data_on_stack) {
297
sq_poptop(this->engine->GetVM());
298
this->is_save_data_on_stack = false;
290
301
this->callback(this);
291
302
} catch (AI_VMSuspend e) {
321
332
} catch (AI_VMSuspend e) {
322
333
this->suspend = e.GetSuspendTime();
323
334
this->callback = e.GetSuspendCallback();
335
} catch (AI_FatalError e) {
336
this->is_dead = true;
337
this->engine->ThrowError(e.GetErrorMessage());
338
this->engine->ResumeError();
326
342
this->is_started = true;
345
if (this->is_save_data_on_stack) {
346
sq_poptop(this->engine->GetVM());
347
this->is_save_data_on_stack = false;
330
350
/* Continue the VM */
333
353
} catch (AI_VMSuspend e) {
334
354
this->suspend = e.GetSuspendTime();
335
355
this->callback = e.GetSuspendCallback();
356
} catch (AI_FatalError e) {
357
this->is_dead = true;
358
this->engine->ThrowError(e.GetErrorMessage());
359
this->engine->ResumeError();
339
364
void AIInstance::CollectGarbage()
341
if (this->is_started && !this->is_dead) this->engine->CollectGarbage();
366
if (this->is_started && !this->IsDead()) this->engine->CollectGarbage();
344
369
/* static */ void AIInstance::DoCommandReturn(AIInstance *instance)
546
571
HSQUIRRELVM vm = this->engine->GetVM();
547
if (!this->is_started) {
549
sq_getbool(vm, -1, &res);
554
/* Push the loaded savegame data to the top of the stack. */
572
if (this->is_save_data_on_stack) {
557
574
SlObject(NULL, _ai_byte);
558
575
/* Save the data that was just loaded. */
559
576
SaveObject(vm, -1, AISAVE_MAX_DEPTH, false);
577
} else if (!this->is_started) {
561
580
} else if (this->engine->MethodExists(*this->instance, "Save")) {
562
581
HSQOBJECT savedata;
563
582
/* We don't want to be interrupted during the save function. */
564
583
bool backup_allow = AIObject::GetAllowDoCommand();
565
584
AIObject::SetAllowDoCommand(false);
566
if (!this->engine->CallMethod(*this->instance, "Save", &savedata)) {
567
/* The script crashed in the Save function. We can't kill
568
* it here, but do so in the next AI tick. */
586
if (!this->engine->CallMethod(*this->instance, "Save", &savedata)) {
587
/* The script crashed in the Save function. We can't kill
588
* it here, but do so in the next AI tick. */
590
this->engine->CrashOccurred();
593
} catch (AI_FatalError e) {
594
/* If we don't mark the AI as dead here cleaning up the squirrel
595
* stack could throw AI_FatalError again. */
596
this->is_dead = true;
597
this->engine->ThrowError(e.GetErrorMessage());
598
this->engine->ResumeError();
600
/* We can't kill the AI here, so mark it as crashed (not dead) and
601
* kill it in the next AI tick. */
602
this->is_dead = false;
603
this->engine->CrashOccurred();
572
606
AIObject::SetAllowDoCommand(backup_allow);
574
608
if (!sq_istable(savedata)) {
575
609
AILog::Error("Save function should return a table.");
611
this->engine->CrashOccurred();
579
614
sq_pushobject(vm, savedata);
582
617
SlObject(NULL, _ai_byte);
583
618
SaveObject(vm, -1, AISAVE_MAX_DEPTH, false);
619
this->is_save_data_on_stack = true;
586
SlObject(NULL, _ai_byte);
622
this->engine->CrashOccurred();
590
625
AILog::Warning("Save function is not implemented");
672
707
/* Check if there was anything saved at all. */
673
708
if (_ai_sl_byte == 0) return;
675
/* First remove the value "false" since we have data to load. */
677
710
sq_pushinteger(vm, version);
679
sq_pushbool(vm, true);
712
this->is_save_data_on_stack = true;
682
715
bool AIInstance::CallLoad()
684
717
HSQUIRRELVM vm = this->engine->GetVM();
685
718
/* Is there save data that we should load? */
687
sq_getbool(vm, -1, &res);
689
if (!res) return true;
719
if (!this->is_save_data_on_stack) return true;
720
/* Whatever happens, after CallLoad the savegame data is removed from the stack. */
721
this->is_save_data_on_stack = false;
691
723
if (!this->engine->MethodExists(*this->instance, "Load")) {
692
724
AILog::Warning("Loading failed: there was data for the AI to load, but the AI does not have a Load() function.");