~ubuntu-branches/debian/squeeze/openttd/squeeze

« back to all changes in this revision

Viewing changes to src/ai/ai_instance.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Matthijs Kooijman, Matthijs Kooijman
  • Date: 2009-10-01 22:52:59 UTC
  • mfrom: (1.1.8 upstream) (2.1.6 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091001225259-5kpkp4sthbszpyif
[ Matthijs Kooijman ]
* New upstream release
* Use printf instead of echo -en in openttd-wrapper to make it POSIX
  compatible (Closes: #547758).
* Remove three patches that are now included in upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: ai_instance.cpp 16481 2009-05-31 12:18:03Z rubidium $ */
 
1
/* $Id: ai_instance.cpp 17564 2009-09-18 07:00:35Z rubidium $ */
2
2
 
3
3
/** @file ai_instance.cpp Implementation of AIInstance. */
4
4
 
100
100
        instance(NULL),
101
101
        is_started(false),
102
102
        is_dead(false),
 
103
        is_save_data_on_stack(false),
103
104
        suspend(0),
104
105
        callback(NULL)
105
106
{
118
119
        /* Register the AIController */
119
120
        SQAIController_Register(this->engine);
120
121
 
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)) {
127
 
                this->Died();
128
 
                return;
129
 
        }
130
 
 
131
 
        /* Create the main-class */
132
 
        this->instance = MallocT<SQObject>(1);
133
 
        if (!this->engine->CreateClassInstance(info->GetInstanceName(), this->controller, this->instance)) {
134
 
                this->Died();
135
 
                return;
136
 
        }
137
 
 
138
122
        /* Register the API functions and classes */
139
123
        this->RegisterAPI();
140
124
 
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);
 
125
        try {
 
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.");
 
134
                        this->Died();
 
135
                        return;
 
136
                }
 
137
 
 
138
                /* Create the main-class */
 
139
                this->instance = MallocT<SQObject>(1);
 
140
                if (!this->engine->CreateClassInstance(info->GetInstanceName(), this->controller, this->instance)) {
 
141
                        this->Died();
 
142
                        return;
 
143
                }
 
144
                AIObject::SetAllowDoCommand(true);
 
145
        } catch (AI_FatalError e) {
 
146
                this->is_dead = true;
 
147
                this->engine->ThrowError(e.GetErrorMessage());
 
148
                this->engine->ResumeError();
 
149
                this->Died();
 
150
        }
144
151
}
145
152
 
146
153
AIInstance::~AIInstance()
272
279
 
273
280
void AIInstance::GameLoop()
274
281
{
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. */
278
285
                this->Died();
286
293
 
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;
 
299
                }
289
300
                try {
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();
 
339
                        this->Died();
324
340
                }
325
341
 
326
342
                this->is_started = true;
327
343
                return;
328
344
        }
 
345
        if (this->is_save_data_on_stack) {
 
346
                sq_poptop(this->engine->GetVM());
 
347
                this->is_save_data_on_stack = false;
 
348
        }
329
349
 
330
350
        /* Continue the VM */
331
351
        try {
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();
 
360
                this->Died();
336
361
        }
337
362
}
338
363
 
339
364
void AIInstance::CollectGarbage()
340
365
{
341
 
        if (this->is_started && !this->is_dead) this->engine->CollectGarbage();
 
366
        if (this->is_started && !this->IsDead()) this->engine->CollectGarbage();
342
367
}
343
368
 
344
369
/* static */ void AIInstance::DoCommandReturn(AIInstance *instance)
544
569
        }
545
570
 
546
571
        HSQUIRRELVM vm = this->engine->GetVM();
547
 
        if (!this->is_started) {
548
 
                SQBool res;
549
 
                sq_getbool(vm, -1, &res);
550
 
                if (!res) {
551
 
                        SaveEmpty();
552
 
                        return;
553
 
                }
554
 
                /* Push the loaded savegame data to the top of the stack. */
555
 
                sq_push(vm, -2);
 
572
        if (this->is_save_data_on_stack) {
556
573
                _ai_sl_byte = 1;
557
574
                SlObject(NULL, _ai_byte);
558
575
                /* Save the data that was just loaded. */
559
576
                SaveObject(vm, -1, AISAVE_MAX_DEPTH, false);
560
 
                sq_poptop(vm);
 
577
        } else if (!this->is_started) {
 
578
                SaveEmpty();
 
579
                return;
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. */
 
585
                try {
 
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. */
 
589
                                SaveEmpty();
 
590
                                this->engine->CrashOccurred();
 
591
                                return;
 
592
                        }
 
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();
569
599
                        SaveEmpty();
 
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();
570
604
                        return;
571
605
                }
572
606
                AIObject::SetAllowDoCommand(backup_allow);
574
608
                if (!sq_istable(savedata)) {
575
609
                        AILog::Error("Save function should return a table.");
576
610
                        SaveEmpty();
 
611
                        this->engine->CrashOccurred();
577
612
                        return;
578
613
                }
579
614
                sq_pushobject(vm, savedata);
581
616
                        _ai_sl_byte = 1;
582
617
                        SlObject(NULL, _ai_byte);
583
618
                        SaveObject(vm, -1, AISAVE_MAX_DEPTH, false);
 
619
                        this->is_save_data_on_stack = true;
584
620
                } else {
585
 
                        _ai_sl_byte = 0;
586
 
                        SlObject(NULL, _ai_byte);
 
621
                        SaveEmpty();
 
622
                        this->engine->CrashOccurred();
587
623
                }
588
 
                sq_pop(vm, 1);
589
624
        } else {
590
625
                AILog::Warning("Save function is not implemented");
591
626
                _ai_sl_byte = 0;
672
707
        /* Check if there was anything saved at all. */
673
708
        if (_ai_sl_byte == 0) return;
674
709
 
675
 
        /* First remove the value "false" since we have data to load. */
676
 
        sq_poptop(vm);
677
710
        sq_pushinteger(vm, version);
678
711
        LoadObjects(vm);
679
 
        sq_pushbool(vm, true);
 
712
        this->is_save_data_on_stack = true;
680
713
}
681
714
 
682
715
bool AIInstance::CallLoad()
683
716
{
684
717
        HSQUIRRELVM vm = this->engine->GetVM();
685
718
        /* Is there save data that we should load? */
686
 
        SQBool res;
687
 
        sq_getbool(vm, -1, &res);
688
 
        sq_poptop(vm);
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;
690
722
 
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.");