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