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  * along 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 
23 #include "asylum/resources/actor.h"
24 
25 #include "asylum/resources/encounters.h"
26 #include "asylum/resources/object.h"
27 #include "asylum/resources/polygons.h"
28 #include "asylum/resources/special.h"
29 #include "asylum/resources/script.h"
30 #include "asylum/resources/worldstats.h"
31 
32 #include "asylum/system/cursor.h"
33 #include "asylum/system/graphics.h"
34 #include "asylum/system/screen.h"
35 #include "asylum/system/speech.h"
36 #include "asylum/system/text.h"
37 
38 #include "asylum/views/scene.h"
39 
40 #include "asylum/asylum.h"
41 #include "asylum/staticres.h"
42 
43 
44 namespace Asylum {
45 
46 #define DIR(val) (ActorDirection)((val) & 7)
47 
Actor(AsylumEngine * engine,ActorIndex index)48 Actor::Actor(AsylumEngine *engine, ActorIndex index) : _vm(engine), _index(index), inventory(engine, _numberValue01) {
49  	// Init all variables
50  	_resourceId = kResourceNone;
51  	_objectIndex = 0;
52  	_frameIndex = 0;
53  	_frameCount = 0;
54  	_direction = kDirectionN;
55  	_field_3C = 0;
56  	_status = kActorStatusNone;
57  	_field_44 = 0;
58  	_priority = 0;
59  	flags = 0;
60  	_field_50 = 0;
61  	_field_54 = 0;
62  	_field_58 = 0;
63  	_field_5C = 0;
64  	_field_60 = 0;
65  	_actionIdx3 = 0;
66  	// TODO field_68 till field_617
67  	_walkingSound1 = 0;
68  	_walkingSound2 = 0;
69  	_walkingSound3 = 0;
70  	_walkingSound4 = 0;
71  	_field_64C = 0;
72  	_field_650 = 0;
73  	memset(_graphicResourceIds, 0 , sizeof(_graphicResourceIds));
74  	memset(&_name, 0, sizeof(_name));
75  	memset(&_distancesEO, 0, sizeof(_distancesEO));
76  	memset(&_distancesNS, 0, sizeof(_distancesNS));
77  	memset(&_distancesNSEO, 0, sizeof(_distancesNSEO));
78  	_actionIdx2 = 0;
79  	_field_924 = 0;
80  	_lastScreenUpdate = 0;
81  	_scriptIndex = 0;
82  	actionType = 0;
83  	_field_934 = 0;
84  	_field_938 = 0;
85  	_soundResourceId = kResourceNone;
86  	_numberValue01 = 0;
87  	_field_944 = 0;
88  	_field_948 = 0;
89  	_field_94C = 0;
90  	_numberFlag01 = 0;
91  	_numberStringWidth = 0;
92  	memset(&_numberString01, 0, 8);
93  	_field_968 = 0;
94  	_transparency = 0;
95  	_processNewDirection = false;
96  	_invertPriority = false;
97  	_nextDirection = kDirectionN;
98  	_nextActionIndex = 0;
99  	_nextActorIndex = kActorMax;
100  	_field_994 = 0;
101  	_field_998 = 0;
102  	_field_99C = 0;
103  	_field_9A0 = 0;
104 
105 	// Instance data
106 	_tickCount = -1;
107 	_updateCounter = 0;
108 
109 	// Path finding
110 	_frameNumber = 0;
111 }
112 
113 /////////////////////////////////////////////////////////////////////////
114 // Loading
115 //////////////////////////////////////////////////////////////////////////
load(Common::SeekableReadStream * stream)116 void Actor::load(Common::SeekableReadStream *stream) {
117 	if (!stream)
118 		error("[Actor::load] invalid stream");
119 
120 	_point.x              = (int16)stream->readSint32LE();
121 	_point.y              = (int16)stream->readSint32LE();
122 	_resourceId           = (ResourceId)stream->readSint32LE();
123 	_objectIndex          = stream->readSint32LE();
124 	_frameIndex           = stream->readUint32LE();
125 	_frameCount           = stream->readUint32LE();
126 	_point1.x             = (int16)stream->readSint32LE();
127 	_point1.y             = (int16)stream->readSint32LE();
128 	_point2.x             = (int16)stream->readSint32LE();
129 	_point2.y             = (int16)stream->readSint32LE();
130 
131 	_boundingRect.left   = (int16)(stream->readSint32LE() & 0xFFFF);
132 	_boundingRect.top    = (int16)(stream->readSint32LE() & 0xFFFF);
133 	_boundingRect.right  = (int16)(stream->readSint32LE() & 0xFFFF);
134 	_boundingRect.bottom = (int16)(stream->readSint32LE() & 0xFFFF);
135 
136 	_direction  = (ActorDirection)stream->readSint32LE();
137 	_field_3C   = stream->readSint32LE();
138 	_status     = (ActorStatus)stream->readSint32LE();
139 	_field_44   = stream->readSint32LE();
140 	_priority   = stream->readSint32LE();
141 	flags       = stream->readSint32LE();
142 	_field_50   = stream->readSint32LE();
143 	_field_54   = stream->readSint32LE();
144 	_field_58   = stream->readSint32LE();
145 	_field_5C   = stream->readSint32LE();
146 	_field_60   = stream->readSint32LE();
147 	_actionIdx3 = stream->readSint32LE();
148 
149 	// TODO skip field_68 till field_617
150 	stream->skip(0x5B0);
151 
152 	inventory.load(stream);
153 	_walkingSound1 = stream->readSint32LE();
154 	_walkingSound2 = stream->readSint32LE();
155 	_walkingSound3 = stream->readSint32LE();
156 	_walkingSound4 = stream->readSint32LE();
157 	_field_64C     = stream->readUint32LE();
158 	_field_650     = stream->readUint32LE();
159 
160 	for (int32 i = 0; i < 55; i++)
161 		_graphicResourceIds[i] = (ResourceId)stream->readSint32LE();
162 
163 	stream->read(_name, sizeof(_name));
164 
165 	for (int32 i = 0; i < 20; i++)
166 		_distancesEO[i] = stream->readSint32LE();
167 
168 	for (int32 i = 0; i < 20; i++)
169 		_distancesNS[i] = stream->readSint32LE();
170 
171 	for (int32 i = 0; i < 20; i++)
172 		_distancesNSEO[i] = stream->readSint32LE();
173 
174 	_actionIdx2           = stream->readSint32LE();
175 	_field_924            = stream->readSint32LE();
176 	_lastScreenUpdate     = stream->readUint32LE();
177 	_scriptIndex          = stream->readSint32LE();
178 	actionType            = stream->readSint32LE();
179 	_field_934            = stream->readSint32LE();
180 	_field_938            = stream->readSint32LE();
181 	_soundResourceId      = (ResourceId)stream->readSint32LE();
182 	_numberValue01        = stream->readSint32LE();
183 	_field_944            = stream->readSint32LE();
184 	_field_948            = stream->readSint32LE();
185 	_field_94C            = stream->readSint32LE();
186 	_numberFlag01         = stream->readSint32LE();
187 	_numberStringWidth    = (int16)stream->readSint32LE();
188 	_numberPoint.x        = (int16)stream->readSint32LE();
189 	_numberPoint.y        = (int16)stream->readSint32LE();
190 	stream->read(_numberString01, sizeof(_numberString01));
191 	_field_968            = stream->readSint32LE();
192 	_transparency         = stream->readSint32LE();
193 	_processNewDirection  = (bool)stream->readSint32LE();
194 	_invertPriority       = (bool)stream->readSint32LE();
195 	_nextDirection        = (ActorDirection)stream->readSint32LE();
196 	_nextActionIndex      = stream->readSint32LE();
197 	_nextActorIndex       = stream->readSint32LE();
198 	_nextPositionOffset.x = (int16)stream->readSint32LE();
199 	_nextPositionOffset.y = (int16)stream->readSint32LE();
200 	_nextPosition.x       = (int16)stream->readSint32LE();
201 	_nextPosition.y       = (int16)stream->readSint32LE();
202 	_field_994            = stream->readSint32LE();
203 	_field_998            = stream->readSint32LE();
204 	_field_99C            = stream->readSint32LE();
205 	_field_9A0            = stream->readSint32LE();
206 }
207 
saveLoadWithSerializer(Common::Serializer & s)208 void Actor::saveLoadWithSerializer(Common::Serializer &s) {
209 	s.syncAsSint32LE(_point.x);
210 	s.syncAsSint32LE(_point.y);
211 	s.syncAsSint32LE(_resourceId);
212 	s.syncAsSint32LE(_objectIndex);
213 	s.syncAsUint32LE(_frameIndex);
214 	s.syncAsUint32LE(_frameCount);
215 	s.syncAsSint32LE(_point1.x);
216 	s.syncAsSint32LE(_point1.y);
217 	s.syncAsSint32LE(_point2.x);
218 	s.syncAsSint32LE(_point2.y);
219 
220 	s.syncAsSint32LE(_boundingRect.left);
221 	s.syncAsSint32LE(_boundingRect.top);
222 	s.syncAsSint32LE(_boundingRect.right);
223 	s.syncAsSint32LE(_boundingRect.bottom);
224 
225 	s.syncAsSint32LE(_direction);
226 	s.syncAsSint32LE(_field_3C);
227 	s.syncAsSint32LE(_status);
228 	s.syncAsSint32LE(_field_44);
229 	s.syncAsSint32LE(_priority);
230 	s.syncAsSint32LE(flags);
231 	s.syncAsSint32LE(_field_50);
232 	s.syncAsSint32LE(_field_54);
233 	s.syncAsSint32LE(_field_58);
234 	s.syncAsSint32LE(_field_5C);
235 	s.syncAsSint32LE(_field_60);
236 	s.syncAsSint32LE(_actionIdx3);
237 
238 	// TODO skip field_68 till field_617
239 	s.skip(0x5B0);
240 
241 	inventory.saveLoadWithSerializer(s);
242 
243 	s.syncAsSint32LE(_walkingSound1);
244 	s.syncAsSint32LE(_walkingSound2);
245 	s.syncAsSint32LE(_walkingSound3);
246 	s.syncAsSint32LE(_walkingSound4);
247 	s.syncAsUint32LE(_field_64C);
248 	s.syncAsUint32LE(_field_650);
249 
250 	for (int32 i = 0; i < ARRAYSIZE(_graphicResourceIds); i++)
251 		s.syncAsSint32LE(_graphicResourceIds[i]);
252 
253 	s.syncBytes((byte *)&_name, sizeof(_name));
254 
255 	for (int32 i = 0; i < 20; i++)
256 		s.syncAsSint32LE(_distancesEO[i]);
257 
258 	for (int32 i = 0; i < 20; i++)
259 		s.syncAsSint32LE(_distancesNS[i]);
260 
261 	for (int32 i = 0; i < 20; i++)
262 		s.syncAsSint32LE(_distancesNSEO[i]);
263 
264 	s.syncAsSint32LE(_actionIdx2);
265 	s.syncAsSint32LE(_field_924);
266 	s.syncAsSint32LE(_lastScreenUpdate);
267 	s.syncAsSint32LE(_scriptIndex);
268 	s.syncAsSint32LE(actionType);
269 	s.syncAsSint32LE(_field_934);
270 	s.syncAsSint32LE(_field_938);
271 	s.syncAsSint32LE(_soundResourceId);
272 	s.syncAsSint32LE(_numberValue01);
273 	s.syncAsSint32LE(_field_944);
274 	s.syncAsSint32LE(_field_948);
275 	s.syncAsSint32LE(_field_94C);
276 	s.syncAsSint32LE(_numberFlag01);
277 	s.syncAsSint32LE(_numberStringWidth);
278 	s.syncAsSint32LE(_numberPoint.x);
279 	s.syncAsSint32LE(_numberPoint.y);
280 	s.syncBytes((byte *)&_numberString01, sizeof(_numberString01));
281 	s.syncAsSint32LE(_field_968);
282 	s.syncAsSint32LE(_transparency);
283 	s.syncAsSint32LE(_processNewDirection);
284 	s.syncAsSint32LE(_invertPriority);
285 	s.syncAsSint32LE(_nextDirection);
286 	s.syncAsSint32LE(_nextActionIndex);
287 	s.syncAsSint32LE(_nextActorIndex);
288 	s.syncAsSint32LE(_nextPositionOffset.x);
289 	s.syncAsSint32LE(_nextPositionOffset.y);
290 	s.syncAsSint32LE(_nextPosition.x);
291 	s.syncAsSint32LE(_nextPosition.y);
292 	s.syncAsSint32LE(_field_994);
293 	s.syncAsSint32LE(_field_998);
294 	s.syncAsSint32LE(_field_99C);
295 	s.syncAsSint32LE(_field_9A0);
296 }
297 
298 /////////////////////////////////////////////////////////////////////////
299 // Update & status
300 //////////////////////////////////////////////////////////////////////////
draw()301 void Actor::draw() {
302 	if (!isVisible())
303 		return;
304 
305 	// Draw the actor
306 	Common::Point point;
307 	adjustCoordinates(&point);
308 	point.x += _point.x;
309 	point.y += _point.y;
310 
311 	// Compute frame index
312 	uint32 frameIndex = _frameIndex;
313 	if (_frameIndex >= _frameCount)
314 		frameIndex = 2 * _frameCount - (_frameIndex + 1);
315 
316 	if (flags & kActorFlagMasked) {
317 		Object *object = getWorld()->objects[_objectIndex];
318 		Common::Point objPoint;
319 		object->adjustCoordinates(&objPoint);
320 
321 		getScreen()->addGraphicToQueueMasked(_resourceId, frameIndex, point, object->getResourceId(), objPoint, getGraphicsFlags(), _priority);
322 
323 		// Update flags
324 		flags &= ~kActorFlagMasked;
325 	} else {
326 		getScreen()->addGraphicToQueue(_resourceId, frameIndex, point, getGraphicsFlags(), _transparency, _priority);
327 	}
328 }
329 
drawNumber()330 void Actor::drawNumber() {
331 	if (!_numberFlag01)
332 		return;
333 
334 	getText()->loadFont(getWorld()->font1);
335 	getText()->drawCentered(_numberPoint, _numberStringWidth, (char *)&_numberString01);
336 }
337 
update()338 void Actor::update() {
339 	if (!isVisible())
340 		return;
341 
342 	switch (_status) {
343 	default:
344 		break;
345 
346 	case kActorStatusGettingHurt:
347 		if (getWorld()->chapter == kChapter2) {
348 			MaxGetsSome();
349 		} else if (getWorld()->chapter == kChapter11 && _index == getSharedData()->getPlayerIndex()) {
350 			SarahGetsSome();
351 		}
352 		break;
353 
354 	case kActorStatusRestarting:
355 		if (getWorld()->chapter == kChapter2) {
356 			if (_index > 12) {
357 				if (_frameIndex <= _frameCount - 1) {
358 					++_frameIndex;
359 				} else {
360 					hide();
361 					getScene()->getActor(_index + 9)->hide();
362 				}
363 			}
364 
365 			if (_index == 11) {
366 				if (_frameIndex <= _frameCount - 1) {
367 					// Looks like a simple check using the counter, since it doesn't seem to be used anywhere else
368 					if (_updateCounter == 0) {
369 						++_updateCounter;
370 					} else {
371 						_updateCounter = 0;
372 						++_frameIndex;
373 					}
374 				} else {
375 					if (_vm->isGameFlagSet(kGameFlag556)) {
376 						Actor *player = getScene()->getActor();
377 
378 						getSpeech()->playPlayer(453);
379 						getScene()->getActor(11)->hide();
380 
381 						player->changeStatus(kActorStatusInteracting);
382 						player->setResourceId(player->getResourcesId(35));
383 						player->setDirection(kDirectionS);
384 						player->setFrameCount(GraphicResource::getFrameCount(_vm, player->getResourceId()));
385 
386 						getCursor()->hide();
387 						getScene()->getActor(0)->changeDirection(kDirectionS);
388 
389 						// Queue script
390 						getScript()->queueScript(getWorld()->getActionAreaById(2696)->scriptIndex, getSharedData()->getPlayerIndex());
391 
392 						_vm->setGameFlag(kGameFlag279);
393 						_vm->clearGameFlag(kGameFlag368);
394 
395 						player->setFrameIndex(0);
396 						getScene()->getActor(0)->setLastScreenUpdate(_vm->getTick());
397 
398 						getSound()->playMusic(MAKE_RESOURCE(kResourcePackMusic, 1));
399 
400 						getWorld()->musicCurrentResourceIndex = 1;
401 
402 						if (getSound()->isPlaying(getWorld()->soundResourceIds[7]))
403 							getSound()->stop(getWorld()->soundResourceIds[7]);
404 
405 						if (getSound()->isPlaying(getWorld()->soundResourceIds[6]))
406 							getSound()->stop(getWorld()->soundResourceIds[6]);
407 
408 						if (getSound()->isPlaying(getWorld()->soundResourceIds[5]))
409 							getSound()->stop(getWorld()->soundResourceIds[5]);
410 
411 						_vm->setGameFlag(kGameFlag1131);
412 					} else {
413 						getScene()->getActor(11)->updateGraphicData(25);
414 						_vm->setGameFlag(kGameFlag556);
415 					}
416 				}
417 			}
418 
419 			if (_index == getSharedData()->getPlayerIndex()) {
420 				if (_frameIndex <= _frameCount - 1) {
421 					++_frameIndex;
422 				} else {
423 					_vm->clearGameFlag(kGameFlag239);
424 					getScene()->getActor(10)->changeStatus(kActorStatusEnabled2);
425 					hide();
426 					_vm->setGameFlag(kGameFlag238);
427 
428 					// Queue script
429 					getScript()->queueScript(getWorld()->getActionAreaById(1000)->scriptIndex, getSharedData()->getPlayerIndex());
430 				}
431 			}
432 
433 		} else if (getWorld()->chapter == kChapter11) {
434 			if (_index == getSharedData()->getPlayerIndex()) {
435 				if (_frameIndex <= _frameCount - 1)
436 					++_frameIndex;
437 				else
438 					SarahDies();
439 			}
440 
441 			if (_index >= 10)
442 				TentacleDies();
443 		}
444 		break;
445 
446 	case kActorStatusAttacking:
447 		if (getWorld()->chapter == kChapter2) {
448 			if (_index > 12)
449 				CrowDives();
450 
451 			if (_index == getSharedData()->getPlayerIndex())
452 				MaxAttacks();
453 
454 			if (_index == 11)
455 				ScareCrowAttacks();
456 
457 		} else if (getWorld()->chapter == kChapter11) {
458 			if (_index >= 10 && _index < 16)
459 				TentacleWhips();
460 
461 			if (_index == getSharedData()->getPlayerIndex())
462 				SarahAttacks();
463 		}
464 		break;
465 
466 	case kActorStatus18:
467 		if (getWorld()->chapter == kChapter2) {
468 			if (_index > 12)
469 				CrowSwoops();
470 
471 			if (_index == 11)
472 				ScareCrowRetreats();
473 		}
474 		break;
475 
476 	case kActorStatusDisabled:
477 		_frameIndex = (_frameIndex + 1) % _frameCount;
478 
479 		if (_vm->screenUpdateCount - _lastScreenUpdate > 300) {
480 			if (_vm->getRandom(100) < 50) {
481 				if (!getSpeech()->getSoundResourceId() || !getSound()->isPlaying(getSpeech()->getSoundResourceId())) {
482 					if (canChangeStatus(10))
483 						changeStatus(kActorStatusFidget);
484 				}
485 			}
486 			_lastScreenUpdate = _vm->screenUpdateCount;
487 		}
488 		break;
489 
490 	case kActorStatusWalking2:
491 		if (getWorld()->chapter == kChapter2) {
492 			if (_index > 12) {
493 				CrowClosesIn();
494 				return;
495 			}
496 
497 			if (_index == 11) {
498 				ScareCrowClosesIn();
499 				return;
500 			}
501 		} else if (getWorld()->chapter == kChapter11) {
502 			switch (_index) {
503 			default:
504 				break;
505 
506 			case 1:
507 				getSpecial()->run(NULL, _index);
508 				return;
509 
510 			case 10:
511 			case 11:
512 			case 12:
513 			case 13:
514 			case 14:
515 			case 15:
516 				TentacleRises();
517 				return;
518 
519 			case 2:
520 			case 3:
521 			case 4:
522 			case 5:
523 			case 6:
524 			case 7:
525 			case 8:
526 				return;
527 			}
528 		}
529 		// fallthrough
530 
531 	case kActorStatusWalking: {
532 		uint32 index = (_frameIndex >= _frameCount) ? 2 * _frameCount - (_frameIndex + 1) : _frameIndex;
533 
534 		uint32 dist = (uint32)abs((double)getWalkIncrement(_direction, index));
535 		Common::Point point = _point1 + _point2;
536 
537 		if (canMove(&point, _direction, dist, false)) {
538 			move(_direction, dist);
539 		} else if (canMove(&point, DIR(_direction + 1), dist, false)) {
540 			move(DIR(_direction + 1), dist);
541 		} else if (canMove(&point, DIR(_direction + 7), dist, false)) {
542 			move(DIR(_direction + 7), dist);
543 		} else if (canMove(&point, DIR(_direction + 2), dist, false)) {
544 			move(DIR(_direction + 2), dist);
545 		} else if (canMove(&point, DIR(_direction + 6), dist, false)) {
546 			move(DIR(_direction + 6), dist);
547 		}
548 
549 		// Finish
550 		if (_soundResourceId != kResourceNone && getSound()->isPlaying(_soundResourceId))
551 			setVolume();
552 
553 		if (_index != getSharedData()->getPlayerIndex() && getWorld()->chapter != kChapter9)
554 			getSpecial()->run(NULL, _index);
555 
556 		updateReflectionData();
557 
558 		if (_field_944 != 5)
559 			actionAreaCheck();
560 
561 		}
562 		break;
563 
564 	case kActorStatusWalkingTo:
565 	case kActorStatusWalkingTo2: {
566 		uint32 index = (_frameIndex >= _frameCount) ? 2 * _frameCount - (_frameIndex + 1) : _frameIndex;
567 
568 		int32 dist = (int32)abs((double)getWalkIncrement(_direction, index));
569 
570 		Common::Point point = _point1 + _point2;
571 		Common::Point current = _data.points[_data.current];
572 
573 		if (point.x < (int16)(current.x - (dist + 1))
574 		 || point.x > (int16)(current.x + (dist + 1))
575 		 || point.y < (int16)(current.y - (dist + 1))
576 		 || point.y > (int16)(current.y + (dist + 1))) {
577 			if (canMove(&point, _direction, (uint32)dist, false)) {
578 				move(_direction, (uint32)dist);
579 			} else {
580 				stopWalking();
581 			}
582 		} else {
583 			int32 area = getScene()->findActionArea(kActionAreaType1, current);
584 			if (_field_944 == 1 || _field_944 == 4)
585 				area = 1;
586 
587 			if (area == -1 && _data.current >= (int32)(_data.count - 1)) {
588 				stopWalking();
589 			} else {
590 				_frameIndex = (_frameIndex + 1) % _frameCount;
591 
592 				if (testActorCollision(&current, _direction)) {
593 					_point1.x = current.x - _point2.x;
594 					_point1.y = current.y - _point2.y;
595 
596 					if (_data.current < (int32)(_data.count - 1)) {
597 						_data.current++;
598 
599 						changeDirection(_data.directions[_data.current]);
600 					} else {
601 						stopWalking();
602 					}
603 				} else {
604 					stopWalking();
605 				}
606 			}
607 		}
608 
609 		// Finish
610 		if (_soundResourceId != kResourceNone && getSound()->isPlaying(_soundResourceId))
611 			setVolume();
612 
613 		if (_index != getSharedData()->getPlayerIndex() && getWorld()->chapter != kChapter9)
614 			getSpecial()->run(NULL, _index);
615 
616 		updateReflectionData();
617 
618 		if (_field_944 != 5)
619 			actionAreaCheck();
620 
621 		}
622 		break;
623 
624 	case kActorStatusInteracting:
625 	case kActorStatusHittingPumpkin:
626 		updateStatusInteracting();
627 		break;
628 
629 	case kActorStatusStoppedInteracting:
630 		if (getSharedData()->actorEnableForStatus7) {
631 			getSharedData()->actorEnableForStatus7 = false;
632 			enable();
633 		}
634 		break;
635 
636 	case kActorStatusEnabled:
637 		if (_field_944 != 5)
638 			updateStatusEnabled();
639 		break;
640 
641 	case kActorStatusEnabled2:
642 		updateStatusEnabled2();
643 		break;
644 
645 	case kActorStatusMorphingInto:
646 		updateStatusMorphing();
647 		break;
648 
649 	case kActorStatusFidget:
650 		updateStatusBored();
651 		break;
652 
653 	case kActorStatusShowingInventory:
654 	case kActorStatus10:
655 		_frameIndex = (_frameIndex + 1) % _frameCount;
656 		break;
657 
658 	case kActorStatus8:
659 		if (getSharedData()->getFlag(kFlagIsEncounterRunning)
660 		 || !_soundResourceId
661 		 || getSound()->isPlaying(_soundResourceId)) {
662 			_frameIndex = (_frameIndex + 1) % _frameCount;
663 		} else {
664 			enable();
665 			_soundResourceId = kResourceNone;
666 		}
667 		break;
668 	}
669 
670 	if (_soundResourceId && getSound()->isPlaying(_soundResourceId))
671 		setVolume();
672 
673 	if (_index != getSharedData()->getPlayerIndex() && getWorld()->chapter != kChapter9)
674 		getSpecial()->run(NULL, _index);
675 
676 	updateReflectionData();
677 
678 	if (_field_944 != 5)
679 		actionAreaCheck();
680 }
681 
changeStatus(ActorStatus actorStatus)682 void Actor::changeStatus(ActorStatus actorStatus) {
683 	debugC(kDebugLevelActor, "[changeStatus] %d point1(%d:%d) point2(%d:%d)", actorStatus, _point1.x, _point1.y, _point2.x, _point2.y);
684 
685 	switch (actorStatus) {
686 	default:
687 		break;
688 
689 	case kActorStatusWalking:
690 	case kActorStatusWalking2:
691 		if ((getWorld()->chapter == kChapter2
692 		 && _index == getSharedData()->getPlayerIndex() && (_status == kActorStatus18 || _status == kActorStatusGettingHurt || _status == kActorStatusRestarting))
693 		 || (_status != kActorStatusEnabled && _status != kActorStatusFidget && _status != kActorStatusEnabled2 && _status != kActorStatusAttacking && _status != kActorStatus18))
694 			return;
695 
696 		updateGraphicData(0);
697 
698 		// Force status in some cases
699 		if (_status == kActorStatusEnabled2 || _status == kActorStatusAttacking || _status == kActorStatus18) {
700 			_status = kActorStatusWalking2;
701 			return;
702 		}
703 		break;
704 
705 	case kActorStatusWalkingTo:
706 	case kActorStatusWalkingTo2:
707 		updateGraphicData(0);
708 		break;
709 
710 	case kActorStatusInteracting:
711 	case kActorStatusHittingPumpkin:
712 		if (!strcmp(_name, "Big Crow"))
713 			_status = kActorStatusEnabled;
714 		break;
715 
716 	case kActorStatusEnabled:
717 	case kActorStatusShowingInventory:
718 	case kActorStatusEnabled2:
719 		updateGraphicData(5);
720 		break;
721 
722 	case kActorStatusDisabled:
723 		updateGraphicData(5);
724 		_resourceId = _graphicResourceIds[(_direction > kDirectionS ? kDirection8 - _direction : _direction) + 5];
725 
726 		getScreen()->setFlag(-1);
727 		break;
728 
729 	case kActorStatusStoppedInteracting:
730 		if (getWorld()->chapter == kChapter2 && _index == 10 && _vm->isGameFlagSet(kGameFlag279)) {
731 			Actor *actor = getScene()->getActor(0);
732 			actor->getPoint1()->x = _point2.x + _point1.x - actor->getPoint2()->x;
733 			actor->getPoint1()->y = _point2.y + _point1.y - actor->getPoint2()->y;
734 			actor->setDirection(kDirectionS);
735 
736 			getSharedData()->setPlayerIndex(0);
737 
738 			// Hide this actor and the show the other one
739 			hide();
740 			actor->show();
741 
742 			_vm->clearGameFlag(kGameFlag279);
743 
744 			getCursor()->show();
745 		}
746 		break;
747 
748 	case kActorStatus8:
749 	case kActorStatus10:
750 	case kActorStatusRestarting:
751 		updateGraphicData(20);
752 		break;
753 
754 	case kActorStatusFidget:
755 		if (getSharedData()->getFlag(kFlagIsEncounterRunning))
756 			return;
757 
758 		if (_vm->getRandomBit() == 1 && canChangeStatus(15))
759 			updateGraphicData(15);
760 		else
761 			updateGraphicData(10);
762 		break;
763 
764 	case kActorStatusAttacking:
765 	case kActorStatusGettingHurt:
766 		updateGraphicData(actorStatus == kActorStatusAttacking ? 10 : 15);
767 		break;
768 
769 	case kActorStatus18:
770 		if (getWorld()->chapter == kChapter2) {
771 			GraphicResource *resource = new GraphicResource(_vm);
772 			_frameIndex = 0;
773 
774 			if (_index > 12)
775 				_resourceId = _graphicResourceIds[_direction + 30];
776 
777 			if (getSharedData()->getPlayerIndex() == _index) {
778 				resource->load(_resourceId);
779 				_frameIndex = resource->count() - 1;
780 			}
781 
782 			if (_index == 11)
783 				_resourceId = _graphicResourceIds[getSharedData()->globalDirection > 4 ? 8 - getSharedData()->globalDirection : getSharedData()->globalDirection];
784 
785 			// Reload the graphic resource if the resource ID has changed
786 			if (resource->getResourceId() != _resourceId)
787 				resource->load(_resourceId);
788 
789 			_frameCount = resource->count();
790 
791 			delete resource;
792 		}
793 		break;
794 	}
795 
796 	_status = actorStatus;
797 }
798 
799 /////////////////////////////////////////////////////////////////////////
800 // Direction & position
801 //////////////////////////////////////////////////////////////////////////
802 
updateReflectionData()803 void Actor::updateReflectionData() {
804 	if (!_processNewDirection)
805 		return;
806 
807 	Common::Point sum = _point1 + _point2;
808 	if (_nextActionIndex != -1 && !getScene()->polygons()->get(getWorld()->actions[_nextActionIndex]->polygonIndex).contains(sum))
809 		return;
810 
811 	ActorDirection direction = kDirectionN;
812 	Common::Point position = sum;
813 	ResourceId resourceId;
814 	switch (_nextDirection) {
815 	default:
816 		// position is unchanged
817 		break;
818 
819 	case kDirectionN:
820 	case kDirectionS:
821 		position.x = _nextPosition.x + sum.x;
822 		position.y = _nextPosition.y + sum.y;
823 		position.y += (int16)((_nextDirection == kDirectionN ? -1 : 1) * 2 * abs(sum.y - _nextPositionOffset.y));
824 
825 		switch (_direction) {
826 		default:
827 			break;
828 
829 		case kDirectionN:
830 			direction = kDirectionS;
831 			break;
832 
833 		case kDirectionS:
834 			direction = kDirectionN;
835 			break;
836 
837 		case kDirectionNE:
838 			direction = kDirectionSE;
839 			break;
840 
841 		case kDirectionSE:
842 			direction = kDirectionNE;
843 			break;
844 
845 		case kDirectionNW:
846 			direction = kDirectionSW;
847 			break;
848 
849 		case kDirectionSW:
850 			direction = kDirectionNW;
851 			break;
852 		}
853 		break;
854 
855 	case kDirectionW:
856 	case kDirectionE:
857 		position.x = _nextPosition.x + sum.x;
858 		position.x += (int16)((_nextDirection == kDirectionW ? -1 : 1) * 2 * abs(sum.x - _nextPositionOffset.x));
859 		position.y = _nextPosition.y + sum.y;
860 
861 		switch (_direction) {
862 		default:
863 			break;
864 
865 		case kDirectionW:
866 			direction = kDirectionE;
867 			break;
868 
869 		case kDirectionE:
870 			direction = kDirectionW;
871 			break;
872 
873 		case kDirectionSW:
874 			direction = kDirectionSE;
875 			break;
876 
877 		case kDirectionNW:
878 			direction = kDirectionNE;
879 			break;
880 
881 		case kDirectionSE:
882 			direction = kDirectionSW;
883 			break;
884 
885 		case kDirectionNE:
886 			direction = kDirectionNW;
887 			break;
888 		}
889 		break;
890 
891 	case kDirectionNW:
892 	case kDirectionSE:
893 		position.x = _nextPosition.x + _nextPositionOffset.x;
894 		position.y = _nextPosition.y + _nextPositionOffset.y;
895 		position.x += (int16)((_nextDirection == kDirectionNW ? -1 : 1) * abs(sum.y - _nextPositionOffset.y));
896 		position.y += (int16)((_nextDirection == kDirectionNW ? -1 : 1) * abs(sum.x - _nextPositionOffset.x));
897 
898 		switch (_direction) {
899 		default:
900 			break;
901 
902 		case kDirectionN:
903 			direction = kDirectionE;
904 			break;
905 
906 		case kDirectionS:
907 			direction = kDirectionW;
908 			break;
909 
910 		case kDirectionW:
911 			direction = kDirectionS;
912 			break;
913 
914 		case kDirectionE:
915 			direction = kDirectionN;
916 			break;
917 
918 		case kDirectionNW:
919 			direction = kDirectionSE;
920 			break;
921 
922 		case kDirectionNE:
923 			direction = kDirectionNE;
924 			break;
925 
926 		case kDirectionSW:
927 			direction = kDirectionSW;
928 			break;
929 
930 		case kDirectionSE:
931 			direction = kDirectionNW;
932 			break;
933 		}
934 		break;
935 
936 	case kDirectionSW:
937 	case kDirectionNE:
938 		if (_nextDirection == kDirectionSW) {
939 			position.x = (int16)(_nextPosition.x + _nextPositionOffset.x - abs(sum.y - _nextPositionOffset.y));
940 			position.y = (int16)(_nextPosition.y + _nextPositionOffset.y + abs(sum.x - _nextPositionOffset.x));
941 		} else {
942 			double deltaX = sum.x * -0.56666666;
943 			double deltaY = (419 - (sum.y + deltaX)) * 0.87613291;
944 			position.x = (int16)(sum.x + 2 * (_nextPositionOffset.x - deltaY));
945 			position.y = (int16)(sum.y + 2 * (_nextPositionOffset.y - (sum.y + deltaX + (deltaY * 0.56666666))));
946 		}
947 
948 		switch (_direction) {
949 		default:
950 			break;
951 
952 		case kDirectionS:
953 			direction = kDirectionE;
954 			break;
955 
956 		case kDirectionN:
957 			direction = kDirectionW;
958 			break;
959 
960 		case kDirectionE:
961 			direction = kDirectionS;
962 			break;
963 
964 		case kDirectionW:
965 			direction = kDirectionN;
966 			break;
967 
968 		case kDirectionSE:
969 			direction = kDirectionSE;
970 			break;
971 
972 		case kDirectionSW:
973 			direction = kDirectionNE;
974 			break;
975 
976 		case kDirectionNE:
977 			direction = kDirectionSW;
978 			break;
979 
980 		case kDirectionNW:
981 			direction = kDirectionNW;
982 			break;
983 		}
984 		break;
985 
986 	case kDirection8:
987 		position = _nextPosition + sum;
988 		break;
989 	}
990 
991 	// Get the next resource index offset
992 	uint32 index = 0;
993 	while (_graphicResourceIds[index] != _resourceId) {
994 		index++;
995 
996 		if (index >= 55)
997 			error("[Actor::updateReflectionData] Invalid resource id index");
998 	}
999 
1000 	// Compute resource id and adjust frame count
1001 	Actor *nextActor = getScene()->getActor(_nextActorIndex);
1002 
1003 	resourceId = nextActor->getResourcesId((index - index % 5) + (direction > kDirectionS ? 8 - direction : direction));
1004 	nextActor->setFrameCount(GraphicResource::getFrameCount(_vm, resourceId));
1005 
1006 	// Adjust graphic resource and position
1007 	uint32 frameIndex = _frameIndex % nextActor->getFrameCount();
1008 	nextActor->setPosition(position.x, position.y, direction, frameIndex);
1009 	nextActor->setFrameIndex(frameIndex);
1010 	nextActor->setResourceId(resourceId);
1011 }
1012 
changeDirection(ActorDirection actorDirection)1013 void Actor::changeDirection(ActorDirection actorDirection) {
1014 	_direction = actorDirection;
1015 
1016 	if (_field_944 == 5)
1017 		return;
1018 
1019 	switch (_status) {
1020 	default:
1021 		break;
1022 
1023 	case kActorStatusDisabled:
1024 	case kActorStatusEnabled:
1025 	case kActorStatusEnabled2:
1026 		_resourceId = _graphicResourceIds[(actorDirection > kDirectionS ? kDirection8 - actorDirection : actorDirection) + 5];
1027 		_frameCount = GraphicResource::getFrameCount(_vm, _resourceId);
1028 		break;
1029 
1030 	case kActorStatus18:
1031 		if (getWorld()->chapter == kChapter2)
1032 			if (_index == 11) // we are actor 11
1033 				_resourceId = _graphicResourceIds[(actorDirection > kDirectionS) ? kDirection8 - actorDirection : actorDirection];
1034 		break;
1035 
1036 	case kActorStatusWalking:
1037 	case kActorStatusWalkingTo:
1038 	case kActorStatusWalking2:
1039 		_resourceId = _graphicResourceIds[(actorDirection > kDirectionS ? kDirection8 - actorDirection : actorDirection)];
1040 		_frameCount = GraphicResource::getFrameCount(_vm, _resourceId);
1041 		break;
1042 
1043 	case kActorStatus8:
1044 		_resourceId = _graphicResourceIds[(actorDirection > kDirectionS ? kDirection8 - actorDirection : actorDirection) + 20];
1045 		break;
1046 	}
1047 }
1048 
faceTarget(uint32 target,DirectionFrom from)1049 void Actor::faceTarget(uint32 target, DirectionFrom from) {
1050 	debugC(kDebugLevelActor, "[Actor] Facing target %d using direction from %d", target, from);
1051 
1052 	Common::Point point;
1053 
1054 	switch (from) {
1055 	default:
1056 		error("[Actor::faceTarget] Invalid direction input: %d (should be 0-3)", from);
1057 
1058 	case kDirectionFromObject: {
1059 		Object *object = getWorld()->getObjectById((ObjectId)target);
1060 		if (!object) {
1061 			warning("[Actor::faceTarget] No Object found for id %d", target);
1062 			return;
1063 		}
1064 
1065 		Common::Rect frameRect = GraphicResource::getFrameRect(_vm, object->getResourceId(), object->getFrameIndex());
1066 
1067 		point.x = (int16)Common::Rational(frameRect.width(), 2).toInt()  + object->x;
1068 		point.y = (int16)Common::Rational(frameRect.height(), 2).toInt() + object->y;
1069 		}
1070 		break;
1071 
1072 	case kDirectionFromPolygons: {
1073 		int32 actionIndex = getWorld()->getActionAreaIndexById(target);
1074 		if (actionIndex == -1) {
1075 			warning("[Actor::faceTarget] No ActionArea found for id %d", target);
1076 			return;
1077 		}
1078 
1079 		Polygon polygon = getScene()->polygons()->get(getWorld()->actions[actionIndex]->polygonIndex);
1080 
1081 		point.x = polygon.boundingRect.left + (polygon.boundingRect.right  - polygon.boundingRect.left) / 2;
1082 		point.y = polygon.boundingRect.top  + (polygon.boundingRect.bottom - polygon.boundingRect.top)  / 2;
1083 		}
1084 		break;
1085 
1086 	case kDirectionFromActor: {
1087 		Actor *actor = getScene()->getActor((ActorIndex)target);
1088 		point = *actor->getPoint1() + *actor->getPoint2();
1089 		}
1090 		break;
1091 
1092 	case kDirectionFromParameters:
1093 		point.x = point.y = (int16)target;
1094 		break;
1095 	}
1096 
1097 	Common::Point mid(_point1.x + _point2.x, _point1.y + _point2.y);
1098 	changeDirection(getAngle(mid, point));
1099 }
1100 
setPosition(int16 newX,int16 newY,ActorDirection newDirection,uint32 frame)1101 void Actor::setPosition(int16 newX, int16 newY, ActorDirection newDirection, uint32 frame) {
1102 	_point1.x = newX - _point2.x;
1103 	_point1.y = newY - _point2.y;
1104 
1105 	if (_direction != kDirection8)
1106 		changeDirection(newDirection);
1107 
1108 	if (frame > 0)
1109 		_frameIndex = frame;
1110 }
1111 
1112 /////////////////////////////////////////////////////////////////////////
1113 // Misc
1114 //////////////////////////////////////////////////////////////////////////
stopSound()1115 void Actor::stopSound() {
1116 	if (_soundResourceId && getSound()->isPlaying(_soundResourceId))
1117 		getSound()->stop(_soundResourceId);
1118 }
1119 
toString(bool shortString)1120 Common::String Actor::toString(bool shortString) {
1121 	Common::String output;
1122 
1123 	output += Common::String::format("Actor %d: %s\n", _index, _name);
1124 	if (!shortString) {
1125 		output += Common::String::format("resourceId:   %d (0x%X): \n", _resourceId, _resourceId);
1126 		output += Common::String::format("objectIndex:  %d: \n", _objectIndex);
1127 		output += Common::String::format("frameIndex:   %d: \n", _frameIndex);
1128 		output += Common::String::format("frameCount:   %d: \n", _frameCount);
1129 		output += Common::String::format("(x, y):       (%d , %d): \n", _point.x, _point.y);
1130 		output += Common::String::format("(x1, y1):     (%d , %d): \n", _point1.x, _point1.y);
1131 		output += Common::String::format("(x2, y2):     (%d , %d): \n", _point2.x, _point2.y);
1132 		output += Common::String::format("flags:        %d: \n", flags);
1133 		output += Common::String::format("actionType:   %d: \n", actionType);
1134 		output += Common::String::format("boundingRect: top[%d] left[%d] right[%d] bottom[%d]: \n", _boundingRect.top, _boundingRect.left, _boundingRect.right, _boundingRect.bottom);
1135 		output += Common::String::format("direction:    %d: \n", _direction);
1136 		output += Common::String::format("field_3C:     %d: \n", _field_3C);
1137 		output += Common::String::format("status:       %d: \n", _status);
1138 		output += Common::String::format("field_44:     %d: \n", _field_44);
1139 		output += Common::String::format("priority:     %d: \n", _priority);
1140 	}
1141 
1142 	return output;
1143 }
1144 
1145 //////////////////////////////////////////////////////////////////////////
1146 // Unknown methods
1147 //////////////////////////////////////////////////////////////////////////
1148 
clearFields()1149 void Actor::clearFields() {
1150 	_processNewDirection = false;
1151 	_invertPriority = false;
1152 	_nextDirection = kDirectionN;
1153 	_nextActionIndex = 0;
1154 	_nextActorIndex = 0;
1155 	_nextPositionOffset = Common::Point(0, 0);
1156 	_nextPosition = Common::Point(0, 0);
1157 	_field_994 = 0;
1158 	_field_998 = 0;
1159 	_field_99C = 0;
1160 	_field_9A0 = 0;
1161 }
1162 
checkBoredStatus() const1163 bool Actor::checkBoredStatus() const {
1164 	if (_status != kActorStatusFidget)
1165 		return false;
1166 
1167 	int index;
1168 	for (index = 10; index < 20; index++) {
1169 		if (_graphicResourceIds[index] == _resourceId)
1170 			break;
1171 	}
1172 
1173 	return (index >= 15);
1174 }
1175 
canReach(const Common::Point & point)1176 bool Actor::canReach(const Common::Point &point) {
1177 	// Compute point and delta
1178 	Common::Point sum(_point1.x + _point2.x, _point1.y + _point2.y);
1179 	Common::Point delta = point - sum;
1180 
1181 	// Compute modifiers
1182 	int16 a1 = 0;
1183 	int16 a2 = 0;
1184 	int16 a3 = 0;
1185 
1186 	if (delta.x <= 0) {
1187 		if (delta.y >= 0) {
1188 			a1 = -1;
1189 			a2 = 1;
1190 			a3 = 3;
1191 		} else {
1192 			a1 = -1;
1193 			a2 = -1;
1194 			a3 = 0;
1195 		}
1196 	} else {
1197 		if (delta.y >= 0) {
1198 			a1 = 1;
1199 			a2 = 1;
1200 			a3 = 2;
1201 		} else {
1202 			a1 = 1;
1203 			a2 = -1;
1204 			a3 = 1;
1205 		}
1206 	}
1207 
1208 	if (point == sum) {
1209 		if (canMove(&sum, a3 >= 2 ? kDirectionS : kDirectionN, (uint32)abs(delta.y), false)) {
1210 			_data.points[0] = point;
1211 			_data.current   = 0;
1212 			_data.count     = 1;
1213 
1214 			return true;
1215 		}
1216 	}
1217 
1218 	if (point.x == sum.x) {
1219 		ActorDirection actorDir = a3 >= 2 ? kDirectionS : kDirectionN;
1220 		if (canMove(&sum, actorDir, (uint32)abs(delta.y), false)) {
1221 			_data.points[0] = point;
1222 			_data.current   = 0;
1223 			_data.count     = 1;
1224 
1225 			changeDirection(actorDir);
1226 
1227 			return true;
1228 		}
1229 
1230 		return false;
1231 	}
1232 
1233 	if (point.y == sum.y) {
1234 		ActorDirection actorDir = (a3 != 0 && a3 != 3) ? kDirectionE : kDirectionW;
1235 
1236 		if (canMove(&sum, actorDir, (uint32)abs(delta.x), true)) {
1237 			_data.points[0] = point;
1238 			_data.current   = 0;
1239 			_data.count     = 1;
1240 
1241 			changeDirection(actorDir);
1242 
1243 			return true;
1244 		}
1245 
1246 		return false;
1247 	}
1248 
1249 	if (abs(delta.x) != abs(delta.y)) {
1250 		Common::Array<int> actions;
1251 		Common::Point point1;
1252 		Common::Point point2;
1253 		uint32 count1 = 0;
1254 		uint32 count2 = 0;
1255 		ActorDirection direction1 = kDirectionInvalid;
1256 		ActorDirection direction2 = kDirectionInvalid;
1257 
1258 		// Compute coordinates, directions and counts
1259 		if (abs(delta.x) < abs(delta.y)) {
1260 			point1 = Common::Point((int16)(sum.x + abs(delta.x) * a1), (int16)(sum.y + abs(delta.x) * a2));
1261 			point2 = Common::Point(sum.x                             , (int16)(sum.y + abs(abs(delta.x) - abs(delta.y)) * a2));
1262 			count1 = (uint32)abs(point1.x - sum.x);
1263 			count2 = (uint32)abs(point1.y - point.y);
1264 
1265 			switch (a3) {
1266 			default:
1267 				error("[Actor::canReach] Invalid value for a3");
1268 				break;
1269 
1270 			case 0:
1271 				direction1 = kDirectionNW;
1272 				direction2 = kDirectionN;
1273 				break;
1274 
1275 			case 1:
1276 				direction1 = kDirectionNE;
1277 				direction2 = kDirectionN;
1278 				break;
1279 
1280 			case 2:
1281 				direction1 = kDirectionSE;
1282 				direction2 = kDirectionS;
1283 				break;
1284 
1285 			case 3:
1286 				direction1 = kDirectionSW;
1287 				direction2 = kDirectionS;
1288 				break;
1289 			}
1290 		} else {
1291 			point1 = Common::Point((int16)(sum.x + abs(delta.y) * a1),                     (int16)(sum.y + abs(delta.y) * a2));
1292 			point2 = Common::Point((int16)(sum.x + abs(abs(delta.y) - abs(delta.x)) * a1), sum.y);
1293 			count1 = (uint32)abs(abs(delta.y) * a2);
1294 			count2 = (uint32)abs(point1.x - point.x);
1295 
1296 			switch (a3) {
1297 			default:
1298 				error("[Actor::canReach] Invalid value for a3");
1299 				break;
1300 
1301 			case 0:
1302 				direction1 = kDirectionNW;
1303 				direction2 = kDirectionW;
1304 				break;
1305 
1306 			case 1:
1307 				direction1 = kDirectionNE;
1308 				direction2 = kDirectionE;
1309 				break;
1310 
1311 			case 2:
1312 				direction1 = kDirectionSE;
1313 				direction2 = kDirectionE;
1314 				break;
1315 
1316 			case 3:
1317 				direction1 = kDirectionSW;
1318 				direction2 = kDirectionW;
1319 				break;
1320 			}
1321 		}
1322 
1323 		// Check scene rects
1324 		if (getWorld()->chapter != kChapter2 || strcmp(_name, "Big Crow")) {
1325 			Common::Rect currentRect = getWorld()->sceneRects[getWorld()->sceneRectIdx];
1326 
1327 			if (!currentRect.contains(point1) || !currentRect.contains(point2))
1328 				return false;
1329 		}
1330 
1331 		if (canMove(&sum,    direction1, count1, true)
1332 		 && canMove(&point1, direction2, count2, true)) {
1333 			_data.points[0] = point1;
1334 			_data.points[1] = point;
1335 			_data.current = 0;
1336 			_data.count = 2;
1337 
1338 			changeDirection(direction1);
1339 
1340 			_data.directions[1] = direction2;
1341 
1342 			return true;
1343 		}
1344 
1345 		if (canMove(&sum,    direction2, count2, true)
1346 		 && canMove(&point2, direction1, count1, true)) {
1347 			_data.points[0] = point2;
1348 			_data.points[1] = point;
1349 			_data.current = 0;
1350 			_data.count = 2;
1351 
1352 			changeDirection(direction2);
1353 
1354 			_data.directions[1] = direction1;
1355 
1356 			return true;
1357 		}
1358 
1359 		// Compute actor actions
1360 		int actorActions[5];
1361 		ActionArea *actorArea = getWorld()->actions[_actionIdx3];
1362 		for (uint32 i = 0; i < 5; i++) {
1363 			if (actorArea->paths[i])
1364 				actorActions[i] = actorArea->paths[i];
1365 			else
1366 				actorActions[i] = -1;
1367 		}
1368 
1369 		if (actorActions[0] == -1)
1370 			actions.push_back(_actionIdx3);
1371 
1372 		// Process all scene actions
1373 		for (uint32 i = 0; i < getWorld()->actions.size(); i++) {
1374 			// Check each area action against each actor action
1375 			ActionArea *area = getWorld()->actions[i];
1376 			for (uint32 j = 0; j < 5; j++) {
1377 				for (uint32 k = 0; k < 5; k++) {
1378 					if (area->paths[j] == actorActions[k])
1379 						actions.push_back(i);
1380 				}
1381 			}
1382 		}
1383 
1384 		//////////////////////////////////////////////////////////////////////////
1385 		// Process actions
1386 		_frameNumber = 0;
1387 
1388 		if (abs(sum.x - point.x) > abs(sum.y - point.y)) {
1389 			if (sum.x <= point.x) {
1390 				if (!findLeftPath(sum, point, &actions))
1391 					return false;
1392 			} else {
1393 				if (!findRightPath(sum, point, &actions))
1394 					return false;
1395 			}
1396 
1397 			changeDirection(_data.directions[0]);
1398 
1399 			return true;
1400 		}
1401 
1402 		if (sum.y > point.y) {
1403 			if (!findUpPath(sum, point, &actions))
1404 				return false;
1405 
1406 			changeDirection(_data.directions[0]);
1407 
1408 			return true;
1409 		}
1410 
1411 		// last case: sum.y < point.y
1412 		if (!findDownPath(sum, point, &actions))
1413 			return false;
1414 
1415 		changeDirection(_data.directions[0]);
1416 
1417 		return true;
1418 	}
1419 
1420 	//////////////////////////////////////////////////////////////////////////
1421 	// Last case: abs(delta.x) == abs(delta.y)
1422 
1423 	// Compute direction
1424 	ActorDirection actorDir = kDirectionSW;
1425 	switch (a3) {
1426 	default:
1427 		break;
1428 
1429 	case 0:
1430 		actorDir = kDirectionNW;
1431 		break;
1432 
1433 	case 1:
1434 		actorDir = kDirectionNE;
1435 		break;
1436 
1437 	case 2:
1438 		actorDir = kDirectionSE;
1439 		break;
1440 	}
1441 
1442 	if (!canMove(&sum, actorDir, (uint32)abs(delta.y), true))
1443 		return false;
1444 
1445 	// Update actor data
1446 	_data.points[0] = point;
1447 	_data.current   = 0;
1448 	_data.count     = 1;
1449 
1450 	// Update actor from direction
1451 	changeDirection(actorDir);
1452 
1453 	return true;
1454 }
1455 
forceTo(int16 actorX,int16 actorY,bool doSpeech)1456 void Actor::forceTo(int16 actorX, int16 actorY, bool doSpeech) {
1457 	if (canReach(Common::Point(actorX, actorY))) {
1458 		if (_status <= kActorStatus11)
1459 			changeStatus(kActorStatusWalkingTo);
1460 		else
1461 			changeStatus(kActorStatusWalkingTo2);
1462 	} else if (doSpeech) {
1463 		getSpeech()->playIndexed(1);
1464 	}
1465 }
1466 
setupReflectionData(ActorIndex nextActor,int32 actionAreaId,ActorDirection nextDirection,const Common::Point & nextPosition,bool invertPriority,const Common::Point & nextPositionOffset)1467 void Actor::setupReflectionData(ActorIndex nextActor, int32 actionAreaId, ActorDirection nextDirection, const Common::Point &nextPosition, bool invertPriority, const Common::Point &nextPositionOffset) {
1468 	_nextActorIndex = nextActor;
1469 	_nextActionIndex = (actionAreaId != -1) ? getWorld()->getActionAreaIndexById(actionAreaId) : -1;
1470 	_nextDirection = nextDirection;
1471 	_nextPosition = nextPosition;
1472 	_invertPriority = invertPriority;
1473 
1474 	Common::Point offset;
1475 	if (actionAreaId != -1) {
1476 		if (nextPositionOffset.x) {
1477 			offset = nextPositionOffset;
1478 		} else {
1479 			Polygon polygon = getScene()->polygons()->get((uint32)_nextActionIndex);
1480 
1481 			offset = polygon.points[0];
1482 
1483 			// Iterate through points
1484 			if (polygon.count() > 1) {
1485 				for (uint i = 1; i < polygon.count() - 1; i++) {
1486 					Common::Point point = polygon.points[i];
1487 
1488 					switch (nextDirection) {
1489 					default:
1490 						break;
1491 
1492 					case kDirectionN:
1493 						if (offset.y > point.y)
1494 							offset.y = point.y;
1495 						break;
1496 
1497 					case kDirectionNW:
1498 						if (offset.y > point.y)
1499 							offset.y = point.y;
1500 
1501 						if (offset.x > point.x)
1502 							offset.x = point.x;
1503 						break;
1504 
1505 					case kDirectionW:
1506 						if (offset.x > point.x)
1507 							offset.x = point.x;
1508 						break;
1509 
1510 					case kDirectionSW:
1511 						if (offset.y < point.y)
1512 							offset.y = point.y;
1513 
1514 						if (offset.x > point.x)
1515 							offset.x = point.x;
1516 						break;
1517 
1518 					case kDirectionS:
1519 						if (offset.y < point.y)
1520 							offset.y = point.y;
1521 						break;
1522 
1523 					case kDirectionSE:
1524 						if (offset.y < point.y)
1525 							offset.y = point.y;
1526 
1527 						if (offset.x < point.x)
1528 							offset.x = point.x;
1529 						break;
1530 
1531 					case kDirectionE:
1532 						if (offset.x < point.x)
1533 							offset.x = point.x;
1534 						break;
1535 
1536 					case kDirectionNE:
1537 						if (offset.y > point.y)
1538 							offset.y = point.y;
1539 
1540 						if (offset.x < point.x)
1541 							offset.x = point.x;
1542 						break;
1543 
1544 					case kDirection8:
1545 						offset = Common::Point(0, 0);
1546 						break;
1547 					}
1548 				}
1549 			}
1550 		}
1551 	}
1552 
1553 	_nextPositionOffset = offset;
1554 
1555 	int16 cosValue = (int16)(cos(0.523598775) * 1000.0);
1556 	int16 sinValue = (int16)(sin(0.523598775) * 1000.0);
1557 
1558 	_field_994 = offset.x - cosValue;
1559 	_field_998 = offset.y + sinValue;
1560 	_field_99C = offset.x + cosValue;
1561 	_field_9A0 = offset.y - sinValue;
1562 
1563 	_processNewDirection = true;
1564 
1565 	updateReflectionData();
1566 }
1567 
aNicePlaceToTalk(Common::Point * point,int32 * param)1568 bool Actor::aNicePlaceToTalk(Common::Point *point, int32* param) {
1569 	Actor *player = getScene()->getActor();
1570 
1571 	int16 offset = 65;
1572 	if (getWorld()->chapter != kChapter2 || _index != 8)
1573 		offset = 40;
1574 
1575 	int32 parameter;
1576 	Common::Point actorPoint = _point1 + _point2, pt = actorPoint;
1577 
1578 	if (getWorld()->chapter != kChapter2 || _index != 1) {
1579 		Common::Point diff = *player->getPoint1() - _point1;
1580 
1581 		if (abs(diff.y) <= abs(diff.x)) {
1582 
1583 			if (diff.x < 0) {
1584 
1585 				parameter = 2;
1586 				pt.x -= offset;
1587 				if (getScene()->findActionArea(kActionAreaType2, pt) != -1)
1588 					goto processActor;
1589 
1590 				parameter = 3;
1591 				pt = actorPoint;
1592 				pt.x -= offset;
1593 				pt.y += offset;
1594 				if (getScene()->findActionArea(kActionAreaType2, pt) != -1)
1595 					goto processActor;
1596 
1597 				parameter = 1;
1598 				pt = actorPoint;
1599 				pt.x -= offset;
1600 				pt.y -= offset;
1601 
1602 			} else {
1603 
1604 				parameter = 6;
1605 				pt.x += offset;
1606 				if (getScene()->findActionArea(kActionAreaType2, pt) != -1)
1607 					goto processActor;
1608 
1609 				parameter = 5;
1610 				pt = actorPoint;
1611 				pt.x += offset;
1612 				pt.y += offset;
1613 				if (getScene()->findActionArea(kActionAreaType2, pt) != -1)
1614 					goto processActor;
1615 
1616 				parameter = 7;
1617 				pt = actorPoint;
1618 				pt.x += offset;
1619 				pt.y -= offset;
1620 			}
1621 
1622 		} else {
1623 
1624 			if (diff.y >= 0) {
1625 
1626 				parameter = 4;
1627 				pt.y += offset;
1628 				if (getScene()->findActionArea(kActionAreaType2, pt) != -1)
1629 					goto processActor;
1630 
1631 				parameter = 3;
1632 				pt = actorPoint;
1633 				pt.x -= offset;
1634 				pt.y += offset;
1635 				if (getScene()->findActionArea(kActionAreaType2, pt) != -1)
1636 					goto processActor;
1637 
1638 				parameter = 5;
1639 				pt = actorPoint;
1640 				pt.x += offset;
1641 				pt.y += offset;
1642 
1643 			} else {
1644 
1645 				parameter = 0;
1646 				pt.y -= offset;
1647 				if (getScene()->findActionArea(kActionAreaType2, pt) != -1)
1648 					goto processActor;
1649 
1650 				parameter = 1;
1651 				pt = actorPoint;
1652 				pt.x -= offset;
1653 				pt.y -= offset;
1654 				if (getScene()->findActionArea(kActionAreaType2, pt) != -1)
1655 					goto processActor;
1656 
1657 				parameter = 7;
1658 				pt = actorPoint;
1659 				pt.x += offset;
1660 				pt.y -= offset;
1661 			}
1662 		}
1663 	} else {
1664 		parameter = 5;
1665 		pt.x += offset;
1666 		pt.y += offset;
1667 	}
1668 
1669 	if (getScene()->findActionArea(kActionAreaType2, pt) == -1)
1670 		return false;
1671 
1672 processActor:
1673 	if (!player->canReach(pt))
1674 		return false;
1675 
1676 	*point = pt;
1677 	*param = abs(parameter + 4) & 7;
1678 
1679 	return true;
1680 }
1681 
canMove(Common::Point * point,ActorDirection direction,uint32 distance,bool hasDelta)1682 bool Actor::canMove(Common::Point *point, ActorDirection direction, uint32 distance, bool hasDelta) {
1683 	if (_field_944 == 1 || _field_944 == 4)
1684 		return true;
1685 
1686 	int16 x = (hasDelta ? point->x : point->x + deltaPointsArray[direction][0]);
1687 	int16 y = (hasDelta ? point->y : point->y + deltaPointsArray[direction][1]);
1688 
1689 	// Check scene rect
1690 	if (!_field_944) {
1691 		Common::Rect rct = getWorld()->sceneRects[getWorld()->sceneRectIdx];
1692 
1693 		if (x > rct.right)
1694 			return false;
1695 
1696 		if (x < rct.left)
1697 			return false;
1698 
1699 		if (y < rct.top)
1700 			return false;
1701 
1702 		if (y > rct.bottom)
1703 			return false;
1704 
1705 		if (!testActorCollision(point, direction))
1706 			return false;
1707 	}
1708 
1709 	if (distance > 0) {
1710 		uint32 allowed = 0;
1711 
1712 		while (getScene()->findActionArea(kActionAreaType1, Common::Point(x, y), true) != -1) {
1713 			x += deltaPointsArray[direction][0];
1714 			y += deltaPointsArray[direction][1];
1715 
1716 			++allowed;
1717 
1718 			if (allowed >= distance)
1719 				return true;
1720 		}
1721 
1722 		return false;
1723 	}
1724 
1725 	return true;
1726 }
1727 
move(ActorDirection actorDir,uint32 dist)1728 void Actor::move(ActorDirection actorDir, uint32 dist) {
1729 	if (_frameCount == 0)
1730 		error("[Actor::move] Invalid frame count (cannot be 0)");
1731 
1732 	_lastScreenUpdate = _vm->screenUpdateCount;
1733 
1734 	Common::Point sum(_point1.x + _point2.x, _point1.y + _point2.y);
1735 	int32 panning = getSound()->calculatePanningAtPoint(sum);
1736 
1737 	switch (_status) {
1738 	default:
1739 		break;
1740 
1741 	case kActorStatusWalking:
1742 	case kActorStatusWalkingTo:
1743 	case kActorStatusWalking2:
1744 	case kActorStatusWalkingTo2:
1745 		incPosition(actorDir, (int16)dist, &_point1);
1746 
1747 		_frameIndex = (_frameIndex + 1) % _frameCount;
1748 
1749 		if (_walkingSound1 != kResourceNone) {
1750 
1751 			// Compute volume
1752 			int32 vol = (int32)sqrt((double)-Config.sfxVolume);
1753 			if (_index != getSharedData()->getPlayerIndex())
1754 				vol += (int32)sqrt((double)abs(getSound()->calculateVolumeAdjustement(sum, 10, 0)));
1755 
1756 			int32 volume = (Config.sfxVolume + vol) * (Config.sfxVolume + vol);
1757 			if (volume > 10000)
1758 				volume = 10000;
1759 
1760 			if (_field_944 != 1 && _field_944 != 4) {
1761 				// Compute resource Id
1762 				ResourceId resourceId = kResourceNone;
1763 				if (getWorld()->actions[_actionIdx3]->soundResourceIdFrame != kResourceNone && strcmp((char *)&_name, "Crow") && strcmp((char *)&_name, "Big Crow")) {
1764 					if (_frameIndex == _field_64C)
1765 						resourceId = (ResourceId)(getWorld()->actions[_actionIdx3]->soundResourceIdFrame + (int)rnd(2));
1766 					else if (_frameIndex == _field_650)
1767 						resourceId = (ResourceId)(getWorld()->actions[_actionIdx3]->soundResourceId + (int)rnd(2));
1768 				} else {
1769 					if (_frameIndex == _field_64C)
1770 						resourceId = (ResourceId)(_walkingSound1 + (int)rnd(2));
1771 					else if (_frameIndex == _field_650)
1772 						resourceId = (ResourceId)(_walkingSound3 + (int)rnd(2));
1773 				}
1774 
1775 				// Play sound
1776 				getSound()->playSound(resourceId, false, -volume, panning);
1777 			}
1778 		}
1779 		break;
1780 
1781 	case kActorStatus18:
1782 		if (getWorld()->chapter == kChapter2) {
1783 			incPosition(actorDir, (int16)dist, &_point1);
1784 
1785 			if (_walkingSound1 == kResourceNone)
1786 				break;
1787 
1788 			// Compute volume
1789 			int32 vol = getWorld()->actions[_actionIdx3]->volume;
1790 			if (_index != getSharedData()->getPlayerIndex())
1791 				vol += (int32)sqrt((double)abs(getSound()->calculateVolumeAdjustement(sum, 10, 0)));
1792 
1793 			int32 volume = (Config.sfxVolume + vol) * (Config.sfxVolume + vol);
1794 			if (volume > 10000)
1795 				volume = 10000;
1796 
1797 			// Compute resource Id
1798 			ResourceId resourceId = kResourceNone;
1799 			if (getWorld()->actions[_actionIdx3]->soundResourceIdFrame != kResourceNone && strcmp((char *)&_name, "Crow") && strcmp((char *)&_name, "Big Crow")) {
1800 				if (_frameIndex == _field_64C)
1801 					resourceId = (ResourceId)(getWorld()->actions[_actionIdx3]->soundResourceIdFrame + (int)rnd(2));
1802 				else if (_frameIndex == _field_650)
1803 					resourceId = (ResourceId)(getWorld()->actions[_actionIdx3]->soundResourceId + (int)rnd(2));
1804 			} else {
1805 				if (_frameIndex == _field_64C)
1806 					resourceId = (ResourceId)(_walkingSound1 + (int)rnd(2));
1807 				else if (_frameIndex == _field_650)
1808 					resourceId = (ResourceId)(_walkingSound3 + (int)rnd(2));
1809 			}
1810 
1811 			// Play sound
1812 			getSound()->playSound(resourceId, false, -volume, panning);
1813 		}
1814 		break;
1815 	}
1816 }
1817 
testActorCollision(Common::Point * point,ActorDirection dir)1818 bool Actor::testActorCollision(Common::Point *point, ActorDirection dir) {
1819 	int32 dist = getStride(dir, (_frameIndex >= _frameCount) ? 2 * _frameCount - (_frameIndex + 1) : _frameIndex);
1820 
1821 	int32 x = point->x + deltaPointsArray[dir][0] * dist - (_field_948 + 10);
1822 	int32 y = point->y + deltaPointsArray[dir][1] * dist - (_field_94C + 10);
1823 	int32 x1 = x + 2 * _field_948 + 20;
1824 	int32 y1 = y + 2 * _field_94C + 20;
1825 
1826 	for (int32 i = 0; i < (int32)getWorld()->actors.size(); i++) {
1827 		if (i == _index)
1828 			continue;
1829 
1830 		Actor *actor = getScene()->getActor(i);
1831 
1832 		if (!actor->isOnScreen())
1833 			continue;
1834 
1835 		if (actor->_field_944)
1836 			continue;
1837 
1838 		int32 x2 = actor->getPoint1()->x + actor->getPoint2()->x -    (actor->getField948() + 15);
1839 		int32 y2 = actor->getPoint1()->y + actor->getPoint2()->y -    (actor->getField94C() + 10);
1840 		int32 x3 = actor->getPoint1()->x + actor->getPoint2()->x + 2 * actor->getField948() + 15;
1841 		int32 y3 = actor->getPoint1()->y + actor->getPoint2()->y + 2 * actor->getField94C() + 10;
1842 
1843 		if (i == getSharedData()->getPlayerIndex() && getWorld()->chapter != kChapter11) {
1844 			x2 -= 10;
1845 			y2 -= 10;
1846 			x3 += 10;
1847 			y3 += 10;
1848 		}
1849 
1850 		if (getScene()->rectIntersect(x, y, x1, y1, x2, y2, x3, y3)) {
1851 			if (i)
1852 				return false;
1853 
1854 			int32 x4 = x2 + 10;
1855 			int32 y4 = y2 + 10;
1856 			int32 x5 = x3 - 10;
1857 			int32 y5 = y3 - 10;
1858 
1859 			switch (_direction) {
1860 			default:
1861 				break;
1862 
1863 			case kDirectionNW:
1864 				if (x4 >= x)
1865 					break;
1866 				// fallthrough
1867 
1868 			case kDirectionN:
1869 				if (y4 >= y)
1870 					break;
1871 
1872 				return false;
1873 
1874 			case kDirectionW:
1875 				if (x4 < x)
1876 					return false;
1877 
1878 				break;
1879 
1880 			case kDirectionSW:
1881 				if (x4 < x && y4 > y)
1882 					return false;
1883 
1884 				break;
1885 
1886 			case kDirectionS:
1887 				if (y5 > y1)
1888 					return false;
1889 
1890 				break;
1891 
1892 			case kDirectionE:
1893 				if (x5 > x1)
1894 					return false;
1895 
1896 				break;
1897 
1898 			case kDirectionNE:
1899 				if (x5 > x1 && y4 < y)
1900 					return false;
1901 
1902 				break;
1903 			}
1904 
1905 			if (getScene()->rectIntersect(x, y, x1, y1, x4, y4, x5, y5))
1906 				return false;
1907 		}
1908 	}
1909 
1910 	return true;
1911 }
1912 
drawInventory()1913 void Actor::drawInventory() {
1914 	Actor *player = getScene()->getActor();
1915 	Common::Point mouse = getCursor()->position();
1916 	bool keepField = false;
1917 
1918 	uint count = inventory.find();
1919 	for (uint32 i = 0; i < count; i++) {
1920 		// Compute points
1921 		Common::Point coords;
1922 		adjustCoordinates(&coords);
1923 
1924 		Common::Point ringPoint = Inventory::getInventoryRingPoint(_vm, count, i);
1925 		Common::Point point = coords + Common::Point(player->getPoint2()->x + ringPoint.x, player->getPoint2()->y / 2 - ringPoint.y);
1926 
1927 		if (mouse.x < point.x || mouse.x > (point.x + 40) || mouse.y < point.y || mouse.y > (point.y + 40)) {
1928 			getScreen()->addGraphicToQueue(getWorld()->inventoryIconsNormal[inventory[i] - 1],
1929 			                               0,
1930 			                               point,
1931 			                               kDrawFlagNone,
1932 			                               0,
1933 			                               1);
1934 		} else {
1935 			if (getWorld()->field_120 != (int32)(i + 1)) {
1936 				getSound()->playSound(MAKE_RESOURCE(kResourcePackSound, 3));
1937 				Inventory::describe(_vm, inventory[i] - 1);
1938 			}
1939 
1940 			getWorld()->field_120 = i + 1;
1941 			keepField = true;
1942 
1943 			getScreen()->addGraphicToQueue(getWorld()->inventoryIconsActive[inventory[i] - 1],
1944 			                               0,
1945 			                               point,
1946 			                               kDrawFlagNone,
1947 			                               0,
1948 			                               1);
1949 		}
1950 
1951 		if (getWorld()->chapter == kChapter4)
1952 			updateNumbers(inventory[i] - 1, point);
1953 	}
1954 
1955 	if (!keepField)
1956 		getWorld()->field_120 = 0;
1957 }
1958 
stopWalking()1959 void Actor::stopWalking() {
1960 	changeStatus(_status <= 11 ? kActorStatusEnabled : kActorStatusEnabled2);
1961 	_data.current = 0;
1962 }
1963 
1964 //////////////////////////////////////////////////////////////////////////
1965 // Static update methods
1966 //////////////////////////////////////////////////////////////////////////
crowsReturn(AsylumEngine * engine)1967 void Actor::crowsReturn(AsylumEngine *engine) {
1968 	engine->clearGameFlag(kGameFlag438);
1969 	engine->clearGameFlag(kGameFlag439);
1970 	engine->clearGameFlag(kGameFlag440);
1971 	engine->clearGameFlag(kGameFlag441);
1972 	engine->clearGameFlag(kGameFlag442);
1973 
1974 	// Reset shared data
1975 	engine->data()->resetChapter2Data();
1976 
1977 	engine->scene()->getActor(13)->enable();
1978 	engine->scene()->getActor(13)->forceTo(2300, 71, false);
1979 
1980 	engine->scene()->getActor(14)->enable();
1981 	engine->scene()->getActor(14)->forceTo(2600, 1300, false);
1982 
1983 	engine->scene()->getActor(15)->enable();
1984 	engine->scene()->getActor(15)->forceTo(2742, 615, false);
1985 
1986 	engine->scene()->getActor(16)->enable();
1987 	engine->scene()->getActor(16)->forceTo(2700, 1200, false);
1988 
1989 	engine->scene()->getActor(17)->enable();
1990 	engine->scene()->getActor(17)->forceTo(2751, 347, false);
1991 
1992 	engine->scene()->getActor(18)->enable();
1993 	engine->scene()->getActor(18)->forceTo(2420, 284, false);
1994 
1995 	engine->scene()->getActor(19)->enable();
1996 	engine->scene()->getActor(19)->forceTo(2800, 370, false);
1997 
1998 	engine->scene()->getActor(20)->enable();
1999 	engine->scene()->getActor(20)->forceTo(1973, 1, false);
2000 
2001 	engine->scene()->getActor(21)->enable();
2002 	engine->scene()->getActor(21)->forceTo(2541, 40, false);
2003 }
2004 
morphInto(AsylumEngine * engine,int nextPlayer)2005 void Actor::morphInto(AsylumEngine *engine, int nextPlayer) {
2006 	WorldStats *world = engine->scene()->worldstats();
2007 	if (world->chapter != kChapter9)
2008 		return;
2009 
2010 	Actor *player = engine->scene()->getActor();
2011 	world->nextPlayer = nextPlayer;
2012 
2013 	switch (engine->data()->getPlayerIndex()) {
2014 	default:
2015 		break;
2016 
2017 	case 1:
2018 		if (nextPlayer == 2) {
2019 			player->setResourceId(world->graphicResourceIds[7]);
2020 
2021 			uint32 frameCount = GraphicResource::getFrameCount(engine, player->getResourceId());
2022 			player->setFrameCount(frameCount);
2023 			player->setFrameIndex(frameCount - 1);
2024 
2025 		} else if (nextPlayer == 3) {
2026 			player->setResourceId(world->graphicResourceIds[8]);
2027 
2028 			uint32 frameCount = GraphicResource::getFrameCount(engine, player->getResourceId());
2029 			player->setFrameCount(frameCount);
2030 			player->setFrameIndex(frameCount - 1);
2031 		}
2032 		break;
2033 
2034 	case 2:
2035 		if (nextPlayer == 1) {
2036 			player->setResourceId(world->graphicResourceIds[4]);
2037 
2038 			uint32 frameCount = GraphicResource::getFrameCount(engine, player->getResourceId());
2039 			player->setFrameCount(frameCount);
2040 			player->setFrameIndex(0);
2041 
2042 		} else if (nextPlayer == 3) {
2043 			player->setResourceId(world->graphicResourceIds[3]);
2044 
2045 			uint32 frameCount = GraphicResource::getFrameCount(engine, player->getResourceId());
2046 			player->setFrameCount(frameCount);
2047 			player->setFrameIndex(0);
2048 		}
2049 		break;
2050 
2051 	case 3:
2052 		if (nextPlayer == 1) {
2053 			player->setResourceId(world->graphicResourceIds[5]);
2054 
2055 			uint32 frameCount = GraphicResource::getFrameCount(engine, player->getResourceId());
2056 			player->setFrameCount(frameCount);
2057 			player->setFrameIndex(0);
2058 
2059 		} else if (nextPlayer == 2) {
2060 			player->setResourceId(world->graphicResourceIds[6]);
2061 
2062 			uint32 frameCount = GraphicResource::getFrameCount(engine, player->getResourceId());
2063 			player->setFrameCount(frameCount);
2064 			player->setFrameIndex(frameCount - 1);
2065 		}
2066 		break;
2067 	}
2068 
2069 	player->changeStatus(kActorStatusMorphingInto);
2070 }
2071 
2072 //////////////////////////////////////////////////////////////////////////
2073 // Update methods
2074 //////////////////////////////////////////////////////////////////////////
2075 
updateStatusInteracting()2076 void Actor::updateStatusInteracting() {
2077 	if (getWorld()->chapter != kChapter2 || _frameIndex != 6 || _status == kActorStatusInteracting) { /* Original check: _status  <= kActorStatus11 */
2078 		if (_frameIndex < _frameCount - 1) {
2079 			++_frameIndex;
2080 		} else {
2081 			if (_status == kActorStatusInteracting)
2082 				changeStatus(kActorStatusStoppedInteracting);
2083 			else
2084 				changeStatus(kActorStatusStoppedHitting);
2085 		}
2086 	} else {
2087 		if (_index == getSharedData()->getPlayerIndex())
2088 			checkPumpkinDeath();
2089 
2090 		++_frameIndex;
2091 	}
2092 }
2093 
checkPumpkinDeath()2094 void Actor::checkPumpkinDeath() {
2095 	updatePumpkin(kGameFlag263, kGameFlag270, kObjectPumpkin2Dies, kObjectPumpkin2Loop);
2096 	updatePumpkin(kGameFlag264, kGameFlag271, kObjectPumpkin3Dies, kObjectPumpkin3Loop);
2097 	updatePumpkin(kGameFlag265, kGameFlag272, kObjectPumpkin4Dies, kObjectPumpkin4Loop);
2098 	updatePumpkin(kGameFlag266, kGameFlag273, kObjectPumpkin5Dies, kObjectPumpkin5Loop);
2099 	updatePumpkin(kGameFlag267, kGameFlag274, kObjectPumpkin6Dies, kObjectPumpkin6Loop);
2100 	updatePumpkin(kGameFlag268, kGameFlag275, kObjectPumpkin7Dies, kObjectPumpkin7Loop);
2101 	updatePumpkin(kGameFlag269, kGameFlag276, kObjectPumpkin1Dies, kObjectPumpkin1Loop);
2102 }
2103 
updatePumpkin(GameFlag flagToCheck,GameFlag flagToSet,ObjectId objectToUpdate,ObjectId objectToDisable)2104 void Actor::updatePumpkin(GameFlag flagToCheck, GameFlag flagToSet, ObjectId objectToUpdate, ObjectId objectToDisable) {
2105 	if (_vm->isGameFlagSet(flagToCheck)) {
2106 		_vm->setGameFlag(flagToSet);
2107 		_vm->clearGameFlag(flagToCheck);
2108 
2109 		getSharedData()->setChapter2Counter(5, getSharedData()->getChapter2Counter(5) + 1);
2110 
2111 		getWorld()->getObjectById(objectToUpdate)->setNextFrame(8);
2112 		getSound()->playSound(getWorld()->soundResourceIds[17], false, Config.sfxVolume - 10);
2113 		getWorld()->getObjectById(objectToDisable)->disable();
2114 	}
2115 }
2116 
updateStatusEnabled()2117 void Actor::updateStatusEnabled() {
2118 	if (_frameCount == 0)
2119 		error("[Actor::updateStatusEnabled] Actor has no frame!");
2120 
2121 	_frameIndex = (_frameIndex + 1) % _frameCount;
2122 
2123 	if (_vm->screenUpdateCount - _lastScreenUpdate > 300) {
2124 		// All actors except Crow and Armed Max
2125 		if (strcmp((char *)&_name, "Crow") && strcmp((char *)_name, "Armed Max")) {
2126 			if (_vm->getRandom(100) < 50
2127 			 && (!getSpeech()->getSoundResourceId() || !getSound()->isPlaying(getSpeech()->getSoundResourceId()))
2128 			 && canChangeStatus(10))
2129 				changeStatus(kActorStatusFidget);
2130 
2131 			_lastScreenUpdate = _vm->screenUpdateCount;
2132 		}
2133 	}
2134 
2135 	// Actor: Player
2136 	if (_index == getSharedData()->getPlayerIndex()) {
2137 		if (_vm->lastScreenUpdate && (_vm->screenUpdateCount - _vm->lastScreenUpdate) > 500) {
2138 
2139 			if (_vm->isGameFlagNotSet(kGameFlagScriptProcessing)
2140 			 && isVisible()
2141 			 && !getSharedData()->getFlag(kFlagIsEncounterRunning)
2142 			 && !getSpeech()->getSoundResourceId()) {
2143 				if (_vm->getRandom(100) < 50) {
2144 					if (getWorld()->chapter == kChapter13)
2145 						getSpeech()->playPlayer(507);
2146 					else
2147 						getSpeech()->playIndexed(4);
2148 				}
2149 			}
2150 			_lastScreenUpdate = _vm->screenUpdateCount;
2151 			_vm->lastScreenUpdate = _vm->screenUpdateCount;
2152 		}
2153 
2154 		return;
2155 	}
2156 
2157 	// Actor:: BigCrow
2158 	if (!strcmp(_name, "Big Crow")) {
2159 		if (_vm->getRandom(10) < 5) {
2160 			switch (_vm->getRandom(4)) {
2161 			default:
2162 				break;
2163 
2164 			case 0:
2165 				setPosition(10, 1350, kDirectionN, 0);
2166 				forceTo(1460, -100, false);
2167 				break;
2168 
2169 			case 1:
2170 				setPosition(300, 0, kDirectionN, 0);
2171 				forceTo(1700, 1400, false);
2172 				break;
2173 
2174 			case 2:
2175 				setPosition(1560, -100, kDirectionN, 0);
2176 				forceTo(-300, 1470, false);
2177 				break;
2178 
2179 			case 3:
2180 				setPosition(1150, 1400, kDirectionN, 0);
2181 				forceTo(-250, 0, false);
2182 				break;
2183 			}
2184 		}
2185 
2186 		return;
2187 	}
2188 
2189 	// All other actors
2190 	if (getWorld()->chapter != kChapter2 || _index != 8) {
2191 		if (_field_944 == 4) {
2192 			Common::Rect frameRect = GraphicResource::getFrameRect(_vm, getWorld()->backgroundImage, 0);
2193 			forceTo((int16)rnd(frameRect.width() + 200) - 100, (int16)rnd(frameRect.height() + 200) - 100, false);
2194 		} else {
2195 			// Actor: Crow
2196 			if (rnd(1000) < 5 || !strcmp(_name, "Crow")) {
2197 				if (_actionIdx2 != -1) {
2198 
2199 					// Process action area
2200 					int32 areaIndex = getWorld()->getRandomActionAreaIndexById(_actionIdx2);
2201 					if (areaIndex != -1) {
2202 
2203 						ActionArea *area = getWorld()->actions[areaIndex];
2204 						Polygon poly = getScene()->polygons()->get(area->polygonIndex);
2205 
2206 						Common::Point pt(poly.boundingRect.left + (int16)rnd((uint16)poly.boundingRect.width()),
2207 						                 poly.boundingRect.top  + (int16)rnd((uint16)poly.boundingRect.height()));
2208 
2209 						if (!getSharedData()->getFlag(kFlagActorUpdateEnabledCheck)) {
2210 							if (!isInActionArea(pt, area)) {
2211 								Common::Point polyPoint = poly.points[rnd(poly.count())];
2212 								forceTo(polyPoint.x, polyPoint.y, false);
2213 							} else {
2214 								forceTo(pt.x, pt.y, false);
2215 							}
2216 						}
2217 					}
2218 				}
2219 			}
2220 		}
2221 	} else {
2222 		switch (getSharedData()->getActorUpdateStatusEnabledCounter()) {
2223 		default:
2224 			break;
2225 
2226 		case 0:
2227 			updateStatusEnabledProcessStatus(1055, 989, 1, 1088, 956);
2228 			break;
2229 
2230 		case 1:
2231 			updateStatusEnabledProcessStatus(1088, 956, 2, _point1.x + _point2.x, 900);
2232 			break;
2233 
2234 		case 2:
2235 			updateStatusEnabledProcessStatus(1088, 900, 3, 1018, 830);
2236 			break;
2237 
2238 		case 3:
2239 			updateStatusEnabledProcessStatus(1018, 830, 4, 970, 830);
2240 			break;
2241 
2242 		case 4:
2243 			updateStatusEnabledProcessStatus(970, 830, 5, 912, 936);
2244 			break;
2245 
2246 		case 5:
2247 			updateStatusEnabledProcessStatus(912, 936, 0, 1055, 989);
2248 			break;
2249 		}
2250 	}
2251 }
2252 
updateStatusEnabledProcessStatus(int16 testX,int16 testY,uint32 counter,int16 setX,int16 setY)2253 void Actor::updateStatusEnabledProcessStatus(int16 testX, int16 testY, uint32 counter, int16 setX, int16 setY) {
2254 	int32 xsum = _point1.x + _point2.x;
2255 	int32 ysum = _point1.y + _point2.y;
2256 
2257 	if (xsum != testX || ysum != testY) {
2258 		if (rnd(1000) < 5)
2259 			forceTo(testX, testY, false);
2260 	} else {
2261 		getSharedData()->setActorUpdateStatusEnabledCounter(counter);
2262 
2263 		if (rnd(1000) < 5)
2264 			forceTo(setX, setY, false);
2265 	}
2266 }
2267 
updateStatusBored()2268 void Actor::updateStatusBored() {
2269 	if (_index == getSharedData()->getPlayerIndex()
2270 	 && getWorld()->chapter != kChapter9
2271 	 && getWorld()->actorType == 0
2272 	 && _frameIndex == 0
2273 	 && checkBoredStatus()) {
2274 		if (!getSpeech()->getSoundResourceId() || !getSound()->isPlaying(getSpeech()->getSoundResourceId()))
2275 			getSpeech()->playPlayer(13);
2276 	}
2277 
2278 	++_frameIndex;
2279 	if (_frameIndex == _frameCount) {
2280 		enable();
2281 		_lastScreenUpdate = _vm->screenUpdateCount;
2282 	}
2283 }
2284 
CrowClosesIn()2285 void Actor::CrowClosesIn() {
2286 	// Compute distance
2287 	uint32 frameIndex = _frameIndex;
2288 	if (_frameIndex >= _frameCount)
2289 		frameIndex = 2 * _frameCount - (_frameIndex + 1);
2290 
2291 	uint32 distance = (uint32)abs((double)getWalkIncrement(_direction, frameIndex));
2292 
2293 	// Face actor
2294 	faceTarget((uint32)getSharedData()->getPlayerIndex(), kDirectionFromActor);
2295 
2296 	int32 data = getSharedData()->crowsData[_index + 25];
2297 	if (data > 0) {
2298 		_direction = DIR(_direction + 4);
2299 		getSharedData()->crowsData[_index + 25] = data - 1;
2300 	}
2301 
2302 	// Compute coordinates and distance
2303 	Actor *player = getScene()->getActor();
2304 	Common::Point sumPlayer = *player->getPoint1() + *player->getPoint2();
2305 	Common::Point sum = _point1 + _point2;
2306 
2307 	uint32 absX = (uint32)abs(sum.x - sumPlayer.x);
2308 	uint32 absY = (uint32)abs(sum.y - sumPlayer.y);
2309 
2310 	// Adjust distance
2311 	if (absX <= absY)
2312 		absX = absY;
2313 
2314 	if (sum.y < sumPlayer.y)
2315 		absX += 20;
2316 
2317 	if (absX >= 50) {
2318 		move(_direction, distance);
2319 	} else {
2320 		_frameIndex = 0;
2321 
2322 		getSharedData()->crowsData[2 * _index + 30] = player->getPoint1()->x - _point1.x;
2323 		getSharedData()->crowsData[2 * _index + 31] = player->getPoint1()->y - _point1.y;
2324 
2325 		changeStatus(kActorStatus18);
2326 	}
2327 }
2328 
ScareCrowClosesIn()2329 void Actor::ScareCrowClosesIn() {
2330 	bool processEnd = true;
2331 	Actor *player = getScene()->getActor();
2332 	Common::Point sum = _point1 + _point2;
2333 	Common::Point sumPlayer = *player->getPoint1() + *player->getPoint2();
2334 
2335 	// Compute distance
2336 	uint32 frameIndex = _frameIndex;
2337 	if (_frameIndex >= _frameCount)
2338 		frameIndex = 2 * _frameCount - (_frameIndex + 1);
2339 
2340 	uint32 distance = (uint32)abs((double)getWalkIncrement(_direction, frameIndex));
2341 
2342 	// Update status
2343 	if (player->getStatus() == kActorStatusRestarting || !getScene()->getActor(10)->isVisible()) {
2344 		changeStatus(kActorStatusEnabled);
2345 		getSharedData()->crowsData[_index - 11] = 160;
2346 	}
2347 
2348 	// Face player
2349 	faceTarget((uint32)getSharedData()->getPlayerIndex(), kDirectionFromActor);
2350 
2351 	// Compute coordinates
2352 	Common::Point delta  = Common::Point((sumPlayer.x + sum.x) / 2,       (sumPlayer.y + sum.y) / 2);
2353 	Common::Point point1 = Common::Point((delta.x     + sum.x) / 2,       (delta.y     + sum.y) / 2);
2354 	Common::Point point2 = Common::Point((delta.x     + sumPlayer.x) / 2, (delta.y     + sumPlayer.y) / 2);
2355 
2356 	if (getScene()->findActionArea(kActionAreaType1, delta) == -1
2357 	 || getScene()->findActionArea(kActionAreaType1, point1) == -1
2358 	 || getScene()->findActionArea(kActionAreaType1, point2) == -1) {
2359 		processEnd = false;
2360 
2361 		if (determineLeftOrRight(sum, sumPlayer) == false) {
2362 			if (canMove(&sum, DIR(_direction + 1), distance, false)) {
2363 				move(DIR(_direction + 1), distance);
2364 			} else if (canMove(&sum, DIR(_direction + 2), distance, false)) {
2365 				move(DIR(_direction + 2), distance);
2366 			} else if (canMove(&sum, DIR(_direction + 3), distance, false)) {
2367 				move(DIR(_direction + 3), distance);
2368 			} else if (canMove(&sum, DIR(_direction + 4), distance, false)) {
2369 				move(DIR(_direction + 4), distance);
2370 			}
2371 		} else {
2372 			if (canMove(&sum, DIR(_direction + 7), distance, false)) {
2373 				move(DIR(_direction + 7), distance);
2374 			} else if (canMove(&sum, DIR(_direction + 6), distance, false)) {
2375 				move(DIR(_direction + 6), distance);
2376 			} else if (canMove(&sum, DIR(_direction + 5), distance, false)) {
2377 				move(DIR(_direction + 5), distance);
2378 			} else if (canMove(&sum, DIR(_direction + 4), distance, false)) {
2379 				move(DIR(_direction + 4), distance);
2380 			}
2381 		}
2382 	} else {
2383 		if (canMove(&sum, DIR(_direction + 1), distance, false)) {
2384 			move(DIR(_direction + 1), distance);
2385 		} else if (canMove(&sum, DIR(_direction + 2), distance, false)) {
2386 			move(DIR(_direction + 2), distance);
2387 		} else if (canMove(&sum, DIR(_direction + 7), distance, false)) {
2388 			move(DIR(_direction + 7), distance);
2389 		} else if (canMove(&sum, DIR(_direction + 6), distance, false)) {
2390 			move(DIR(_direction + 6), distance);
2391 		}
2392 	}
2393 
2394 	if (processEnd) {
2395 		if (player->getStatus() != kActorStatusRestarting && player->getStatus() != kActorStatusGettingHurt) {
2396 			if (sqrt((double)((sum.y - sumPlayer.y) * (sum.y - sumPlayer.y) + (sum.x - sumPlayer.x) * (sum.x - sumPlayer.x))) < 80.0) {
2397 				_frameIndex = 0;
2398 				faceTarget((uint32)getSharedData()->getPlayerIndex(), kDirectionFromActor);
2399 				changeStatus(kActorStatusAttacking);
2400 			}
2401 		}
2402 	}
2403 }
2404 
TentacleRises()2405 void Actor::TentacleRises() {
2406 	if (!_frameIndex)
2407 		getSound()->playSound(getWorld()->soundResourceIds[6]);
2408 
2409 	++_frameIndex;
2410 
2411 	if (_frameIndex >= _frameCount) {
2412 		_frameIndex = 0;
2413 		changeStatus(kActorStatusEnabled2);
2414 		getWorld()->tickValueArray[_index] = rnd(4000) + _vm->getTick();
2415 	}
2416 
2417 	Actor *actor0 = getScene()->getActor(0);
2418 
2419 	getSharedData()->vector1.x = actor0->getPoint1()->x + actor0->getPoint2()->x;
2420 	getSharedData()->vector1.y = actor0->getPoint1()->y + actor0->getPoint2()->y - 5;
2421 
2422 	getSharedData()->vector2.x = _point1.x + _point2.x;
2423 	getSharedData()->vector2.y = _point1.y + _point2.y;
2424 
2425 	TentacleBlocksSarah(getSharedData()->vector1, getSharedData()->vector2);
2426 }
2427 
updateStatusEnabled2()2428 void Actor::updateStatusEnabled2() {
2429 	if (_frameCount == 0)
2430 		error("[Actor::updateStatusEnabled2] Invalid frame count (cannot be 0)");
2431 
2432 	_frameIndex = (_frameIndex + 1) % _frameCount;
2433 	_lastScreenUpdate = _vm->screenUpdateCount;
2434 
2435 	switch (getWorld()->chapter) {
2436 	default:
2437 		break;
2438 
2439 	case kChapter2:
2440 		if (_index == 11)
2441 			changeStatus(kActorStatusWalking2);
2442 		else if (_index > 12)
2443 			CrowStatusQuo();
2444 		break;
2445 
2446 	case kChapter11:
2447 		if (_index >= 10 && _index < 16)
2448 			TentacleWigglesForSarah();
2449 		break;
2450 	}
2451 }
2452 
CrowStatusQuo()2453 void Actor::CrowStatusQuo() {
2454 	if (getSharedData()->crowsData[_index + 61])
2455 		CrowHoveringBeforeKill();
2456 	else
2457 		changeStatus(kActorStatusWalking2);
2458 }
2459 
CrowHoveringBeforeKill()2460 void Actor::CrowHoveringBeforeKill() {
2461 	// Original calls getWalkIncrement but does not seem to do anything with the results
2462 
2463 	Actor *player = getScene()->getActor();
2464 	ActorStatus playerStatus = player->getStatus();
2465 
2466 	if (playerStatus == kActorStatusRestarting || !getScene()->getActor(10)->isVisible()) {
2467 		changeStatus(kActorStatusEnabled);
2468 		getSharedData()->crowsData[_index - 11] = 160;
2469 	}
2470 
2471 	if (playerStatus != kActorStatusGettingHurt) {
2472 		_point1.x = player->getPoint1()->x - (int16)getSharedData()->crowsData[2 * _index + 30];
2473 		_point1.y = player->getPoint1()->y - (int16)getSharedData()->crowsData[2 * _index + 31] + 54;
2474 	}
2475 
2476 	if (_frameIndex == _frameCount - 1) {
2477 		_frameIndex = 0;
2478 		if (getSharedData()->crowsData[_index + 29] <= 1 || playerStatus == kActorStatusGettingHurt || playerStatus == kActorStatusRestarting) {
2479 			getSharedData()->crowsData[_index + 29]++;
2480 		} else {
2481 			changeStatus(kActorStatusAttacking);
2482 			_point1.y -= 54;
2483 			getSharedData()->crowsData[_index + 29] = 0;
2484 			getSharedData()->crowsData[_index - 2] += 54;
2485 		}
2486 	}
2487 
2488 	if (playerStatus == kActorStatusRestarting && getSharedData()->crowsData[_index + 17] < 100) {
2489 		_point1.y -= 6;
2490 		getSharedData()->crowsData[_index + 29] = 100;
2491 		getSharedData()->crowsData[_index - 2] += 6;
2492 	}
2493 
2494 	if (getSharedData()->crowsData[_index + 17] > 99) {
2495 		_point1.y -= 6;
2496 		getSharedData()->crowsData[_index + 17]++;
2497 		getSharedData()->crowsData[_index - 2] += 6;
2498 
2499 		if (getSharedData()->crowsData[_index + 17] > 108) {
2500 			getSharedData()->crowsData[_index + 29] = 0;
2501 
2502 			changeStatus(kActorStatusEnabled);
2503 
2504 			switch (_index) {
2505 			default:
2506 				error("Invalid actor index (was: %d)", _index);
2507 				break;
2508 
2509 			case 13:
2510 				forceTo(2300, 671, false);
2511 				break;
2512 
2513 			case 14:
2514 				forceTo(2600, 1300, false);
2515 				break;
2516 
2517 			case 15:
2518 				forceTo(2742, 615, false);
2519 				break;
2520 
2521 			case 16:
2522 				forceTo(2700, 1400, false);
2523 				break;
2524 
2525 			case 17:
2526 				forceTo(2751, 347, false);
2527 				break;
2528 
2529 			case 18:
2530 				forceTo(2420, 284, false);
2531 				break;
2532 
2533 			case 19:
2534 				forceTo(2800, 370, false);
2535 				break;
2536 
2537 			case 20:
2538 				forceTo(1973, 1, false);
2539 				break;
2540 			}
2541 		}
2542 	}
2543 }
2544 
TentacleWigglesForSarah()2545 void Actor::TentacleWigglesForSarah() {
2546 	Actor *actor0 = getScene()->getActor(0);
2547 
2548 	getSharedData()->vector1.x = actor0->getPoint1()->x + actor0->getPoint2()->x;
2549 	getSharedData()->vector1.y = actor0->getPoint1()->y + actor0->getPoint2()->y - 5;
2550 
2551 	getSharedData()->vector2.x = _point1.x + _point2.x;
2552 	getSharedData()->vector2.y = _point1.y + _point2.y;
2553 
2554 	if (getWorld()->tickValueArray[_index] == -666)
2555 		getWorld()->tickValueArray[_index] = rnd(4000) + _vm->getTick();
2556 
2557 	faceTarget(kActorMax, kDirectionFromActor);
2558 	TentacleBlocksSarah(getSharedData()->vector1, getSharedData()->vector2);
2559 
2560 	if (getWorld()->tickValueArray[_index] < (int)_vm->getTick()) {
2561 		if (euclidianDistance(getSharedData()->vector1, getSharedData()->vector2) >= 75) {
2562 			getWorld()->tickValueArray[_index] = rnd(1000) + 2000 + _vm->getTick();
2563 		} else {
2564 			if (actor0->getStatus() == kActorStatusWalking2 || actor0->getStatus() == kActorStatusEnabled2 || actor0->getStatus() == kActorStatusAttacking)
2565 				changeStatus(kActorStatusAttacking);
2566 
2567 			getWorld()->tickValueArray[_index] = -666;
2568 		}
2569 	}
2570 }
2571 
CrowDives()2572 void Actor::CrowDives() {
2573 	Actor *player = getScene()->getActor();
2574 
2575 	Common::Point sum = _point1 + _point2;
2576 	Common::Point sumPlayer = *player->getPoint1() + *player->getPoint2();
2577 
2578 	if (getScene()->getActor(10)->getStatus() == kActorStatusRestarting || !getScene()->getActor(10)->isVisible()) {
2579 		changeStatus(kActorStatusEnabled);
2580 		getSharedData()->crowsData[_index - 11] = 160;
2581 	}
2582 
2583 	if (_frameIndex == 1)
2584 		getSound()->playSound(getWorld()->soundResourceIds[1], false, Config.sfxVolume - 10);
2585 
2586 	if (player->getStatus() == kActorStatusRestarting && _frameIndex < 6)
2587 		changeStatus(kActorStatusEnabled);
2588 
2589 	uint32 dist = euclidianDistance(sumPlayer, sum);
2590 	int16 offset = (dist <= 10) ? 7 : 12;
2591 	if (dist > 20) {
2592 		faceTarget((uint32)getSharedData()->getPlayerIndex(), kDirectionFromActor);
2593 		getScene()->getActor(_index + 9)->setDirection(_direction);
2594 	}
2595 
2596 	if (_frameIndex < 5 || !getSharedData()->crowsData[_index + 61])
2597 		_frameIndex++;
2598 
2599 	if (sumPlayer.x > sum.x)
2600 		_point1.x += offset;
2601 	else if (sumPlayer.x < sum.x)
2602 		_point1.x -= offset;
2603 
2604 	if (sumPlayer.y > sum.y)
2605 		_point1.y += offset;
2606 	else if (sumPlayer.y < sum.y)
2607 		_point1.y -= offset;
2608 
2609 	if ((int32)dist < (offset + 1)) {
2610 		if (player->getStatus() != kActorStatusGettingHurt && player->getStatus() != kActorStatusRestarting && player->getFrameIndex() < 6) {
2611 			_point1 = sumPlayer - _point2;
2612 
2613 			MaxGetsHit();
2614 			getSpeech()->playPlayer(51);
2615 			_vm->setGameFlag(kGameFlag219);
2616 
2617 			player->changeDirection(DIR(_direction + 4));
2618 			player->changeStatus(kActorStatusGettingHurt);
2619 
2620 			getSharedData()->crowsData[_index + 61] = 0;
2621 		}
2622 	}
2623 
2624 	if (_frameIndex > _frameCount - 1) {
2625 		switch (rnd(4)) {
2626 		default:
2627 		case 0:
2628 			sum.y -= 200;
2629 			break;
2630 
2631 		case 1:
2632 			sum.y += 200;
2633 			break;
2634 
2635 		case 2:
2636 			sum.x -= 200;
2637 			break;
2638 
2639 		case 3:
2640 			sum.x += 200;
2641 			break;
2642 		}
2643 
2644 		_frameIndex = 0;
2645 
2646 		if (getSharedData()->getChapter2Counter(6) <= 2)
2647 			forceTo(sum.x, sum.y, false);
2648 		else
2649 			changeStatus(kActorStatusEnabled);
2650 
2651 		getSharedData()->crowsData[_index + 61] = 0;
2652 	}
2653 }
2654 
MaxGetsHit()2655 void Actor::MaxGetsHit() {
2656 	Actor *actor39 = getScene()->getActor(39);
2657 
2658 	actor39->setFrameIndex(0);
2659 	*actor39->getPoint1() = *getScene()->getActor()->getPoint1();
2660 
2661 	if (_vm->isGameFlagSet(kGameFlag169))
2662 		actor39->getPoint1()->y += 80;
2663 
2664 	switch (getSharedData()->getChapter2Counter(6)) {
2665 	default:
2666 		break;
2667 
2668 	case 0:
2669 		_vm->setGameFlag(kGameFlag369);
2670 
2671 		if (getSound()->isPlaying(getWorld()->soundResourceIds[5]))
2672 			getSound()->stop(getWorld()->soundResourceIds[5]);
2673 
2674 		if (!getSound()->isPlaying(getWorld()->soundResourceIds[6]))
2675 			getSound()->playSound(getWorld()->soundResourceIds[6], true, Config.sfxVolume - 10);
2676 		break;
2677 
2678 	case 1:
2679 		_vm->setGameFlag(kGameFlag370);
2680 
2681 		if (getSound()->isPlaying(getWorld()->soundResourceIds[6]))
2682 			getSound()->stop(getWorld()->soundResourceIds[6]);
2683 
2684 		if (!getSound()->isPlaying(getWorld()->soundResourceIds[7]))
2685 			getSound()->playSound(getWorld()->soundResourceIds[7], true, Config.sfxVolume - 10);
2686 		break;
2687 
2688 	case 2:
2689 		if (getSound()->isPlaying(getWorld()->soundResourceIds[7]))
2690 			getSound()->stop(getWorld()->soundResourceIds[7]);
2691 		break;
2692 	}
2693 
2694 	getSharedData()->setChapter2Counter(6, getSharedData()->getChapter2Counter(6) + 1);
2695 
2696 	switch (getSharedData()->getChapter2Counter(6)) {
2697 	default:
2698 		crowsReturn(_vm);
2699 		getCursor()->hide();
2700 		break;
2701 
2702 	case 0:
2703 		break;
2704 
2705 	case 1:
2706 		_vm->setGameFlag(kGameFlag369);
2707 		break;
2708 
2709 	case 2:
2710 		_vm->setGameFlag(kGameFlag370);
2711 		break;
2712 	}
2713 }
2714 
MaxAttacks()2715 void Actor::MaxAttacks() {
2716 	if (_index != getSharedData()->getPlayerIndex())
2717 		error("[Actor::MaxAttacks] Function is only available for the current player");
2718 
2719 	// Update frame index and process
2720 	_frameIndex++;
2721 
2722 	if (_frameIndex == 1)
2723 		getSound()->playSound(getWorld()->soundResourceIds[3], false, Config.sfxVolume - 10);
2724 
2725 	ActorIndex actorIndex = getSharedData()->getChapter2ActorIndex();
2726 	if (_frameIndex == 3) {
2727 
2728 		if (actorIndex > 12) {
2729 
2730 			Actor *otherActor = getScene()->getActor(actorIndex);
2731 
2732 			if (otherActor->getStatus() == kActorStatusEnabled2) {
2733 				// FIXME: this is a bit strange, but it looks like the original does exactly that
2734 				// this might be dead code (the actor 38 never exists and thus setting values has no effect)
2735 				Actor* actor38 = getScene()->getActor(38);
2736 				actor38->setFrameIndex(0);
2737 				*actor38->getPoint1() = *otherActor->getPoint1();
2738 
2739 				switch (actorIndex) {
2740 				default:
2741 					break;
2742 
2743 				case 13:
2744 					_vm->setGameFlag(kGameFlag319);
2745 					_vm->clearGameFlag(kGameFlag235);
2746 					break;
2747 
2748 				case 14:
2749 					_vm->setGameFlag(kGameFlag320);
2750 					_vm->clearGameFlag(kGameFlag235);
2751 					break;
2752 
2753 				case 15:
2754 					if (getScene()->getActor(16)->checkCrowDeath()) {
2755 						_vm->setGameFlag(kGameFlag321);
2756 						_vm->clearGameFlag(kGameFlag235);
2757 					}
2758 					break;
2759 
2760 				case 16:
2761 					if (getScene()->getActor(15)->checkCrowDeath()) {
2762 						_vm->setGameFlag(kGameFlag321);
2763 						_vm->clearGameFlag(kGameFlag235);
2764 					}
2765 					break;
2766 
2767 				case 17:
2768 					if (getScene()->getActor(21)->checkCrowDeath()) {
2769 						_vm->setGameFlag(kGameFlag322);
2770 						_vm->clearGameFlag(kGameFlag235);
2771 					}
2772 					break;
2773 
2774 				case 18:
2775 					if (getScene()->getActor(19)->checkCrowDeath() && getScene()->getActor(20)->checkCrowDeath()) {
2776 						_vm->setGameFlag(kGameFlag323);
2777 						_vm->clearGameFlag(kGameFlag235);
2778 					}
2779 					break;
2780 
2781 				case 19:
2782 					if (getScene()->getActor(18)->checkCrowDeath() && getScene()->getActor(20)->checkCrowDeath()) {
2783 						_vm->setGameFlag(kGameFlag323);
2784 						_vm->clearGameFlag(kGameFlag235);
2785 					}
2786 					break;
2787 
2788 				case 20:
2789 					if (getScene()->getActor(19)->checkCrowDeath() && getScene()->getActor(18)->checkCrowDeath()) {
2790 						_vm->setGameFlag(kGameFlag323);
2791 						_vm->clearGameFlag(kGameFlag235);
2792 					}
2793 					break;
2794 
2795 				case 21:
2796 					if (getScene()->getActor(17)->checkCrowDeath()) {
2797 						_vm->setGameFlag(kGameFlag322);
2798 						_vm->clearGameFlag(kGameFlag235);
2799 					}
2800 					break;
2801 				}
2802 
2803 				otherActor->changeStatus(kActorStatusRestarting);
2804 				getSound()->playSound(getWorld()->soundResourceIds[2], false, Config.sfxVolume - 10);
2805 			}
2806 		}
2807 
2808 		if (actorIndex == 11)
2809 			checkScareCrowDeath();
2810 	}
2811 
2812 	if (_frameIndex >= _frameCount) {
2813 		_frameIndex = 0;
2814 		changeStatus(kActorStatusEnabled2);
2815 	}
2816 }
2817 
checkScareCrowDeath()2818 void Actor::checkScareCrowDeath() {
2819 	// we are the current player
2820 	Actor *actor11 = getScene()->getActor(11);
2821 	Actor *actor40 = getScene()->getActor(40);
2822 
2823 	Common::Point point(_point1.x + _point2.x, _point1.y + _point2.y);
2824 	Common::Point point11(actor11->getPoint1()->x + actor11->getPoint2()->x, actor11->getPoint1()->y + actor11->getPoint2()->y);
2825 
2826 	if (actor11->getStatus() == kActorStatusAttacking && euclidianDistance(point, point11) < 100) {
2827 		Actor *actor = getScene()->getActor(getSharedData()->getChapter2ActorIndex());
2828 
2829 		actor40->show();
2830 		actor40->setFrameIndex(0);
2831 		actor40->getPoint1()->x = actor->getPoint1()->x;
2832 		actor40->getPoint1()->y = actor->getPoint1()->y;
2833 
2834 		if (actor11->getFrameIndex() <= 7) {
2835 			getSound()->playSound(getWorld()->soundResourceIds[9], false, Config.sfxVolume - 10);
2836 		} else if (getSharedData()->getChapter2Counter(5) <= 6) {
2837 			getSound()->playSound(getWorld()->soundResourceIds[9], false, Config.sfxVolume - 10);
2838 		} else {
2839 			getScene()->getActor(11)->changeStatus(kActorStatusRestarting);
2840 			getSound()->playSound(getWorld()->soundResourceIds[10], false, Config.sfxVolume - 10);
2841 		}
2842 	}
2843 }
2844 
checkCrowDeath()2845 bool Actor::checkCrowDeath() {
2846 	return (!isVisible() || _status == kActorStatusRestarting);
2847 }
2848 
ScareCrowAttacks()2849 void Actor::ScareCrowAttacks() {
2850 	Actor *player = getScene()->getActor();
2851 
2852 	Common::Point sum = _point1 + _point2;
2853 	Common::Point sumPlayer = *player->getPoint1() + *player->getPoint2();
2854 
2855 	Common::Rect rect;
2856 	getCrowStrikeZone(&rect, _direction, sum);
2857 
2858 	switch (_frameIndex) {
2859 	default:
2860 		break;
2861 
2862 	case 1:
2863 		getSound()->playSound(getWorld()->soundResourceIds[4], false, Config.sfxVolume - 10);
2864 		break;
2865 
2866 	case 9:
2867 		getSharedData()->setChapter2FrameIndexOffset(1);
2868 		getSharedData()->setChapter2Counter(8, getSharedData()->getChapter2Counter(8) + 1);
2869 		break;
2870 
2871 	case 11:
2872 		if (getSharedData()->getChapter2Counter(8) >= 3)
2873 			getSharedData()->setChapter2Counter(8, 0);
2874 		else
2875 			getSharedData()->setChapter2FrameIndexOffset(-1);
2876 		break;
2877 	}
2878 
2879 	_frameIndex += getSharedData()->getChapter2FrameIndexOffset();
2880 
2881 	Common::Point actionPoint = sum;
2882 	actionPoint.x += pointInRectXAdjust(rect, sumPlayer);
2883 	actionPoint.y += pointInRectYAdjust(rect, sumPlayer);
2884 
2885 	if (getScene()->getActor(11)->getFrameIndex() < 8
2886 	 && getScene()->findActionArea(kActionAreaType2, actionPoint) != -1
2887 	 && !actorsIntersect(10, 11))
2888 		 _point1 = actionPoint - _point2;
2889 
2890 	if (_frameIndex != 8 || _status == kActorStatusGettingHurt) { /* FIXME the status test seems useless */
2891 		if (_frameIndex > _frameCount - 1) {
2892 			_frameIndex = 0;
2893 
2894 			if (!getSharedData()->getFlag(kFlagActorUpdateStatus15Check)) {
2895 				changeStatus(kActorStatusWalking2);
2896 			} else {
2897 				getSharedData()->setFlag(kFlagActorUpdateStatus15Check, false);
2898 				getScene()->getActor(11)->changeStatus(kActorStatus18);
2899 			}
2900 		}
2901 	} else {
2902 		if (rect.contains(sumPlayer)) {
2903 
2904 			_vm->clearGameFlag(kGameFlag263);
2905 			_vm->clearGameFlag(kGameFlag264);
2906 			_vm->clearGameFlag(kGameFlag265);
2907 			_vm->clearGameFlag(kGameFlag266);
2908 			_vm->clearGameFlag(kGameFlag267);
2909 			_vm->clearGameFlag(kGameFlag268);
2910 			_vm->clearGameFlag(kGameFlag269);
2911 
2912 			player->stopWalking();
2913 			player->changeStatus(kActorStatusGettingHurt);
2914 			MaxGetsHit();
2915 
2916 			getSpeech()->playPlayer(52);
2917 
2918 			_vm->setGameFlag(kGameFlag219);
2919 
2920 		} else {
2921 			if ((abs(sum.y - sumPlayer.y) + abs(sum.x - sumPlayer.x)) < 100) {
2922 				getSharedData()->setChapter2Counter(7, 5);
2923 				getSharedData()->setFlag(kFlagActorUpdateStatus15Check, true);
2924 			}
2925 		}
2926 	}
2927 }
2928 
actorsIntersect(ActorIndex actorIndex1,ActorIndex actorIndex2)2929 bool Actor::actorsIntersect(ActorIndex actorIndex1, ActorIndex actorIndex2) {
2930 	Actor *actor1 = getScene()->getActor(actorIndex1);
2931 	Actor *actor2 = getScene()->getActor(actorIndex2);
2932 
2933 	if (actor1->getField944())
2934 		return false;
2935 
2936 	if (actor2->getField944())
2937 		return false;
2938 
2939 	int16 actor2_x = actor2->getPoint1()->x + actor2->getPoint2()->x;
2940 	int16 actor2_y = actor2->getPoint1()->y + actor2->getPoint2()->y;
2941 
2942 	Common::Point pt1((int16)(actor2_x -    (actor1->getField948() + 10)), (int16)(actor2_y -    (actor1->getField94C() + 10)));
2943 	Common::Point pt2((int16)(actor2_x +     actor1->getField948() + 10),  (int16)(actor2_y +     actor1->getField94C() + 10));
2944 	Common::Point pt3((int16)(actor2_x -    (actor2->getField948() + 25)), (int16)(actor2_y -    (actor2->getField94C() + 20)));
2945 	Common::Point pt4((int16)(actor2_x + 2 * actor2->getField948() + 25),  (int16)(actor2_y + 2 * actor2->getField94C() + 20));
2946 
2947 	return getScene()->rectIntersect(pt1.x, pt1.y, pt2.x, pt2.y, pt3.x, pt3.y, pt4.x, pt4.y);
2948 }
2949 
TentacleWhips()2950 void Actor::TentacleWhips() {
2951 	Actor *actor0 = getScene()->getActor(0);
2952 
2953 	// Update vectors
2954 	getSharedData()->vector1.x = actor0->getPoint1()->x + actor0->getPoint2()->x;
2955 	getSharedData()->vector1.y = actor0->getPoint1()->y + actor0->getPoint2()->y - 5;
2956 
2957 	getSharedData()->vector2.x = getPoint1()->x + getPoint2()->x;
2958 	getSharedData()->vector2.y = getPoint1()->y + getPoint2()->y;
2959 
2960 	TentacleBlocksSarah(getSharedData()->vector1, getSharedData()->vector2);
2961 
2962 	++_frameIndex;
2963 	if (_frameIndex >= _frameCount)
2964 		changeStatus(kActorStatusEnabled2);
2965 
2966 	if (_frameIndex == 14) {
2967 		if (Actor::euclidianDistance(getSharedData()->vector1, getSharedData()->vector2) < 75) {
2968 
2969 			actor0->changeStatus(kActorStatusGettingHurt);
2970 			++getWorld()->field_E848C;
2971 
2972 			getSound()->stop(getWorld()->soundResourceIds[3]);
2973 			getSound()->stop(getWorld()->soundResourceIds[4]);
2974 			getSound()->stop(getWorld()->soundResourceIds[5]);
2975 
2976 			getSpeech()->playPlayer(131);
2977 		}
2978 	}
2979 }
2980 
SarahAttacks()2981 void Actor::SarahAttacks() {
2982 	_frameIndex++;
2983 
2984 	if (_frameIndex == 17) {
2985 		getSpeech()->playPlayer(130);
2986 
2987 		if (getWorld()->field_E849C >= 666) {
2988 			if (_vm->isGameFlagSet(kGameFlag583)) {
2989 				_vm->setGameFlag(kGameFlag582);
2990 				_vm->clearGameFlag(kGameFlag565);
2991 				++getWorld()->field_E8518;
2992 				getSound()->playSound(getWorld()->soundResourceIds[2]);
2993 			}
2994 		} else {
2995 			Actor *actor2 = getScene()->getActor(getWorld()->field_E849C);
2996 
2997 			double diffX = (actor2->getPoint1()->x + actor2->getPoint2()->x) - (_point1.x + _point2.x);
2998 			double diffY = (actor2->getPoint1()->y + actor2->getPoint2()->y) - (_point1.y + _point2.y);
2999 
3000 			if (sqrt(diffX * diffX + diffY * diffY) < 75.0f
3001 			 && (actor2->getStatus() == kActorStatusEnabled2 || actor2->getStatus() == kActorStatusAttacking)) {
3002 				getSound()->playSound(getWorld()->soundResourceIds[2]);
3003 
3004 				switch (getWorld()->field_E849C) {
3005 				default:
3006 					break;
3007 
3008 				case 10:
3009 					_vm->setGameFlag(kGameFlag563);
3010 					break;
3011 
3012 				case 11:
3013 					_vm->setGameFlag(kGameFlag724);
3014 					break;
3015 
3016 				case 12:
3017 					_vm->setGameFlag(kGameFlag727);
3018 					break;
3019 
3020 				case 13:
3021 					_vm->setGameFlag(kGameFlag730);
3022 					break;
3023 				}
3024 
3025 				actor2->changeStatus(kActorStatusRestarting);
3026 			}
3027 		}
3028 	}
3029 
3030 	if (_frameIndex >= _frameCount) {
3031 		getCursor()->show();
3032 		getSharedData()->setFlag(kFlag1, false);
3033 		_frameIndex = 0;
3034 		changeStatus(kActorStatusEnabled2);
3035 	}
3036 }
3037 
MaxGetsSome()3038 void Actor::MaxGetsSome() {
3039 	Actor *player = getScene()->getActor();
3040 
3041 	player->setFrameIndex(player->getFrameIndex() + 1);
3042 
3043 	if (player->getFrameIndex() > (player->getFrameCount() - 1)) {
3044 		if (getSharedData()->getChapter2Counter(6) <= 2) {
3045 			player->setFrameIndex(0);
3046 			player->changeStatus(kActorStatusEnabled2);
3047 		} else {
3048 			_vm->clearGameFlag(kGameFlag438);
3049 			_vm->clearGameFlag(kGameFlag439);
3050 			_vm->clearGameFlag(kGameFlag440);
3051 			_vm->clearGameFlag(kGameFlag441);
3052 			_vm->clearGameFlag(kGameFlag442);
3053 
3054 			getSpeech()->playPlayer(53);
3055 
3056 			_vm->setGameFlag(kGameFlag219);
3057 
3058 			player->setFrameIndex(0);
3059 			player->changeStatus(kActorStatusRestarting);
3060 
3061 			_vm->clearGameFlag(kGameFlag369);
3062 			_vm->clearGameFlag(kGameFlag370);
3063 
3064 			if (getSound()->isPlaying(getWorld()->soundResourceIds[5]))
3065 				getSound()->stop(getWorld()->soundResourceIds[5]);
3066 
3067 			if (getSound()->isPlaying(getWorld()->soundResourceIds[6]))
3068 				getSound()->stop(getWorld()->soundResourceIds[6]);
3069 
3070 			if (getSound()->isPlaying(getWorld()->soundResourceIds[7]))
3071 				getSound()->stop(getWorld()->soundResourceIds[7]);
3072 
3073 			if (_vm->isGameFlagSet(kGameFlag235)) {
3074 				Actor::crowsReturn(_vm);
3075 				_vm->clearGameFlag(kGameFlag235);
3076 			}
3077 		}
3078 	}
3079 }
3080 
SarahGetsSome()3081 void Actor::SarahGetsSome() {
3082 	// We are sure to be the current player
3083 	getCursor()->show();
3084 	getSharedData()->setFlag(kFlag1, false);
3085 
3086 	if (_frameIndex != 5 || _vm->isGameFlagNotSet(kGameFlag570))
3087 		++_frameIndex;
3088 
3089 	if (_frameIndex > _frameCount - 1) {
3090 		if (getWorld()->field_E848C >= 3) {
3091 			_frameIndex = 0;
3092 
3093 			getScene()->getActor(0)->changeStatus(kActorStatusRestarting);
3094 			getScene()->getActor(1)->setTickCount(_vm->getTick() + 2000);
3095 		} else {
3096 			getScene()->getActor(0)->changeStatus(kActorStatusEnabled2);
3097 		}
3098 	}
3099 }
3100 
TentacleDies()3101 void Actor::TentacleDies() {
3102 	++_frameIndex;
3103 
3104 	if (_frameIndex >= _frameCount) {
3105 		_frameIndex = 0;
3106 		changeStatus(kActorStatusEnabled2);
3107 		hide();
3108 
3109 		if (_vm->getRandomBit() == 1) {
3110 			_vm->setGameFlag(kGameFlag219);
3111 			getSpeech()->playPlayer(133);
3112 		}
3113 	}
3114 }
3115 
CrowSwoops()3116 void Actor::CrowSwoops() {
3117 	Actor *player = getScene()->getActor();
3118 
3119 	_point1.x = player->getPoint1()->x - (int16)getSharedData()->crowsData[2 * _index + 30];
3120 	_point1.y = player->getPoint1()->y - (int16)getSharedData()->crowsData[2 * _index + 31];
3121 
3122 	_frameIndex++;
3123 
3124 	if (_frameIndex > _frameCount - 1) {
3125 		getSharedData()->crowsData[_index + 61] = 1;
3126 		changeStatus(kActorStatusEnabled2);
3127 
3128 		_point1.y += 54;
3129 		getSound()->playSound(getWorld()->soundResourceIds[1], false, Config.sfxVolume - 10);
3130 
3131 		getSharedData()->crowsData[_index - 2] -= 54;
3132 	}
3133 }
3134 
ScareCrowRetreats()3135 void Actor::ScareCrowRetreats() {
3136 	int32 frameIndex = (int32)_frameIndex;
3137 	uint32 distance = (uint32)abs((double)getWalkIncrement(_direction, (_frameIndex < _frameCount) ? _frameIndex : 2 * _frameCount - (_frameIndex + 1)));
3138 
3139 	getSharedData()->setChapter2Counter(7, getSharedData()->getChapter2Counter(7) + 1);
3140 	if (getSharedData()->getChapter2Counter(7) > 14) {
3141 		getSharedData()->setChapter2Counter(7, 0);
3142 		changeStatus(kActorStatusWalking2);
3143 	}
3144 
3145 	faceTarget((uint32)getSharedData()->getPlayerIndex(), kDirectionFromActor);
3146 
3147 	Common::Point sum = _point1 + _point2;
3148 	if (canMove(&sum, DIR(_direction + 4), distance, false)) {
3149 		move(DIR(_direction + 4), distance);
3150 		--frameIndex;
3151 	} else if (canMove(&sum, DIR(_direction + 5), distance, false)) {
3152 		move(DIR(_direction + 5), distance);
3153 		--frameIndex;
3154 	} else if (canMove(&sum, DIR(_direction + 3), distance, false)) {
3155 		move(DIR(_direction + 3), distance);
3156 		--frameIndex;
3157 	} else if (canMove(&sum, DIR(_direction + 6), distance, false)) {
3158 		move(DIR(_direction + 6), distance);
3159 		--frameIndex;
3160 	} else if (canMove(&sum, DIR(_direction + 2), distance, false)) {
3161 		move(DIR(_direction + 2), distance);
3162 		--frameIndex;
3163 	}
3164 
3165 	if (frameIndex < 0)
3166 		_frameIndex = _frameCount - 1;
3167 	else
3168 		_frameIndex = (uint32)frameIndex;
3169 }
3170 
updateStatusMorphing()3171 void Actor::updateStatusMorphing() {
3172 	if (_resourceId == getWorld()->graphicResourceIds[3] || _resourceId == getWorld()->graphicResourceIds[4] || _resourceId == getWorld()->graphicResourceIds[5]) {
3173 		if (_frameIndex < _frameCount - 1) {
3174 			++_frameIndex;
3175 
3176 			if (_frameIndex == _frameCount / 2) {
3177 				getWorld()->currentPaletteId = getWorld()->graphicResourceIds[getWorld()->nextPlayer - 1];
3178 				getScreen()->setPalette(getWorld()->currentPaletteId);
3179 				getScreen()->setGammaLevel(getWorld()->currentPaletteId);
3180 			}
3181 
3182 			return;
3183 		}
3184 	} else {
3185 		if (_frameIndex > 0) {
3186 			--_frameIndex;
3187 
3188 			if (_frameIndex == _frameCount / 2)
3189 				getScreen()->setPalette(getWorld()->graphicResourceIds[getWorld()->nextPlayer - 1]);
3190 
3191 			getWorld()->currentPaletteId = getWorld()->graphicResourceIds[getWorld()->nextPlayer - 1];
3192 			getScreen()->setGammaLevel(getWorld()->currentPaletteId);
3193 			return;
3194 		}
3195 	}
3196 
3197 	getScene()->changePlayer(getWorld()->nextPlayer);
3198 	changeStatus(kActorStatusEnabled);
3199 	getWorld()->nextPlayer = kActorInvalid;
3200 }
3201 
actionAreaCheck()3202 void Actor::actionAreaCheck() {
3203 	if (_field_944 == 4 || !isVisible())
3204 		return;
3205 
3206 	int32 areaIndex = getScene()->findActionArea(kActionAreaType1, Common::Point((int16)(_point1.x + _point2.x), (int16)(_point1.y + _point2.y)));
3207 	if (areaIndex == _actionIdx3 || areaIndex == -1)
3208 		return;
3209 
3210 	ActionArea *area = getWorld()->actions[areaIndex];
3211 	ActionArea *actorArea = getWorld()->actions[_actionIdx3];
3212 
3213 	if ((area->flags & 1) && !getSharedData()->getFlag(kFlagSkipScriptProcessing)) {
3214 		debugC(kDebugLevelScripts, "[Script] Entered ActionArea (idx: %d, name: %s)", areaIndex, area->name);
3215 		debugC(kDebugLevelScripts, "[Script] Queuing Script #1 (idx: %d) for Actor (idx: %d)", actorArea->scriptIndex2, _index);
3216 		getScript()->queueScript(actorArea->scriptIndex2, _index);
3217 		debugC(kDebugLevelScripts, "[Script] Queuing Script #2 (idx: %d) for Actor (idx: %d)", area->scriptIndex, _index);
3218 		getScript()->queueScript(area->scriptIndex, _index);
3219 	}
3220 
3221 	if (!area->paletteResourceId || area->paletteResourceId == actorArea->paletteResourceId || _index) {
3222 		if (area->paletteResourceId != actorArea->paletteResourceId && !_index)
3223 			_vm->screen()->startPaletteFade(getWorld()->currentPaletteId, 100, 3);
3224 
3225 		_actionIdx3 = areaIndex;
3226 	} else {
3227 		_vm->screen()->startPaletteFade(area->paletteResourceId, 50, 3);
3228 		_actionIdx3 = areaIndex;
3229 	}
3230 }
3231 
TentacleBlocksSarah(const Common::Point & vec1,Common::Point vec2)3232 void Actor::TentacleBlocksSarah(const Common::Point &vec1, Common::Point vec2) {
3233 	if (getScene()->getActor(1)->isVisible())
3234 		return;
3235 
3236 	uint32 diffY = (uint32)abs(vec2.y - vec1.y);
3237 	if (diffY > 5)
3238 		diffY = 5;
3239 
3240 	if (diffY == 0)
3241 		return;
3242 
3243 	ActorDirection dir = (vec1.y > vec2.y) ? kDirectionS : kDirectionN;
3244 
3245 	if (canMove(&vec2, dir, diffY + 3, false))
3246 		incPosition(dir, (int16)(diffY - 1), &_point1);
3247 }
3248 
SarahDies()3249 void Actor::SarahDies() {
3250 	getCursor()->hide();
3251 	getScene()->getActor(0)->hide();
3252 	getScene()->getActor(1)->setFrameIndex(0);
3253 
3254 	getWorld()->tickCount1 = _vm->getTick() + 3000;
3255 }
3256 
updateNumbers(uint item,const Common::Point & point)3257 void Actor::updateNumbers(uint item, const Common::Point &point) {
3258 	if (item != 1)
3259 		return;
3260 
3261 	_numberPoint.x = point.x;
3262 	_numberPoint.y = point.y + 8;
3263 	_numberStringWidth = 40;
3264 	snprintf(_numberString01, sizeof(_numberString01), "%d", _numberValue01);
3265 
3266 	_numberFlag01 = 1;
3267 }
3268 
3269 //////////////////////////////////////////////////////////////////////////
3270 // Path finding functions
3271 //////////////////////////////////////////////////////////////////////////
findLeftPath(Common::Point source,const Common::Point & destination,Common::Array<int> * actions)3272 bool Actor::findLeftPath(Common::Point source, const Common::Point &destination, Common::Array<int> *actions) {
3273 	// Reset pathfinding data
3274 	_data.count = 0;
3275 	_data.current = 0;
3276 
3277 	bool flag = false;
3278 	Common::Point src = source;
3279 
3280 	for (uint32 i = 0; i < 60; i++) {
3281 
3282 		// Note: this is handled differently from other tryDirection functions
3283 		// as we break instead of checking the other actors
3284 		if (!tryDirection(source, actions, &src, kDirectionE,  destination, &flag)
3285 		 && !tryDirection(source, actions, &src, kDirectionNE, destination, &flag)
3286 		 && !tryDirection(source, actions, &src, kDirectionSE, destination, &flag)
3287 		 && !tryDirection(source, actions, &src, kDirectionN,  destination, &flag)
3288 		 && !tryDirection(source, actions, &src, kDirectionS,  destination, &flag))
3289 			break;
3290 
3291 		// Update source point after all processing
3292 		source = src;
3293 
3294 		if (flag)
3295 			return true;
3296 	}
3297 
3298 	return false;
3299 }
3300 
findRightPath(Common::Point source,const Common::Point & destination,Common::Array<int> * actions)3301 bool Actor::findRightPath(Common::Point source, const Common::Point &destination, Common::Array<int> *actions) {
3302 	// Reset pathfinding data
3303 	_data.count = 0;
3304 	_data.current = 0;
3305 
3306 	bool flag = false;
3307 	Common::Point src = source;
3308 
3309 	for (uint32 i = 0; i < 60; i++) {
3310 		if (!tryDirection(source, actions, &src, kDirectionW,  destination, &flag)
3311 		 && !tryDirection(source, actions, &src, kDirectionNW, destination, &flag)
3312 		 && !tryDirection(source, actions, &src, kDirectionSW, destination, &flag)) {
3313 			if (src.y <= destination.y) {
3314 				if (!tryDirection(source, actions, &src, kDirectionS,  destination, &flag)
3315 				 && !tryDirection(source, actions, &src, kDirectionN,  destination, &flag)
3316 				 && !tryDirection(source, actions, &src, kDirectionSE, destination, &flag)
3317 				 && !tryDirection(source, actions, &src, kDirectionE,  destination, &flag)
3318 				 && !tryDirection(source, actions, &src, kDirectionNE, destination, &flag))
3319 					continue;
3320 			} else {
3321 				if (!tryDirection(source, actions, &src, kDirectionN,  destination, &flag)
3322 				 && !tryDirection(source, actions, &src, kDirectionS,  destination, &flag)
3323 				 && !tryDirection(source, actions, &src, kDirectionNE, destination, &flag)
3324 				 && !tryDirection(source, actions, &src, kDirectionE,  destination, &flag)
3325 				 && !tryDirection(source, actions, &src, kDirectionSE, destination, &flag))
3326 					continue;
3327 			}
3328 		}
3329 
3330 		// Update source point after all processing
3331 		source = src;
3332 
3333 		if (flag)
3334 			return true;
3335 	}
3336 
3337 	return false;
3338 }
3339 
findUpPath(Common::Point source,const Common::Point & destination,Common::Array<int> * actions)3340 bool Actor::findUpPath(Common::Point source, const Common::Point &destination, Common::Array<int> *actions) {
3341 	// Reset pathfinding data
3342 	_data.count = 0;
3343 	_data.current = 0;
3344 
3345 	bool flag = false;
3346 	Common::Point src = source;
3347 
3348 	for (uint32 i = 0; i < 60; i++) {
3349 		if (!tryDirection(source, actions, &src, kDirectionN, destination, &flag)) {
3350 			if (src.x >= destination.x) {
3351 				if (!tryDirection(source, actions, &src, kDirectionNW, destination, &flag)
3352 				 && !tryDirection(source, actions, &src, kDirectionW,  destination, &flag)
3353 				 && !tryDirection(source, actions, &src, kDirectionNE, destination, &flag)
3354 				 && !tryDirection(source, actions, &src, kDirectionE,  destination, &flag))
3355 					continue;
3356 			} else {
3357 				if (!tryDirection(source, actions, &src, kDirectionNE, destination, &flag)
3358 				 && !tryDirection(source, actions, &src, kDirectionE,  destination, &flag)
3359 				 && !tryDirection(source, actions, &src, kDirectionNW, destination, &flag)
3360 				 && !tryDirection(source, actions, &src, kDirectionW,  destination, &flag))
3361 					continue;
3362 			}
3363 		}
3364 
3365 		// Update source point after all processing
3366 		source = src;
3367 
3368 		if (flag)
3369 			return true;
3370 	}
3371 
3372 	return false;
3373 }
3374 
findDownPath(Common::Point source,const Common::Point & destination,Common::Array<int> * actions)3375 bool Actor::findDownPath(Common::Point source, const Common::Point &destination, Common::Array<int> *actions) {
3376 	// Reset pathfinding data
3377 	_data.count = 0;
3378 	_data.current = 0;
3379 
3380 	bool flag = false;
3381 	Common::Point src = source;
3382 
3383 	for (uint32 i = 0; i < 60; i++) {
3384 		if (!tryDirection(source, actions, &src, kDirectionS,  destination, &flag)
3385 		 && !tryDirection(source, actions, &src, kDirectionSE, destination, &flag)
3386 		 && !tryDirection(source, actions, &src, kDirectionSW, destination, &flag)
3387 		 && !tryDirection(source, actions, &src, kDirectionE,  destination, &flag)
3388 		 && !tryDirection(source, actions, &src, kDirectionW,  destination, &flag))
3389 			continue;
3390 
3391 		// Update source point after all processing
3392 		source = src;
3393 
3394 		if (flag)
3395 			return true;
3396 	}
3397 
3398 	return false;
3399 }
3400 
tryDirection(const Common::Point & source,Common::Array<int> * actions,Common::Point * point,ActorDirection direction,const Common::Point & destination,bool * flag)3401 bool Actor::tryDirection(const Common::Point &source, Common::Array<int> *actions, Common::Point *point, ActorDirection direction, const Common::Point &destination, bool *flag) {
3402 	Common::Point sign;
3403 	Common::Point src = source;
3404 	uint32 frameNumber = _frameNumber;
3405 
3406 	switch (direction) {
3407 	default:
3408 		return false;
3409 
3410 	case kDirectionN:
3411 		sign.y = -1;
3412 		break;
3413 
3414 	case kDirectionNW:
3415 		sign.x = -1;
3416 		sign.y = -1;
3417 		break;
3418 
3419 	case kDirectionW:
3420 		sign.x = -1;
3421 		break;
3422 
3423 	case kDirectionSW:
3424 		sign.x = -1;
3425 		sign.y = 1;
3426 		break;
3427 
3428 	case kDirectionS:
3429 		sign.y = 1;
3430 		break;
3431 
3432 	case kDirectionSE:
3433 		sign.x = 1;
3434 		sign.y = 1;
3435 		break;
3436 
3437 	case kDirectionE:
3438 		sign.x = 1;
3439 		break;
3440 
3441 	case kDirectionNE:
3442 		sign.x = 1;
3443 		sign.y = -1;
3444 		break;
3445 	}
3446 
3447 	for (int i = 0; i < 10; i++) {
3448 		if (!testPolyInLink(src, actions))
3449 			break;
3450 
3451 		int32 dist = getStride(direction, frameNumber);
3452 		src.x += (int16)(sign.x * dist);
3453 		src.y += (int16)(sign.y * dist);
3454 
3455 		if (abs(src.x - destination.x) >= getStride(kDirectionW, frameNumber)) {
3456 			if (abs(src.y - destination.y) < getStride(kDirectionN, frameNumber)) {
3457 
3458 				if (src.x >= destination.x) {
3459 					if (canGetToDest(actions, src, kDirectionW, src.x - destination.x)) {
3460 						*flag = true;
3461 						*point = src;
3462 
3463 						_data.points[_data.count]     = src;
3464 						_data.directions[_data.count] = direction;
3465 						_data.count++;
3466 
3467 						_data.points[_data.count]     = destination;
3468 						_data.directions[_data.count] = kDirectionW;
3469 						_data.count++;
3470 
3471 						return true;
3472 					}
3473 				} else {
3474 					if (canGetToDest(actions, src, kDirectionE, destination.x - src.x)) {
3475 						*flag = true;
3476 						*point = src;
3477 
3478 						_data.points[_data.count]     = src;
3479 						_data.directions[_data.count] = direction;
3480 						_data.count++;
3481 
3482 						_data.points[_data.count]     = destination;
3483 						_data.directions[_data.count] = kDirectionE;
3484 						_data.count++;
3485 
3486 						return true;
3487 					}
3488 				}
3489 			}
3490 		} else {
3491 			if (src.y >= destination.y) {
3492 				if (canGetToDest(actions, src, kDirectionN, src.y - destination.y)) {
3493 					*flag = true;
3494 					*point = src;
3495 
3496 					_data.points[_data.count]     = src;
3497 					_data.directions[_data.count] = direction;
3498 					_data.count++;
3499 
3500 					_data.points[_data.count]     = destination;
3501 					_data.directions[_data.count] = kDirectionN;
3502 					_data.count++;
3503 
3504 					return true;
3505 				}
3506 			} else {
3507 				if (canGetToDest(actions, src, kDirectionS, destination.y - src.y)) {
3508 					*flag = true;
3509 					*point = src;
3510 
3511 					_data.points[_data.count]     = src;
3512 					_data.directions[_data.count] = direction;
3513 					_data.count++;
3514 
3515 					_data.points[_data.count]     = destination;
3516 					_data.directions[_data.count] = kDirectionS;
3517 					_data.count++;
3518 
3519 					return true;
3520 				}
3521 			}
3522 		}
3523 
3524 		// Proceed to next frame
3525 		++frameNumber;
3526 
3527 		if (frameNumber >= _frameCount)
3528 			frameNumber = 0;
3529 	}
3530 
3531 	// Check if we need to process
3532 	int32 distance = getStride(direction, frameNumber);
3533 	if (source.x == (src.x - sign.x * distance) && source.y == (src.y - sign.y * distance))
3534 		return false;
3535 
3536 	if (!getWorld()->sceneRects[getWorld()->sceneRectIdx].contains(src))
3537 		return false;
3538 
3539 	// Update frame and setup pathfinding
3540 	_frameNumber = frameNumber;
3541 
3542 	if (_frameNumber == 0)
3543 		distance = getStride(direction, _frameCount - 1);
3544 	else
3545 		distance = getStride(direction, _frameNumber - 1);
3546 
3547 	src.x -= (int16)(sign.x * distance);
3548 	src.y -= (int16)(sign.y * distance);
3549 
3550 	*point = src;
3551 	_data.points[_data.count]     = src;
3552 	_data.directions[_data.count] = direction;
3553 	_data.count++;
3554 
3555 	return true;
3556 }
3557 
canGetToDest(Common::Array<int> * actions,const Common::Point & point,ActorDirection direction,int16 loopcount)3558 bool Actor::canGetToDest(Common::Array<int> *actions, const Common::Point &point, ActorDirection direction, int16 loopcount) {
3559 	if (loopcount <= 1)
3560 		return true;
3561 
3562 	// Initialize base coordinates
3563 	Common::Point delta     = Common::Point(deltaPointsArray[direction][0], deltaPointsArray[direction][1]);
3564 	Common::Point basePoint = delta + point;
3565 	Common::Rect  rect      = getWorld()->sceneRects[getWorld()->sceneRectIdx];
3566 
3567 	for (int16 i = 1; i < loopcount; i++) {
3568 		if (!testPolyInLink(basePoint, actions))
3569 			return false;
3570 
3571 		if (!rect.contains(basePoint))
3572 			return false;
3573 
3574 		basePoint += delta;
3575 	}
3576 
3577 	return true;
3578 }
3579 
testPolyInLink(const Common::Point & pt,Common::Array<int> * actions)3580 bool Actor::testPolyInLink(const Common::Point &pt, Common::Array<int> *actions) {
3581 	if (actions->size() == 0)
3582 		return false;
3583 
3584 	for (Common::Array<int>::iterator it = actions->begin(); it != actions->end(); it++) {
3585 		if (isInActionArea(pt, getWorld()->actions[*it]))
3586 			return true;
3587 	}
3588 
3589 	return false;
3590 
3591 }
3592 
isInActionArea(const Common::Point & pt,ActionArea * area)3593 bool Actor::isInActionArea(const Common::Point &pt, ActionArea *area) {
3594 	Common::Rect sceneRect = getWorld()->sceneRects[getWorld()->sceneRectIdx];
3595 
3596 	if (!sceneRect.contains(pt))
3597 		return false;
3598 
3599 	if (!(area->flags & 1))
3600 		return false;
3601 
3602 	// Check flags
3603 	bool found = false;
3604 	for (uint32 i = 0; i < 10; i++) {
3605 		int32 flag = area->flagNums[i];
3606 		bool state = (flag <= 0) ? _vm->isGameFlagNotSet((GameFlag)-flag) : _vm->isGameFlagSet((GameFlag)flag);
3607 
3608 		if (!state) {
3609 			found = true;
3610 			break;
3611 		}
3612 	}
3613 
3614 	if (found)
3615 		return false;
3616 
3617 	Polygon poly = getScene()->polygons()->get(area->polygonIndex);
3618 	if (!poly.contains(pt))
3619 		return false;
3620 
3621 	return true;
3622 }
3623 
3624 //////////////////////////////////////////////////////////////////////////
3625 // Misc
3626 //////////////////////////////////////////////////////////////////////////
3627 
setVisible(bool value)3628 void Actor::setVisible(bool value) {
3629 	if (value)
3630 		flags |= kActorFlagVisible;
3631 	else
3632 		flags &= ~kActorFlagVisible;
3633 
3634 	stopSound();
3635 }
3636 
isOnScreen()3637 bool Actor::isOnScreen() {
3638 	Common::Rect scene(getWorld()->xLeft, getWorld()->yTop, getWorld()->xLeft + 640, getWorld()->yTop + 480);
3639 	Common::Rect actor(_boundingRect);
3640 	actor.translate(_point1.x, _point1.y);
3641 
3642 	return isVisible() && scene.intersects(actor);
3643 }
3644 
setVolume()3645 void Actor::setVolume() {
3646 	if (!_soundResourceId || !getSound()->isPlaying(_soundResourceId))
3647 		return;
3648 
3649 	// Compute volume
3650 	int32 volume = Config.voiceVolume + getSound()->calculateVolumeAdjustement(_point1 + _point2, _field_968, 0);
3651 	if (volume < -10000)
3652 		volume = -10000;
3653 
3654 	getSound()->setVolume(_soundResourceId, volume);
3655 }
3656 
3657 //////////////////////////////////////////////////////////////////////////
3658 // Helper methods
3659 //////////////////////////////////////////////////////////////////////////
3660 
getAngle(const Common::Point & vec1,const Common::Point & vec2)3661 ActorDirection Actor::getAngle(const Common::Point &vec1, const Common::Point &vec2) {
3662 	int32 diffX = (vec2.x << 16) - (vec1.x << 16);
3663 	int32 diffY = (vec1.y << 16) - (vec2.y << 16);
3664 	int32 adjust = 0;
3665 
3666 	if (diffX < 0) {
3667 		adjust = 2;
3668 		diffX = -diffX;
3669 	}
3670 
3671 	if (diffY < 0) {
3672 		adjust |= 1;
3673 		diffY = -diffY;
3674 	}
3675 
3676 	int32 dirAngle = -1;
3677 
3678 	if (diffX) {
3679 		uint32 index = (uint32)((diffY * 256) / diffX);
3680 
3681 		if (index < 256)
3682 			dirAngle = angleTable01[index];
3683 		else if (index < 4096)
3684 			dirAngle = angleTable02[index / 16];
3685 		else if (index < 65536)
3686 			dirAngle = angleTable03[index / 256];
3687 		else
3688 			dirAngle = 90;
3689 	} else {
3690 		dirAngle = 90;
3691 	}
3692 
3693 	switch (adjust) {
3694 	default:
3695 		break;
3696 
3697 	case 1:
3698 		dirAngle = 360 - dirAngle;
3699 		break;
3700 
3701 	case 2:
3702 		dirAngle = 180 - dirAngle;
3703 		break;
3704 
3705 	case 3:
3706 		dirAngle += 180;
3707 		break;
3708 	}
3709 
3710 	if (dirAngle >= 360)
3711 		dirAngle -= 360;
3712 
3713 	ActorDirection dir;
3714 
3715 	if (dirAngle < 157 || dirAngle >= 202) {
3716 		if (dirAngle < 112 || dirAngle >= 157) {
3717 			if (dirAngle < 67 || dirAngle >= 112) {
3718 				if (dirAngle < 22 || dirAngle >= 67) {
3719 					if ((dirAngle < 0 || dirAngle >= 22) && (dirAngle < 337 || dirAngle > 359)) {
3720 						if (dirAngle < 292 || dirAngle >= 337) {
3721 							if (dirAngle < 247 || dirAngle >= 292) {
3722 								if (dirAngle < 202 || dirAngle >= 247) {
3723 									error("[Actor::direction] got a bad direction angle: %d!", dirAngle);
3724 								} else {
3725 									dir = kDirectionSW;
3726 								}
3727 							} else {
3728 								dir = kDirectionS;
3729 							}
3730 						} else {
3731 							dir = kDirectionSE;
3732 						}
3733 					} else {
3734 						dir = kDirectionE;
3735 					}
3736 				} else {
3737 					dir = kDirectionNE;
3738 				}
3739 			} else {
3740 				dir = kDirectionN;
3741 			}
3742 		} else {
3743 			dir = kDirectionNW;
3744 		}
3745 	} else {
3746 		dir = kDirectionW;
3747 	}
3748 
3749 	return dir;
3750 }
3751 
updateGraphicData(uint32 offset)3752 void Actor::updateGraphicData(uint32 offset) {
3753 	int32 index = ((_direction > kDirectionS) ? kDirection8 - _direction : _direction) + (int32)offset;
3754 	_resourceId = _graphicResourceIds[index];
3755 	_frameCount = GraphicResource::getFrameCount(_vm, _resourceId);
3756 	_frameIndex = 0;
3757 }
3758 
canChangeStatus(int index) const3759 bool Actor::canChangeStatus(int index) const {
3760 	return _graphicResourceIds[index] != _graphicResourceIds[5];
3761 }
3762 
adjustCoordinates(Common::Point * point)3763 void Actor::adjustCoordinates(Common::Point *point) {
3764 	if (!point)
3765 		error("[Actor::adjustCoordinates] Invalid point parameter!");
3766 
3767 	point->x = _point1.x - getWorld()->xLeft;
3768 	point->y = _point1.y - getWorld()->yTop;
3769 }
3770 
getGraphicsFlags()3771 DrawFlags Actor::getGraphicsFlags() {
3772 	if (getWorld()->chapter == kChapter11) {
3773 		int res = strcmp((char *)&_name, "Dead Sarah");
3774 
3775 		if (res == 0)
3776 			return kDrawFlagNone;
3777 	}
3778 
3779 	if (_direction < kDirectionSE)
3780 		return kDrawFlagNone;
3781 
3782 	return kDrawFlagMirrorLeftRight;
3783 }
3784 
getStride(ActorDirection dir,uint32 frameIndex) const3785 int32 Actor::getStride(ActorDirection dir, uint32 frameIndex) const {
3786 	if (frameIndex >= ARRAYSIZE(_distancesNS))
3787 		debugC(kDebugLevelMain, "[Actor::getStride] Invalid frame index (was: %d, max: %d)", _frameIndex, ARRAYSIZE(_distancesNS) - 1);
3788 
3789 	switch (dir) {
3790 	default:
3791 		error("[Actor::getStride] Invalid direction");
3792 
3793 	case kDirectionN:
3794 	case kDirectionS:
3795 		// XXX it seems that the original allows frameIndex to be out of range
3796 		return (frameIndex < ARRAYSIZE(_distancesNS) ? _distancesNS[frameIndex] : _distancesNSEO[frameIndex % ARRAYSIZE(_distancesNS)]);
3797 
3798 	case kDirectionNW:
3799 	case kDirectionSW:
3800 	case kDirectionSE:
3801 	case kDirectionNE:
3802 		return _distancesNSEO[frameIndex];
3803 
3804 	case kDirectionW:
3805 	case kDirectionE:
3806 		return _distancesEO[frameIndex];
3807 	}
3808 }
3809 
getWalkIncrement(ActorDirection dir,uint32 frameIndex) const3810 int32 Actor::getWalkIncrement(ActorDirection dir, uint32 frameIndex) const {
3811 	if (frameIndex >= ARRAYSIZE(_distancesNS))
3812 		error("[Actor::getWalkIncrement] Invalid frame index (was: %d, max: %d)", _frameIndex, ARRAYSIZE(_distancesNS) - 1);
3813 
3814 	switch (dir) {
3815 	default:
3816 		error("[Actor::getWalkIncrement] Invalid direction");
3817 
3818 	case kDirectionN:
3819 		return -_distancesNS[frameIndex];
3820 
3821 	case kDirectionS:
3822 		return _distancesNS[frameIndex];
3823 
3824 	case kDirectionNW:
3825 		return -_distancesNSEO[frameIndex];
3826 
3827 	case kDirectionNE:
3828 		return -_distancesNSEO[frameIndex];
3829 
3830 	case kDirectionSW:
3831 		return _distancesNSEO[frameIndex];
3832 
3833 	case kDirectionSE:
3834 		return _distancesNSEO[frameIndex];
3835 
3836 	case kDirectionW:
3837 		return -_distancesEO[frameIndex];
3838 
3839 	case kDirectionE:
3840 		return _distancesEO[frameIndex];
3841 	}
3842 }
3843 
incPosition(ActorDirection direction,int16 delta,Common::Point * point)3844 void Actor::incPosition(ActorDirection direction, int16 delta, Common::Point *point) {
3845 	if (!point)
3846 		error("[Actor::incPosition] Invalid point (NULL)!");
3847 
3848 	switch (direction) {
3849 	default:
3850 		break;
3851 
3852 	case kDirectionN:
3853 		point->y -= delta;
3854 		break;
3855 
3856 	case kDirectionNW:
3857 		point->x -= delta;
3858 		point->y -= delta;
3859 		break;
3860 
3861 	case kDirectionW:
3862 		point->x -= delta;
3863 		break;
3864 
3865 	case kDirectionSW:
3866 		point->x -= delta;
3867 		point->y += delta;
3868 		break;
3869 
3870 	case kDirectionS:
3871 		point->y += delta;
3872 		break;
3873 
3874 	case kDirectionSE:
3875 		point->x += delta;
3876 		point->y += delta;
3877 		break;
3878 
3879 	case kDirectionE:
3880 		point->x += delta;
3881 		break;
3882 
3883 	case kDirectionNE:
3884 		point->x += delta;
3885 		point->y -= delta;
3886 		break;
3887 	}
3888 }
3889 
euclidianDistance(const Common::Point & point1,const Common::Point & point2)3890 uint32 Actor::euclidianDistance(const Common::Point &point1, const Common::Point &point2) {
3891 	return (uint32)sqrt(pow((double)(point2.y - point1.y), 2) + pow((double)(point2.x - point1.x), 2));
3892 }
3893 
getAngleOfVector(const Common::Point & vec1,const Common::Point & vec2)3894 int32 Actor::getAngleOfVector(const Common::Point &vec1, const Common::Point &vec2) {
3895 	int32 result = (int32)(((long)(180 - acos((double)(vec2.y - vec1.y) / euclidianDistance(vec1, vec2)) * 180 / -M_PI)) % 360);
3896 
3897 	if (vec1.x < vec2.x)
3898 		return 360 - result;
3899 
3900 	return result;
3901 }
3902 
getCrowStrikeZone(Common::Rect * rect,ActorDirection direction,const Common::Point & point)3903 void Actor::getCrowStrikeZone(Common::Rect *rect, ActorDirection direction, const Common::Point &point) {
3904 	if (!rect)
3905 		error("[Actor::rect] Invalid rect (NULL)!");
3906 
3907 	switch (direction) {
3908 	default:
3909 		rect->top = 0;
3910 		rect->left = 0;
3911 		rect->bottom = 0;
3912 		rect->right = 0;
3913 		return;
3914 
3915 	case kDirectionN:
3916 		rect->top = point.y - 84;
3917 		rect->left = point.x - 9;
3918 		break;
3919 
3920 	case kDirectionNW:
3921 		rect->top = point.y - 55;
3922 		rect->left = point.x - 84;
3923 		break;
3924 
3925 	case kDirectionW:
3926 		rect->top = point.y - 34;
3927 		rect->left = point.x - 93;
3928 		break;
3929 
3930 	case kDirectionSW:
3931 		rect->top = point.y + 27;
3932 		rect->left = point.x - 94;
3933 		break;
3934 
3935 	case kDirectionS:
3936 		rect->top = point.y + 41;
3937 		rect->left = point.x - 9;
3938 		break;
3939 
3940 	case kDirectionSE:
3941 		rect->top = point.y + 27;
3942 		rect->left = point.x + 54;
3943 		break;
3944 
3945 	case kDirectionE:
3946 		rect->top = point.y - 34;
3947 		rect->left = point.x + 53;
3948 		break;
3949 
3950 	case kDirectionNE:
3951 		rect->top = point.y - 55;
3952 		rect->left = point.x + 44;
3953 		break;
3954 	}
3955 
3956 	rect->setWidth(40);
3957 	rect->setHeight(40);
3958 }
3959 
determineLeftOrRight(const Common::Point & vec1,const Common::Point & vec2)3960 bool Actor::determineLeftOrRight(const Common::Point &vec1, const Common::Point &vec2) {
3961 	Common::Point vec3(2289, 171);
3962 
3963 	int32 diff = getAngleOfVector(vec1, vec3) - getAngleOfVector(vec1, vec2);
3964 
3965 	if (diff < 0)
3966 		diff += 359;
3967 
3968 	return (diff > 180);
3969 }
3970 
pointInRectXAdjust(const Common::Rect & rect,const Common::Point & point)3971 int16 Actor::pointInRectXAdjust(const Common::Rect &rect, const Common::Point &point) {
3972 	if (point.x > rect.right)
3973 		return 3;
3974 
3975 	if (point.x < rect.left)
3976 		return -3;
3977 	else
3978 		return 0;
3979 }
3980 
pointInRectYAdjust(const Common::Rect & rect,const Common::Point & point)3981 int16 Actor::pointInRectYAdjust(const Common::Rect &rect, const Common::Point &point) {
3982 	if (point.y > rect.bottom)
3983 		return 3;
3984 
3985 	if (point.y < rect.top)
3986 		return -3;
3987 	else
3988 		return 0;
3989 }
3990 
3991 
3992 } // end of namespace Asylum
3993