1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * aint32 with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 *
22 * Based on the original sources
23 * Faery Tale II -- The Halls of the Dead
24 * (c) 1993-1996 The Wyrmkeep Entertainment Co.
25 */
26
27 #include "saga2/saga2.h"
28 #include "saga2/fta.h"
29 #include "saga2/cmisc.h"
30 #include "saga2/actor.h"
31 #include "saga2/task.h"
32 #include "saga2/motion.h"
33 #include "saga2/band.h"
34 #include "saga2/sensor.h"
35 #include "saga2/tilemode.h"
36 #include "saga2/tile.h"
37
38 namespace Saga2 {
39
40 bool actorTasksPaused;
41
42 /* ===================================================================== *
43 Prototypes
44 * ===================================================================== */
45
46 void readTask(TaskID id, Common::InSaveFile *in);
47
48 // Return the number of bytes necessary to create an archive of the
49 // specified Task
50 int32 taskArchiveSize(Task *t);
51
52 void writeTask(Task *t, Common::MemoryWriteStreamDynamic *out);
53
54 #if DEBUG
55 // Debugging function used to check the integrity of the global task
56 // list
57 void checkTaskListIntegrity(void);
58 #endif
59
60 /* ===================================================================== *
61 Utility functions
62 * ===================================================================== */
63
64 //----------------------------------------------------------------------
65 // Compute a repulsion vector based on an array of repulsor vectors
66
computeRepulsionVector(TilePoint * repulsorVectorArray,int16 * repulsorStrengthArray,int numRepulsors)67 TilePoint computeRepulsionVector(
68 TilePoint *repulsorVectorArray,
69 int16 *repulsorStrengthArray,
70 int numRepulsors) {
71 int i;
72 TilePoint repulsionVector(0, 0, 0);
73
74 for (i = 0; i < numRepulsors; i++) {
75 int16 repulsorWeight,
76 repulsorDist;
77
78 repulsorDist = repulsorVectorArray[i].quickHDistance()
79 + ABS(repulsorVectorArray[i].z);
80 repulsorWeight =
81 repulsorDist != 0
82 ? 64 * 64 / (repulsorDist * repulsorDist)
83 : 64 * 64;
84
85 repulsionVector +=
86 (-repulsorVectorArray[i]
87 * repulsorStrengthArray[i]
88 * repulsorWeight)
89 / 16;
90 }
91
92 return repulsionVector;
93 }
94
95 /* ===================================================================== *
96 TaskStackList class
97 * ===================================================================== */
98
99 const int numTaskStacks = 32;
100
101 // Manages the memory used for the TaskStack's. There will
102 // only be one global instantiation of this class
103 class TaskStackList {
104 TaskStack *_list[numTaskStacks];
105
106 public:
107 // Constructor -- initial construction
108 TaskStackList(void);
109
110 // Destructor
111 ~TaskStackList(void);
112
113 void read(Common::InSaveFile *in);
114
115 // Return the number of bytes needed to make an archive of the
116 // TaskStackList
117 int32 archiveSize(void);
118
119 void write(Common::MemoryWriteStreamDynamic *out);
120
121 // Place a TaskStack from the inactive list into the active
122 // list.
123 TaskStack *newTaskStack(Actor *a);
124
125 void newTaskStack(TaskStack *p);
126
127 void newTaskStack(TaskStack *p, TaskID id);
128
129 // Place a TaskStack back into the inactive list.
130 void deleteTaskStack(TaskStack *p);
131
132 // Return the specified TaskStack's ID
getTaskStackID(TaskStack * ts)133 TaskStackID getTaskStackID(TaskStack *ts) {
134 for (int i = 0; i < numTaskStacks; i++)
135 if (_list[i] == ts)
136 return i;
137
138 error("getTaskStackID(): Unknown stack %p", (void *)ts);
139 }
140
141 // Return a pointer to a TaskStack given a TaskStackID
getTaskStackAddress(TaskStackID id)142 TaskStack *getTaskStackAddress(TaskStackID id) {
143 assert(id >= 0 && id < numTaskStacks);
144 return _list[id];
145 }
146
147 // Run through the TaskStacks in the active list and update
148 // each.
149 void updateTaskStacks(void);
150 };
151
152 //----------------------------------------------------------------------
153 // TaskStackList constructor -- simply place each element the array in
154 // the inactive list
155
TaskStackList(void)156 TaskStackList::TaskStackList(void) {
157 for (int i = 0; i < numTaskStacks; i++)
158 _list[i] = nullptr;
159 }
160
161 //----------------------------------------------------------------------
162 // TaskStackList destructor
163
~TaskStackList(void)164 TaskStackList::~TaskStackList(void) {
165 for (int i = 0; i < numTaskStacks; i++) {
166 if (_list[i] == nullptr)
167 continue;
168
169 delete _list[i];
170 _list[i] = nullptr;
171 }
172 }
173
read(Common::InSaveFile * in)174 void TaskStackList::read(Common::InSaveFile *in) {
175 int16 taskStackCount;
176
177 // Get the count of task stacks and increment the buffer pointer
178 taskStackCount = in->readSint16LE();
179 debugC(3, kDebugSaveload, "... taskStackCount = %d", taskStackCount);
180
181 // Iterate through the archive data, reconstructing the TaskStacks
182 for (int i = 0; i < taskStackCount; i++) {
183 TaskStackID id;
184 TaskStack *ts;
185
186 // Retreive the TaskStack's id number
187 id = in->readSint16LE();
188 debugC(3, kDebugSaveload, "Loading Task Stack %d", id);
189
190 ts = new TaskStack;
191 newTaskStack(ts, id);
192
193 ts->read(in);
194
195 // Plug this TaskStack into the Actor
196 ts->getActor()->_curTask = ts;
197 }
198 }
199
200 //----------------------------------------------------------------------
201 // Return the number of bytes necessary to archive this TaskStackList
202
archiveSize(void)203 int32 TaskStackList::archiveSize(void) {
204 int32 size = sizeof(int16);
205
206 for (int i = 0; i < numTaskStacks; i++) {
207 size += sizeof(TaskStackID);
208
209 if (_list[i])
210 size += _list[i]->archiveSize();
211 }
212
213 return size;
214 }
215
write(Common::MemoryWriteStreamDynamic * out)216 void TaskStackList::write(Common::MemoryWriteStreamDynamic *out) {
217 int16 taskStackCount = 0;
218
219 // Count the active task stacks
220 for (int i = 0; i < numTaskStacks; i++)
221 if (_list[i])
222 taskStackCount++;
223
224 // Store the task stack count in the archive buffer
225 out->writeSint16LE(taskStackCount);
226 debugC(3, kDebugSaveload, "... taskStackCount = %d", taskStackCount);
227
228 for (int i = 0; i < numTaskStacks; i++) {
229 if (_list[i] == nullptr)
230 continue;
231
232 debugC(3, kDebugSaveload, "Saving Task Stack %d", i);
233
234 TaskStack *ts = _list[i];
235 out->writeSint16LE(i);
236 ts->write(out);
237 }
238 }
239
240 //----------------------------------------------------------------------
241 // Place a TaskStack into the active list and return its address
242
newTaskStack(Actor * a)243 TaskStack *TaskStackList::newTaskStack(Actor *a) {
244 for (int i = 0; i < numTaskStacks; i++)
245 if (!_list[i]) {
246 _list[i] = new TaskStack(a);
247
248 return _list[i];
249 }
250
251 warning("Too many task stacks in the list, > %d", numTaskStacks);
252
253 return nullptr;
254 }
255
newTaskStack(TaskStack * p)256 void TaskStackList::newTaskStack(TaskStack *p) {
257 for (int i = 0; i < numTaskStacks; i++) {
258 if (_list[i] == p) {
259 warning("TaskStack %d (%p) already added", i, (void *)p);
260
261 return;
262 }
263 }
264
265 debugC(1, kDebugTasks, "List: %p Adding task stack %p", (void *)this, (void *)p);
266 for (int i = 0; i < numTaskStacks; i++) {
267 if (!_list[i]) {
268 _list[i] = p;
269
270 return;
271 }
272 }
273 }
274
newTaskStack(TaskStack * p,TaskID id)275 void TaskStackList::newTaskStack(TaskStack *p, TaskID id) {
276 if (_list[id])
277 error("Task already exists");
278 _list[id] = p;
279 }
280
281 //----------------------------------------------------------------------
282 // Remove the specified TaskStack from the active list and place it
283 // back into the inactive list
284
deleteTaskStack(TaskStack * p)285 void TaskStackList::deleteTaskStack(TaskStack *p) {
286 debugC(1, kDebugTasks, "List: %p Deleting task stack %p", (void *)this, (void *)p);
287 for (int i = 0; i < numTaskStacks; i++) {
288 if (_list[i] == p) {
289 _list[i] = nullptr;
290 }
291 }
292 }
293
294 //----------------------------------------------------------------------
295 // Iterate through all of the TaskStacks in the active list and call
296 // their update function
297
updateTaskStacks(void)298 void TaskStackList::updateTaskStacks(void) {
299 for (int i = 0; i < numTaskStacks; i++) {
300 if (_list[i]) {
301 TaskStack *ts = _list[i];
302 TaskResult result;
303
304 // Update the task stack and delete it if it is done
305 if ((result = ts->update()) != taskNotDone) {
306 Actor *a = ts->getActor();
307 assert(a != NULL);
308
309 a->handleTaskCompletion(result);
310 }
311 }
312 }
313 }
314
315 /* ===================================================================== *
316 Misc. task stack management functions
317 * ===================================================================== */
318
319 //----------------------------------------------------------------------
320 // Simply pass this call to the stackList member function,
321 // updateTaskStacks().
322
updateActorTasks(void)323 void updateActorTasks(void) {
324 if (!actorTasksPaused)
325 g_vm->_stackList->updateTaskStacks();
326 }
327
pauseActorTasks(void)328 void pauseActorTasks(void) {
329 actorTasksPaused = true;
330 }
resumeActorTasks(void)331 void resumeActorTasks(void) {
332 actorTasksPaused = false;
333 }
334
335 //----------------------------------------------------------------------
336 // Call the stackList member function newTaskStack() to get a pointer
337 // to a new TaskStack
338
newTaskStack(Actor * a)339 TaskStack *newTaskStack(Actor *a) {
340 return g_vm->_stackList->newTaskStack(a);
341 }
342
newTaskStack(TaskStack * p)343 void newTaskStack(TaskStack *p) {
344 return g_vm->_stackList->newTaskStack(p);
345 }
346
347 //----------------------------------------------------------------------
348 // Call the stackList member function deleteTaskStack() to dispose of
349 // a previously allocated TaskStack
350
deleteTaskStack(TaskStack * p)351 void deleteTaskStack(TaskStack *p) {
352 g_vm->_stackList->deleteTaskStack(p);
353 }
354
355 //----------------------------------------------------------------------
356 // Return the specified TaskStack's ID
357
getTaskStackID(TaskStack * ts)358 TaskStackID getTaskStackID(TaskStack *ts) {
359 return g_vm->_stackList->getTaskStackID(ts);
360 }
361
362 //----------------------------------------------------------------------
363 // Return a pointer to a TaskStack given a TaskStackID
364
getTaskStackAddress(TaskStackID id)365 TaskStack *getTaskStackAddress(TaskStackID id) {
366 return g_vm->_stackList->getTaskStackAddress(id);
367 }
368
369 //----------------------------------------------------------------------
370 // Initialize the stackList
371
initTaskStacks(void)372 void initTaskStacks(void) {
373 g_vm->_stackList = new TaskStackList;
374 }
375
saveTaskStacks(Common::OutSaveFile * outS)376 void saveTaskStacks(Common::OutSaveFile *outS) {
377 debugC(2, kDebugSaveload, "Saving Task Stacks");
378
379 outS->write("TSTK", 4);
380 CHUNK_BEGIN;
381 g_vm->_stackList->write(out);
382 CHUNK_END;
383 }
384
loadTaskStacks(Common::InSaveFile * in,int32 chunkSize)385 void loadTaskStacks(Common::InSaveFile *in, int32 chunkSize) {
386 debugC(2, kDebugSaveload, "Loading Task Stacks");
387
388 // If there is no saved data, simply call the default constructor
389 if (chunkSize == 0) {
390 g_vm->_stackList = new TaskStackList;
391 return;
392 }
393
394 // Reconstruct stackList from archived data
395 g_vm->_stackList = new TaskStackList;
396 g_vm->_stackList->read(in);
397 }
398
399 //----------------------------------------------------------------------
400 // Cleanup the stackList
401
cleanupTaskStacks(void)402 void cleanupTaskStacks(void) {
403 // Simply call stackList's destructor
404 delete g_vm->_stackList;
405 }
406
407 /* ===================================================================== *
408 TaskList class
409 * ===================================================================== */
410
411 const int numTasks = 64;
412
413 // Manages the memory used for the Task's. There will only be one
414 // global instantiation of this class
415 class TaskList {
416
417 int _size;
418 Task *_list[numTasks];
419
420 public:
421 // Constructor -- initial construction
422 TaskList(void);
423
424 // Destructor
425 ~TaskList(void);
426
427 void read(Common::InSaveFile *in);
428
429 // Return the number of bytes necessary to archive this task list
430 // in a buffer
431 int32 archiveSize(void);
432
433 void write(Common::MemoryWriteStreamDynamic *out);
434
435 // Place a Task from the inactive list into the active
436 // list.
437 void newTask(Task *t);
438 void newTask(Task *t, TaskID id);
439
440 // Place a Task back into the inactive list.
441 void deleteTask(Task *t);
442
443 // Return the specified Task's ID
getTaskID(Task * t)444 TaskID getTaskID(Task *t) {
445 for (int i = 0; i < numTasks; i++)
446 if (_list[i] == t)
447 return i;
448
449 error("getTaskID: unknown task %p", (void *)t);
450 }
451
452 // Return a pointer to a Task given a TaskID
getTaskAddress(TaskID id)453 Task *getTaskAddress(TaskID id) {
454 assert(id >= 0 && id < numTasks);
455 return _list[id];
456 }
457 };
458
459 //----------------------------------------------------------------------
460 // TaskList constructor -- simply place each element of the array in
461 // the inactive list
462
TaskList(void)463 TaskList::TaskList(void) {
464 _size = 0;
465 for (int i = 0; i < numTasks; i++)
466 _list[i] = nullptr;
467 }
468
469 //----------------------------------------------------------------------
470 // TaskList destructor
471
~TaskList(void)472 TaskList::~TaskList(void) {
473 for (int i = 0; i < numTasks; i++) {
474 if (_list[i] == nullptr)
475 continue;
476
477 delete _list[i];
478 _list[i] = nullptr;
479 }
480 }
481
read(Common::InSaveFile * in)482 void TaskList::read(Common::InSaveFile *in) {
483 int16 taskCount;
484
485 // Get the count of tasks and increment the buffer pointer
486 taskCount = in->readSint16LE();
487 debugC(3, kDebugSaveload, "... taskCount = %d", taskCount);
488
489 // Iterate through the archive data, reconstructing the Tasks
490 for (int i = 0; i < taskCount; i++) {
491 TaskID id;
492
493 // Retreive the Task's id number
494 id = in->readSint16LE();
495 debugC(3, kDebugSaveload, "Loading Task %d (%d)", i, id);
496
497 readTask(id, in);
498 }
499
500 // Iterate through the Tasks to fixup the subtask pointers
501 for (int i = 0; i < numTasks; ++i) {
502 if (_list[i] == nullptr)
503 continue;
504
505 _list[i]->fixup();
506 }
507 }
508
509 //----------------------------------------------------------------------
510 // Return the number of bytes necessary to archive this TaskList
511
archiveSize(void)512 int32 TaskList::archiveSize(void) {
513 int32 size = sizeof(int16);
514
515 for (int i = 0; i < numTasks; i++) {
516 size += sizeof(TaskID);
517
518 if (_list[i])
519 size += taskArchiveSize(_list[i]);
520 }
521
522 return size;
523 }
524
write(Common::MemoryWriteStreamDynamic * out)525 void TaskList::write(Common::MemoryWriteStreamDynamic *out) {
526 int16 taskCount = 0;
527
528 // Count the active tasks
529 for (int i = 0 ; i < numTasks; ++i)
530 if (_list[i])
531 taskCount++;
532
533 // Store the task count in the archive buffer
534 out->writeSint16LE(taskCount);
535 debugC(3, kDebugSaveload, "... taskCount = %d", taskCount);
536
537 for (int i = 0; i < numTasks; ++i) {
538 if (_list[i] == nullptr)
539 continue;
540
541 debugC(3, kDebugSaveload, "Saving Task %d", i);
542
543 out->writeSint16LE(i);
544 writeTask(_list[i], out);
545 }
546 }
547
newTask(Task * t)548 void TaskList::newTask(Task *t) {
549 debugC(1, kDebugTasks, "List: %p Adding task %p (total %d)", (void *)this, (void *)t, ++_size);
550 for (int i = 0; i < numTasks; i++)
551 if (!_list[i]) {
552 _list[i] = t;
553
554 return;
555 }
556
557 for (int i = 0; i < numTasks; i++)
558 debug("%d: %p (%s)", i, (void *)_list[i], _list[i]->_type.c_str());
559 error("Too many tasks in the list, > %d", numTasks);
560 }
561
newTask(Task * t,TaskID id)562 void TaskList::newTask(Task *t, TaskID id) {
563 if (_list[id])
564 error("Task already exists");
565 _list[id] = t;
566 }
567
568 //----------------------------------------------------------------------
569 // Remove the specified Task from the active list and place it back
570 // into the inactive list
571
deleteTask(Task * p)572 void TaskList::deleteTask(Task *p) {
573 debugC(1, kDebugTasks, "List: %p Deleting task %p (%s) (total %d)", (void *)this, (void *)p, p->_type.c_str(), --_size);
574 for (int i = 0; i < numTasks; i++)
575 if (_list[i] == p) {
576 _list[i] = nullptr;
577 }
578 }
579
580 /* ===================================================================== *
581 Misc. task management functions
582 * ===================================================================== */
583
newTask(Task * t)584 void newTask(Task *t) {
585 return g_vm->_taskList->newTask(t);
586 }
587
newTask(Task * t,TaskID id)588 void newTask(Task *t, TaskID id) {
589 return g_vm->_taskList->newTask(t, id);
590 }
591
592 //----------------------------------------------------------------------
593 // Call the taskList member function deleteTask() to dispose of a
594 // previously allocated TaskStack
595
deleteTask(Task * p)596 void deleteTask(Task *p) {
597 g_vm->_taskList->deleteTask(p);
598 }
599
600 //----------------------------------------------------------------------
601 // Return the specified Task's ID
602
getTaskID(Task * t)603 TaskID getTaskID(Task *t) {
604 return g_vm->_taskList->getTaskID(t);
605 }
606
607 //----------------------------------------------------------------------
608 // Return a pointer to a Task given a TaskID
609
getTaskAddress(TaskID id)610 Task *getTaskAddress(TaskID id) {
611 return g_vm->_taskList->getTaskAddress(id);
612 }
613
614 //----------------------------------------------------------------------
615 // Initialize the taskList
616
initTasks(void)617 void initTasks(void) {
618 // Simply call the default constructor for the task list
619 g_vm->_taskList = new TaskList;
620 }
621
saveTasks(Common::OutSaveFile * outS)622 void saveTasks(Common::OutSaveFile *outS) {
623 debugC(2, kDebugSaveload, "Saving Tasks");
624
625 outS->write("TASK", 4);
626 CHUNK_BEGIN;
627 g_vm->_taskList->write(out);
628 CHUNK_END;
629 }
630
loadTasks(Common::InSaveFile * in,int32 chunkSize)631 void loadTasks(Common::InSaveFile *in, int32 chunkSize) {
632 debugC(2, kDebugSaveload, "Loading Tasks");
633
634 // If there is no saved data, simply call the default constructor
635 if (chunkSize == 0) {
636 g_vm->_taskList = new TaskList;
637 return;
638 }
639
640 // Reconstruct taskList from archived data
641 g_vm->_taskList = new TaskList;
642 g_vm->_taskList->read(in);
643 }
644
645 //----------------------------------------------------------------------
646 // Cleanup the taskList
647
cleanupTasks(void)648 void cleanupTasks(void) {
649 // Simply call the taskList's destructor
650 delete g_vm->_taskList;
651 }
652
readTask(TaskID id,Common::InSaveFile * in)653 void readTask(TaskID id, Common::InSaveFile *in) {
654 int16 type;
655
656 // Get the Task type
657 type = in->readSint16LE();
658
659 // Reconstruct the Task based upon the type
660 switch (type) {
661 case wanderTask:
662 new WanderTask(in, id);
663 break;
664
665 case tetheredWanderTask:
666 new TetheredWanderTask(in, id);
667 break;
668
669 case gotoLocationTask:
670 new GotoLocationTask(in, id);
671 break;
672
673 case gotoRegionTask:
674 new GotoRegionTask(in, id);
675 break;
676
677 case gotoObjectTask:
678 new GotoObjectTask(in, id);
679 break;
680
681 case gotoActorTask:
682 new GotoActorTask(in, id);
683 break;
684
685 case goAwayFromObjectTask:
686 new GoAwayFromObjectTask(in, id);
687 break;
688
689 case goAwayFromActorTask:
690 new GoAwayFromActorTask(in, id);
691 break;
692
693 case huntToBeNearLocationTask:
694 new HuntToBeNearLocationTask(in, id);
695 break;
696
697 case huntToBeNearObjectTask:
698 new HuntToBeNearObjectTask(in, id);
699 break;
700
701 case huntToPossessTask:
702 new HuntToPossessTask(in, id);
703 break;
704
705 case huntToBeNearActorTask:
706 new HuntToBeNearActorTask(in, id);
707 break;
708
709 case huntToKillTask:
710 new HuntToKillTask(in, id);
711 break;
712
713 case huntToGiveTask:
714 new HuntToGiveTask(in, id);
715 break;
716
717 case bandTask:
718 new BandTask(in, id);
719 break;
720
721 case bandAndAvoidEnemiesTask:
722 new BandAndAvoidEnemiesTask(in, id);
723 break;
724
725 case followPatrolRouteTask:
726 new FollowPatrolRouteTask(in, id);
727 break;
728
729 case attendTask:
730 new AttendTask(in, id);
731 break;
732 }
733 }
734
735 //----------------------------------------------------------------------
736 // Return the number of bytes necessary to create an archive of the
737 // specified Task
738
taskArchiveSize(Task * t)739 int32 taskArchiveSize(Task *t) {
740 return sizeof(int16) // Task type
741 + t->archiveSize();
742 }
743
writeTask(Task * t,Common::MemoryWriteStreamDynamic * out)744 void writeTask(Task *t, Common::MemoryWriteStreamDynamic *out) {
745 // Store the task's type
746 out->writeSint16LE(t->getType());
747
748 // Store the task
749 t->write(out);
750 }
751
752 /* ===================================================================== *
753 Task member functions
754 * ===================================================================== */
755
Task(Common::InSaveFile * in,TaskID id)756 Task::Task(Common::InSaveFile *in, TaskID id) {
757 // Place the stack ID into the stack pointer field
758 _stackID = in->readSint16LE();
759 stack = nullptr;
760 newTask(this, id);
761 }
762
763 //----------------------------------------------------------------------
764 // Fixup the Task pointers
765
fixup(void)766 void Task::fixup(void) {
767 // Convert the stack ID to a stack pointer
768 stack = getTaskStackAddress(_stackID);
769 }
770
771 //----------------------------------------------------------------------
772 // Return the number of bytes necessary to create an archive of this
773 // object's data
774
archiveSize(void) const775 inline int32 Task::archiveSize(void) const {
776 return sizeof(TaskStackID); // stack's ID
777 }
778
write(Common::MemoryWriteStreamDynamic * out) const779 void Task::write(Common::MemoryWriteStreamDynamic *out) const {
780 out->writeSint16LE(getTaskStackID(stack));
781 }
782
783 /* ===================================================================== *
784 WanderTask member functions
785 * ===================================================================== */
786
WanderTask(Common::InSaveFile * in,TaskID id)787 WanderTask::WanderTask(Common::InSaveFile *in, TaskID id) : Task(in, id) {
788 // Restore the paused flag
789 paused = in->readUint16LE();
790
791 // Restore the counter
792 counter = in->readSint16LE();
793 }
794
795 //----------------------------------------------------------------------
796 // Return the number of bytes needed to archive this object in
797 // a buffer
798
archiveSize(void) const799 int32 WanderTask::archiveSize(void) const {
800 return Task::archiveSize()
801 + sizeof(paused)
802 + sizeof(counter);
803 }
804
write(Common::MemoryWriteStreamDynamic * out) const805 void WanderTask::write(Common::MemoryWriteStreamDynamic *out) const {
806 // Let the base class archive its data
807 Task::write(out);
808
809 // Store the paused flag
810 out->writeUint16LE(paused);
811
812 // Store the counter
813 out->writeSint16LE(counter);
814 }
815
816 //----------------------------------------------------------------------
817 // Return an integer representing the type of this task
818
getType(void) const819 int16 WanderTask::getType(void) const {
820 return wanderTask;
821 }
822
823 //----------------------------------------------------------------------
824
abortTask(void)825 void WanderTask::abortTask(void) {
826 // if the actor has a wander motion, abort it
827 MotionTask *actorMotion = stack->getActor()->_moveTask;
828
829 if (actorMotion && actorMotion->isWander()) actorMotion->finishWalk();
830 }
831
832 //----------------------------------------------------------------------
833
evaluate(void)834 TaskResult WanderTask::evaluate(void) {
835 // Wandering is never done. It must be stopped manually.
836 return taskNotDone;
837 }
838
839 //----------------------------------------------------------------------
840
update(void)841 TaskResult WanderTask::update(void) {
842 if (counter == 0) {
843 if (!paused)
844 pause();
845 else
846 wander();
847 } else
848 counter--;
849
850 return !paused ? handleWander() : handlePaused();
851 }
852
853 //----------------------------------------------------------------------
854 // Determine if the specified task is equivalent to this task
855
operator ==(const Task & t) const856 bool WanderTask::operator == (const Task &t) const {
857 return t.getType() == wanderTask;
858 }
859
860 //----------------------------------------------------------------------
861 // Update function used when task is not paused
862
handleWander(void)863 TaskResult WanderTask::handleWander(void) {
864 MotionTask *actorMotion = stack->getActor()->_moveTask;
865
866 // If the actor is not already wandering, start a wander motion
867 // task
868 if (!actorMotion
869 || !actorMotion->isWander())
870 MotionTask::wander(*stack->getActor());
871
872 return taskNotDone;
873 }
874
875 //----------------------------------------------------------------------
876 // Set this task into the paused state
877
pause(void)878 void WanderTask::pause(void) {
879 // Call abort to stop the wandering motion
880 abortTask();
881
882 paused = true;
883 counter = (g_vm->_rnd->getRandomNumber(63) + g_vm->_rnd->getRandomNumber(63)) / 2;
884 }
885
886 //----------------------------------------------------------------------
887 // Set this task into the wander state
888
wander(void)889 void WanderTask::wander(void) {
890 paused = false;
891 counter = (g_vm->_rnd->getRandomNumber(255) + g_vm->_rnd->getRandomNumber(255)) / 2;
892 }
893
894 /* ===================================================================== *
895 TetheredWanderTask member functions
896 * ===================================================================== */
897
TetheredWanderTask(Common::InSaveFile * in,TaskID id)898 TetheredWanderTask::TetheredWanderTask(Common::InSaveFile *in, TaskID id) : WanderTask(in, id) {
899 debugC(3, kDebugSaveload, "... Loading TetheredWanderTask");
900
901 // Restore the tether coordinates
902 minU = in->readSint16LE();
903 minV = in->readSint16LE();
904 maxU = in->readSint16LE();
905 maxV = in->readSint16LE();
906
907 // Put the gotoTether ID into the gotoTether pointer field
908 _gotoTetherID = in->readSint16LE();
909 gotoTether = nullptr;
910 }
911
912 //----------------------------------------------------------------------
913 // Fixup the subtask pointers
914
fixup(void)915 void TetheredWanderTask::fixup(void) {
916 // Let the base class fixup it's pointers
917 WanderTask::fixup();
918
919 // Restore the gotoTether pointer
920 gotoTether = _gotoTetherID != NoTask
921 ? (GotoRegionTask *)getTaskAddress(_gotoTetherID)
922 : NULL;
923 }
924
925 //----------------------------------------------------------------------
926 // Return the number of bytes needed to archive this object in a buffer
927
archiveSize(void) const928 inline int32 TetheredWanderTask::archiveSize(void) const {
929 return WanderTask::archiveSize()
930 + sizeof(minU)
931 + sizeof(minU)
932 + sizeof(minU)
933 + sizeof(minU)
934 + sizeof(TaskID); // gotoTether ID
935 }
936
write(Common::MemoryWriteStreamDynamic * out) const937 void TetheredWanderTask::write(Common::MemoryWriteStreamDynamic *out) const {
938 debugC(3, kDebugSaveload, "... Saving TetheredWanderTask");
939
940 // Let the base class archive its data
941 WanderTask::write(out);
942
943 // Archive tether coordinates
944 out->writeSint16LE(minU);
945 out->writeSint16LE(minV);
946 out->writeSint16LE(maxU);
947 out->writeSint16LE(maxV);
948
949 // Archive gotoTether ID
950 if (gotoTether != NULL)
951 out->writeSint16LE(getTaskID(gotoTether));
952 else
953 out->writeSint16LE(NoTask);
954 }
955
956 #if DEBUG
957 //----------------------------------------------------------------------
958 // Debugging function used to mark this task and any sub tasks as being
959 // used. This is used to find task leaks.
960
mark(void)961 void TetheredWanderTask::mark(void) {
962 WanderTask::mark();
963 if (gotoTether != NULL)
964 gotoTether->mark();
965 }
966 #endif
967
968 //----------------------------------------------------------------------
969 // Return an integer representing the type of this task
970
getType(void) const971 int16 TetheredWanderTask::getType(void) const {
972 return tetheredWanderTask;
973 }
974
975 //----------------------------------------------------------------------
976
abortTask(void)977 void TetheredWanderTask::abortTask(void) {
978 if (gotoTether != NULL) {
979 gotoTether->abortTask();
980 delete gotoTether;
981 gotoTether = NULL;
982 } else {
983 MotionTask *actorMotion = stack->getActor()->_moveTask;
984
985 // if the actor has a tethered wander motion, abort it
986 if (actorMotion && actorMotion->isTethered())
987 actorMotion->finishWalk();
988 }
989 }
990
991 //----------------------------------------------------------------------
992 // Determine if the specified task is equivalent to this task
993
operator ==(const Task & t) const994 bool TetheredWanderTask::operator == (const Task &t) const {
995 if (t.getType() != tetheredWanderTask) return false;
996
997 const TetheredWanderTask *taskPtr = (const TetheredWanderTask *)&t;
998
999 return minU == taskPtr->minU && minV == taskPtr->minV
1000 && maxU == taskPtr->maxU && maxV == taskPtr->maxV;
1001 }
1002
1003 //----------------------------------------------------------------------
1004 // Update function used when task is not paused
1005
handleWander(void)1006 TaskResult TetheredWanderTask::handleWander(void) {
1007 Actor *a = stack->getActor();
1008 TilePoint actorLoc = a->getLocation();
1009
1010 if (actorLoc.u < minU || actorLoc.u >= maxU
1011 || actorLoc.v < minV || actorLoc.v >= maxV) {
1012 if (gotoTether != NULL)
1013 gotoTether->update();
1014 else {
1015 gotoTether = new GotoRegionTask(stack, minU, minV, maxU, maxV);
1016 if (gotoTether != NULL) gotoTether->update();
1017 }
1018 } else {
1019 if (gotoTether != NULL) {
1020 gotoTether->abortTask();
1021 delete gotoTether;
1022 gotoTether = NULL;
1023 }
1024
1025 bool startWander = false;
1026 TileRegion motionTether;
1027
1028 MotionTask *actorMotion = a->_moveTask;
1029
1030 if (actorMotion) {
1031 TileRegion motionTeth = actorMotion->getTether();
1032 startWander = ((!actorMotion->isWander())
1033 || motionTeth.min.u != minU
1034 || motionTeth.min.v != minV
1035 || motionTeth.max.u != maxU
1036 || motionTeth.max.v != maxV);
1037
1038 } else
1039 startWander = true;
1040
1041 // If the actor is not already wandering, start a wander motion
1042 // task
1043
1044 // JeffL - prevent null pointer reference
1045 /*
1046 if ( !actorMotion
1047 || !actorMotion->isWander()
1048 || motionTether.min.u != minU
1049 || motionTether.min.v != minV
1050 || motionTether.max.u != maxU
1051 || motionTether.max.v != maxV )
1052 */
1053 if (startWander) {
1054 TileRegion reg;
1055
1056 reg.min = TilePoint(minU, minV, 0);
1057 reg.max = TilePoint(maxU, maxV, 0);
1058 MotionTask::tetheredWander(*stack->getActor(), reg);
1059 }
1060 }
1061
1062 return taskNotDone;
1063 }
1064
1065 /* ===================================================================== *
1066 GotoTask member functions
1067 * ===================================================================== */
1068
GotoTask(Common::InSaveFile * in,TaskID id)1069 GotoTask::GotoTask(Common::InSaveFile *in, TaskID id) : Task(in, id) {
1070 // Get the wander TaskID
1071 _wanderID = in->readSint16LE();
1072 wander = nullptr;
1073
1074 // Restore prevRunState
1075 prevRunState = in->readUint16LE();
1076 }
1077
1078 //----------------------------------------------------------------------
1079 // Fixup the subtask pointers
1080
fixup(void)1081 void GotoTask::fixup(void) {
1082 // Let the base class fixup its pointers
1083 Task::fixup();
1084
1085 // Convert wanderID to a Task pointer
1086 wander = _wanderID != NoTask
1087 ? (WanderTask *)getTaskAddress(_wanderID)
1088 : NULL;
1089 }
1090
1091 //----------------------------------------------------------------------
1092 // Return the number of bytes needed to archive this object in
1093 // a buffer
1094
archiveSize(void) const1095 inline int32 GotoTask::archiveSize(void) const {
1096 return Task::archiveSize()
1097 + sizeof(TaskID) // wander ID
1098 + sizeof(prevRunState);
1099 }
1100
write(Common::MemoryWriteStreamDynamic * out) const1101 void GotoTask::write(Common::MemoryWriteStreamDynamic *out) const {
1102 // Let the base class archive its data
1103 Task::write(out);
1104
1105 // Convert the wander Task pointer to a TaskID and store it
1106 // in the buffer
1107 if (wander != NULL)
1108 out->writeSint16LE(getTaskID(wander));
1109 else
1110 out->writeSint16LE(NoTask);
1111
1112 // Store prevRunState
1113 out->writeUint16LE(prevRunState);
1114 }
1115
1116 #if DEBUG
1117 //----------------------------------------------------------------------
1118 // Debugging function used to mark this task and any sub tasks as being
1119 // used. This is used to find task leaks.
1120
mark(void)1121 void GotoTask::mark(void) {
1122 Task::mark();
1123 if (wander != NULL)
1124 wander->mark();
1125 }
1126 #endif
1127
1128 //----------------------------------------------------------------------
1129
abortTask(void)1130 void GotoTask::abortTask(void) {
1131 // If there is a wander subtask, delete it.
1132 if (wander) {
1133 wander->abortTask();
1134 delete wander;
1135 wander = NULL;
1136 } else {
1137 MotionTask *actorMotion = stack->getActor()->_moveTask;
1138
1139 if (actorMotion && actorMotion->isWalk()) actorMotion->finishWalk();
1140 }
1141 }
1142
1143 //----------------------------------------------------------------------
1144
evaluate(void)1145 TaskResult GotoTask::evaluate(void) {
1146 // Determine if we have reach the target.
1147 if (stack->getActor()->getLocation() == destination()) {
1148 abortTask();
1149 return taskSucceeded;
1150 }
1151
1152 return taskNotDone;
1153 }
1154
1155 //----------------------------------------------------------------------
1156
update(void)1157 TaskResult GotoTask::update(void) {
1158 // Check to see if we have reached the target
1159 {
1160 TaskResult result = evaluate();
1161 if (result != taskNotDone) return result;
1162 }
1163
1164 Actor *const a = stack->getActor();
1165 // Compute the immediate destination based upon wether or not the
1166 // actor has a line of sight to the target.
1167 TilePoint immediateDest = lineOfSight()
1168 ? destination()
1169 : intermediateDest();
1170
1171 // If we have a destination, walk there, else wander
1172 if (immediateDest != Nowhere) {
1173 // If wandering, cut it out
1174 if (wander != NULL) {
1175 delete wander;
1176 wander = NULL;
1177 }
1178
1179 // Determine if there is aready a motion task, and if so,
1180 // wether or not it needs to be modified.
1181 MotionTask *actorMotion = a->_moveTask;
1182 TilePoint actorLoc = a->getLocation();
1183
1184 if (actorMotion != NULL && actorMotion->isWalkToDest()) {
1185 bool runState = run();
1186 TilePoint motionTarget = actorMotion->getTarget();
1187
1188 if ((actorLoc.u >> kTileUVShift)
1189 == (immediateDest.u >> kTileUVShift)
1190 && (actorLoc.v >> kTileUVShift)
1191 == (immediateDest.v >> kTileUVShift)) {
1192 if (motionTarget != immediateDest
1193 || runState != prevRunState)
1194 actorMotion->changeDirectTarget(
1195 immediateDest,
1196 prevRunState = runState);
1197 } else {
1198 if ((motionTarget.u >> kTileUVShift)
1199 != (immediateDest.u >> kTileUVShift)
1200 || (motionTarget.v >> kTileUVShift)
1201 != (immediateDest.v >> kTileUVShift)
1202 || ABS(motionTarget.z - immediateDest.z) > 16
1203 || runState != prevRunState)
1204 actorMotion->changeTarget(
1205 immediateDest,
1206 prevRunState = runState);
1207 }
1208 } else {
1209 if ((actorLoc.u >> kTileUVShift)
1210 == (immediateDest.u >> kTileUVShift)
1211 && (actorLoc.v >> kTileUVShift)
1212 == (immediateDest.v >> kTileUVShift)) {
1213 MotionTask::walkToDirect(
1214 *a,
1215 immediateDest,
1216 prevRunState = run());
1217 } else
1218 MotionTask::walkTo(*a, immediateDest, prevRunState = run());
1219 }
1220 } else {
1221 // If wandering, update the wander task else set up a new
1222 // wander task
1223 if (wander != NULL)
1224 wander->update();
1225 else {
1226 wander = new WanderTask(stack);
1227 if (wander != NULL) wander->update();
1228 }
1229
1230 return taskNotDone;
1231 }
1232
1233 return taskNotDone;
1234 }
1235
1236 /* ===================================================================== *
1237 GotoLocationTask member functions
1238 * ===================================================================== */
1239
GotoLocationTask(Common::InSaveFile * in,TaskID id)1240 GotoLocationTask::GotoLocationTask(Common::InSaveFile *in, TaskID id) : GotoTask(in, id) {
1241 debugC(3, kDebugSaveload, "... Loading GotoLocationTask");
1242
1243 // Restore the target location
1244 targetLoc.load(in);
1245
1246 // Restore the runThreshold
1247 runThreshold = in->readByte();
1248 }
1249
1250 //----------------------------------------------------------------------
1251 // Return the number of bytes needed to archive this object in
1252 // a buffer
1253
archiveSize(void) const1254 inline int32 GotoLocationTask::archiveSize(void) const {
1255 return GotoTask::archiveSize()
1256 + sizeof(targetLoc)
1257 + sizeof(runThreshold);
1258 }
1259
write(Common::MemoryWriteStreamDynamic * out) const1260 void GotoLocationTask::write(Common::MemoryWriteStreamDynamic *out) const {
1261 debugC(3, kDebugSaveload, "... Saving GotoLocationTask");
1262
1263 // Let the base class archive its data
1264 GotoTask::write(out);
1265
1266 // Archive the target location
1267 targetLoc.write(out);
1268
1269 // Archive the run threshold
1270 out->writeByte(runThreshold);
1271 }
1272
1273 //----------------------------------------------------------------------
1274 // Return an integer representing the type of this task
1275
getType(void) const1276 int16 GotoLocationTask::getType(void) const {
1277 return gotoLocationTask;
1278 }
1279
1280 //----------------------------------------------------------------------
1281 // Determine if the specified task is equivalent to this task
1282
operator ==(const Task & t) const1283 bool GotoLocationTask::operator == (const Task &t) const {
1284 if (t.getType() != gotoLocationTask) return false;
1285
1286 const GotoLocationTask *taskPtr = (const GotoLocationTask *)&t;
1287
1288 return targetLoc == taskPtr->targetLoc
1289 && runThreshold == taskPtr->runThreshold;
1290 }
1291
1292 //----------------------------------------------------------------------
1293
destination(void)1294 TilePoint GotoLocationTask::destination(void) {
1295 // Simply return the target location
1296 return targetLoc;
1297 }
1298
1299 //----------------------------------------------------------------------
1300
intermediateDest(void)1301 TilePoint GotoLocationTask::intermediateDest(void) {
1302 // GotoLocationTask's never have an intermediate destination
1303 return targetLoc;
1304 }
1305
1306 //----------------------------------------------------------------------
1307
lineOfSight(void)1308 bool GotoLocationTask::lineOfSight(void) {
1309 // Let's pretend that there is always a line of sight to the
1310 // target location
1311 return true;
1312 }
1313
1314 //----------------------------------------------------------------------
1315
run(void)1316 bool GotoLocationTask::run(void) {
1317 TilePoint actorLoc = stack->getActor()->getLocation();
1318
1319 return runThreshold != maxuint8
1320 ? (targetLoc - actorLoc).quickHDistance() > runThreshold
1321 || ABS(targetLoc.z - actorLoc.z) > runThreshold
1322 : false;
1323 }
1324
1325 /* ===================================================================== *
1326 GotoRegionTask member functions
1327 * ===================================================================== */
1328
GotoRegionTask(Common::InSaveFile * in,TaskID id)1329 GotoRegionTask::GotoRegionTask(Common::InSaveFile *in, TaskID id) : GotoTask(in, id) {
1330 debugC(3, kDebugSaveload, "... Loading GotoRegionTask");
1331
1332 // Restore the region coordinates
1333 regionMinU = in->readSint16LE();
1334 regionMinV = in->readSint16LE();
1335 regionMaxU = in->readSint16LE();
1336 regionMaxV = in->readSint16LE();
1337 }
1338
1339 //----------------------------------------------------------------------
1340 // Return the number of bytes needed to archive this object in
1341 // a buffer
1342
archiveSize(void) const1343 inline int32 GotoRegionTask::archiveSize(void) const {
1344 return GotoTask::archiveSize()
1345 + sizeof(regionMinU)
1346 + sizeof(regionMinV)
1347 + sizeof(regionMaxU)
1348 + sizeof(regionMaxV);
1349 }
1350
write(Common::MemoryWriteStreamDynamic * out) const1351 void GotoRegionTask::write(Common::MemoryWriteStreamDynamic *out) const {
1352 debugC(3, kDebugSaveload, "... Saving GotoRegionTask");
1353
1354 // Let the base class archive its data
1355 GotoTask::write(out);
1356 // Archive the region coordinates
1357 out->writeSint16LE(regionMinU);
1358 out->writeSint16LE(regionMinV);
1359 out->writeSint16LE(regionMaxU);
1360 out->writeSint16LE(regionMaxV);
1361 }
1362
1363 //----------------------------------------------------------------------
1364 // Return an integer representing the type of this task
1365
getType(void) const1366 int16 GotoRegionTask::getType(void) const {
1367 return gotoRegionTask;
1368 }
1369
1370 //----------------------------------------------------------------------
1371 // Determine if the specified task is equivalent to this task
1372
operator ==(const Task & t) const1373 bool GotoRegionTask::operator == (const Task &t) const {
1374 if (t.getType() != gotoRegionTask) return false;
1375
1376 const GotoRegionTask *taskPtr = (const GotoRegionTask *)&t;
1377
1378 return regionMinU == taskPtr->regionMinU
1379 && regionMinV == taskPtr->regionMinV
1380 && regionMaxU == taskPtr->regionMaxU
1381 && regionMaxV == taskPtr->regionMaxV;
1382 }
1383
destination(void)1384 TilePoint GotoRegionTask::destination(void) {
1385 TilePoint actorLoc = stack->getActor()->getLocation();
1386
1387 return TilePoint(
1388 clamp(regionMinU, actorLoc.u, regionMaxU - 1),
1389 clamp(regionMinV, actorLoc.v, regionMaxV - 1),
1390 actorLoc.z);
1391 }
1392
1393 //----------------------------------------------------------------------
1394
intermediateDest(void)1395 TilePoint GotoRegionTask::intermediateDest(void) {
1396 return destination();
1397 }
1398
1399 //----------------------------------------------------------------------
1400
lineOfSight(void)1401 bool GotoRegionTask::lineOfSight(void) {
1402 return true;
1403 }
1404
1405 //----------------------------------------------------------------------
1406
run(void)1407 bool GotoRegionTask::run(void) {
1408 return false;
1409 }
1410
1411 /* ===================================================================== *
1412 GotoObjectTargetTask member functions
1413 * ===================================================================== */
1414
GotoObjectTargetTask(Common::InSaveFile * in,TaskID id)1415 GotoObjectTargetTask::GotoObjectTargetTask(Common::InSaveFile *in, TaskID id) : GotoTask(in, id) {
1416 // Restore lastTestedLoc and increment pointer
1417 lastTestedLoc.load(in);
1418
1419 // Restore sightCtr and increment pointer
1420 sightCtr = in->readSint16LE();
1421
1422 // Restore the flags and increment pointer
1423 flags = in->readByte();
1424
1425 // Restore lastKnownLoc
1426 lastKnownLoc.load(in);
1427 }
1428
1429 //----------------------------------------------------------------------
1430 // Return the number of bytes needed to archive this object in
1431 // a buffer
1432
archiveSize(void) const1433 inline int32 GotoObjectTargetTask::archiveSize(void) const {
1434 return GotoTask::archiveSize()
1435 + sizeof(lastTestedLoc)
1436 + sizeof(sightCtr)
1437 + sizeof(flags)
1438 + sizeof(lastKnownLoc);
1439 }
1440
write(Common::MemoryWriteStreamDynamic * out) const1441 void GotoObjectTargetTask::write(Common::MemoryWriteStreamDynamic *out) const {
1442 // Let the base class archive its data
1443 GotoTask::write(out);
1444
1445 // Archive lastTestedLoc and increment pointer
1446 lastTestedLoc.write(out);
1447
1448 // Archive sightCtr and increment pointer
1449 out->writeSint16LE(sightCtr);
1450
1451 // Archive the flags and increment pointer
1452 out->writeByte(flags);
1453
1454 // Archive lastKnownLoc
1455 lastKnownLoc.write(out);
1456 }
1457
1458 //----------------------------------------------------------------------
1459
destination(void)1460 TilePoint GotoObjectTargetTask::destination(void) {
1461 // Return the object's true location
1462 return getObject()->getLocation();
1463 }
1464
1465 //----------------------------------------------------------------------
1466
intermediateDest(void)1467 TilePoint GotoObjectTargetTask::intermediateDest(void) {
1468 // Return the last known location
1469 return lastKnownLoc;
1470 }
1471
1472 //----------------------------------------------------------------------
1473
lineOfSight(void)1474 bool GotoObjectTargetTask::lineOfSight(void) {
1475 if (flags & track) {
1476 flags |= inSight;
1477 lastKnownLoc = getObject()->getLocation();
1478 } else {
1479 Actor *a = stack->getActor();
1480 GameObject *target = getObject();
1481 ObjectID targetID = target->thisID();
1482 TilePoint targetLoc = target->getLocation();
1483 SenseInfo info;
1484
1485 // Determine if we need to retest the line of sight
1486 if (flags & inSight) {
1487 // If the object was previously in sight, retest the line of
1488 // sight if the target has moved beyond a certain range from
1489 // the last location it was tested at.
1490 if ((targetLoc - lastTestedLoc).quickHDistance() > 25
1491 || ABS(targetLoc.z - lastTestedLoc.z) > 25) {
1492 if (a->canSenseSpecificObject(
1493 info,
1494 maxSenseRange,
1495 targetID)
1496 || a->canSenseSpecificObjectIndirectly(
1497 info,
1498 maxSenseRange,
1499 targetID))
1500 flags |= inSight;
1501 else
1502 flags &= ~inSight;
1503 lastTestedLoc = targetLoc;
1504 }
1505 } else {
1506 // If the object was not privously in sight, retest the line
1507 // of sight periodically
1508 if (sightCtr == 0) {
1509 sightCtr = sightRate;
1510 if (a->canSenseSpecificObject(
1511 info,
1512 maxSenseRange,
1513 targetID)
1514 || a->canSenseSpecificObjectIndirectly(
1515 info,
1516 maxSenseRange,
1517 targetID))
1518 flags |= inSight;
1519 else
1520 flags &= ~inSight;
1521 lastTestedLoc = targetLoc;
1522 }
1523 sightCtr--;
1524 }
1525
1526 if (flags & inSight) {
1527 // If the target is in sight, the last known location is the
1528 // objects current location.
1529 lastKnownLoc = targetLoc;
1530 } else {
1531 // If the target is not in sight, determine if we've already
1532 // reached the last know location and if so set the last
1533 // known location to Nowhere
1534 if (lastKnownLoc != Nowhere
1535 && (lastKnownLoc - a->getLocation()).quickHDistance() <= 4)
1536 lastKnownLoc = Nowhere;
1537 }
1538 }
1539
1540 return flags & inSight;
1541 }
1542
1543 /* ===================================================================== *
1544 GotoObjectTask member functions
1545 * ===================================================================== */
1546
GotoObjectTask(Common::InSaveFile * in,TaskID id)1547 GotoObjectTask::GotoObjectTask(Common::InSaveFile *in, TaskID id) :
1548 GotoObjectTargetTask(in, id) {
1549 debugC(3, kDebugSaveload, "... Loading GotoObjectTask");
1550
1551 ObjectID targetID = in->readUint16LE();
1552
1553 // Restore the targetObj pointer
1554 targetObj = targetID != Nothing
1555 ? GameObject::objectAddress(targetID)
1556 : NULL;
1557 }
1558
1559 //----------------------------------------------------------------------
1560 // Return the number of bytes needed to archive this object in
1561 // a buffer
1562
archiveSize(void) const1563 inline int32 GotoObjectTask::archiveSize(void) const {
1564 return GotoObjectTargetTask::archiveSize() + sizeof(ObjectID);
1565 }
1566
write(Common::MemoryWriteStreamDynamic * out) const1567 void GotoObjectTask::write(Common::MemoryWriteStreamDynamic *out) const {
1568 debugC(3, kDebugSaveload, "... Saving GotoObjectTask");
1569
1570 // Let the base class archive its data
1571 GotoObjectTargetTask::write(out);
1572
1573 if (targetObj != NULL)
1574 out->writeUint16LE(targetObj->thisID());
1575 else
1576 out->writeUint16LE(Nothing);
1577 }
1578
1579 //----------------------------------------------------------------------
1580 // Return an integer representing the type of this task
1581
getType(void) const1582 int16 GotoObjectTask::getType(void) const {
1583 return gotoObjectTask;
1584 }
1585
1586 //----------------------------------------------------------------------
1587 // Determine if the specified task is equivalent to this task
1588
operator ==(const Task & t) const1589 bool GotoObjectTask::operator == (const Task &t) const {
1590 if (t.getType() != gotoObjectTask) return false;
1591
1592 const GotoObjectTask *taskPtr = (const GotoObjectTask *)&t;
1593
1594 return tracking() == taskPtr->tracking()
1595 && targetObj == taskPtr->targetObj;
1596 }
1597
1598 //----------------------------------------------------------------------
1599
getObject(void)1600 GameObject *GotoObjectTask::getObject(void) {
1601 // Simply return the pointer to the target object
1602 return targetObj;
1603 }
1604
1605 //----------------------------------------------------------------------
1606
run(void)1607 bool GotoObjectTask::run(void) {
1608 // Running after objects has not been implemented yet
1609 return false;
1610 }
1611
1612 /* ===================================================================== *
1613 GotoActorTask member functions
1614 * ===================================================================== */
1615
GotoActorTask(Common::InSaveFile * in,TaskID id)1616 GotoActorTask::GotoActorTask(Common::InSaveFile *in, TaskID id) :
1617 GotoObjectTargetTask(in, id) {
1618 debugC(3, kDebugSaveload, "... Loading GotoActorTask");
1619 // Restore the targetObj pointer
1620 ObjectID targetID = in->readUint16LE();
1621 targetActor = targetID != Nothing
1622 ? (Actor *)GameObject::objectAddress(targetID)
1623 : NULL;
1624 }
1625
1626 //----------------------------------------------------------------------
1627 // Return the number of bytes needed to archive this object in
1628 // a buffer
1629
archiveSize(void) const1630 inline int32 GotoActorTask::archiveSize(void) const {
1631 return GotoObjectTargetTask::archiveSize() + sizeof(ObjectID);
1632 }
1633
write(Common::MemoryWriteStreamDynamic * out) const1634 void GotoActorTask::write(Common::MemoryWriteStreamDynamic *out) const {
1635 debugC(3, kDebugSaveload, "... Saving GotoActorTask");
1636
1637 // Let the base class archive its data
1638 GotoObjectTargetTask::write(out);
1639
1640 if (targetActor != NULL)
1641 out->writeUint16LE(targetActor->thisID());
1642 else
1643 out->writeUint16LE(Nothing);
1644 }
1645
1646 //----------------------------------------------------------------------
1647 // Return an integer representing the type of this task
1648
getType(void) const1649 int16 GotoActorTask::getType(void) const {
1650 return gotoActorTask;
1651 }
1652
1653 //----------------------------------------------------------------------
1654 // Determine if the specified task is equivalent to this task
1655
operator ==(const Task & t) const1656 bool GotoActorTask::operator == (const Task &t) const {
1657 if (t.getType() != gotoActorTask) return false;
1658
1659 const GotoActorTask *taskPtr = (const GotoActorTask *)&t;
1660
1661 return tracking() == taskPtr->tracking()
1662 && targetActor == taskPtr->targetActor;
1663 }
1664
1665 //----------------------------------------------------------------------
1666
getObject(void)1667 GameObject *GotoActorTask::getObject(void) {
1668 // Simply return the pointer to the target actor
1669 return (GameObject *)targetActor;
1670 }
1671
1672 //----------------------------------------------------------------------
1673
run(void)1674 bool GotoActorTask::run(void) {
1675 if (isInSight()) {
1676 TilePoint actorLoc = stack->getActor()->getLocation(),
1677 targetLoc = getTarget()->getLocation();
1678
1679 return (actorLoc - targetLoc).quickHDistance() >= kTileUVSize * 4;
1680 } else
1681 return lastKnownLoc != Nowhere;
1682 }
1683
GoAwayFromTask(Common::InSaveFile * in,TaskID id)1684 GoAwayFromTask::GoAwayFromTask(Common::InSaveFile *in, TaskID id) : Task(in, id) {
1685 // Get the subtask ID
1686 _goTaskID = in->readSint16LE();
1687 goTask = nullptr;
1688
1689 // Restore the flags
1690 flags = in->readByte();
1691 }
1692
1693 //----------------------------------------------------------------------
1694 // Fixup the subtask pointer
1695
fixup(void)1696 void GoAwayFromTask::fixup(void) {
1697 // Let the base class fixup its pointers
1698 Task::fixup();
1699
1700 goTask = _goTaskID != NoTask
1701 ? (GotoLocationTask *)getTaskAddress(_goTaskID)
1702 : NULL;
1703 }
1704
1705 //----------------------------------------------------------------------
1706 // Return the number of bytes needed to archive this object in
1707 // a buffer
1708
archiveSize(void) const1709 inline int32 GoAwayFromTask::archiveSize(void) const {
1710 return Task::archiveSize() + sizeof(TaskID) + sizeof(flags);
1711 }
1712
write(Common::MemoryWriteStreamDynamic * out) const1713 void GoAwayFromTask::write(Common::MemoryWriteStreamDynamic *out) const {
1714 // Let the base class archive its data
1715 Task::write(out);
1716
1717 // Store the subTask's ID
1718 if (goTask != NULL)
1719 out->writeSint16LE(getTaskID(goTask));
1720 else
1721 out->writeSint16LE(NoTask);
1722
1723 // Store the flags
1724 out->writeByte(flags);
1725 }
1726
1727 #if DEBUG
1728 //----------------------------------------------------------------------
1729 // Debugging function used to mark this task and any sub tasks as being
1730 // used. This is used to find task leaks.
1731
mark(void)1732 void GoAwayFromTask::mark(void) {
1733 Task::mark();
1734 if (goTask != NULL)
1735 goTask->mark();
1736 }
1737 #endif
1738
1739 //----------------------------------------------------------------------
1740 // Abort this task
1741
abortTask(void)1742 void GoAwayFromTask::abortTask(void) {
1743 if (goTask != NULL) {
1744 goTask->abortTask();
1745 delete goTask;
1746 goTask = NULL;
1747 }
1748 }
1749
1750 //----------------------------------------------------------------------
1751 // Evaluate this task
1752
evaluate(void)1753 TaskResult GoAwayFromTask::evaluate(void) {
1754 // Going away is never done, it must be stopped manually
1755 return taskNotDone;
1756 }
1757
1758 //----------------------------------------------------------------------
1759 // Update this task
1760
update(void)1761 TaskResult GoAwayFromTask::update(void) {
1762 static const TilePoint dirTable_[] = {
1763 TilePoint(64, 64, 0),
1764 TilePoint(0, 64, 0),
1765 TilePoint(-64, 64, 0),
1766 TilePoint(-64, 0, 0),
1767 TilePoint(-64, -64, 0),
1768 TilePoint(0, -64, 0),
1769 TilePoint(64, -64, 0),
1770 TilePoint(64, 0, 0),
1771 };
1772
1773 Actor *a = stack->getActor();
1774 TilePoint actorLoc = a->getLocation(),
1775 repulsionVector = getRepulsionVector(),
1776 dest;
1777 int16 repulsionDist = repulsionVector.quickHDistance();
1778
1779 // Compute a point for the actor to walk toward
1780 if (repulsionDist != 0) {
1781 dest.u = actorLoc.u + ((int32)repulsionVector.u * 64 / repulsionDist);
1782 dest.v = actorLoc.v + ((int32)repulsionVector.v * 64 / repulsionDist);
1783 dest.z = actorLoc.z;
1784 } else
1785 dest = actorLoc + dirTable_[a->_currentFacing];
1786
1787 if (goTask != NULL) {
1788 if (goTask->getTarget() != dest)
1789 goTask->changeTarget(dest);
1790
1791 goTask->update();
1792 } else {
1793 if ((goTask = flags & run
1794 ? new GotoLocationTask(stack, dest, 0)
1795 : new GotoLocationTask(stack, dest))
1796 != NULL)
1797 goTask->update();
1798 }
1799
1800 return taskNotDone;
1801 }
1802
1803 /* ===================================================================== *
1804 GoAwayFromObjectTask member functions
1805 * ===================================================================== */
1806
GoAwayFromObjectTask(Common::InSaveFile * in,TaskID id)1807 GoAwayFromObjectTask::GoAwayFromObjectTask(Common::InSaveFile *in, TaskID id) :
1808 GoAwayFromTask(in, id) {
1809 debugC(3, kDebugSaveload, "... Loading GoAwayFromObjectTask");
1810
1811 // Get the object's ID
1812 ObjectID objectID = in->readUint16LE();
1813
1814 // Convert the ID to an object pointer
1815 obj = objectID != Nothing
1816 ? GameObject::objectAddress(objectID)
1817 : NULL;
1818 }
1819
1820 //----------------------------------------------------------------------
1821 // Return the number of bytes needed to archive this object in
1822 // a buffer
1823
archiveSize(void) const1824 int32 GoAwayFromObjectTask::archiveSize(void) const {
1825 return GoAwayFromTask::archiveSize() + sizeof(ObjectID);
1826 }
1827
write(Common::MemoryWriteStreamDynamic * out) const1828 void GoAwayFromObjectTask::write(Common::MemoryWriteStreamDynamic *out) const {
1829 debugC(3, kDebugSaveload, "... Saving GoAwayFromObjectTask");
1830
1831 // Let the base class archive its data
1832 GoAwayFromTask::write(out);
1833
1834 // Store the object's ID
1835 if (obj != NULL)
1836 out->writeUint16LE(obj->thisID());
1837 else
1838 out->writeUint16LE(Nothing);
1839 }
1840
1841 //----------------------------------------------------------------------
1842 // Return an integer representing the type of this task
1843
getType(void) const1844 int16 GoAwayFromObjectTask::getType(void) const {
1845 return goAwayFromObjectTask;
1846 }
1847
1848 //----------------------------------------------------------------------
1849 // Determine if the specified task is equivalent to this task
1850
operator ==(const Task & t) const1851 bool GoAwayFromObjectTask::operator == (const Task &t) const {
1852 if (t.getType() != goAwayFromObjectTask) return false;
1853
1854 const GoAwayFromObjectTask *taskPtr = (const GoAwayFromObjectTask *)&t;
1855
1856 return obj == taskPtr->obj;
1857 }
1858
1859 //----------------------------------------------------------------------
1860 // Simply return the object's location
1861
getRepulsionVector(void)1862 TilePoint GoAwayFromObjectTask::getRepulsionVector(void) {
1863 return stack->getActor()->getLocation() - obj->getLocation();
1864 }
1865
1866 /* ===================================================================== *
1867 GoAwayFromActorTask member functions
1868 * ===================================================================== */
1869
1870 //----------------------------------------------------------------------
1871 // Constructor -- initial construction
1872
GoAwayFromActorTask(TaskStack * ts,Actor * a,bool runFlag)1873 GoAwayFromActorTask::GoAwayFromActorTask(
1874 TaskStack *ts,
1875 Actor *a,
1876 bool runFlag) :
1877 GoAwayFromTask(ts, runFlag) {
1878 debugC(2, kDebugTasks, " - GoAwayFromActorTask1");
1879 SpecificActorTarget(a).clone(targetMem);
1880 }
1881
GoAwayFromActorTask(TaskStack * ts,const ActorTarget & at,bool runFlag)1882 GoAwayFromActorTask::GoAwayFromActorTask(
1883 TaskStack *ts,
1884 const ActorTarget &at,
1885 bool runFlag) :
1886 GoAwayFromTask(ts, runFlag) {
1887 assert(at.size() <= sizeof(targetMem));
1888 debugC(2, kDebugTasks, " - GoAwayFromActorTask2");
1889 // Copy the target to the target buffer
1890 at.clone(targetMem);
1891 }
1892
1893
GoAwayFromActorTask(Common::InSaveFile * in,TaskID id)1894 GoAwayFromActorTask::GoAwayFromActorTask(Common::InSaveFile *in, TaskID id) : GoAwayFromTask(in, id) {
1895 debugC(3, kDebugSaveload, "... Loading GoAwayFromActorTask");
1896
1897 // Restore the target
1898 readTarget(targetMem, in);
1899 }
1900
1901 //----------------------------------------------------------------------
1902 // Return the number of bytes needed to archive this object in
1903 // a buffer
1904
archiveSize(void) const1905 int32 GoAwayFromActorTask::archiveSize(void) const {
1906 return GoAwayFromTask::archiveSize() + targetArchiveSize(getTarget());
1907 }
1908
write(Common::MemoryWriteStreamDynamic * out) const1909 void GoAwayFromActorTask::write(Common::MemoryWriteStreamDynamic *out) const {
1910 debugC(3, kDebugSaveload, "... Saving GoAwayFromActorTask");
1911
1912 // Let the base class archive its data
1913 GoAwayFromTask::write(out);
1914
1915 // Store the target
1916 writeTarget(getTarget(), out);
1917 }
1918
1919 //----------------------------------------------------------------------
1920 // Return an integer representing the type of this task
1921
getType(void) const1922 int16 GoAwayFromActorTask::getType(void) const {
1923 return goAwayFromActorTask;
1924 }
1925
1926 //----------------------------------------------------------------------
1927 // Determine if the specified task is equivalent to this task
1928
operator ==(const Task & t) const1929 bool GoAwayFromActorTask::operator == (const Task &t) const {
1930 if (t.getType() != goAwayFromActorTask) return false;
1931
1932 const GoAwayFromActorTask *taskPtr = (const GoAwayFromActorTask *)&t;
1933
1934 return *getTarget() == *taskPtr->getTarget();
1935 }
1936
1937 //----------------------------------------------------------------------
1938
getRepulsionVector(void)1939 TilePoint GoAwayFromActorTask::getRepulsionVector(void) {
1940 Actor *a = stack->getActor();
1941 TilePoint actorLoc = a->getLocation(),
1942 repulsionVector;
1943 int16 i;
1944 TilePoint locArray[6];
1945 int16 strengthArray[ARRAYSIZE(locArray)] =
1946 { 1, 1, 1, 1, 1, 1 };
1947 int16 distArray[ARRAYSIZE(locArray)];
1948 TargetLocationArray tla(
1949 ARRAYSIZE(locArray),
1950 locArray,
1951 distArray);
1952
1953 getTarget()->where(a->world(), actorLoc, tla);
1954
1955 if (tla.locs == 0) return TilePoint(0, 0, 0);
1956
1957 for (i = 0; i < tla.locs; i++)
1958 locArray[i] -= actorLoc;
1959
1960 repulsionVector = computeRepulsionVector(locArray, strengthArray, tla.locs);
1961
1962 return repulsionVector.quickHDistance() > 0
1963 ? repulsionVector
1964 : -locArray[0];
1965 }
1966
1967 /* ===================================================================== *
1968 HuntTask member functions
1969 * ===================================================================== */
1970
HuntTask(Common::InSaveFile * in,TaskID id)1971 HuntTask::HuntTask(Common::InSaveFile *in, TaskID id) : Task(in, id) {
1972 // Restore the flags
1973 huntFlags = in->readByte();
1974 subTask = nullptr;
1975
1976 // If the flags say we have a sub task, restore it too
1977 if (huntFlags & (huntGoto | huntWander))
1978 _subTaskID = in->readSint16LE();
1979 else
1980 _subTaskID = NoTask;
1981 }
1982
1983 //----------------------------------------------------------------------
1984 // Fixup the subtask pointers
1985
fixup(void)1986 void HuntTask::fixup( void ) {
1987 // Let the base class fixup its pointers
1988 Task::fixup();
1989
1990 if (huntFlags & (huntGoto | huntWander))
1991 subTask = getTaskAddress(_subTaskID);
1992 else
1993 subTask = nullptr;
1994 }
1995
1996 //----------------------------------------------------------------------
1997 // Return the number of bytes needed to archive this object in
1998 // a buffer
1999
archiveSize(void) const2000 inline int32 HuntTask::archiveSize(void) const {
2001 int32 size = 0;
2002
2003 size += Task::archiveSize() + sizeof(huntFlags);
2004 if (huntFlags & (huntGoto | huntWander)) size += sizeof(TaskID);
2005
2006 return size;
2007 }
2008
write(Common::MemoryWriteStreamDynamic * out) const2009 void HuntTask::write(Common::MemoryWriteStreamDynamic *out) const {
2010 // Let the base class archive its data
2011 Task::write(out);
2012
2013 // Store the flags
2014 out->writeByte(huntFlags);
2015
2016 // If the flags say we have a sub task, store it too
2017 if (huntFlags & (huntGoto | huntWander))
2018 out->writeSint16LE(getTaskID(subTask));
2019 }
2020
2021 #if DEBUG
2022 //----------------------------------------------------------------------
2023 // Debugging function used to mark this task and any sub tasks as being
2024 // used. This is used to find task leaks.
2025
mark(void)2026 void HuntTask::mark(void) {
2027 Task::mark();
2028 if (huntFlags & (huntGoto | huntWander))
2029 subTask->mark();
2030 }
2031 #endif
2032
2033 //----------------------------------------------------------------------
2034
abortTask(void)2035 void HuntTask::abortTask(void) {
2036 if (huntFlags & (huntWander | huntGoto)) {
2037 subTask->abortTask();
2038 delete subTask;
2039 }
2040
2041 // If we've reached the target call the atTargetabortTask() function
2042 if (atTarget()) atTargetabortTask();
2043 }
2044
2045 //----------------------------------------------------------------------
2046
evaluate(void)2047 TaskResult HuntTask::evaluate(void) {
2048 if (atTarget()) {
2049 // If we've reached the target abort any sub tasks
2050 if (huntFlags & huntWander)
2051 removeWanderTask();
2052 else if (huntFlags & huntGoto)
2053 removeGotoTask();
2054
2055 return atTargetEvaluate();
2056 } else
2057 // If we haven't reached the target, we know we're not done
2058 return taskNotDone;
2059 }
2060
2061 //----------------------------------------------------------------------
2062
update(void)2063 TaskResult HuntTask::update(void) {
2064 Actor *a = stack->getActor();
2065
2066 if (a->_moveTask && a->_moveTask->isPrivledged()) return taskNotDone;
2067
2068 // Reevaluate the target
2069 evaluateTarget();
2070
2071 // Determine if we have reached the target
2072 if (atTarget()) {
2073 // If we've reached the target abort any sub tasks
2074 if (huntFlags & huntWander)
2075 removeWanderTask();
2076 else if (huntFlags & huntGoto)
2077 removeGotoTask();
2078
2079 return atTargetUpdate();
2080 } else {
2081 // If we are going to a target, determine if the goto task
2082 // is still valid. If not, abort it.
2083 if ((huntFlags & huntGoto)
2084 && targetHasChanged((GotoTask *)subTask))
2085 removeGotoTask();
2086
2087 // Determine if there is a goto subtask
2088 if (!(huntFlags & huntGoto)) {
2089 GotoTask *gotoResult;
2090
2091 // Try to set up a goto subtask
2092 if ((gotoResult = setupGoto()) != NULL) {
2093 if (huntFlags & huntWander) removeWanderTask();
2094
2095 subTask = gotoResult;
2096 huntFlags |= huntGoto;
2097 } else {
2098 // If we couldn't setup a goto task, setup a wander task
2099 if (!(huntFlags & huntWander)) {
2100 if ((subTask = new WanderTask(stack)) != NULL)
2101 huntFlags |= huntWander;
2102 }
2103 }
2104 }
2105
2106 // If there is a subtask, update it
2107 if ((huntFlags & (huntGoto | huntWander)) && subTask)
2108 subTask->update();
2109
2110 // If we're not at the target, we know the hunt task is not
2111 // done
2112 return taskNotDone;
2113 }
2114 }
2115
2116 //----------------------------------------------------------------------
2117
removeWanderTask(void)2118 void HuntTask::removeWanderTask(void) {
2119 subTask->abortTask();
2120 delete subTask;
2121 huntFlags &= ~huntWander;
2122 }
2123
2124 //----------------------------------------------------------------------
2125
removeGotoTask(void)2126 void HuntTask::removeGotoTask(void) {
2127 subTask->abortTask();
2128 delete subTask;
2129 subTask = nullptr;
2130 huntFlags &= ~huntGoto;
2131 }
2132
2133 /* ===================================================================== *
2134 HuntLocationTask member functions
2135 * ===================================================================== */
2136
2137 //----------------------------------------------------------------------
2138 // Constructor -- initial construction
2139
HuntLocationTask(TaskStack * ts,const Target & t)2140 HuntLocationTask::HuntLocationTask(TaskStack *ts, const Target &t) :
2141 HuntTask(ts),
2142 currentTarget(Nowhere) {
2143 assert(t.size() <= sizeof(targetMem));
2144 debugC(2, kDebugTasks, " - HuntLocationTask");
2145 // Copy the target to the target buffer
2146 t.clone(targetMem);
2147 }
2148
HuntLocationTask(Common::InSaveFile * in,TaskID id)2149 HuntLocationTask::HuntLocationTask(Common::InSaveFile *in, TaskID id) : HuntTask(in, id) {
2150 // Restore the currentTarget location
2151 currentTarget.load(in);
2152
2153 // Restore the target
2154 readTarget(targetMem, in);
2155 }
2156
2157 //----------------------------------------------------------------------
2158 // Return the number of bytes needed to archive this object in
2159 // a buffer
2160
archiveSize(void) const2161 inline int32 HuntLocationTask::archiveSize(void) const {
2162 return HuntTask::archiveSize()
2163 + sizeof(currentTarget)
2164 + targetArchiveSize(getTarget());
2165 }
2166
write(Common::MemoryWriteStreamDynamic * out) const2167 void HuntLocationTask::write(Common::MemoryWriteStreamDynamic *out) const {
2168 // Let the base class archive its data
2169 HuntTask::write(out);
2170
2171 // Store the current target location
2172 currentTarget.write(out);
2173
2174 // Store the target
2175 writeTarget(getTarget(), out);
2176 }
2177
2178 //----------------------------------------------------------------------
2179
targetHasChanged(GotoTask * gotoTarget)2180 bool HuntLocationTask::targetHasChanged(GotoTask *gotoTarget) {
2181 // Determine if the specified goto task is going to the current
2182 // target.
2183 GotoLocationTask *gotoLoc = (GotoLocationTask *)gotoTarget;
2184 return gotoLoc->getTarget() != currentTarget;
2185 }
2186
2187 //----------------------------------------------------------------------
2188
setupGoto(void)2189 GotoTask *HuntLocationTask::setupGoto(void) {
2190 // If there is somewhere to go, setup a goto task, else return NULL
2191 return currentTarget != Nowhere
2192 ? new GotoLocationTask(stack, currentTarget)
2193 : NULL;
2194 }
2195
2196 //----------------------------------------------------------------------
2197
currentTargetLoc(void)2198 TilePoint HuntLocationTask::currentTargetLoc(void) {
2199 return currentTarget;
2200 }
2201
2202 /* ===================================================================== *
2203 HuntToBeNearLocationTask member functions
2204 * ===================================================================== */
2205
HuntToBeNearLocationTask(Common::InSaveFile * in,TaskID id)2206 HuntToBeNearLocationTask::HuntToBeNearLocationTask(Common::InSaveFile *in, TaskID id) :
2207 HuntLocationTask(in, id) {
2208 debugC(3, kDebugSaveload, "... Loading HuntToBeNearLocationTask");
2209
2210 // Restore the range
2211 range = in->readUint16LE();
2212
2213 // Restore the evaluation counter
2214 targetEvaluateCtr = in->readByte();
2215 }
2216
2217 //----------------------------------------------------------------------
2218 // Return the number of bytes needed to archive this object in
2219 // a buffer
2220
archiveSize(void) const2221 inline int32 HuntToBeNearLocationTask::archiveSize(void) const {
2222 return HuntLocationTask::archiveSize()
2223 + sizeof(range)
2224 + sizeof(targetEvaluateCtr);
2225 }
2226
write(Common::MemoryWriteStreamDynamic * out) const2227 void HuntToBeNearLocationTask::write(Common::MemoryWriteStreamDynamic *out) const {
2228 debugC(3, kDebugSaveload, "... Saving HuntToBeNearLocationTask");
2229
2230 // Let the base class archive its data
2231 HuntLocationTask::write(out);
2232
2233 // Store the range
2234 out->writeUint16LE(range);
2235
2236 // Store the evaluation counter
2237 out->writeByte(targetEvaluateCtr);
2238 }
2239
2240 //----------------------------------------------------------------------
2241 // Return an integer representing the type of this task
2242
getType(void) const2243 int16 HuntToBeNearLocationTask::getType(void) const {
2244 return huntToBeNearLocationTask;
2245 }
2246
2247 //----------------------------------------------------------------------
2248 // Determine if the specified task is equivalent to this task
2249
operator ==(const Task & t) const2250 bool HuntToBeNearLocationTask::operator == (const Task &t) const {
2251 if (t.getType() != huntToBeNearLocationTask) return false;
2252
2253 const HuntToBeNearLocationTask *taskPtr = (const HuntToBeNearLocationTask *)&t;
2254
2255 return *getTarget() == *taskPtr->getTarget()
2256 && range == taskPtr->range;
2257 }
2258
2259 //----------------------------------------------------------------------
2260
evaluateTarget(void)2261 void HuntToBeNearLocationTask::evaluateTarget(void) {
2262 // If its time to reevaluate the target, simply get the nearest
2263 // target location from the LocationTarget
2264 if (targetEvaluateCtr == 0) {
2265 Actor *a = stack->getActor();
2266
2267 currentTarget =
2268 getTarget()->where(a->world(), a->getLocation());
2269
2270 targetEvaluateCtr = targetEvaluateRate;
2271 }
2272 targetEvaluateCtr--;
2273 }
2274
2275 //----------------------------------------------------------------------
2276
atTarget(void)2277 bool HuntToBeNearLocationTask::atTarget(void) {
2278 TilePoint targetLoc = currentTargetLoc();
2279
2280 // Determine if we are within the specified range of the target
2281 return targetLoc != Nowhere
2282 && stack->getActor()->inRange(targetLoc, range);
2283 }
2284
2285 //----------------------------------------------------------------------
2286
atTargetabortTask(void)2287 void HuntToBeNearLocationTask::atTargetabortTask(void) {}
2288
2289 //----------------------------------------------------------------------
2290
atTargetEvaluate(void)2291 TaskResult HuntToBeNearLocationTask::atTargetEvaluate(void) {
2292 // If we're at the target, we're done
2293 return taskSucceeded;
2294 }
2295
2296 //----------------------------------------------------------------------
2297
atTargetUpdate(void)2298 TaskResult HuntToBeNearLocationTask::atTargetUpdate(void) {
2299 // If we're at the target, we're done
2300 return taskSucceeded;
2301 }
2302
2303 /* ===================================================================== *
2304 HuntObjectTask member functions
2305 * ===================================================================== */
2306
2307 //----------------------------------------------------------------------
2308 // Constructor -- initial construction
2309
HuntObjectTask(TaskStack * ts,const ObjectTarget & ot)2310 HuntObjectTask::HuntObjectTask(TaskStack *ts, const ObjectTarget &ot) :
2311 HuntTask(ts),
2312 currentTarget(NULL) {
2313 assert(ot.size() <= sizeof(targetMem));
2314 debugC(2, kDebugTasks, " - HuntObjectTask");
2315 // Copy the target to the target buffer
2316 ot.clone(targetMem);
2317 }
2318
HuntObjectTask(Common::InSaveFile * in,TaskID id)2319 HuntObjectTask::HuntObjectTask(Common::InSaveFile *in, TaskID id) : HuntTask(in, id) {
2320 // Restore the current target ID
2321 ObjectID currentTargetID = in->readUint16LE();
2322
2323 // Convert the ID to a GameObject pointer
2324 currentTarget = currentTargetID != Nothing
2325 ? GameObject::objectAddress(currentTargetID)
2326 : NULL;
2327
2328 // Reconstruct the object target
2329 readTarget(targetMem, in);
2330 }
2331
2332 //----------------------------------------------------------------------
2333 // Return the number of bytes needed to archive this object in
2334 // a buffer
2335
archiveSize(void) const2336 inline int32 HuntObjectTask::archiveSize(void) const {
2337 return HuntTask::archiveSize()
2338 + sizeof(ObjectID)
2339 + targetArchiveSize(getTarget());
2340 }
2341
write(Common::MemoryWriteStreamDynamic * out) const2342 void HuntObjectTask::write(Common::MemoryWriteStreamDynamic *out) const {
2343 // Let the base class archive its data
2344 HuntTask::write(out);
2345
2346 // Store the ID
2347 if (currentTarget != NULL)
2348 out->writeByte(currentTarget->thisID());
2349 else
2350 out->writeByte(Nothing);
2351
2352 // Store the object target
2353 writeTarget(getTarget(), out);
2354 }
2355
2356 //----------------------------------------------------------------------
2357
targetHasChanged(GotoTask * gotoTarget)2358 bool HuntObjectTask::targetHasChanged(GotoTask *gotoTarget) {
2359 // Determine if the specified goto task's destination is the
2360 // current target object
2361 GotoObjectTask *gotoObj = (GotoObjectTask *)gotoTarget;
2362 return gotoObj->getTarget() != currentTarget;
2363 }
2364
2365 //----------------------------------------------------------------------
2366
setupGoto(void)2367 GotoTask *HuntObjectTask::setupGoto(void) {
2368 // If there is an object to goto, setup a GotoObjectTask, else
2369 // return NULL
2370 return currentTarget
2371 ? new GotoObjectTask(stack, currentTarget)
2372 : NULL;
2373 }
2374
2375 //----------------------------------------------------------------------
2376
currentTargetLoc(void)2377 TilePoint HuntObjectTask::currentTargetLoc(void) {
2378 // If there is a current target object, return its locatio, else
2379 // return Nowhere
2380 return currentTarget ? currentTarget->getLocation() : Nowhere;
2381 }
2382
2383 /* ===================================================================== *
2384 HuntToBeNearObjectTask member functions
2385 * ===================================================================== */
2386
HuntToBeNearObjectTask(Common::InSaveFile * in,TaskID id)2387 HuntToBeNearObjectTask::HuntToBeNearObjectTask(Common::InSaveFile *in, TaskID id) :
2388 HuntObjectTask(in, id) {
2389 debugC(3, kDebugSaveload, "... Loading HuntToBeNearObjectTask");
2390
2391 // Restore the range
2392 range = in->readUint16LE();
2393
2394 // Restore the evaluation counter
2395 targetEvaluateCtr = in->readByte();
2396 }
2397
2398 //----------------------------------------------------------------------
2399 // Return the number of bytes needed to archive this object in
2400 // a buffer
2401
archiveSize(void) const2402 inline int32 HuntToBeNearObjectTask::archiveSize(void) const {
2403 return HuntObjectTask::archiveSize()
2404 + sizeof(range)
2405 + sizeof(targetEvaluateCtr);
2406 }
2407
write(Common::MemoryWriteStreamDynamic * out) const2408 void HuntToBeNearObjectTask::write(Common::MemoryWriteStreamDynamic *out) const {
2409 debugC(3, kDebugSaveload, "... Saving HuntToBeNearObjectTask");
2410
2411 // Let the base class archive its data
2412 HuntObjectTask::write(out);
2413
2414 // Store the range
2415 out->writeUint16LE(range);
2416
2417 // Store the evaluation counter
2418 out->writeByte(targetEvaluateCtr);
2419 }
2420
2421 //----------------------------------------------------------------------
2422 // Return an integer representing the type of this task
2423
getType(void) const2424 int16 HuntToBeNearObjectTask::getType(void) const {
2425 return huntToBeNearObjectTask;
2426 }
2427
2428 //----------------------------------------------------------------------
2429 // Determine if the specified task is equivalent to this task
2430
operator ==(const Task & t) const2431 bool HuntToBeNearObjectTask::operator == (const Task &t) const {
2432 if (t.getType() != huntToBeNearObjectTask) return false;
2433
2434 const HuntToBeNearObjectTask *taskPtr = (const HuntToBeNearObjectTask *)&t;
2435
2436 return *getTarget() == *taskPtr->getTarget()
2437 && range == taskPtr->range;
2438 }
2439
2440 //----------------------------------------------------------------------
2441
evaluateTarget(void)2442 void HuntToBeNearObjectTask::evaluateTarget(void) {
2443 // Determine if it is time to reevaluate the target object
2444 if (targetEvaluateCtr == 0) {
2445 Actor *a = stack->getActor();
2446 int16 i;
2447 GameObject *objArray[16];
2448 int16 distArray[ARRAYSIZE(objArray)];
2449 TargetObjectArray toa(
2450 ARRAYSIZE(objArray),
2451 objArray,
2452 distArray);
2453 SenseInfo info;
2454
2455 // Get an array of objects from the ObjectTarget
2456 getTarget()->object(a->world(), a->getLocation(), toa);
2457
2458 // Iterate through each object in the array and determine if
2459 // there is a line of sight to that object
2460 for (i = 0; i < toa.objs; i++) {
2461 ObjectID objID = objArray[i]->thisID();
2462
2463 if (a->canSenseSpecificObject(
2464 info,
2465 maxSenseRange,
2466 objID)
2467 || a->canSenseSpecificObjectIndirectly(
2468 info,
2469 maxSenseRange,
2470 objID)) {
2471 currentTarget = objArray[i];
2472 break;
2473 }
2474 }
2475
2476 targetEvaluateCtr = targetEvaluateRate;
2477 }
2478
2479 // Decrement the target reevaluate counter
2480 targetEvaluateCtr--;
2481 }
2482
2483 //----------------------------------------------------------------------
2484
atTarget(void)2485 bool HuntToBeNearObjectTask::atTarget(void) {
2486 TilePoint targetLoc = currentTargetLoc();
2487
2488 // Determine if we are within the specified range of the current
2489 // target
2490 return targetLoc != Nowhere
2491 && stack->getActor()->inRange(targetLoc, range);
2492 }
2493
2494 //----------------------------------------------------------------------
2495
atTargetabortTask(void)2496 void HuntToBeNearObjectTask::atTargetabortTask(void) {}
2497
2498 //----------------------------------------------------------------------
2499
atTargetEvaluate(void)2500 TaskResult HuntToBeNearObjectTask::atTargetEvaluate(void) {
2501 // If we're at the target, we're done
2502 return taskSucceeded;
2503 }
2504
2505 //----------------------------------------------------------------------
2506
atTargetUpdate(void)2507 TaskResult HuntToBeNearObjectTask::atTargetUpdate(void) {
2508 // If we're at the target, we're done
2509 return taskSucceeded;
2510 }
2511
2512 /* ===================================================================== *
2513 HuntToPossessTask member functions
2514 * ===================================================================== */
2515
2516 // Hunt to possess in not fully implemented yet
2517
HuntToPossessTask(Common::InSaveFile * in,TaskID id)2518 HuntToPossessTask::HuntToPossessTask(Common::InSaveFile *in, TaskID id) : HuntObjectTask(in, id) {
2519 debugC(3, kDebugSaveload, "... Loading HuntToPossessTask");
2520
2521 // Restore evaluation counter
2522 targetEvaluateCtr = in->readByte();
2523
2524 // Restore grab flag
2525 grabFlag = in->readUint16LE();
2526 }
2527
2528 //----------------------------------------------------------------------
2529 // Return the number of bytes needed to archive this object in
2530 // a buffer
2531
archiveSize(void) const2532 inline int32 HuntToPossessTask::archiveSize(void) const {
2533 return HuntObjectTask::archiveSize()
2534 + sizeof(targetEvaluateCtr)
2535 + sizeof(grabFlag);
2536 }
2537
write(Common::MemoryWriteStreamDynamic * out) const2538 void HuntToPossessTask::write(Common::MemoryWriteStreamDynamic *out) const {
2539 debugC(3, kDebugSaveload, "... Saving HuntToPossessTask");
2540
2541 // Let the base class archive its data
2542 HuntObjectTask::write(out);
2543
2544 // Store the evaluation counter
2545 out->writeByte(targetEvaluateCtr);
2546
2547 // Store the grab flag
2548 out->writeUint16LE(grabFlag);
2549 }
2550
2551 //----------------------------------------------------------------------
2552 // Return an integer representing the type of this task
2553
getType(void) const2554 int16 HuntToPossessTask::getType(void) const {
2555 return huntToPossessTask;
2556 }
2557
2558 //----------------------------------------------------------------------
2559 // Determine if the specified task is equivalent to this task
2560
operator ==(const Task & t) const2561 bool HuntToPossessTask::operator == (const Task &t) const {
2562 if (t.getType() != huntToPossessTask) return false;
2563
2564 const HuntToPossessTask *taskPtr = (const HuntToPossessTask *)&t;
2565
2566 return *getTarget() == *taskPtr->getTarget();
2567 }
2568
2569 //----------------------------------------------------------------------
2570
evaluateTarget(void)2571 void HuntToPossessTask::evaluateTarget(void) {
2572 // Determine if it is time to reevaluate the target object
2573 if (targetEvaluateCtr == 0) {
2574 Actor *a = stack->getActor();
2575 int16 i;
2576 GameObject *objArray[16];
2577 int16 distArray[ARRAYSIZE(objArray)];
2578 TargetObjectArray toa(
2579 ARRAYSIZE(objArray),
2580 objArray,
2581 distArray);
2582 SenseInfo info;
2583
2584 // Get an array of objects from the ObjectTarget
2585 getTarget()->object(a->world(), a->getLocation(), toa);
2586
2587 // Iterate through each object in the array and determine if
2588 // there is a line of sight to that object
2589 for (i = 0; i < toa.objs; i++) {
2590 ObjectID objID = objArray[i]->thisID();
2591
2592 if (a->canSenseSpecificObject(
2593 info,
2594 maxSenseRange,
2595 objID)
2596 || a->canSenseSpecificObjectIndirectly(
2597 info,
2598 maxSenseRange,
2599 objID)) {
2600 currentTarget = objArray[i];
2601 break;
2602 }
2603 }
2604
2605 targetEvaluateCtr = targetEvaluateRate;
2606 }
2607
2608 // Decrement the target reevaluate counter
2609 targetEvaluateCtr--;
2610 }
2611
2612 //----------------------------------------------------------------------
2613
atTarget(void)2614 bool HuntToPossessTask::atTarget(void) {
2615 Actor *a = stack->getActor();
2616
2617 return currentTarget
2618 && (a->inReach(currentTarget->getLocation())
2619 || (grabFlag
2620 && a->isContaining(currentTarget)));
2621 }
2622
2623 //----------------------------------------------------------------------
2624
atTargetabortTask(void)2625 void HuntToPossessTask::atTargetabortTask(void) {}
2626
2627 //----------------------------------------------------------------------
2628
atTargetEvaluate(void)2629 TaskResult HuntToPossessTask::atTargetEvaluate(void) {
2630 if (currentTarget && stack->getActor()->isContaining(currentTarget))
2631 return taskSucceeded;
2632
2633 return taskNotDone;
2634 }
2635
2636 //----------------------------------------------------------------------
2637
atTargetUpdate(void)2638 TaskResult HuntToPossessTask::atTargetUpdate(void) {
2639 // Hunt to possess in not implemented yet
2640 return taskNotDone;
2641 }
2642
2643 /* ===================================================================== *
2644 HuntActorTask member functions
2645 * ===================================================================== */
2646
2647 //----------------------------------------------------------------------
2648 // Constructor -- initial construction
2649
HuntActorTask(TaskStack * ts,const ActorTarget & at,bool trackFlag)2650 HuntActorTask::HuntActorTask(
2651 TaskStack *ts,
2652 const ActorTarget &at,
2653 bool trackFlag) :
2654 HuntTask(ts),
2655 flags(trackFlag ? track : 0),
2656 currentTarget(NULL) {
2657 assert(at.size() <= sizeof(targetMem));
2658 debugC(2, kDebugTasks, " - HuntActorTask");
2659 // Copy the target to the target buffer
2660 at.clone(targetMem);
2661 }
2662
HuntActorTask(Common::InSaveFile * in,TaskID id)2663 HuntActorTask::HuntActorTask(Common::InSaveFile *in, TaskID id) : HuntTask(in, id) {
2664 // Restore the flags
2665 flags = in->readByte();
2666
2667 // Restore the current target ID
2668 ObjectID currentTargetID = in->readUint16LE();
2669
2670 // Convert the ID to a GameObject pointer
2671 currentTarget = currentTargetID != Nothing
2672 ? (Actor *)GameObject::objectAddress(currentTargetID)
2673 : NULL;
2674
2675 // Reconstruct the object target
2676 readTarget(targetMem, in);
2677 }
2678
2679 //----------------------------------------------------------------------
2680 // Return the number of bytes needed to archive this object in
2681 // a buffer
2682
archiveSize(void) const2683 inline int32 HuntActorTask::archiveSize(void) const {
2684 return HuntTask::archiveSize()
2685 + sizeof(flags)
2686 + sizeof(ObjectID)
2687 + targetArchiveSize(getTarget());
2688 }
2689
write(Common::MemoryWriteStreamDynamic * out) const2690 void HuntActorTask::write(Common::MemoryWriteStreamDynamic *out) const {
2691 // Let the base class archive its data
2692 HuntTask::write(out);
2693
2694 // Store the flags
2695 out->writeByte(flags);
2696
2697 // Store the ID
2698 if (currentTarget != NULL)
2699 out->writeUint16LE(currentTarget->thisID());
2700 else
2701 out->writeUint16LE(Nothing);
2702
2703 // Store the object target
2704 writeTarget(getTarget(), out);
2705 }
2706
2707 //----------------------------------------------------------------------
2708
targetHasChanged(GotoTask * gotoTarget)2709 bool HuntActorTask::targetHasChanged(GotoTask *gotoTarget) {
2710 // Determine if the specified goto task's destination is the
2711 // current target actor
2712 GotoActorTask *gotoActor = (GotoActorTask *)gotoTarget;
2713 return gotoActor->getTarget() != currentTarget;
2714 }
2715
2716 //----------------------------------------------------------------------
2717
setupGoto(void)2718 GotoTask *HuntActorTask::setupGoto(void) {
2719 // If there is an actor to goto, setup a GotoActorTask, else
2720 // return NULL
2721 /* return currentTarget
2722 ? new GotoActorTask( stack, currentTarget, flags & track )
2723 : NULL;
2724 */
2725 if (currentTarget != NULL) {
2726 return new GotoActorTask(
2727 stack,
2728 currentTarget,
2729 flags & track);
2730 }
2731
2732 return NULL;
2733 }
2734
2735 //----------------------------------------------------------------------
2736
currentTargetLoc(void)2737 TilePoint HuntActorTask::currentTargetLoc(void) {
2738 // If there is a current target actor, return its location, else
2739 // return Nowhere
2740 return currentTarget ? currentTarget->getLocation() : Nowhere;
2741 }
2742
2743 /* ===================================================================== *
2744 HuntToBeNearActorTask member functions
2745 * ===================================================================== */
2746
HuntToBeNearActorTask(Common::InSaveFile * in,TaskID id)2747 HuntToBeNearActorTask::HuntToBeNearActorTask(Common::InSaveFile *in, TaskID id) :
2748 HuntActorTask(in, id) {
2749 debugC(3, kDebugSaveload, "... Loading HuntToBeNearActorTask");
2750
2751 // Get the goAway task ID
2752 _goAwayID = in->readSint16LE();
2753 goAway = nullptr;
2754
2755 // Restore the range
2756 range = in->readUint16LE();
2757
2758 // Restore the evaluation counter
2759 targetEvaluateCtr = in->readByte();
2760 }
2761
2762 //----------------------------------------------------------------------
2763 // Fixup the subtask pointers
2764
fixup(void)2765 void HuntToBeNearActorTask::fixup(void) {
2766 // Let the base class fixup its pointers
2767 HuntActorTask::fixup();
2768
2769 // Convert the task ID to a task pointer
2770 goAway = _goAwayID != NoTask
2771 ? (GoAwayFromObjectTask *)getTaskAddress(_goAwayID)
2772 : NULL;
2773 }
2774
2775 //----------------------------------------------------------------------
2776 // Return the number of bytes needed to archive this object in
2777 // a buffer
2778
archiveSize(void) const2779 inline int32 HuntToBeNearActorTask::archiveSize(void) const {
2780 return HuntActorTask::archiveSize()
2781 + sizeof(TaskID) // goAway ID
2782 + sizeof(range)
2783 + sizeof(targetEvaluateCtr);
2784 }
2785
write(Common::MemoryWriteStreamDynamic * out) const2786 void HuntToBeNearActorTask::write(Common::MemoryWriteStreamDynamic *out) const {
2787 debugC(3, kDebugSaveload, "... Saving HuntToBeNearActorTask");
2788
2789 // Let the base class archive its data
2790 HuntActorTask::write(out);
2791
2792 // Store the task ID
2793 if (goAway != NULL)
2794 out->writeSint16LE(getTaskID(goAway));
2795 else
2796 out->writeSint16LE(NoTask);
2797
2798 // Store the range
2799 out->writeUint16LE(range);
2800
2801 // Store the evaluation counter
2802 out->writeByte(targetEvaluateCtr);
2803 }
2804
2805 #if DEBUG
2806 //----------------------------------------------------------------------
2807 // Debugging function used to mark this task and any sub tasks as being
2808 // used. This is used to find task leaks.
2809
mark(void)2810 void HuntToBeNearActorTask::mark(void) {
2811 HuntActorTask::mark();
2812 if (goAway != NULL)
2813 goAway->mark();
2814 }
2815 #endif
2816
2817 //----------------------------------------------------------------------
2818 // Return an integer representing the type of this task
2819
getType(void) const2820 int16 HuntToBeNearActorTask::getType(void) const {
2821 return huntToBeNearActorTask;
2822 }
2823
2824 //----------------------------------------------------------------------
2825 // Determine if the specified task is equivalent to this task
2826
operator ==(const Task & t) const2827 bool HuntToBeNearActorTask::operator == (const Task &t) const {
2828 if (t.getType() != huntToBeNearActorTask) return false;
2829
2830 const HuntToBeNearActorTask *taskPtr = (const HuntToBeNearActorTask *)&t;
2831
2832 return *getTarget() == *taskPtr->getTarget()
2833 && tracking() ? taskPtr->tracking() : !taskPtr->tracking()
2834 && range == taskPtr->range;
2835 }
2836
2837 //----------------------------------------------------------------------
2838
evaluateTarget(void)2839 void HuntToBeNearActorTask::evaluateTarget(void) {
2840 // Determine if its time to reevaluate the current target actor
2841 if (targetEvaluateCtr == 0) {
2842 Actor *a = stack->getActor();
2843 int16 i;
2844 Actor *actorArray[16];
2845 int16 distArray[ARRAYSIZE(actorArray)];
2846 TargetActorArray taa(
2847 ARRAYSIZE(actorArray),
2848 actorArray,
2849 distArray);
2850 SenseInfo info;
2851
2852 // Get an array of actor pointers from the ActorTarget
2853 getTarget()->actor(a->world(), a->getLocation(), taa);
2854
2855 // Iterate through each actor in the array and determine if
2856 // there is a line of sight to that actor
2857 for (i = 0; i < taa.actors; i++) {
2858 if (tracking()
2859 || a->canSenseSpecificActor(
2860 info,
2861 maxSenseRange,
2862 actorArray[i])
2863 || a->canSenseSpecificActorIndirectly(
2864 info,
2865 maxSenseRange,
2866 actorArray[i])) {
2867 if (currentTarget != actorArray[i]) {
2868 if (atTarget()) atTargetabortTask();
2869 currentTarget = actorArray[i];
2870 }
2871
2872 break;
2873 }
2874 }
2875
2876 targetEvaluateCtr = targetEvaluateRate;
2877 }
2878
2879 // Decrement the target reevaluation counter.
2880 targetEvaluateCtr--;
2881 }
2882
2883 //----------------------------------------------------------------------
2884
atTarget(void)2885 bool HuntToBeNearActorTask::atTarget(void) {
2886 TilePoint targetLoc = currentTargetLoc();
2887
2888 // Determine if we're within the specified range of the current
2889 // target actor
2890 if (targetLoc != Nowhere
2891 && stack->getActor()->inRange(targetLoc, range))
2892 return true;
2893 else {
2894 if (goAway != NULL) {
2895 goAway->abortTask();
2896 delete goAway;
2897 goAway = NULL;
2898 }
2899
2900 return false;
2901 }
2902 }
2903
2904 //----------------------------------------------------------------------
2905
atTargetabortTask(void)2906 void HuntToBeNearActorTask::atTargetabortTask(void) {
2907 if (goAway != NULL) {
2908 goAway->abortTask();
2909 delete goAway;
2910 goAway = NULL;
2911 }
2912 }
2913
2914 //----------------------------------------------------------------------
2915
atTargetEvaluate(void)2916 TaskResult HuntToBeNearActorTask::atTargetEvaluate(void) {
2917 TilePoint targetLoc = currentTargetLoc();
2918
2919 // If we're not TOO close, we're done
2920 if (stack->getActor()->inRange(targetLoc, tooClose))
2921 return taskNotDone;
2922
2923 if (goAway != NULL) {
2924 goAway->abortTask();
2925 delete goAway;
2926 goAway = NULL;
2927 }
2928
2929 return taskSucceeded;
2930 }
2931
2932 //----------------------------------------------------------------------
2933
atTargetUpdate(void)2934 TaskResult HuntToBeNearActorTask::atTargetUpdate(void) {
2935 Actor *a = stack->getActor();
2936 TilePoint targetLoc = currentTargetLoc();
2937
2938 // Determine if we're TOO close
2939 if (a->inRange(targetLoc, tooClose)) {
2940 // Setup a go away task if necessary and update it
2941 if (goAway == NULL) {
2942 goAway = new GoAwayFromObjectTask(stack, currentTarget);
2943 if (goAway != NULL) goAway->update();
2944 } else
2945 goAway->update();
2946
2947 return taskNotDone;
2948 }
2949
2950 // Delete the go away task if it exists
2951 if (goAway != NULL) {
2952 goAway->abortTask();
2953 delete goAway;
2954 goAway = NULL;
2955 }
2956
2957 return taskSucceeded;
2958 }
2959
2960 /* ===================================================================== *
2961 HuntToKillTask member functions
2962 * ===================================================================== */
2963
2964 //----------------------------------------------------------------------
2965 // Constructor -- initial construction
2966
HuntToKillTask(TaskStack * ts,const ActorTarget & at,bool trackFlag)2967 HuntToKillTask::HuntToKillTask(
2968 TaskStack *ts,
2969 const ActorTarget &at,
2970 bool trackFlag) :
2971 HuntActorTask(ts, at, trackFlag),
2972 targetEvaluateCtr(0),
2973 specialAttackCtr(10),
2974 flags(evalWeapon) {
2975 debugC(2, kDebugTasks, " - HuntToKillTask");
2976 Actor *a = stack->getActor();
2977
2978 if (isActor(a->_currentTarget))
2979 currentTarget = (Actor *)a->_currentTarget;
2980
2981 a->setFightStance(true);
2982 }
2983
HuntToKillTask(Common::InSaveFile * in,TaskID id)2984 HuntToKillTask::HuntToKillTask(Common::InSaveFile *in, TaskID id) : HuntActorTask(in, id) {
2985 debugC(3, kDebugSaveload, "... Loading HuntToKillTask");
2986
2987 // Restore the evaluation counter
2988 targetEvaluateCtr = in->readByte();
2989 specialAttackCtr = in->readByte();
2990 flags = in->readByte();
2991 }
2992
2993 //----------------------------------------------------------------------
2994 // Return the number of bytes needed to archive this object in
2995 // a buffer
2996
archiveSize(void) const2997 inline int32 HuntToKillTask::archiveSize(void) const {
2998 return HuntActorTask::archiveSize()
2999 + sizeof(targetEvaluateCtr)
3000 + sizeof(specialAttackCtr)
3001 + sizeof(flags);
3002 }
3003
write(Common::MemoryWriteStreamDynamic * out) const3004 void HuntToKillTask::write(Common::MemoryWriteStreamDynamic *out) const {
3005 debugC(3, kDebugSaveload, "... Saving HuntToKillTask");
3006
3007 // Let the base class archive its data
3008 HuntActorTask::write(out);
3009
3010 // Store the evaluation counter
3011 out->writeByte(targetEvaluateCtr);
3012 out->writeByte(specialAttackCtr);
3013 out->writeByte(flags);
3014 }
3015
3016 //----------------------------------------------------------------------
3017 // Return an integer representing the type of this task
3018
getType(void) const3019 int16 HuntToKillTask::getType(void) const {
3020 return huntToKillTask;
3021 }
3022
3023 //----------------------------------------------------------------------
3024 // Determine if the specified task is equivalent to this task
3025
operator ==(const Task & t) const3026 bool HuntToKillTask::operator == (const Task &t) const {
3027 if (t.getType() != huntToKillTask) return false;
3028
3029 const HuntToKillTask *taskPtr = (const HuntToKillTask *)&t;
3030
3031 return *getTarget() == *taskPtr->getTarget()
3032 && tracking() ? taskPtr->tracking() : !taskPtr->tracking();
3033 }
3034
3035 //----------------------------------------------------------------------
3036
abortTask(void)3037 void HuntToKillTask::abortTask(void) {
3038 HuntActorTask::abortTask();
3039
3040 Actor *a = stack->getActor();
3041
3042 a->_flags &= ~Actor::specialAttack;
3043
3044 a->setFightStance(false);
3045 }
3046
3047 //----------------------------------------------------------------------
3048
update(void)3049 TaskResult HuntToKillTask::update(void) {
3050 if (specialAttackCtr == 0) {
3051 stack->getActor()->_flags |= Actor::specialAttack;
3052 // A little hack to make monsters with 99 spellcraft cast spells more often
3053 if (stack->getActor()->getStats()->spellcraft >= 99)
3054 specialAttackCtr = 3;
3055 else specialAttackCtr = 10;
3056 } else
3057 specialAttackCtr--;
3058
3059 return HuntActorTask::update();
3060 }
3061
3062 //----------------------------------------------------------------------
3063
evaluateTarget(void)3064 void HuntToKillTask::evaluateTarget(void) {
3065 Actor *a = stack->getActor();
3066
3067 if (flags & evalWeapon && a->isInterruptable()) {
3068 evaluateWeapon();
3069 flags &= ~evalWeapon;
3070 }
3071
3072
3073 // Determine if its time to reevaluate the current target actor
3074 if (targetEvaluateCtr == 0
3075 || (currentTarget != NULL
3076 && currentTarget->isDead())) {
3077 Actor *bestTarget = NULL;
3078 ActorProto *proto = (ActorProto *)a->proto();
3079 int16 i;
3080 Actor *actorArray[16];
3081 int16 distArray[ARRAYSIZE(actorArray)];
3082 TargetActorArray taa(
3083 ARRAYSIZE(actorArray),
3084 actorArray,
3085 distArray);
3086 SenseInfo info;
3087
3088 // Get an array of actor pointers from the ActorTarget
3089 getTarget()->actor(a->world(), a->getLocation(), taa);
3090
3091 switch (proto->combatBehavior) {
3092 case behaviorHungry:
3093 // Iterate through each actor in the array and determine if
3094 // there is a line of sight to that actor
3095 for (i = 0; i < taa.actors; i++) {
3096 if (actorArray[i]->isDead()) continue;
3097
3098 if (tracking()
3099 || a->canSenseSpecificActor(
3100 info,
3101 maxSenseRange,
3102 actorArray[i])
3103 || a->canSenseSpecificActorIndirectly(
3104 info,
3105 maxSenseRange,
3106 actorArray[i])) {
3107 bestTarget = actorArray[i];
3108 break;
3109 }
3110 }
3111 break;
3112
3113 case behaviorCowardly: {
3114 int16 bestScore = 0;
3115
3116 for (i = 0; i < taa.actors; i++) {
3117 if (actorArray[i]->isDead()) continue;
3118
3119 if (tracking()
3120 || a->canSenseSpecificActor(
3121 info,
3122 maxSenseRange,
3123 actorArray[i])
3124 || a->canSenseSpecificActorIndirectly(
3125 info,
3126 maxSenseRange,
3127 actorArray[i])) {
3128 int16 score;
3129
3130 score = closenessScore(distArray[i]) * 16
3131 / actorArray[i]->defenseScore();
3132
3133 if (score > bestScore || bestTarget == NULL) {
3134 bestScore = score;
3135 bestTarget = actorArray[i];
3136 }
3137 }
3138 }
3139 }
3140 break;
3141
3142 case behaviorBerserk: {
3143 int16 bestScore = 0;
3144
3145 for (i = 0; i < taa.actors; i++) {
3146 if (actorArray[i]->isDead()) continue;
3147
3148 if (tracking()
3149 || a->canSenseSpecificActor(
3150 info,
3151 maxSenseRange,
3152 actorArray[i])
3153 || a->canSenseSpecificActorIndirectly(
3154 info,
3155 maxSenseRange,
3156 actorArray[i])) {
3157 int16 score;
3158
3159 score = closenessScore(distArray[i])
3160 * actorArray[i]->offenseScore();
3161
3162 if (score > bestScore || bestTarget == NULL) {
3163 bestScore = score;
3164 bestTarget = actorArray[i];
3165 }
3166 }
3167 }
3168 }
3169 break;
3170
3171 case behaviorSmart: {
3172 int16 bestScore = 0;
3173
3174 for (i = 0; i < taa.actors; i++) {
3175 if (actorArray[i]->isDead()) continue;
3176
3177 if (tracking()
3178 || a->canSenseSpecificActor(
3179 info,
3180 maxSenseRange,
3181 actorArray[i])
3182 || a->canSenseSpecificActorIndirectly(
3183 info,
3184 maxSenseRange,
3185 actorArray[i])) {
3186 int16 score;
3187
3188 score = closenessScore(distArray[i])
3189 * actorArray[i]->offenseScore()
3190 / actorArray[i]->defenseScore();
3191
3192 if (score > bestScore || bestTarget == NULL) {
3193 bestScore = score;
3194 bestTarget = actorArray[i];
3195 }
3196 }
3197 }
3198 }
3199 break;
3200 }
3201
3202 if (bestTarget != currentTarget) {
3203 // If the current target has changed, abort any
3204 // action currently taking place
3205 if (atTarget()) atTargetabortTask();
3206 currentTarget = bestTarget;
3207 a->_currentTarget = currentTarget;
3208 }
3209
3210 flags |= evalWeapon;
3211
3212 targetEvaluateCtr = targetEvaluateRate;
3213 }
3214
3215 // Decrement the target reevaluation counter
3216 targetEvaluateCtr--;
3217 }
3218
3219 //----------------------------------------------------------------------
3220
atTarget(void)3221 bool HuntToKillTask::atTarget(void) {
3222 // Determine if we're in attack range of the current target
3223 return currentTarget != NULL
3224 && stack->getActor()->inAttackRange(
3225 currentTarget->getLocation());
3226 }
3227
3228 //----------------------------------------------------------------------
3229
atTargetabortTask(void)3230 void HuntToKillTask::atTargetabortTask(void) {
3231 // If the task is aborted while at the target actor, abort any
3232 // attack currently taking place
3233 stack->getActor()->stopAttack(currentTarget);
3234 }
3235
3236 //----------------------------------------------------------------------
3237
atTargetEvaluate(void)3238 TaskResult HuntToKillTask::atTargetEvaluate(void) {
3239 // This task is never done and must be aborted manually
3240 return taskNotDone;
3241 }
3242
3243 //----------------------------------------------------------------------
3244
atTargetUpdate(void)3245 TaskResult HuntToKillTask::atTargetUpdate(void) {
3246 assert(isActor(currentTarget));
3247
3248 Actor *a = stack->getActor();
3249
3250 // If we're ready to attack, attack
3251 if (a->isInterruptable() && g_vm->_rnd->getRandomNumber(7) == 0) {
3252 a->attack(currentTarget);
3253 flags |= evalWeapon;
3254 }
3255
3256 return taskNotDone;
3257 }
3258
3259 //----------------------------------------------------------------------
3260
evaluateWeapon(void)3261 void HuntToKillTask::evaluateWeapon(void) {
3262 Actor *a = stack->getActor();
3263 ObjectID actorID = a->thisID();
3264 GameObject *obj,
3265 *bestWeapon,
3266 *currentWeapon;
3267 int bestWeaponRating;
3268 ContainerIterator iter(a);
3269
3270 bestWeapon = NULL;
3271 bestWeaponRating = 0;
3272 currentWeapon = a->offensiveObject();
3273 // If the current offensive object is the actor himself then there
3274 // is no current weapon.
3275 if (currentWeapon == a) currentWeapon = NULL;
3276
3277 if (!isAutoWeaponSet() && isPlayerActor(a)) {
3278 WeaponProto *weaponProto = currentWeapon != NULL
3279 ? (WeaponProto *)currentWeapon->proto()
3280 : NULL;
3281
3282 if (currentTarget == NULL) {
3283 warning("%s: currentTarget = NULL (return)", a->objName());
3284 return;
3285 }
3286
3287 if (currentWeapon == NULL
3288 || weaponProto->weaponRating(
3289 a->thisID(),
3290 actorID,
3291 currentTarget->thisID())
3292 != 0)
3293 return;
3294 }
3295
3296 while (iter.next(&obj) != Nothing) {
3297 ProtoObj *proto = obj->proto();
3298 uint16 cSet = proto->containmentSet();
3299
3300 // Simply use all armor objects
3301 if (!isPlayerActor(a) && (cSet & ProtoObj::isArmor)) {
3302 if (proto->useSlotAvailable(obj, a))
3303 obj->use(actorID);
3304 continue;
3305 }
3306
3307 if (cSet & ProtoObj::isWeapon) {
3308 WeaponProto *weaponProto = (WeaponProto *)proto;
3309 int weaponRating;
3310
3311 if (currentTarget) {
3312 warning("%s: currentTarget = NULL (weaponRating = 0)", a->objName());
3313 weaponRating = weaponProto->weaponRating(obj->thisID(),
3314 actorID,
3315 currentTarget->thisID());
3316 } else
3317 weaponRating = 0;
3318
3319 // a rating of zero means this weapon is useless
3320 if (weaponRating == 0) continue;
3321
3322 if (obj == currentWeapon)
3323 weaponRating += currentWeaponBonus;
3324
3325 if (weaponRating > bestWeaponRating) {
3326 bestWeaponRating = weaponRating;
3327 bestWeapon = obj;
3328 }
3329 }
3330 }
3331
3332 if (bestWeapon != NULL) {
3333 if (bestWeapon != currentWeapon)
3334 bestWeapon->use(actorID);
3335 }
3336 // If there is no useful best weapon and the actor is currently
3337 // wielding a weapon, un-wield the weapon
3338 else if (currentWeapon != NULL)
3339 currentWeapon->use(actorID);
3340 }
3341
3342 /* ===================================================================== *
3343 HuntToGiveTask member functions
3344 * ===================================================================== */
3345
3346 // Hunt to give is not implemented yet
3347
HuntToGiveTask(Common::InSaveFile * in,TaskID id)3348 HuntToGiveTask::HuntToGiveTask(Common::InSaveFile *in, TaskID id) : HuntActorTask(in, id) {
3349 debugC(3, kDebugSaveload, "... Loading HuntToGiveTask");
3350
3351 // Get the object ID
3352 ObjectID objToGiveID = in->readUint16LE();
3353
3354 // Convert the object ID to a pointer
3355 objToGive = objToGiveID != Nothing
3356 ? GameObject::objectAddress(objToGiveID)
3357 : NULL;
3358 }
3359
3360 //----------------------------------------------------------------------
3361 // Return the number of bytes needed to archive this object in
3362 // a buffer
3363
archiveSize(void) const3364 inline int32 HuntToGiveTask::archiveSize(void) const {
3365 return HuntActorTask::archiveSize()
3366 + sizeof(ObjectID); // objToGive ID
3367 }
3368
write(Common::MemoryWriteStreamDynamic * out) const3369 void HuntToGiveTask::write(Common::MemoryWriteStreamDynamic *out) const {
3370 debugC(3, kDebugSaveload, "... Saving HuntToGiveTask");
3371
3372 // Let base class archive its data
3373 HuntActorTask::write(out);
3374
3375 // Store the ID
3376 if (objToGive != NULL)
3377 out->writeUint16LE(objToGive->thisID());
3378 else
3379 out->writeUint16LE(Nothing);
3380 }
3381
3382 //----------------------------------------------------------------------
3383 // Return an integer representing the type of this task
3384
getType(void) const3385 int16 HuntToGiveTask::getType(void) const {
3386 return huntToGiveTask;
3387 }
3388
3389 //----------------------------------------------------------------------
3390 // Determine if the specified task is equivalent to this task
3391
operator ==(const Task & t) const3392 bool HuntToGiveTask::operator == (const Task &t) const {
3393 if (t.getType() != huntToGiveTask) return false;
3394
3395 const HuntToGiveTask *taskPtr = (const HuntToGiveTask *)&t;
3396
3397 return *getTarget() == *taskPtr->getTarget()
3398 && tracking() ? taskPtr->tracking() : !taskPtr->tracking()
3399 && objToGive == taskPtr->objToGive;
3400 }
3401
3402 //----------------------------------------------------------------------
3403
evaluateTarget(void)3404 void HuntToGiveTask::evaluateTarget(void) {}
3405
3406 //----------------------------------------------------------------------
3407
atTarget(void)3408 bool HuntToGiveTask::atTarget(void) {
3409 return false;
3410 }
3411
3412 //----------------------------------------------------------------------
3413
atTargetabortTask(void)3414 void HuntToGiveTask::atTargetabortTask(void) {}
3415
3416 //----------------------------------------------------------------------
3417
atTargetEvaluate(void)3418 TaskResult HuntToGiveTask::atTargetEvaluate(void) {
3419 return taskNotDone;
3420 }
3421
3422 //----------------------------------------------------------------------
3423
atTargetUpdate(void)3424 TaskResult HuntToGiveTask::atTargetUpdate(void) {
3425 return taskNotDone;
3426 }
3427
3428 /* ===================================================================== *
3429 BandTask member functions
3430 * ===================================================================== */
3431
3432 //----------------------------------------------------------------------
3433
first(TilePoint & repulsorVector,int16 & repulsorStrength)3434 bool BandTask::BandingRepulsorIterator::first(
3435 TilePoint &repulsorVector,
3436 int16 &repulsorStrength) {
3437 assert(a->_leader != NULL && a->_leader->_followers != NULL);
3438
3439 band = a->_leader->_followers;
3440 bandIndex = 0;
3441
3442 while (bandIndex < band->size()) {
3443 Actor *bandMember = (*band)[bandIndex];
3444
3445 if (bandMember != a) {
3446 repulsorVector = bandMember->getLocation() - a->getLocation();
3447 repulsorStrength = 1;
3448
3449 return true;
3450 }
3451
3452 bandIndex++;
3453 }
3454
3455 return false;
3456 }
3457
3458 //----------------------------------------------------------------------
3459
next(TilePoint & repulsorVector,int16 & repulsorStrength)3460 bool BandTask::BandingRepulsorIterator::next(
3461 TilePoint &repulsorVector,
3462 int16 &repulsorStrength) {
3463 assert(a->_leader != NULL && a->_leader->_followers != NULL);
3464 assert(band == a->_leader->_followers);
3465 assert(bandIndex < band->size());
3466
3467 bandIndex++;
3468 while (bandIndex < band->size()) {
3469 Actor *bandMember = (*band)[bandIndex];
3470
3471 if (bandMember != a) {
3472 repulsorVector = bandMember->getLocation() - a->getLocation();
3473 repulsorStrength = 1;
3474
3475 return true;
3476 }
3477
3478 bandIndex++;
3479 }
3480
3481 return false;
3482 }
3483
BandTask(Common::InSaveFile * in,TaskID id)3484 BandTask::BandTask(Common::InSaveFile *in, TaskID id) : HuntTask(in, id) {
3485 debugC(3, kDebugSaveload, "... Loading BandTask");
3486
3487 _attendID = in->readSint16LE();
3488 attend = nullptr;
3489
3490 // Restore the current target location
3491 currentTarget.load(in);
3492
3493 // Restore the target evaluation counter
3494 targetEvaluateCtr = in->readByte();
3495 }
3496
3497 //----------------------------------------------------------------------
3498 // Fixup the subtask pointers
3499
fixup(void)3500 void BandTask::fixup(void) {
3501 // Let the base class fixup its pointers
3502 HuntTask::fixup();
3503
3504 // Convert the TaskID to a Task pointer
3505 attend = _attendID != NoTask
3506 ? (AttendTask *)getTaskAddress(_attendID)
3507 : NULL;
3508 }
3509
3510 //----------------------------------------------------------------------
3511 // Return the number of bytes needed to archive this object in
3512 // a buffer
3513
archiveSize(void) const3514 inline int32 BandTask::archiveSize(void) const {
3515 return HuntTask::archiveSize()
3516 + sizeof(TaskID) // attend ID
3517 + sizeof(currentTarget)
3518 + sizeof(targetEvaluateCtr);
3519 }
3520
write(Common::MemoryWriteStreamDynamic * out) const3521 void BandTask::write(Common::MemoryWriteStreamDynamic *out) const {
3522 debugC(3, kDebugSaveload, "... Saving BandTask");
3523
3524 // Let the base class archive its data
3525 HuntTask::write(out);
3526
3527 // Store the attend task ID
3528 if (attend != NULL)
3529 out->writeSint16LE(getTaskID(attend));
3530 else
3531 out->writeSint16LE(NoTask);
3532
3533 // Store the current target location
3534 currentTarget.write(out);
3535
3536 // Store the target evaluation counter
3537 out->writeByte(targetEvaluateCtr);
3538 }
3539
3540 #if DEBUG
3541 //----------------------------------------------------------------------
3542 // Debugging function used to mark this task and any sub tasks as being
3543 // used. This is used to find task leaks.
3544
mark(void)3545 void BandTask::mark(void) {
3546 HuntTask::mark();
3547 if (attend != NULL)
3548 attend->mark();
3549 }
3550 #endif
3551
3552 //----------------------------------------------------------------------
3553 // Return an integer representing the type of this task
3554
getType(void) const3555 int16 BandTask::getType(void) const {
3556 return bandTask;
3557 }
3558
3559 //----------------------------------------------------------------------
3560 // Determine if the specified task is equivalent to this task
3561
operator ==(const Task & t) const3562 bool BandTask::operator == (const Task &t) const {
3563 return t.getType() == bandTask;
3564 }
3565
3566 //----------------------------------------------------------------------
3567
evaluateTarget(void)3568 void BandTask::evaluateTarget(void) {
3569 if (targetEvaluateCtr == 0) {
3570 Actor *leader = stack->getActor()->_leader;
3571 TilePoint actorLoc = stack->getActor()->getLocation(),
3572 movementVector;
3573 TilePoint repulsorVector;
3574 int16 repulsorStrength;
3575 TilePoint repulsorVectorArray[6];
3576 int16 repulsorStrengthArray[ARRAYSIZE(repulsorVectorArray)];
3577 int16 repulsorDistArray[ARRAYSIZE(repulsorVectorArray)];
3578 int16 repulsorCount;
3579 bool repulsorFlag;
3580
3581 RepulsorIterator *repulsorIter = getNewRepulsorIterator();
3582
3583 if (repulsorIter == NULL) return;
3584
3585 // Count the leader as two band members to double his
3586 // repulsion
3587 repulsorVectorArray[0] = leader->getLocation() - actorLoc;
3588 repulsorStrengthArray[0] = 3;
3589 repulsorDistArray[0] = repulsorVectorArray[0].quickHDistance();
3590 repulsorCount = 1;
3591
3592 // Iterate through the band members, adding their locations
3593 // to the repulsor array sorted by distance.
3594 for (repulsorFlag = repulsorIter->first(
3595 repulsorVector,
3596 repulsorStrength);
3597 repulsorFlag;
3598 repulsorFlag = repulsorIter->next(
3599 repulsorVector,
3600 repulsorStrength)) {
3601 int16 repulsorDist = repulsorVector.quickHDistance();
3602 int16 j = repulsorCount;
3603
3604 if (repulsorDist < repulsorDistArray[j - 1]) {
3605 if (repulsorCount < (long)ARRAYSIZE(repulsorVectorArray)) {
3606 repulsorDistArray[j] = repulsorDistArray[j - 1];
3607 repulsorVectorArray[j] = repulsorVectorArray[j - 1];
3608 repulsorStrengthArray[j] = repulsorStrengthArray[j - 1];
3609 }
3610 j--;
3611 }
3612
3613 while (j > 0 && repulsorDist < repulsorDistArray[j - 1]) {
3614 repulsorDistArray[j] = repulsorDistArray[j - 1];
3615 repulsorVectorArray[j] = repulsorVectorArray[j - 1];
3616 repulsorStrengthArray[j] = repulsorStrengthArray[j - 1];
3617 j--;
3618 }
3619
3620 if (j < (long)ARRAYSIZE(repulsorVectorArray)) {
3621 if (repulsorCount < (long)ARRAYSIZE(repulsorVectorArray))
3622 repulsorCount++;
3623 repulsorDistArray[j] = repulsorDist;
3624 repulsorVectorArray[j] = repulsorVector;
3625 repulsorStrengthArray[j] = repulsorStrength;
3626 }
3627 }
3628
3629 delete repulsorIter;
3630
3631 // Compute the target location
3632 movementVector = (leader->getLocation() - actorLoc)
3633 + computeRepulsionVector(
3634 repulsorVectorArray,
3635 repulsorStrengthArray,
3636 repulsorCount);
3637
3638 currentTarget = actorLoc + movementVector;
3639 currentTarget.z = leader->getLocation().z;
3640
3641 targetEvaluateCtr = targetEvaluateRate;
3642 }
3643
3644 targetEvaluateCtr--;
3645 }
3646
3647 //----------------------------------------------------------------------
3648
targetHasChanged(GotoTask * gotoTarget)3649 bool BandTask::targetHasChanged(GotoTask *gotoTarget) {
3650 GotoLocationTask *gotoLocation = (GotoLocationTask *)gotoTarget;
3651 TilePoint actorLoc = stack->getActor()->getLocation(),
3652 oldTarget = gotoLocation->getTarget();
3653 int16 slop;
3654
3655 slop = ((currentTarget - actorLoc).quickHDistance()
3656 + ABS(currentTarget.z - actorLoc.z))
3657 / 2;
3658
3659 if ((currentTarget - oldTarget).quickHDistance()
3660 + ABS(currentTarget.z - oldTarget.z)
3661 > slop)
3662 gotoLocation->changeTarget(currentTarget);
3663
3664 return false;
3665 }
3666
3667 //----------------------------------------------------------------------
3668
setupGoto(void)3669 GotoTask *BandTask::setupGoto(void) {
3670 return new GotoLocationTask(stack, currentTarget, getRunThreshold());
3671 }
3672
3673 //----------------------------------------------------------------------
3674
currentTargetLoc(void)3675 TilePoint BandTask::currentTargetLoc(void) {
3676 return currentTarget;
3677 }
3678
3679 //----------------------------------------------------------------------
3680
atTarget(void)3681 bool BandTask::atTarget(void) {
3682 TilePoint actorLoc = stack->getActor()->getLocation();
3683
3684 if ((actorLoc - currentTarget).quickHDistance() > 6
3685 || ABS(actorLoc.z - currentTarget.z) > kMaxStepHeight) {
3686 if (attend != NULL) {
3687 attend->abortTask();
3688 delete attend;
3689 attend = NULL;
3690 }
3691
3692 return false;
3693 }
3694
3695 return true;
3696 }
3697
3698 //----------------------------------------------------------------------
3699
atTargetabortTask(void)3700 void BandTask::atTargetabortTask(void) {
3701 if (attend != NULL) {
3702 attend->abortTask();
3703 delete attend;
3704 attend = NULL;
3705 }
3706 }
3707
3708 //----------------------------------------------------------------------
3709
atTargetEvaluate(void)3710 TaskResult BandTask::atTargetEvaluate(void) {
3711 return taskNotDone;
3712 }
3713
3714 //----------------------------------------------------------------------
3715
atTargetUpdate(void)3716 TaskResult BandTask::atTargetUpdate(void) {
3717 Actor *a = stack->getActor();
3718
3719 if (attend != NULL)
3720 attend->update();
3721 else {
3722 attend = new AttendTask(stack, a->_leader);
3723 if (attend != NULL)
3724 attend->update();
3725 }
3726
3727 return taskNotDone;
3728 }
3729
3730 //----------------------------------------------------------------------
3731
getRunThreshold(void)3732 int16 BandTask::getRunThreshold(void) {
3733 return kTileUVSize * 3;
3734 }
3735
3736 //----------------------------------------------------------------------
3737
getNewRepulsorIterator(void)3738 BandTask::RepulsorIterator *BandTask::getNewRepulsorIterator(void) {
3739 return new BandingRepulsorIterator(stack->getActor());
3740 }
3741
3742 /* ===================================================================== *
3743 BandAndAvoidEnemiesTask member functions
3744 * ===================================================================== */
3745
3746 //----------------------------------------------------------------------
3747
3748 //bool BandAndAvoidEnemiesTask::BandAndAvoidEnemiesRepulsorIterator::firstEnemyRepulsor(
firstEnemyRepulsor(TilePoint & repulsorVector,int16 & repulsorStrength)3749 bool BandTask::BandAndAvoidEnemiesRepulsorIterator::firstEnemyRepulsor(
3750 TilePoint &repulsorVector,
3751 int16 &repulsorStrength) {
3752 assert(iteratingThruEnemies);
3753
3754 int16 actorDistArray[ARRAYSIZE(actorArray)];
3755 TargetActorArray taa(ARRAYSIZE(actorArray), actorArray, actorDistArray);
3756 ActorPropertyTarget target(actorPropIDEnemy);
3757
3758 numActors = target.actor(a->world(), a->getLocation(), taa);
3759
3760 assert(numActors == taa.actors);
3761
3762 actorIndex = 0;
3763
3764 if (actorIndex < numActors) {
3765 repulsorVector =
3766 actorArray[actorIndex]->getLocation() - a->getLocation();
3767 repulsorStrength = 6;
3768
3769 return true;
3770 }
3771
3772 return false;
3773 }
3774
3775 //----------------------------------------------------------------------
3776
3777 //bool BandAndAvoidEnemiesTask::BandAndAvoidEnemiesRepulsorIterator::nextEnemyRepulsor(
nextEnemyRepulsor(TilePoint & repulsorVector,int16 & repulsorStrength)3778 bool BandTask::BandAndAvoidEnemiesRepulsorIterator::nextEnemyRepulsor(
3779 TilePoint &repulsorVector,
3780 int16 &repulsorStrength) {
3781 assert(iteratingThruEnemies);
3782
3783 actorIndex++;
3784
3785 if (actorIndex < numActors) {
3786 repulsorVector =
3787 actorArray[actorIndex]->getLocation() - a->getLocation();
3788 repulsorStrength = 6;
3789
3790 return true;
3791 }
3792
3793 return false;
3794 }
3795
3796 //----------------------------------------------------------------------
3797
3798 //bool BandAndAvoidEnemiesTask::BandAndAvoidEnemiesRepulsorIterator::first(
first(TilePoint & repulsorVector,int16 & repulsorStrength)3799 bool BandTask::BandAndAvoidEnemiesRepulsorIterator::first(
3800 TilePoint &repulsorVector,
3801 int16 &repulsorStrength) {
3802 iteratingThruEnemies = false;
3803
3804 if (BandingRepulsorIterator::first(repulsorVector, repulsorStrength))
3805 return true;
3806
3807 iteratingThruEnemies = true;
3808 return firstEnemyRepulsor(repulsorVector, repulsorStrength);
3809 }
3810
3811 //----------------------------------------------------------------------
3812
3813 //bool BandAndAvoidEnemiesTask::BandAndAvoidEnemiesRepulsorIterator::first(
next(TilePoint & repulsorVector,int16 & repulsorStrength)3814 bool BandTask::BandAndAvoidEnemiesRepulsorIterator::next(
3815 TilePoint &repulsorVector,
3816 int16 &repulsorStrength) {
3817 if (!iteratingThruEnemies) {
3818 if (BandingRepulsorIterator::next(repulsorVector, repulsorStrength))
3819 return true;
3820
3821 iteratingThruEnemies = true;
3822 return firstEnemyRepulsor(repulsorVector, repulsorStrength);
3823 }
3824
3825 return nextEnemyRepulsor(repulsorVector, repulsorStrength);
3826 }
3827
3828 //----------------------------------------------------------------------
3829 // Return an integer representing the type of this task
3830
getType(void) const3831 int16 BandAndAvoidEnemiesTask::getType(void) const {
3832 return bandAndAvoidEnemiesTask;
3833 }
3834
3835 //----------------------------------------------------------------------
3836 // Determine if the specified task is equivalent to this task
3837
operator ==(const Task & t) const3838 bool BandAndAvoidEnemiesTask::operator == (const Task &t) const {
3839 return t.getType() == bandAndAvoidEnemiesTask;
3840 }
3841
3842 //----------------------------------------------------------------------
3843
getRunThreshold(void)3844 int16 BandAndAvoidEnemiesTask::getRunThreshold(void) {
3845 return 0;
3846 }
3847
3848 //----------------------------------------------------------------------
3849
getNewRepulsorIterator(void)3850 BandTask::RepulsorIterator *BandAndAvoidEnemiesTask::getNewRepulsorIterator(void) {
3851 return new BandAndAvoidEnemiesRepulsorIterator(stack->getActor());
3852 }
3853
3854 /* ===================================================================== *
3855 FollowPatrolRouteTask member functions
3856 * ===================================================================== */
3857
FollowPatrolRouteTask(Common::InSaveFile * in,TaskID id)3858 FollowPatrolRouteTask::FollowPatrolRouteTask(Common::InSaveFile *in, TaskID id) : Task(in, id) {
3859 debugC(3, kDebugSaveload, "... Loading FollowPatrolRouteTask");
3860
3861 // Get the gotoWayPoint TaskID
3862 _gotoWayPointID = in->readSint16LE();
3863 gotoWayPoint = nullptr;
3864
3865 // Restore the patrol route iterator
3866 patrolIter.read(in);
3867
3868 // Restore the last waypoint number
3869 lastWayPointNum = in->readSint16LE();
3870
3871 // Restore the paused flag
3872 paused = in->readUint16LE();
3873
3874 // Restore the paused counter
3875 counter = in->readSint16LE();
3876 }
3877
3878 //----------------------------------------------------------------------
3879 // Fixup the subtask pointers
3880
fixup(void)3881 void FollowPatrolRouteTask::fixup(void) {
3882 // Let the base class fixup its pointers
3883 Task::fixup();
3884
3885 // Convert the TaskID to a Task pointer
3886 gotoWayPoint = _gotoWayPointID != NoTask
3887 ? (GotoLocationTask *)getTaskAddress(_gotoWayPointID)
3888 : NULL;
3889 }
3890
3891 //----------------------------------------------------------------------
3892 // Return the number of bytes needed to archive this object in
3893 // a buffer
3894
archiveSize(void) const3895 inline int32 FollowPatrolRouteTask::archiveSize(void) const {
3896 return Task::archiveSize()
3897 + sizeof(TaskID) // gotoWayPoint ID
3898 + sizeof(patrolIter)
3899 + sizeof(lastWayPointNum)
3900 + sizeof(paused)
3901 + sizeof(counter);
3902 }
3903
write(Common::MemoryWriteStreamDynamic * out) const3904 void FollowPatrolRouteTask::write(Common::MemoryWriteStreamDynamic *out) const {
3905 debugC(3, kDebugSaveload, "... Saving FollowPatrolRouteTask");
3906
3907 // Let the base class archive its data
3908 Task::write(out);
3909
3910 // Store the gotoWayPoint ID
3911 if (gotoWayPoint != NULL)
3912 out->writeSint16LE(getTaskID(gotoWayPoint));
3913 else
3914 out->writeSint16LE(NoTask);
3915
3916 // Store the PatrolRouteIterator
3917 patrolIter.write(out);
3918
3919 // Store the last waypoint number
3920 out->writeSint16LE(lastWayPointNum);
3921
3922 // Store the paused flag
3923 out->writeUint16LE(paused);
3924
3925 // Store the paused counter
3926 out->writeSint16LE(counter);
3927 }
3928
3929 #if DEBUG
3930 //----------------------------------------------------------------------
3931 // Debugging function used to mark this task and any sub tasks as being
3932 // used. This is used to find task leaks.
3933
mark(void)3934 void FollowPatrolRouteTask::mark(void) {
3935 Task::mark();
3936 if (gotoWayPoint != NULL)
3937 gotoWayPoint->mark();
3938 }
3939 #endif
3940
3941 //----------------------------------------------------------------------
3942 // Return an integer representing the type of this task
3943
getType(void) const3944 int16 FollowPatrolRouteTask::getType(void) const {
3945 return followPatrolRouteTask;
3946 }
3947
3948 //----------------------------------------------------------------------
3949
abortTask(void)3950 void FollowPatrolRouteTask::abortTask(void) {
3951 // If there is a subtask, get rid of it
3952 if (gotoWayPoint) {
3953 gotoWayPoint->abortTask();
3954 delete gotoWayPoint;
3955 gotoWayPoint = NULL;
3956 }
3957 }
3958
3959 //----------------------------------------------------------------------
3960
evaluate(void)3961 TaskResult FollowPatrolRouteTask::evaluate(void) {
3962 // Simply check the patrol iterator to determine if there are
3963 // any more waypoints
3964 return *patrolIter == Nowhere ? taskSucceeded : taskNotDone;
3965 }
3966
3967 //----------------------------------------------------------------------
3968
update(void)3969 TaskResult FollowPatrolRouteTask::update(void) {
3970 return !paused ? handleFollowPatrolRoute() : handlePaused();
3971 }
3972
3973 //----------------------------------------------------------------------
3974 // Determine if the specified task is equivalent to this task
3975
operator ==(const Task & t) const3976 bool FollowPatrolRouteTask::operator == (const Task &t) const {
3977 if (t.getType() != followPatrolRouteTask) return false;
3978
3979 const FollowPatrolRouteTask *taskPtr = (const FollowPatrolRouteTask *)&t;
3980
3981 return patrolIter == taskPtr->patrolIter
3982 && lastWayPointNum == taskPtr->lastWayPointNum;
3983 }
3984
3985 //----------------------------------------------------------------------
3986 // Update function used if this task is not paused
3987
handleFollowPatrolRoute(void)3988 TaskResult FollowPatrolRouteTask::handleFollowPatrolRoute(void) {
3989 TilePoint currentWayPoint = *patrolIter,
3990 actorLoc = stack->getActor()->getLocation();
3991
3992 if (currentWayPoint == Nowhere) return taskSucceeded;
3993
3994 // Determine if the actor has reached the waypoint tile position
3995 if ((actorLoc.u >> kTileUVShift)
3996 == (currentWayPoint.u >> kTileUVShift)
3997 && (actorLoc.v >> kTileUVShift)
3998 == (currentWayPoint.v >> kTileUVShift)
3999 && ABS(actorLoc.z - currentWayPoint.z) <= kMaxStepHeight) {
4000 // Delete the gotoWayPoint task
4001 if (gotoWayPoint != NULL) {
4002 gotoWayPoint->abortTask();
4003 delete gotoWayPoint;
4004 gotoWayPoint = NULL;
4005 }
4006
4007 // If this way point is the specified last way point,
4008 // return success
4009 if (lastWayPointNum != -1
4010 && patrolIter.wayPointNum() == lastWayPointNum)
4011 return taskSucceeded;
4012
4013 // If there are no more way points in the patrol route, return
4014 // success
4015 if ((currentWayPoint = *++patrolIter) == Nowhere)
4016 return taskSucceeded;
4017
4018 // We are at a way point so randomly determine if we should
4019 // pause for a while.
4020 if (g_vm->_rnd->getRandomNumber(3) == 0) {
4021 pause();
4022 return taskNotDone;
4023 }
4024 }
4025
4026 // Setup a gotoWayPoint task if one doesn't already exist and
4027 // update it
4028 if (gotoWayPoint != NULL)
4029 gotoWayPoint->update();
4030 else {
4031 gotoWayPoint = new GotoLocationTask(stack, currentWayPoint);
4032 if (gotoWayPoint != NULL) gotoWayPoint->update();
4033 }
4034
4035 return taskNotDone;
4036 }
4037
4038 //----------------------------------------------------------------------
4039 // Update function used if this task is paused
4040
handlePaused(void)4041 TaskResult FollowPatrolRouteTask::handlePaused(void) {
4042 TaskResult result;
4043
4044 if ((result = evaluate()) == taskNotDone) {
4045 if (counter == 0)
4046 followPatrolRoute();
4047 else
4048 counter--;
4049 }
4050
4051 return result;
4052 }
4053
4054 //----------------------------------------------------------------------
4055 // Set this task into the paused state
4056
pause(void)4057 void FollowPatrolRouteTask::pause(void) {
4058 paused = true;
4059 counter = (g_vm->_rnd->getRandomNumber(63) + g_vm->_rnd->getRandomNumber(63)) / 2;
4060 }
4061
4062 /* ===================================================================== *
4063 AttendTask member functions
4064 * ===================================================================== */
4065
AttendTask(Common::InSaveFile * in,TaskID id)4066 AttendTask::AttendTask(Common::InSaveFile *in, TaskID id) : Task(in, id) {
4067 debugC(3, kDebugSaveload, "... Loading AttendTask");
4068
4069 // Get the object ID
4070 ObjectID objID = in->readUint16LE();
4071
4072 // Convert the object ID to a pointer
4073 obj = objID != Nothing
4074 ? GameObject::objectAddress(objID)
4075 : NULL;
4076 }
4077
4078 //----------------------------------------------------------------------
4079 // Return the number of bytes needed to archive this object in
4080 // a buffer
4081
archiveSize(void) const4082 inline int32 AttendTask::archiveSize(void) const {
4083 return Task::archiveSize() + sizeof(ObjectID);
4084 }
4085
4086
write(Common::MemoryWriteStreamDynamic * out) const4087 void AttendTask::write(Common::MemoryWriteStreamDynamic *out) const {
4088 debugC(3, kDebugSaveload, "... Saving AttendTask");
4089
4090 // Let the base class archive its data
4091 Task::write(out);
4092
4093 // Store the object ID
4094 if (obj != NULL)
4095 out->writeUint16LE(obj->thisID());
4096 else
4097 out->writeUint16LE(Nothing);
4098 }
4099
4100 //----------------------------------------------------------------------
4101 // Return an integer representing the type of this task
4102
getType(void) const4103 int16 AttendTask::getType(void) const {
4104 return attendTask;
4105 }
4106
4107 //----------------------------------------------------------------------
4108
abortTask(void)4109 void AttendTask::abortTask(void) {
4110 MotionTask *actorMotion = stack->getActor()->_moveTask;
4111
4112 // Determine if we need to abort the actor motion
4113 if (actorMotion != NULL && actorMotion->isTurn())
4114 actorMotion->finishTurn();
4115 }
4116
4117 //----------------------------------------------------------------------
4118
evaluate(void)4119 TaskResult AttendTask::evaluate(void) {
4120 // Attending must be stopped manually
4121 return taskNotDone;
4122 }
4123
4124 //----------------------------------------------------------------------
4125
update(void)4126 TaskResult AttendTask::update(void) {
4127 Actor *a = stack->getActor();
4128 TilePoint attendLoc = obj->getWorldLocation();
4129
4130 // Determine if we are facing the object
4131 if (a->_currentFacing != (attendLoc - a->getLocation()).quickDir()) {
4132 // If not, turn
4133 if (!a->_moveTask || !a->_moveTask->isTurn())
4134 MotionTask::turnTowards(*a, attendLoc);
4135 }
4136
4137 return taskNotDone;
4138 }
4139
4140 //----------------------------------------------------------------------
4141 // Determine if the specified task is equivalent to this task
4142
operator ==(const Task & t) const4143 bool AttendTask::operator == (const Task &t) const {
4144 if (t.getType() != attendTask) return false;
4145
4146 const AttendTask *taskPtr = (const AttendTask *)&t;
4147
4148 return obj == taskPtr->obj;
4149 }
4150
4151 /* ===================================================================== *
4152 TaskStack member functions
4153 * ===================================================================== */
4154
write(Common::MemoryWriteStreamDynamic * out)4155 void TaskStack::write(Common::MemoryWriteStreamDynamic *out) {
4156 // Store the stack bottom TaskID
4157 out->writeSint16LE(stackBottomID);
4158
4159 // Store the actor's id
4160 out->writeUint16LE(actor->thisID());
4161
4162 // Store the evalCount and evalRate
4163 out->writeSint16LE(evalCount);
4164
4165 out->writeSint16LE(evalRate);
4166
4167 debugC(4, kDebugSaveload, "...... stackBottomID = %d", stackBottomID);
4168 debugC(4, kDebugSaveload, "...... actorID = %d", actor->thisID());
4169 debugC(4, kDebugSaveload, "...... evalCount = %d", evalCount);
4170 debugC(4, kDebugSaveload, "...... evalRate = %d", evalRate);
4171 }
4172
read(Common::InSaveFile * in)4173 void TaskStack::read(Common::InSaveFile *in) {
4174 ObjectID actorID;
4175
4176 // Restore the stack bottom pointer
4177 stackBottomID = in->readSint16LE();
4178
4179 // Restore the actor pointer
4180 actorID = in->readUint16LE();
4181 actor = (Actor *)GameObject::objectAddress(actorID);
4182
4183 // Restore the evaluation count
4184 evalCount = in->readSint16LE();
4185
4186 // Restore the evaluation rate
4187 evalRate = in->readSint16LE();
4188
4189 debugC(4, kDebugSaveload, "...... stackBottomID = %d", stackBottomID);
4190 debugC(4, kDebugSaveload, "...... actorID = %d", actorID);
4191 debugC(4, kDebugSaveload, "...... evalCount = %d", evalCount);
4192 debugC(4, kDebugSaveload, "...... evalRate = %d", evalRate);
4193 }
4194
4195 #if DEBUG
4196 //----------------------------------------------------------------------
4197 // Debugging function used to mark this task and any sub tasks as being
4198 // used. This is used to find task leaks.
4199
mark(void)4200 void TaskStack::mark(void) {
4201 if (stackBottomID != NoTask) {
4202 Task *stackBottom = getTaskAddress(stackBottomID);
4203
4204 stackBottom->mark();
4205 }
4206 }
4207 #endif
4208
4209 //----------------------------------------------------------------------
4210 // Set the bottom task of this task stack
4211
setTask(Task * t)4212 void TaskStack::setTask(Task *t) {
4213 assert(stackBottomID == NoTask);
4214
4215 if (t->stack == this) {
4216 TaskID id = getTaskID(t);
4217
4218 stackBottomID = id;
4219 }
4220 }
4221
4222 //----------------------------------------------------------------------
4223 // Abort all tasks in stack
4224
abortTask(void)4225 void TaskStack::abortTask(void) {
4226 if (stackBottomID != NoTask) {
4227 Task *stackBottom = getTaskAddress(stackBottomID);
4228
4229 stackBottom->abortTask();
4230 delete stackBottom;
4231 }
4232 }
4233
4234 //----------------------------------------------------------------------
4235 // Re-evaluate tasks in stack
4236
evaluate(void)4237 TaskResult TaskStack::evaluate(void) {
4238 if (stackBottomID != -1) {
4239 Task *stackBottom = getTaskAddress(stackBottomID);
4240
4241 return stackBottom->evaluate();
4242 } else
4243 return taskNotDone;
4244 }
4245
4246 //----------------------------------------------------------------------
4247 // Update the state of the tasks in stack
4248
update(void)4249 TaskResult TaskStack::update(void) {
4250 TaskResult result;
4251
4252 // If the actor is currently uniterruptable then this task is paused
4253 if (!actor->isInterruptable()) return taskNotDone;
4254
4255 if (stackBottomID != NoTask) {
4256 Task *stackBottom = getTaskAddress(stackBottomID);
4257
4258 // Determine if it is time to reevaluate the tasks
4259 if (--evalCount == 0) {
4260 if ((result = stackBottom->evaluate()) != taskNotDone) {
4261 delete stackBottom;
4262 stackBottomID = NoTask;
4263
4264 return result;
4265 }
4266 evalCount = evalRate;
4267 }
4268
4269 // Update the tasks
4270 if ((result = stackBottom->update()) != taskNotDone) {
4271 delete stackBottom;
4272 stackBottomID = NoTask;
4273
4274 return result;
4275 }
4276 } else
4277 return taskFailed;
4278
4279 return taskNotDone;
4280 }
4281
4282 } // end of namespace Saga2
4283