~ubuntu-branches/ubuntu/precise/widelands/precise-backports

« back to all changes in this revision

Viewing changes to src/bob.cc

  • Committer: Bazaar Package Importer
  • Author(s): Martin Quinson
  • Date: 2005-02-14 10:41:12 UTC
  • Revision ID: james.westby@ubuntu.com-20050214104112-6v08iux9fptxpva9
Tags: upstream-build9
Import upstream version build9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2002-2004 by The Widelands Development Team
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU General Public License
 
6
 * as published by the Free Software Foundation; either version 2
 
7
 * of the License, or (at your option) any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software
 
16
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
17
 *
 
18
 */
 
19
 
 
20
#include <stdio.h>
 
21
#include "animation.h"
 
22
#include "bob.h"
 
23
#include "critter_bob.h"
 
24
#include "game.h"
 
25
#include "map.h"
 
26
#include "player.h"
 
27
#include "profile.h"
 
28
#include "rendertarget.h"
 
29
#include "transport.h"
 
30
#include "tribe.h"
 
31
#include "wexception.h"
 
32
 
 
33
 
 
34
/*
 
35
==============================================================================
 
36
 
 
37
Bob IMPLEMENTATION
 
38
 
 
39
==============================================================================
 
40
*/
 
41
 
 
42
/*
 
43
===============
 
44
Bob_Descr::Bob_Descr
 
45
Bob_Descr::~Bob_Descr
 
46
===============
 
47
*/
 
48
Bob_Descr::Bob_Descr(const char *name, Tribe_Descr* owner_tribe)
 
49
{
 
50
        snprintf(m_name, sizeof(m_name), "%s", name);
 
51
   m_default_encodedata.clear();
 
52
   m_owner_tribe=owner_tribe;
 
53
}
 
54
 
 
55
Bob_Descr::~Bob_Descr(void)
 
56
{
 
57
}
 
58
 
 
59
 
 
60
/*
 
61
===============
 
62
Bob_Descr::parse
 
63
 
 
64
Parse additional information from the config file
 
65
===============
 
66
*/
 
67
void Bob_Descr::parse(const char *directory, Profile *prof, const EncodeData *encdata)
 
68
{
 
69
        char picname[256];
 
70
   char buf[256];
 
71
 
 
72
   Section* global = prof->get_safe_section("idle");
 
73
 
 
74
   // Global options
 
75
        snprintf(buf, sizeof(buf), "%s_00.png", m_name);
 
76
        snprintf(picname, sizeof(picname), "%s/%s", directory, global->get_string("picture", buf));
 
77
   m_picture = picname;
 
78
 
 
79
        m_default_encodedata.parse(global);
 
80
 
 
81
        snprintf(picname, sizeof(picname), "%s_??.png", m_name);
 
82
        add_animation("idle", g_anim.get(directory, prof->get_safe_section("idle"), picname, encdata));
 
83
 
 
84
        // Parse attributes
 
85
   const char* string;
 
86
        global= prof->get_safe_section("global");
 
87
   while(global->get_next_string("attrib", &string)) {
 
88
                uint attrib = get_attribute_id(string);
 
89
 
 
90
                if (attrib < Map_Object::HIGHEST_FIXED_ATTRIBUTE)
 
91
                {
 
92
         throw wexception("Bad attribute '%s'", string);
 
93
                }
 
94
 
 
95
                add_attribute(attrib);
 
96
        }
 
97
}
 
98
 
 
99
 
 
100
/*
 
101
===============
 
102
Bob_Descr::create
 
103
 
 
104
Create a bob of this type
 
105
===============
 
106
*/
 
107
Bob *Bob_Descr::create(Editor_Game_Base *gg, Player *owner, Coords coords)
 
108
{
 
109
   Bob *bob = create_object();
 
110
   bob->set_owner(owner);
 
111
   bob->set_position(gg, coords);
 
112
   bob->init(gg);
 
113
 
 
114
   return bob;
 
115
}
 
116
 
 
117
 
 
118
/*
 
119
==============================
 
120
 
 
121
IMPLEMENTATION
 
122
 
 
123
==============================
 
124
*/
 
125
 
 
126
/*
 
127
===============
 
128
Bob::Bob
 
129
 
 
130
Zero-initialize a map object
 
131
===============
 
132
*/
 
133
Bob::Bob(Bob_Descr* descr)
 
134
        : Map_Object(descr)
 
135
{
 
136
        m_owner = 0;
 
137
        m_position.x = m_position.y = 0; // not linked anywhere
 
138
        m_position.field = 0;
 
139
        m_linknext = 0;
 
140
        m_linkpprev = 0;
 
141
 
 
142
        m_actid = 0; // this isn't strictly necessary, but it shuts up valgrind and "feels" cleaner
 
143
 
 
144
        m_anim = 0;
 
145
        m_animstart = 0;
 
146
 
 
147
        m_walking = IDLE;
 
148
        m_walkstart = m_walkend = 0;
 
149
 
 
150
        m_stack_dirty = false;
 
151
        m_sched_init_task = false;
 
152
}
 
153
 
 
154
 
 
155
/*
 
156
===============
 
157
Bob::~Bob()
 
158
 
 
159
Cleanup an object. Removes map links
 
160
===============
 
161
*/
 
162
Bob::~Bob()
 
163
{
 
164
        if (m_position.field) {
 
165
                molog("Map_Object::~Map_Object: m_pos.field != 0, cleanup() not called!\n");
 
166
                *(int *)0 = 0;
 
167
        }
 
168
}
 
169
 
 
170
 
 
171
/*
 
172
===============
 
173
Bob::get_type
 
174
===============
 
175
*/
 
176
int Bob::get_type()
 
177
{
 
178
        return BOB;
 
179
}
 
180
 
 
181
 
 
182
/*
 
183
Bobs and tasks
 
184
--------------
 
185
 
 
186
Bobs have a call-stack of "tasks". The top-most task is the one that is
 
187
currently being executed. As soon as the task is finished (either successfully
 
188
or with an error signal), it is popped from the top of the stack, and the task
 
189
that is now on top will be asked to update() itself.
 
190
 
 
191
Upon initialization, an object has no task at all. A CMD_ACT will be scheduled
 
192
automatically. When it is executed, init_auto_task() is called to automatically
 
193
select a fallback task.
 
194
However, the creator of the bob can choose to push a specific task immediately
 
195
after creating the bob. This will override the fallback behaviour.
 
196
init_auto_task() is also called when the final task is popped from the stack.
 
197
 
 
198
All state information that a task uses must be stored in the State structure
 
199
returned by get_state(). Note that every task on the task stack has its own
 
200
state structure, i.e. push_task() does not destroy the current task's state.
 
201
 
 
202
In order to start a new sub-task, you have to call push_task(), and then fill
 
203
the State structure returned by get_state() with any parameters that the task
 
204
may need.
 
205
A task is ended by pop_task(). Note, however, that you should only call
 
206
pop_task() from a task's update() or signal() function.
 
207
If you want to interrupt the current task for some reason, you should call
 
208
send_signal().
 
209
 
 
210
To implement a new task, you need to create a new Task object, and at least an
 
211
update() function. The signal() and mask() functions are optional (can be 0).
 
212
The update() function is called once after the task is pushed, and whenever a
 
213
previously scheduled CMD_ACT occured. It is also called when a sub-task is pops
 
214
itself.
 
215
update() must call either schedule_act() or skip_act() if you really don't
 
216
want a CMD_ACT to occur. Note that if you call skip_act(), your task MUST
 
217
implement signal().
 
218
Alternatively, update() can call pop_task() to end the current task.
 
219
 
 
220
signal() is usually called by send_signal().
 
221
signal() is also called when a sub-task returns while a signal is still set.
 
222
Note that after signal() called, update() is also called.
 
223
signal() must call schedule_act(), or pop_task(), or do nothing at all.
 
224
If signal() is not implemented, it is equivalent to a signal() function that
 
225
does nothing at all.
 
226
 
 
227
Whenever send_signal() is called, the mask() function of all tasks are called,
 
228
starting with the highest-level task.
 
229
The mask() function cannot schedule CMD_ACT, but it can use set_signal() to
 
230
modify or even clear the signal before it reaches the normal signal handling
 
231
functions.
 
232
*/
 
233
 
 
234
/*
 
235
===============
 
236
Bob::init
 
237
 
 
238
Make sure you call this from derived classes!
 
239
 
 
240
Initialize the object
 
241
===============
 
242
*/
 
243
void Bob::init(Editor_Game_Base* gg)
 
244
{
 
245
   Map_Object::init(gg);
 
246
                
 
247
   m_sched_init_task = true;
 
248
 
 
249
   if (gg->is_game()) {
 
250
      Game* g=static_cast<Game*>(gg);
 
251
 
 
252
                schedule_act(g, 1);
 
253
   } else {
 
254
      // In editor: play idle task forever
 
255
      set_animation(gg, get_descr()->get_animation("idle"));
 
256
   }
 
257
}
 
258
 
 
259
 
 
260
/*
 
261
===============
 
262
Bob::cleanup
 
263
 
 
264
Perform independant cleanup as necessary.
 
265
===============
 
266
*/
 
267
void Bob::cleanup(Editor_Game_Base *gg)
 
268
{
 
269
        while(m_stack.size()) {
 
270
                pop_task((Game*)gg);
 
271
                m_stack_dirty = false;
 
272
        }
 
273
 
 
274
   if (m_position.field) {
 
275
      m_position.field = 0;
 
276
      *m_linkpprev = m_linknext;
 
277
      if (m_linknext)
 
278
         m_linknext->m_linkpprev = m_linkpprev;
 
279
 
 
280
   }
 
281
   Map_Object::cleanup(gg);
 
282
}
 
283
 
 
284
 
 
285
/*
 
286
===============
 
287
Bob::act
 
288
 
 
289
Called by Cmd_Queue when a CMD_ACT event is triggered.
 
290
Hand the acting over to the task.
 
291
 
 
292
Change to the next task if necessary.
 
293
===============
 
294
*/
 
295
void Bob::act(Game* g, uint data)
 
296
{
 
297
        if (!m_stack.size()) {
 
298
                assert(m_sched_init_task);
 
299
 
 
300
                m_sched_init_task = false;
 
301
                m_signal = "";
 
302
 
 
303
                m_stack_dirty = false;
 
304
                init_auto_task(g);
 
305
                m_sched_init_task = false;
 
306
 
 
307
                if (!m_stack.size())
 
308
                        throw wexception("MO(%u): init_auto_task() failed to set a task", get_serial());
 
309
 
 
310
                assert(m_stack_dirty);
 
311
 
 
312
                m_stack_dirty = false;
 
313
                do_act(g, false);
 
314
                return;
 
315
        } else if (m_sched_init_task) {
 
316
                assert(m_stack_dirty);
 
317
 
 
318
                // This happens when we schedule for an init_auto_task(), but the bob
 
319
                // owner explicitly pushes a task
 
320
                m_sched_init_task = false;
 
321
                m_stack_dirty = false;
 
322
        }
 
323
 
 
324
        // Eliminate spurious calls of act().
 
325
        // These calls are to be expected and perfectly normal, e.g. when a carrier's
 
326
        // idle task is interrupted by the request to pick up a ware from a flag.
 
327
        if (data != m_actid)
 
328
                return;
 
329
 
 
330
        do_act(g, false);
 
331
}
 
332
 
 
333
 
 
334
/*
 
335
===============
 
336
Bob::do_act
 
337
 
 
338
Handle the actual calls to update() and signal() as appropriate.
 
339
 
 
340
signalhandling is true when do_act() is called by send_signal(), and false
 
341
otherwise.
 
342
===============
 
343
*/
 
344
void Bob::do_act(Game* g, bool signalhandling)
 
345
{
 
346
        for(;;) {
 
347
                uint origactid;
 
348
 
 
349
                origactid = m_actid;
 
350
 
 
351
                if (m_stack_dirty)
 
352
                        throw wexception("MO(%u): stack dirty before update[%s]", get_serial(),
 
353
                                                                        get_state() ? get_state()->task->name : "(nil)");
 
354
 
 
355
                // Run the task if we're not coming from signalhandling
 
356
                if (!signalhandling) {
 
357
                        Task* task = get_state()->task;
 
358
 
 
359
                        (this->*task->update)(g, get_state());
 
360
 
 
361
                        if (!m_stack_dirty)
 
362
                        {
 
363
                                if (origactid == m_actid)
 
364
                                        throw wexception("MO(%u): update[%s] failed to act", get_serial(), task->name);
 
365
 
 
366
                                break; // we did our work, now get out of here
 
367
                        }
 
368
                        else if (origactid != m_actid)
 
369
                                throw wexception("MO(%u): [%s] changes both stack and act", get_serial(),
 
370
                                                                        task->name);
 
371
                }
 
372
 
 
373
                do
 
374
                {
 
375
                        m_stack_dirty = false;
 
376
 
 
377
                        // Get a new task as soon as possible
 
378
                        // Sometimes, the owner of a bob will want to force it to stop all
 
379
                        // tasks and start a new task afterwards, which is why we don't
 
380
                        // call init_auto_task() immediately.
 
381
                        if (!m_stack.size()) {
 
382
                                molog("schedule reget auto task\n");
 
383
 
 
384
                                set_signal("");
 
385
                                schedule_act(g, 1);
 
386
                                m_sched_init_task = true;
 
387
                                return;
 
388
                        }
 
389
 
 
390
                        // Prepare the new task
 
391
                        if (m_signal.size())
 
392
                        {
 
393
                                Task* task = get_state()->task;
 
394
 
 
395
                                if (task->signal)
 
396
                                        (this->*task->signal)(g, get_state());
 
397
 
 
398
                                // If the initial signal handler doesn't mess with the stack, get out of here
 
399
                                if (!m_stack_dirty && signalhandling)
 
400
                                        return;
 
401
                        }
 
402
                } while(m_stack_dirty);
 
403
 
 
404
                signalhandling = false; // next pass will be a normal, non-signal handling pass
 
405
        }
 
406
}
 
407
 
 
408
 
 
409
/*
 
410
===============
 
411
Bob::schedule_destroy
 
412
 
 
413
Kill self ASAP.
 
414
===============
 
415
*/
 
416
void Bob::schedule_destroy(Game* g)
 
417
{
 
418
        Map_Object::schedule_destroy(g);
 
419
        m_actid++;
 
420
}
 
421
 
 
422
 
 
423
/*
 
424
===============
 
425
Bob::schedule_act
 
426
 
 
427
Schedule a new act for the current task. All other pending acts are cancelled.
 
428
===============
 
429
*/
 
430
void Bob::schedule_act(Game* g, uint tdelta)
 
431
{
 
432
        Map_Object::schedule_act(g, tdelta, ++m_actid);
 
433
}
 
434
 
 
435
 
 
436
/*
 
437
===============
 
438
Bob::skip_act
 
439
 
 
440
Explicitly state that we don't want to act.
 
441
===============
 
442
*/
 
443
void Bob::skip_act(Game* g)
 
444
{
 
445
        if (!get_state()->task->signal)
 
446
                throw wexception("MO(%u): %s calls skip_act(), but has no signal() function",
 
447
                                        get_serial(), get_state()->task->name);
 
448
 
 
449
        m_actid++;
 
450
}
 
451
 
 
452
 
 
453
/*
 
454
===============
 
455
Bob::force_skip_act
 
456
 
 
457
Explicitly state that we don't want to act, even if we cannot be awoken by a
 
458
signal. Use with great care.
 
459
===============
 
460
*/
 
461
void Bob::force_skip_act(Game* g)
 
462
{
 
463
        m_stack_dirty = false;
 
464
        m_actid++;
 
465
}
 
466
 
 
467
 
 
468
/*
 
469
===============
 
470
Bob::push_task
 
471
 
 
472
Push a new task onto the stack.
 
473
 
 
474
push_task() itself does not call any functions of the task, so the caller can
 
475
fill the state information with parameters for the task.
 
476
===============
 
477
*/
 
478
void Bob::push_task(Game* g, Task* task)
 
479
{
 
480
   State* state;
 
481
                
 
482
   if (m_stack_dirty && m_stack.size())
 
483
      throw wexception("MO(%u): push_task(%s): stack already dirty", get_serial(), task->name);
 
484
 
 
485
   m_stack.push_back(State());
 
486
 
 
487
   state = get_state();
 
488
   state->task = task;
 
489
   state->ivar1 = 0;
 
490
   state->ivar2 = 0;
 
491
   state->diranims = 0;
 
492
   state->path = 0;
 
493
   state->transfer = 0;
 
494
   state->route = 0;
 
495
   state->program = 0;
 
496
 
 
497
   m_stack_dirty = true;
 
498
}
 
499
 
 
500
 
 
501
/*
 
502
===============
 
503
Bob::pop_task
 
504
 
 
505
Remove the current task from the stack.
 
506
 
 
507
pop_task() itself does not call any parent task functions, but it sets a flag
 
508
to make it happen.
 
509
===============
 
510
   */
 
511
void Bob::pop_task(Game* g)
 
512
{
 
513
   State* state = get_state();
 
514
   
 
515
   if (m_stack_dirty) 
 
516
      throw wexception("MO(%u): pop_task(%s): stack already dirty", get_serial(), state->task->name);
 
517
 
 
518
   if (state->path)
 
519
                delete state->path;
 
520
        if (state->route)
 
521
                delete state->route;
 
522
        if (state->transfer)
 
523
                state->transfer->has_failed();
 
524
        
 
525
   m_stack.pop_back();
 
526
 
 
527
 
 
528
        m_stack_dirty = true;
 
529
}
 
530
 
 
531
 
 
532
/*
 
533
===============
 
534
Bob::get_state
 
535
 
 
536
Get the bottom-most (usually the only) state of this task from the stack.
 
537
Return 0 if this task is not running at all.
 
538
===============
 
539
*/
 
540
Bob::State* Bob::get_state(Task* task)
 
541
{
 
542
        std::vector<State>::iterator it = m_stack.end();
 
543
 
 
544
        while(it != m_stack.begin())
 
545
        {
 
546
                --it;
 
547
 
 
548
                if (it->task == task)
 
549
                        return &*it;
 
550
        }
 
551
 
 
552
        return 0;
 
553
}
 
554
 
 
555
 
 
556
/*
 
557
===============
 
558
Bob::send_signal
 
559
 
 
560
Sets the signal string and calls the current task's signal function, if any.
 
561
===============
 
562
*/
 
563
void Bob::send_signal(Game* g, std::string sig)
 
564
{
 
565
        assert(sig.size());     // use set_signal() for signal removal
 
566
 
 
567
        m_signal = sig;
 
568
 
 
569
        for(uint i = 0; i < m_stack.size(); i++) {
 
570
                State* state = &m_stack[i];
 
571
 
 
572
                if (state->task->mask) {
 
573
                        (this->*state->task->mask)(g, state);
 
574
 
 
575
                        if (!m_signal.size())
 
576
                                return;
 
577
                }
 
578
        }
 
579
 
 
580
        do_act(g, true); // signal handler act
 
581
}
 
582
 
 
583
 
 
584
/*
 
585
===============
 
586
Bob::reset_tasks
 
587
 
 
588
Force a complete reset of the state stack.
 
589
The state stack is emptied completely, and an init auto task is scheduled
 
590
as if the Bob has just been created and initialized.
 
591
===============
 
592
*/
 
593
void Bob::reset_tasks(Game* g)
 
594
{
 
595
        while(m_stack.size()) {
 
596
                m_stack_dirty = false;
 
597
 
 
598
                pop_task(g);
 
599
        }
 
600
 
 
601
        set_signal("");
 
602
   schedule_act(g, 1);
 
603
   m_sched_init_task = true;
 
604
        m_stack_dirty = false;
 
605
}
 
606
 
 
607
 
 
608
/*
 
609
===============
 
610
Bob::set_signal
 
611
 
 
612
Simply set the signal string without calling any functions.
 
613
You should use this function to unset a signal, or to set a signal just before
 
614
calling pop_task().
 
615
===============
 
616
*/
 
617
void Bob::set_signal(std::string sig)
 
618
{
 
619
        m_signal = sig;
 
620
}
 
621
 
 
622
 
 
623
/*
 
624
===============
 
625
Bob::init_auto_task
 
626
 
 
627
Automatically select a task.
 
628
===============
 
629
*/
 
630
void Bob::init_auto_task(Game* g)
 
631
{
 
632
}
 
633
 
 
634
 
 
635
/*
 
636
==============================
 
637
 
 
638
IDLE task
 
639
 
 
640
Wait a time or indefinitely.
 
641
Every signal can interrupt this task.  No signals are caught.
 
642
 
 
643
==============================
 
644
*/
 
645
 
 
646
Bob::Task Bob::taskIdle = {
 
647
        "idle",
 
648
 
 
649
        &Bob::idle_update,
 
650
        &Bob::idle_signal,
 
651
        0, // mask
 
652
};
 
653
 
 
654
 
 
655
/*
 
656
===============
 
657
Bob::start_task_idle
 
658
 
 
659
Start an idle phase, using the given animation
 
660
If the timeout is a positive value, the idle phase stops after the given
 
661
time.
 
662
 
 
663
This task always succeeds unless interrupted.
 
664
===============
 
665
*/
 
666
void Bob::start_task_idle(Game* g, uint anim, int timeout)
 
667
{
 
668
        State* state;
 
669
 
 
670
        assert(timeout < 0 || timeout > 0);
 
671
 
 
672
        set_animation(g, anim);
 
673
 
 
674
        push_task(g, &taskIdle);
 
675
 
 
676
        state = get_state();
 
677
        state->ivar1 = timeout;
 
678
}
 
679
 
 
680
void Bob::idle_update(Game* g, State* state)
 
681
{
 
682
        if (!state->ivar1) {
 
683
                pop_task(g);
 
684
                return;
 
685
        }
 
686
 
 
687
        if (state->ivar1 > 0)
 
688
                schedule_act(g, state->ivar1);
 
689
        else
 
690
                skip_act(g);
 
691
 
 
692
        state->ivar1 = 0;
 
693
}
 
694
 
 
695
void Bob::idle_signal(Game* g, State* state)
 
696
{
 
697
        pop_task(g);
 
698
}
 
699
 
 
700
 
 
701
/*
 
702
==============================
 
703
 
 
704
MOVEPATH task
 
705
 
 
706
Move along a predefined path.
 
707
ivar1 is the step number.
 
708
ivar2 is non-zero if we should force moving onto the final field.
 
709
ivar3 is number of steps to take maximally or -1
 
710
 
 
711
Sets the following signal(s):
 
712
"fail" - cannot move along the given path
 
713
 
 
714
==============================
 
715
*/
 
716
 
 
717
Bob::Task Bob::taskMovepath = {
 
718
        "movepath",
 
719
 
 
720
        &Bob::movepath_update,
 
721
        &Bob::movepath_signal,          // lazy signal handling, only act on one signal
 
722
        0,              // mask
 
723
};
 
724
 
 
725
/*
 
726
===============
 
727
Bob::start_task_movepath
 
728
 
 
729
Start moving to the given destination. persist is the same parameter as
 
730
for Map::findpath().
 
731
 
 
732
Returns false if no path could be found.
 
733
 
 
734
The task finishes once the goal has been reached. It may fail.
 
735
 
 
736
only step defines how many steps should be taken, before this returns as a success
 
737
===============
 
738
*/
 
739
bool Bob::start_task_movepath(Game* g, Coords dest, int persist, DirAnimations *anims, bool forceonlast, int only_step)
 
740
{
 
741
        Path* path = new Path;
 
742
        State* state;
 
743
        CheckStepDefault cstep_default(get_movecaps());
 
744
        CheckStepWalkOn cstep_walkon(get_movecaps(), true);
 
745
        CheckStep* cstep;
 
746
 
 
747
        if (forceonlast)
 
748
                cstep = &cstep_walkon;
 
749
        else
 
750
                cstep = &cstep_default;
 
751
 
 
752
        if (g->get_map()->findpath(m_position, dest, persist, path, cstep) < 0) {
 
753
                delete path;
 
754
                return false;
 
755
        }
 
756
 
 
757
        push_task(g, &taskMovepath);
 
758
 
 
759
        state = get_state();
 
760
        state->path = path;
 
761
        state->ivar1 = 0;               // step #
 
762
        state->ivar2 = forceonlast ? 1 : 0;
 
763
   state->ivar3 = only_step;
 
764
   state->diranims = anims;
 
765
 
 
766
        return true;
 
767
}
 
768
 
 
769
 
 
770
/*
 
771
===============
 
772
Bob::start_task_movepath
 
773
 
 
774
Start moving along the given, precalculated path.
 
775
===============
 
776
*/
 
777
void Bob::start_task_movepath(Game* g, const Path &path, DirAnimations *anims, bool forceonlast, int only_step)
 
778
{
 
779
        State* state;
 
780
 
 
781
        assert(path.get_start() == get_position());
 
782
 
 
783
        push_task(g, &taskMovepath);
 
784
 
 
785
        state = get_state();
 
786
        state->path = new Path(path);
 
787
        state->ivar1 = 0;
 
788
        state->ivar2 = forceonlast ? 1 : 0;
 
789
   state->ivar3 = only_step;
 
790
        state->diranims = anims;
 
791
}
 
792
 
 
793
 
 
794
/*
 
795
===============
 
796
Bob::start_task_movepath
 
797
 
 
798
Move to the given index on the given path. The current position must be on the
 
799
given path.
 
800
 
 
801
Return true if a task has been started, or false if we already are on the given
 
802
path index.
 
803
===============
 
804
*/
 
805
bool Bob::start_task_movepath(Game* g, const Path& origpath, int index, DirAnimations* anims, bool forceonlast, int only_step)
 
806
{
 
807
        CoordPath path(origpath);
 
808
        int curidx = path.get_index(get_position());
 
809
 
 
810
        if (curidx == -1)
 
811
                throw wexception("MO(%u): start_task_movepath(index): not on path", get_serial());
 
812
 
 
813
        if (curidx != index) {
 
814
                molog("Bob::walk_to_index: Move from %i to %i.\n", curidx, index);
 
815
 
 
816
                if (curidx < index) {
 
817
                        path.truncate(index);
 
818
                        path.starttrim(curidx);
 
819
 
 
820
                        start_task_movepath(g, path, anims, forceonlast, only_step);
 
821
                } else {
 
822
                        path.truncate(curidx);
 
823
                        path.starttrim(index);
 
824
                        path.reverse();
 
825
 
 
826
                        start_task_movepath(g, path, anims, forceonlast, only_step);
 
827
                }
 
828
 
 
829
                return true;
 
830
        }
 
831
 
 
832
        return false;
 
833
}
 
834
 
 
835
 
 
836
/*
 
837
===============
 
838
Bob::movepath_update
 
839
===============
 
840
*/
 
841
void Bob::movepath_update(Game* g, State* state)
 
842
{
 
843
        if (state->ivar1)
 
844
                end_walk(g);
 
845
 
 
846
        // We ignore signals when they arrive, but interrupt as soon as possible,
 
847
        // i.e. when the next step has finished
 
848
        if (get_signal().size()) {
 
849
                molog("[movepath]: Interrupted by signal '%s'.\n", get_signal().c_str());
 
850
                pop_task(g);
 
851
                return;
 
852
        }
 
853
 
 
854
        if (!state->path || state->ivar1 >= state->path->get_nsteps()) {
 
855
                assert(!state->path || m_position == state->path->get_end());
 
856
      pop_task(g); // success
 
857
                return;
 
858
        } else if(state->ivar1==state->ivar3) {
 
859
      // We have stepped all steps that we were asked for.
 
860
      // This is some kind of success, though we do not are were we wanted
 
861
      // to go
 
862
      pop_task(g);
 
863
      return;
 
864
   }
 
865
 
 
866
        char dir = state->path->get_step(state->ivar1);
 
867
        bool forcemove = false;
 
868
 
 
869
        if (state->ivar2 && (state->ivar1+1) == state->path->get_nsteps())
 
870
                forcemove = true;
 
871
 
 
872
        int tdelta = start_walk(g, (WalkingDir)dir, state->diranims->get_animation(dir), forcemove);
 
873
        if (tdelta < 0) {
 
874
                molog("[movepath]: Can't walk.\n");
 
875
                set_signal("fail"); // failure to reach goal
 
876
                pop_task(g);
 
877
                return;
 
878
        }
 
879
 
 
880
        state->ivar1++;
 
881
 
 
882
        schedule_act(g, tdelta);
 
883
}
 
884
 
 
885
/*
 
886
 * movepath signal
 
887
 */
 
888
void Bob::movepath_signal(Game* g, State* start) {
 
889
   if(get_signal()=="interrupt_now") {
 
890
      // User requests an immediate interrupt.
 
891
      // Well, he better nows what he's doing
 
892
      pop_task(g);
 
893
   }
 
894
}
 
895
 
 
896
/*
 
897
==============================
 
898
 
 
899
FORCEMOVE task
 
900
 
 
901
==============================
 
902
*/
 
903
 
 
904
Bob::Task Bob::taskForcemove = {
 
905
        "forcemove",
 
906
 
 
907
        &Bob::forcemove_update,
 
908
        0,
 
909
        0,
 
910
};
 
911
 
 
912
 
 
913
/*
 
914
===============
 
915
Bob::start_task_forcemove
 
916
 
 
917
Move into the given direction, without passability checks.
 
918
===============
 
919
*/
 
920
void Bob::start_task_forcemove(Game *g, int dir, DirAnimations *anims)
 
921
{
 
922
        State* state;
 
923
 
 
924
        push_task(g, &taskForcemove);
 
925
 
 
926
        state = get_state();
 
927
        state->ivar1 = dir;
 
928
        state->diranims = anims;
 
929
}
 
930
 
 
931
void Bob::forcemove_update(Game* g, State* state)
 
932
{
 
933
        if (state->diranims)
 
934
        {
 
935
                int tdelta = start_walk(g, (WalkingDir)state->ivar1,
 
936
                                        state->diranims->get_animation(state->ivar1), true);
 
937
 
 
938
                state->diranims = 0;
 
939
                schedule_act(g, tdelta);
 
940
        }
 
941
        else
 
942
        {
 
943
                end_walk(g);
 
944
                pop_task(g);
 
945
        }
 
946
}
 
947
 
 
948
 
 
949
/*
 
950
===============
 
951
Bob::calc_drawpos
 
952
 
 
953
Calculates the actual position to draw on from the base field position.
 
954
This function takes walking etc. into account.
 
955
 
 
956
pos is the location, in pixels, of the field m_position (height is already
 
957
taken into account).
 
958
drawpos will be filled with the location of the bob.
 
959
===============
 
960
*/
 
961
void Bob::calc_drawpos(Editor_Game_Base* game, Point pos, Point* drawpos)
 
962
{
 
963
        Map *map = game->get_map();
 
964
        FCoords end;
 
965
        FCoords start;
 
966
        Point spos;
 
967
        Point epos;
 
968
 
 
969
        end = m_position;
 
970
        epos = pos;
 
971
        spos = epos;
 
972
 
 
973
        switch(m_walking) {
 
974
        case WALK_NW: map->get_brn(end, &start); spos.x += FIELD_WIDTH/2; spos.y += FIELD_HEIGHT/2; break;
 
975
        case WALK_NE: map->get_bln(end, &start); spos.x -= FIELD_WIDTH/2; spos.y += FIELD_HEIGHT/2; break;
 
976
        case WALK_W: map->get_rn(end, &start); spos.x += FIELD_WIDTH; break;
 
977
        case WALK_E: map->get_ln(end, &start); spos.x -= FIELD_WIDTH; break;
 
978
        case WALK_SW: map->get_trn(end, &start); spos.x += FIELD_WIDTH/2; spos.y -= FIELD_HEIGHT/2; break;
 
979
        case WALK_SE: map->get_tln(end, &start); spos.x -= FIELD_WIDTH/2; spos.y -= FIELD_HEIGHT/2; break;
 
980
 
 
981
        case IDLE: start.field = 0; break;
 
982
        }
 
983
 
 
984
        if (start.field) {
 
985
                spos.y += MULTIPLY_WITH_HEIGHT_FACTOR(end.field->get_height());
 
986
                spos.y -= MULTIPLY_WITH_HEIGHT_FACTOR(start.field->get_height());
 
987
 
 
988
                float f = (float)(game->get_gametime() - m_walkstart) / (m_walkend - m_walkstart);
 
989
                if (f < 0) f = 0;
 
990
                else if (f > 1) f = 1;
 
991
 
 
992
                epos.x = (int)(f*epos.x + (1-f)*spos.x);
 
993
                epos.y = (int)(f*epos.y + (1-f)*spos.y);
 
994
        }
 
995
 
 
996
        *drawpos = epos;
 
997
}
 
998
 
 
999
 
 
1000
/*
 
1001
===============
 
1002
Bob::draw
 
1003
 
 
1004
Draw the map object.
 
1005
posx/posy is the on-bitmap position of the field we're currently on.
 
1006
 
 
1007
It LERPs between start and end position when we're walking.
 
1008
Note that the current field is actually the field we're walking to, not
 
1009
the one we start from.
 
1010
===============
 
1011
*/
 
1012
void Bob::draw(Editor_Game_Base *game, RenderTarget* dst, Point pos)
 
1013
{
 
1014
        if (!m_anim)
 
1015
                return;
 
1016
 
 
1017
        const RGBColor* playercolors = 0;
 
1018
        Point drawpos;
 
1019
 
 
1020
        calc_drawpos(game, pos, &drawpos);
 
1021
 
 
1022
        if (get_owner())
 
1023
                playercolors = get_owner()->get_playercolor();
 
1024
 
 
1025
        dst->drawanim(drawpos.x, drawpos.y, m_anim, game->get_gametime() - m_animstart, playercolors);
 
1026
}
 
1027
 
 
1028
 
 
1029
/*
 
1030
===============
 
1031
Bob::set_animation
 
1032
 
 
1033
Set a looping animation, starting now.
 
1034
===============
 
1035
*/
 
1036
void Bob::set_animation(Editor_Game_Base* g, uint anim)
 
1037
{
 
1038
        m_anim = anim;
 
1039
        m_animstart = g->get_gametime();
 
1040
}
 
1041
 
 
1042
/*
 
1043
===============
 
1044
Bob::is_walking
 
1045
 
 
1046
Return true if we're currently walking
 
1047
===============
 
1048
*/
 
1049
bool Bob::is_walking()
 
1050
{
 
1051
        return m_walking != IDLE;
 
1052
}
 
1053
 
 
1054
/*
 
1055
===============
 
1056
Bob::end_walk
 
1057
 
 
1058
Call this from your task_act() function that was scheduled after start_walk().
 
1059
===============
 
1060
*/
 
1061
void Bob::end_walk(Game* g)
 
1062
{
 
1063
        m_walking = IDLE;
 
1064
}
 
1065
 
 
1066
 
 
1067
/*
 
1068
===============
 
1069
Bob::start_walk
 
1070
 
 
1071
Cause the object to walk, honoring passable/impassable parts of the map using movecaps.
 
1072
If force is true, the passability check is skipped.
 
1073
 
 
1074
Returns the number of milliseconds after which the walk has ended. You must
 
1075
call end_walk() after this time, so schedule a task_act().
 
1076
 
 
1077
Returns a negative value when we can't walk into the requested direction.
 
1078
===============
 
1079
*/
 
1080
int Bob::start_walk(Game *g, WalkingDir dir, uint a, bool force)
 
1081
{
 
1082
        FCoords newf;
 
1083
 
 
1084
        g->get_map()->get_neighbour(m_position, dir, &newf);
 
1085
 
 
1086
        // Move capability check by ANDing with the field caps
 
1087
        //
 
1088
        // The somewhat crazy check involving MOVECAPS_SWIM should allow swimming objects to
 
1089
        // temporarily land.
 
1090
        uint movecaps = get_movecaps();
 
1091
 
 
1092
        if (!force) {
 
1093
                if (!(m_position.field->get_caps() & movecaps & MOVECAPS_SWIM && newf.field->get_caps() & MOVECAPS_WALK) &&
 
1094
                    !(newf.field->get_caps() & movecaps))
 
1095
                        return -1;
 
1096
        }
 
1097
 
 
1098
        // Move is go
 
1099
        int tdelta = g->get_map()->calc_cost(m_position, dir);
 
1100
 
 
1101
        m_walking = dir;
 
1102
        m_walkstart = g->get_gametime();
 
1103
        m_walkend = m_walkstart + tdelta;
 
1104
 
 
1105
        set_position(g, newf);
 
1106
        set_animation(g, a);
 
1107
 
 
1108
        return tdelta; // yep, we were successful
 
1109
}
 
1110
 
 
1111
/*
 
1112
===============
 
1113
Bob::set_position
 
1114
 
 
1115
Moves the Map_Object to the given position.
 
1116
===============
 
1117
*/
 
1118
void Bob::set_position(Editor_Game_Base* g, Coords coords)
 
1119
{
 
1120
        if (m_position.field) {
 
1121
                *m_linkpprev = m_linknext;
 
1122
                if (m_linknext)
 
1123
                        m_linknext->m_linkpprev = m_linkpprev;
 
1124
        }
 
1125
 
 
1126
        m_position = g->get_map()->get_fcoords(coords);
 
1127
 
 
1128
        m_linknext = m_position.field->bobs;
 
1129
        m_linkpprev = &m_position.field->bobs;
 
1130
        if (m_linknext)
 
1131
                m_linknext->m_linkpprev = &m_linknext;
 
1132
        m_position.field->bobs = this;
 
1133
}
 
1134
/*
 
1135
 * Give debug informations
 
1136
 */
 
1137
void Bob::log_general_info(Editor_Game_Base* egbase) {
 
1138
   molog("Owner: %p\n", m_owner);
 
1139
   
 
1140
   molog("Postition: (%i,%i)\n", m_position.x, m_position.y);
 
1141
   molog("ActID: %i\n", m_actid);
 
1142
 
 
1143
        molog("Animation: %s\n", m_anim ? get_descr()->get_animation_name(m_anim).c_str() : "<none>" );
 
1144
   molog("AnimStart: %i\n", m_animstart);
 
1145
 
 
1146
        molog("WalkingDir: %i\n", m_walking);
 
1147
        molog("WalkingStart: %i\n", m_walkstart);
 
1148
        molog("WalkEnd: %i\n", m_walkend);
 
1149
 
 
1150
        molog("Stack dirty: %i\n", m_stack_dirty);
 
1151
        molog("Init auto task: %i\n", m_sched_init_task);
 
1152
        molog("Signale: %s\n", m_signal.c_str());
 
1153
 
 
1154
   molog("Stack size: %i\n", m_stack.size());
 
1155
   for(uint i=0; i<m_stack.size(); i++) {
 
1156
      molog("Stack dump %i/%i\n", i+1, m_stack.size());
 
1157
 
 
1158
      molog("* task->name: %s\n", m_stack[i].task->name);
 
1159
      
 
1160
      molog("* ivar1: %i\n", m_stack[i].ivar1);
 
1161
      molog("* ivar2: %i\n", m_stack[i].ivar2);
 
1162
      molog("* ivar3: %i\n", m_stack[i].ivar3);
 
1163
 
 
1164
      molog("* object pointer: %p\n", m_stack[i].objvar1.get(egbase));
 
1165
                molog("* svar1: %s\n", m_stack[i].svar1.c_str());
 
1166
 
 
1167
                molog("* coords: (%i,%i)\n", m_stack[i].coords.x, m_stack[i].coords.y);
 
1168
                molog("* diranims: %p\n",  m_stack[i].diranims);
 
1169
                molog("* path: %p\n",  m_stack[i].path);
 
1170
      if(m_stack[i].path) {
 
1171
         Path* p=m_stack[i].path;
 
1172
         molog("** Path length: %i\n", p->get_nsteps());
 
1173
         molog("** Start: (%i,%i)\n", p->get_start().x, p->get_start().y);
 
1174
         molog("** End: (%i,%i)\n", p->get_end().x, p->get_end().y);
 
1175
         for(int i=0; i<p->get_nsteps(); i++) 
 
1176
            molog("** Step %i/%i: %i\n", i+1, p->get_nsteps(), p->get_step(i));
 
1177
      }
 
1178
                molog("* transfer: %p\n",  m_stack[i].transfer);
 
1179
                molog("* route: %p\n",  m_stack[i].route);
 
1180
                
 
1181
      molog("* program: %p\n",  m_stack[i].route);
 
1182
   }
 
1183
}
 
1184
 
 
1185
/*
 
1186
==============================================================================
 
1187
 
 
1188
Bob_Descr factory
 
1189
 
 
1190
==============================================================================
 
1191
*/
 
1192
 
 
1193
/*
 
1194
===============
 
1195
Bob_Descr::create_from_dir(const char *directory) [static]
 
1196
 
 
1197
Master factory to read a bob from the given directory and create the
 
1198
appropriate description class.
 
1199
===============
 
1200
*/
 
1201
Bob_Descr *Bob_Descr::create_from_dir(const char *name, const char *directory, Profile *prof, Tribe_Descr* tribe)
 
1202
{
 
1203
        Bob_Descr *bob = 0;
 
1204
 
 
1205
        try
 
1206
        {
 
1207
                Section *s = prof->get_safe_section("global");
 
1208
                const char *type = s->get_safe_string("type");
 
1209
 
 
1210
                if (!strcasecmp(type, "critter")) {
 
1211
                        bob = new Critter_Bob_Descr(name, tribe);
 
1212
                } else
 
1213
                        throw wexception("Unsupported bob type '%s'", type);
 
1214
 
 
1215
                bob->parse(directory, prof, 0);
 
1216
        }
 
1217
        catch(std::exception &e) {
 
1218
                if (bob)
 
1219
                        delete bob;
 
1220
                throw wexception("Error reading bob %s: %s", directory, e.what());
 
1221
        }
 
1222
        catch(...) {
 
1223
                if (bob)
 
1224
                        delete bob;
 
1225
                throw;
 
1226
        }
 
1227
 
 
1228
        return bob;
 
1229
}