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 "illusions/illusions.h"
24 #include "illusions/actor.h"
25 #include "illusions/camera.h"
26 #include "illusions/cursor.h"
27 #include "illusions/dictionary.h"
28 #include "illusions/fixedpoint.h"
29 #include "illusions/input.h"
30 #include "illusions/screen.h"
31 #include "illusions/scriptopcodes.h"
32 #include "illusions/sequenceopcodes.h"
33 #include "illusions/thread.h"
34 #include "illusions/threads/talkthread.h"
35 
36 namespace Illusions {
37 
38 // DefaultSequences
39 
use(uint32 sequenceId)40 uint32 DefaultSequences::use(uint32 sequenceId) {
41 	ItemsIterator it = Common::find_if(_items.begin(), _items.end(), DefaultSequenceEqual(sequenceId));
42 	return it != _items.end() ? (*it)._newSequenceId : sequenceId;
43 }
44 
set(uint32 sequenceId,uint32 newSequenceId)45 void DefaultSequences::set(uint32 sequenceId, uint32 newSequenceId) {
46 	ItemsIterator it = Common::find_if(_items.begin(), _items.end(), DefaultSequenceEqual(sequenceId));
47 	if (it == _items.end())
48 		_items.push_back(DefaultSequence(sequenceId, newSequenceId));
49 	else if (sequenceId == newSequenceId)
50 		_items.remove_at(it - _items.begin());
51 	else
52 		(*it)._newSequenceId = newSequenceId;
53 }
54 
55 // Actor
56 
Actor(IllusionsEngine * vm)57 Actor::Actor(IllusionsEngine *vm)
58 	: _vm(vm), _pauseCtr(0) {
59 	_pauseCtr = 0;
60 	_spriteFlags = 0;
61 	_drawFlags = 0;
62 	_flags = 0;
63 	_scale = 100;
64 	_frameIndex = 0;
65 	_newFrameIndex = 0;
66 	_surfInfo._pixelSize = 0;
67 	_surfInfo._dimensions._width = 0;
68 	_surfInfo._dimensions._height = 0;
69 	_surface = 0;
70 	_frames = 0;
71 	_scaleLayer = 0;
72 	_priorityLayer = 0;
73 	_regionLayer = 0;
74 	_pathWalkPoints = 0;
75 	_pathWalkRects = 0;
76 	_position.x = 0;
77 	_position.y = 0;
78 	_position2.x = 0;
79 	_position2.y = 0;
80 	_facing = 64;
81 	_regionIndex = 0;
82 	_fontId = 0;
83 	_actorIndex = 0;
84 	_parentObjectId = 0;
85 	_linkIndex = 0;
86 	_linkIndex2 = 0;
87 	for (uint i = 0; i < kSubObjectsCount; ++i) {
88 		_subobjects[i] = 0;
89 	}
90 	_notifyThreadId1 = 0;
91 	_notifyThreadId2 = 0;
92 	_entryTblPtr = 0;
93 	_seqCodeIp = 0;
94 	_sequenceId = 0;
95 	_seqCodeValue1 = 0;
96 	_seqCodeValue2 = 600;
97 	_seqCodeValue3 = 0;
98 
99 	_notifyId3C = 0;
100 
101 	_controlRoutine = 0;
102 	setControlRoutine(new Common::Functor2Mem<Control*, uint32, void, Controls>(_vm->_controls, &Controls::actorControlRoutine));
103 
104 	_walkCallerThreadId1 = 0;
105 	_pathAngle = 0;
106 	_pathFlag50 = false;
107 	_pathCtrX = 0;
108 	_pathCtrY = 0;
109 	_pathInitialPosFlag = true;
110 	_pathInitialPos.x = 0;
111 	_pathInitialPos.y = 0;
112 	_pathPoints = 0;
113 	_pathPointIndex = 0;
114 	_pathPointsCount = 0;
115 	_pathNode = 0;
116 
117 }
118 
~Actor()119 Actor::~Actor() {
120 	delete _controlRoutine;
121 }
122 
pause()123 void Actor::pause() {
124 	++_pauseCtr;
125 }
126 
unpause()127 void Actor::unpause() {
128 	--_pauseCtr;
129 }
130 
createSurface(SurfInfo & surfInfo)131 void Actor::createSurface(SurfInfo &surfInfo) {
132 	_surface = _vm->_screen->allocSurface(surfInfo);
133 	if (_vm->getGameId() == kGameIdDuckman) {
134 		if (_flags & Illusions::ACTOR_FLAG_IS_VISIBLE) {
135 			if (_frameIndex) {
136 				_flags |= Illusions::ACTOR_FLAG_2000;
137 			}
138 			_flags |= Illusions::ACTOR_FLAG_4000;
139 		}
140 	} else {
141 		if (_frameIndex) {
142 			_flags |= Illusions::ACTOR_FLAG_2000;
143 			_flags |= Illusions::ACTOR_FLAG_4000;
144 		}
145 	}
146 }
147 
destroySurface()148 void Actor::destroySurface() {
149 	if (_surface) {
150 		_surface->free();
151 		delete _surface;
152 		_surface = 0;
153 	}
154 }
155 
initSequenceStack()156 void Actor::initSequenceStack() {
157 	_seqStackCount = 0;
158 }
159 
pushSequenceStack(int16 value)160 void Actor::pushSequenceStack(int16 value) {
161 	_seqStack[_seqStackCount++] = value;
162 }
163 
popSequenceStack()164 int16 Actor::popSequenceStack() {
165 	return _seqStack[--_seqStackCount];
166 }
167 
setControlRoutine(ActorControlRoutine * controlRoutine)168 void Actor::setControlRoutine(ActorControlRoutine *controlRoutine) {
169 	delete _controlRoutine;
170 	_controlRoutine = controlRoutine;
171 }
172 
runControlRoutine(Control * control,uint32 deltaTime)173 void Actor::runControlRoutine(Control *control, uint32 deltaTime) {
174 	if (_controlRoutine)
175 		(*_controlRoutine)(control, deltaTime);
176 }
177 
findNamedPoint(uint32 namedPointId,Common::Point & pt)178 bool Actor::findNamedPoint(uint32 namedPointId, Common::Point &pt) {
179 	if (_namedPoints->findNamedPoint(namedPointId, pt)) {
180 		pt.x += _position.x;
181 		pt.y += _position.y;
182 		return true;
183 	}
184 	return false;
185 }
186 
187 // Control
188 
Control(IllusionsEngine * vm)189 Control::Control(IllusionsEngine *vm)
190 	: _vm(vm) {
191 	_flags = 0;
192 	_pauseCtr = 0;
193 	_priority = 0;
194 	_objectId = 0;
195 	_bounds._topLeft.x = 0;
196 	_bounds._topLeft.y = 0;
197 	_bounds._bottomRight.x = 0;
198 	_bounds._bottomRight.y = 0;
199 	_feetPt.x = 0;
200 	_feetPt.y = 0;
201 	_position.x = 0;
202 	_position.y = 0;
203 	_actorTypeId = 0;
204 	_actor = 0;
205 	_sceneId = _vm->getCurrentScene();
206 }
207 
~Control()208 Control::~Control() {
209 }
210 
pause()211 void Control::pause() {
212 
213 	if (_vm->getGameId() == kGameIdBBDOU || !(_flags & 4)) {
214 		_vm->_dict->setObjectControl(_objectId, 0);
215 		if (_objectId == Illusions::CURSOR_OBJECT_ID)
216 			_vm->setCursorControl(0);
217 	}
218 
219 	if (_actor && !(_actor->_flags & Illusions::ACTOR_FLAG_200))
220 		_actor->destroySurface();
221 
222 }
223 
unpause()224 void Control::unpause() {
225 
226 	if (_vm->getGameId() == kGameIdBBDOU || !(_flags & 4)) {
227 		_vm->_dict->setObjectControl(_objectId, this);
228 		if (_objectId == Illusions::CURSOR_OBJECT_ID)
229 			_vm->setCursorControl(this);
230 	}
231 
232 	if (_actor && !(_actor->_flags & Illusions::ACTOR_FLAG_200)) {
233 		SurfInfo surfInfo;
234 		ActorType *actorType = _vm->_dict->findActorType(_actorTypeId);
235 		if (actorType)
236 			surfInfo = actorType->_surfInfo;
237 		else
238 			surfInfo = _actor->_surfInfo;
239 		_actor->createSurface(surfInfo);
240 	}
241 }
242 
appearActor()243 void Control::appearActor() {
244 	if (_vm->getGameId() == kGameIdDuckman) {
245 		_flags |= 1;
246 		_actor->_flags |= Illusions::ACTOR_FLAG_IS_VISIBLE;
247 		if (_objectId == Illusions::CURSOR_OBJECT_ID) {
248 			if (_actor->_frameIndex) {
249 				_actor->_flags |= Illusions::ACTOR_FLAG_2000;
250 				_actor->_flags |= Illusions::ACTOR_FLAG_4000;
251 			}
252 			_vm->_input->discardAllEvents();
253 		}
254 	} else {
255 		if (_objectId == Illusions::CURSOR_OBJECT_ID) {
256 			_vm->showCursor();
257 		} else {
258 			if (_actor->_frameIndex || _actorTypeId == 0x50004) {
259 				_actor->_flags |= Illusions::ACTOR_FLAG_IS_VISIBLE;
260 			} else {
261 				_actor->_flags |= Illusions::ACTOR_FLAG_1000;
262 			}
263 			for (uint i = 0; i < kSubObjectsCount; ++i) {
264 				if (_actor->_subobjects[i]) {
265 					Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[i]);
266 					subControl->appearActor();
267 				}
268 			}
269 		}
270 	}
271 }
272 
disappearActor()273 void Control::disappearActor() {
274 	if (_vm->getGameId() == kGameIdDuckman) {
275 		_flags &= ~1;
276 		_actor->_flags &= ~Illusions::ACTOR_FLAG_IS_VISIBLE;
277 	} else {
278 		if (_objectId == Illusions::CURSOR_OBJECT_ID) {
279 			_vm->hideCursor();
280 		} else {
281 			_actor->_flags &= ~Illusions::ACTOR_FLAG_IS_VISIBLE;
282 			_actor->_flags &= ~Illusions::ACTOR_FLAG_1000;
283 			for (uint i = 0; i < kSubObjectsCount; ++i) {
284 				if (_actor->_subobjects[i]) {
285 					Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[i]);
286 					subControl->disappearActor();
287 				}
288 			}
289 		}
290 	}
291 }
292 
isActorVisible()293 bool Control::isActorVisible() {
294 	return (_actor->_flags & Illusions::ACTOR_FLAG_IS_VISIBLE) != 0;
295 }
296 
activateObject()297 void Control::activateObject() {
298 	_flags |= 1;
299 	if (_actor) {
300 		for (uint i = 0; i < kSubObjectsCount; ++i) {
301 			if (_actor->_subobjects[i]) {
302 				Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[i]);
303 				subControl->activateObject();
304 			}
305 		}
306 	}
307 }
308 
deactivateObject()309 void Control::deactivateObject() {
310 	_flags &= ~1;
311 	if (_actor) {
312 		for (uint i = 0; i < kSubObjectsCount; ++i) {
313 			if (_actor->_subobjects[i]) {
314 				Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[i]);
315 				subControl->deactivateObject();
316 			}
317 		}
318 	}
319 }
320 
readPointsConfig(byte * pointsConfig)321 void Control::readPointsConfig(byte *pointsConfig) {
322 	_bounds._topLeft.x = READ_LE_UINT16(pointsConfig + 0);
323 	_bounds._topLeft.y = READ_LE_UINT16(pointsConfig + 2);
324 	pointsConfig += 4;
325 	_bounds._bottomRight.x = READ_LE_UINT16(pointsConfig + 0);
326 	_bounds._bottomRight.y = READ_LE_UINT16(pointsConfig + 2);
327 	pointsConfig += 4;
328 	_feetPt.x = READ_LE_UINT16(pointsConfig + 0);
329 	_feetPt.y = READ_LE_UINT16(pointsConfig + 2);
330 	pointsConfig += 4;
331 	_position.x = READ_LE_UINT16(pointsConfig + 0);
332 	_position.y = READ_LE_UINT16(pointsConfig + 2);
333 	pointsConfig += 4;
334 	for (uint i = 0; i < kSubObjectsCount; ++i) {
335 		_subobjectsPos[i].x = READ_LE_UINT16(pointsConfig + 0);
336 		_subobjectsPos[i].y = READ_LE_UINT16(pointsConfig + 2);
337 		pointsConfig += 4;
338 	}
339 }
340 
setActorPosition(Common::Point position)341 void Control::setActorPosition(Common::Point position) {
342 	_actor->_position = position;
343 }
344 
getActorPosition()345 Common::Point Control::getActorPosition() {
346 	if (_actor)
347 		return _actor->_position;
348 	return _position;
349 }
350 
setActorScale(int scale)351 void Control::setActorScale(int scale) {
352 	_actor->_scale = scale;
353 	for (uint i = 0; i < kSubObjectsCount; ++i) {
354 		if (_actor->_subobjects[i]) {
355 			Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[i]);
356 			subControl->setActorScale(scale);
357 		}
358 	}
359 }
360 
faceActor(uint facing)361 void Control::faceActor(uint facing) {
362 	_actor->_facing = facing;
363 	for (uint i = 0; i < kSubObjectsCount; ++i) {
364 		if (_actor->_subobjects[i]) {
365 			Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[i]);
366 			subControl->faceActor(facing);
367 		}
368 	}
369 }
370 
linkToObject(uint32 parentObjectId,uint32 linkedObjectValue)371 void Control::linkToObject(uint32 parentObjectId, uint32 linkedObjectValue) {
372 	_actor->_parentObjectId = parentObjectId;
373 	_actor->_linkIndex = linkedObjectValue;
374 }
375 
unlinkObject()376 void Control::unlinkObject() {
377 	_actor->_parentObjectId = 0;
378 	_actor->_linkIndex = 0;
379 }
380 
clearNotifyThreadId1()381 void Control::clearNotifyThreadId1() {
382 	_actor->_notifyThreadId1 = 0;
383 }
384 
clearNotifyThreadId2()385 void Control::clearNotifyThreadId2() {
386 	for (uint i = 0; i < kSubObjectsCount; ++i) {
387 		if (_actor->_subobjects[i]) {
388 			Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[i]);
389 			subControl->_actor->_flags &= ~Illusions::ACTOR_FLAG_80;
390 			subControl->_actor->_entryTblPtr = 0;
391 			subControl->_actor->_notifyThreadId2 = 0;
392 		}
393 	}
394 	_actor->_flags &= ~Illusions::ACTOR_FLAG_80;
395 	_actor->_entryTblPtr = 0;
396 	_actor->_notifyThreadId2 = 0;
397 }
398 
setPriority(int16 priority)399 void Control::setPriority(int16 priority) {
400 	_priority = priority;
401 }
402 
getPriority()403 uint32 Control::getPriority() {
404 	uint32 objectId;
405 	int16 positionY, priority, priority1;
406 	if (_actor) {
407 		if (_actor->_parentObjectId && (_actor->_flags & Illusions::ACTOR_FLAG_40)) {
408 			uint32 parentObjectId = getSubActorParent();
409 			Control *parentControl = _vm->_dict->getObjectControl(parentObjectId);
410 			objectId = parentControl->_objectId;
411 			priority = parentControl->_priority;
412 			positionY = parentControl->_actor->_position.y;
413 			priority1 = _priority;
414 		} else {
415 			objectId = _objectId;
416 			positionY = _actor->_position.y;
417 			priority = _priority;
418 			priority1 = 50;
419 		}
420 	} else {
421 		positionY = _position.y;
422 		objectId = _objectId;
423 		priority = _priority;
424 		priority1 = 1;
425 	}
426 
427 	priority -= 1;
428 	uint32 p = 50 * priority1 / 100;
429 	if (p)
430 		--p;
431 
432 	positionY = CLIP<int16>(positionY, -5000, 5000);
433 
434 	return p + 50 * ((objectId & 0x3F) + ((10000 * priority + positionY + 5000) << 6));
435 }
436 
getOverlapPriority()437 uint32 Control::getOverlapPriority() {
438 	if (_vm->getGameId() == kGameIdBBDOU)
439 		return getPriority();
440 	return _priority;
441 }
442 
getDrawPriority()443 uint32 Control::getDrawPriority() {
444 	if (_vm->getGameId() == kGameIdBBDOU)
445 		return getPriority();
446 	return (_actor->_position.y + 32768) | (_priority << 16);
447 }
448 
calcPosition(Common::Point posDelta)449 Common::Point Control::calcPosition(Common::Point posDelta) {
450 	Common::Point pos;
451 	if (_actor->_parentObjectId) {
452 		int16 accuX = 0, accuY = 0;
453 		Actor *actor = _actor;
454 		while (actor->_parentObjectId) {
455 			Control *parentControl = _vm->_dict->getObjectControl(actor->_parentObjectId);
456 			accuX += parentControl->_subobjectsPos[actor->_linkIndex - 1].x;
457 			accuY += parentControl->_subobjectsPos[actor->_linkIndex - 1].y;
458 			actor = parentControl->_actor;
459 		}
460 		pos = actor->_position;
461 		pos.x += accuX * actor->_scale / 100;
462 		pos.y += accuY * actor->_scale / 100;
463 		_actor->_position = pos;
464 		if (!(_flags & 8)) {
465 			pos.x -= posDelta.x;
466 			pos.y -= posDelta.y;
467 		}
468 	} else {
469 		pos = _actor->_position;
470 		if (!(_flags & 8)) {
471 			pos.x -= posDelta.x;
472 			pos.y -= posDelta.y;
473 		}
474 	}
475 	return pos;
476 }
477 
getSubActorParent()478 uint32 Control::getSubActorParent() {
479 	uint32 parentObjectId = _objectId;
480 	while (1) {
481 		Actor *actor = _vm->_dict->getObjectControl(parentObjectId)->_actor;
482 		if (actor->_parentObjectId && (actor->_flags & Illusions::ACTOR_FLAG_40))
483 			parentObjectId = actor->_parentObjectId;
484 		else
485 			break;
486 	}
487 	return parentObjectId;
488 }
489 
getCollisionRectAccurate(Common::Rect & collisionRect)490 void Control::getCollisionRectAccurate(Common::Rect &collisionRect) {
491 
492 	if (_actor && _actor->_frameIndex) {
493 		collisionRect = Common::Rect(-_position.x, -_position.y,
494 			-_position.x + _actor->_surfInfo._dimensions._width - 1,
495 			-_position.y + _actor->_surfInfo._dimensions._height - 1);
496 	} else {
497 		collisionRect = Common::Rect(_bounds._topLeft.x, _bounds._topLeft.y, _bounds._bottomRight.x, _bounds._bottomRight.y);
498 	}
499 
500 	if (_actor) {
501 		if (_actor->_scale != 100) {
502 			collisionRect.left = collisionRect.left * _actor->_scale / 100;
503 			collisionRect.top = collisionRect.top * _actor->_scale / 100;
504 			collisionRect.right = collisionRect.right * _actor->_scale / 100;
505 			collisionRect.bottom = collisionRect.bottom * _actor->_scale / 100;
506 		}
507 		collisionRect.translate(_actor->_position.x, _actor->_position.y);
508 	}
509 
510 	if (_flags & 8) {
511 		Common::Point screenOffs = _vm->_camera->getScreenOffset();
512 		collisionRect.translate(screenOffs.x, screenOffs.y);
513 	}
514 
515 }
516 
getCollisionRect(Common::Rect & collisionRect)517 void Control::getCollisionRect(Common::Rect &collisionRect) {
518 	collisionRect = Common::Rect(_bounds._topLeft.x, _bounds._topLeft.y, _bounds._bottomRight.x, _bounds._bottomRight.y);
519 	if (_actor) {
520 		if (_actor->_scale != 100) {
521 			collisionRect.left = collisionRect.left * _actor->_scale / 100;
522 			collisionRect.top = collisionRect.top * _actor->_scale / 100;
523 			collisionRect.right = collisionRect.right * _actor->_scale / 100;
524 			collisionRect.bottom = collisionRect.bottom * _actor->_scale / 100;
525 		}
526 		collisionRect.translate(_actor->_position.x, _actor->_position.y);
527 	}
528 	if (_flags & 8) {
529 		Common::Point screenOffs = _vm->_camera->getScreenOffset();
530 		collisionRect.translate(screenOffs.x, screenOffs.y);
531 	}
532 }
533 
setActorUsePan(int usePan)534 void Control::setActorUsePan(int usePan) {
535 	if (usePan == 1)
536 		_flags &= ~8;
537 	else
538 		_flags |= 8;
539 }
540 
setActorFrameIndex(int16 frameIndex)541 void Control::setActorFrameIndex(int16 frameIndex) {
542 	if (frameIndex) {
543 		_actor->_frameIndex = frameIndex;
544 		const Frame &frame = (*_actor->_frames)[frameIndex - 1];
545 		_actor->_surfInfo = frame._surfInfo;
546 		readPointsConfig(frame._pointsConfig);
547 		_actor->_flags |= Illusions::ACTOR_FLAG_2000;
548 		_actor->_flags |= Illusions::ACTOR_FLAG_4000;
549 		_actor->_newFrameIndex = 0;
550 	}
551 }
552 
stopActor()553 void Control::stopActor() {
554 	_actor->_seqCodeIp = 0;
555 	if (_actor->_pathNode) {
556 		if (_actor->_flags & Illusions::ACTOR_FLAG_400) {
557 			delete _actor->_pathNode;
558 			_actor->_flags &= ~Illusions::ACTOR_FLAG_400;
559 		}
560 		_actor->_pathNode = 0;
561 		_actor->_pathPoints = 0;
562 		_actor->_pathPointsCount = 0;
563 		_actor->_pathPointIndex = 0;
564 		_actor->_walkCallerThreadId1 = 0;
565 	}
566 	if (_vm->getGameId() == kGameIdBBDOU) {
567 		_vm->notifyThreadId(_actor->_notifyId3C);
568 		_vm->notifyThreadId(_actor->_notifyThreadId1);
569 	}
570 }
571 
startSequenceActor(uint32 sequenceId,int value,uint32 notifyThreadId)572 void Control::startSequenceActor(uint32 sequenceId, int value, uint32 notifyThreadId) {
573 	startSequenceActorIntern(sequenceId, value, 0, notifyThreadId);
574 }
575 
stopSequenceActor()576 void Control::stopSequenceActor() {
577 	if (_actor->_flags & Illusions::ACTOR_FLAG_40) {
578 		stopActor();
579 		_actor->_frameIndex = 0;
580 		if ((_actor->_flags & Illusions::ACTOR_FLAG_IS_VISIBLE) || (_actor->_flags & Illusions::ACTOR_FLAG_1000)) {
581 			_actor->_flags &= ~Illusions::ACTOR_FLAG_IS_VISIBLE;
582 			_actor->_flags |= Illusions::ACTOR_FLAG_1000;
583 		}
584 	}
585 	for (uint i = 0; i < kSubObjectsCount; ++i) {
586 		if (_actor->_subobjects[i]) {
587 			Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[i]);
588 			subControl->stopSequenceActor();
589 		}
590 	}
591 }
592 
startTalkActor(uint32 sequenceId,byte * entryTblPtr,uint32 threadId)593 void Control::startTalkActor(uint32 sequenceId, byte *entryTblPtr, uint32 threadId) {
594 	bool doSeq = true;
595 	if (_actor->_linkIndex2) {
596 		Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[_actor->_linkIndex2 - 1]);
597 		if (subControl->_actor->_flags & Illusions::ACTOR_FLAG_IS_VISIBLE) {
598 			if (_actor->_pathNode) {
599 				doSeq = false;
600 				subControl->_actor->_notifyThreadId2 = threadId;
601 				subControl->_actor->_entryTblPtr = entryTblPtr;
602 				subControl->_actor->_flags |= Illusions::ACTOR_FLAG_80;
603 				Thread *thread = _vm->_threads->findThread(threadId);
604 				thread->sendMessage(kMsgClearSequenceId2, 0);
605 			}
606 		}
607 	}
608 	if (doSeq)
609 		startSequenceActorIntern(sequenceId, 2, entryTblPtr, threadId);
610 }
611 
sequenceActor()612 void Control::sequenceActor() {
613 	if (_actor->_pauseCtr > 0)
614 		return;
615 
616 	OpCall opCall;
617   	bool sequenceFinished = false;
618 
619 	opCall._result = 0;
620 	_actor->_seqCodeValue3 -= _actor->_seqCodeValue1;
621 
622 	while (_actor->_seqCodeValue3 <= 0 && !sequenceFinished) {
623 		bool breakInner = false;
624 		while (!breakInner) {
625 			//debug(1, "[%08X] SEQ[%08X] op: %08X", _objectId, _actor->_sequenceId, _actor->_seqCodeIp[0]);
626 			opCall._op = _actor->_seqCodeIp[0] & 0x7F;
627 			opCall._opSize = _actor->_seqCodeIp[1];
628 			opCall._code = _actor->_seqCodeIp + 2;
629 			opCall._deltaOfs = opCall._opSize;
630 			if (_actor->_seqCodeIp[0] & 0x80)
631 				breakInner = true;
632 			execSequenceOpcode(opCall);
633 			if (opCall._result == 1) {
634 				sequenceFinished = true;
635 				breakInner = true;
636 			} else if (opCall._result == 2) {
637 				breakInner = true;
638 			}
639 			_actor->_seqCodeIp += opCall._deltaOfs;
640 		}
641 		_actor->_seqCodeValue3 += _actor->_seqCodeValue2;
642 	}
643 
644 	if (_actor->_newFrameIndex != 0) {
645 		//debug(1, "New frame %d", _actor->_newFrameIndex);
646 		setActorFrameIndex(_actor->_newFrameIndex);
647 		if (_vm->getGameId() == kGameIdBBDOU &&
648 			!(_actor->_flags & Illusions::ACTOR_FLAG_IS_VISIBLE) && (_actor->_flags & Illusions::ACTOR_FLAG_1000) && (_objectId != Illusions::CURSOR_OBJECT_ID)) {
649 			appearActor();
650 			_actor->_flags &= ~Illusions::ACTOR_FLAG_1000;
651 		}
652 		//debug(1, "New frame OK");
653 	}
654 
655 	if (sequenceFinished) {
656 		//debug(1, "Sequence has finished");
657 		_actor->_seqCodeIp = 0;
658 	}
659 }
660 
setActorIndex(int actorIndex)661 void Control::setActorIndex(int actorIndex) {
662 	_actor->_actorIndex = actorIndex;
663 }
664 
setActorIndexTo1()665 void Control::setActorIndexTo1() {
666 	_actor->_actorIndex = 1;
667 }
668 
setActorIndexTo2()669 void Control::setActorIndexTo2() {
670 	_actor->_actorIndex = 2;
671 }
672 
startSubSequence(int linkIndex,uint32 sequenceId)673 void Control::startSubSequence(int linkIndex, uint32 sequenceId) {
674 	Control *linkedControl = _vm->_dict->getObjectControl(_actor->_subobjects[linkIndex - 1]);
675 	Actor *linkedActor = linkedControl->_actor;
676 	if (!linkedActor->_entryTblPtr)
677 		linkedActor->_flags &= ~Illusions::ACTOR_FLAG_80;
678 	linkedActor->_flags &= ~Illusions::ACTOR_FLAG_400;
679 	linkedActor->_flags |= Illusions::ACTOR_FLAG_100;
680 	linkedActor->_sequenceId = sequenceId;
681 	linkedActor->_notifyThreadId1 = 0;
682 	linkedActor->_notifyId3C = 0;
683 	linkedActor->_walkCallerThreadId1 = 0;
684 
685 	Sequence *sequence = _vm->_dict->findSequence(sequenceId);
686 	linkedActor->_seqCodeIp = sequence->_sequenceCode;
687 	linkedActor->_frames = _vm->findActorSequenceFrames(sequence);
688 	linkedActor->_seqCodeValue3 = 0;
689 	linkedActor->_seqCodeValue1 = 0;
690 	linkedActor->_seqCodeValue2 = 600;
691 	linkedActor->initSequenceStack();
692 	linkedControl->sequenceActor();
693 	linkedControl->appearActor();
694 }
695 
stopSubSequence(int linkIndex)696 void Control::stopSubSequence(int linkIndex) {
697 	Control *linkedControl = _vm->_dict->getObjectControl(_actor->_subobjects[linkIndex - 1]);
698 	Actor *linkedActor = linkedControl->_actor;
699 	uint32 notifyThreadId2 = _actor->_notifyThreadId2;
700 	_actor->_linkIndex2 = linkIndex;
701 	if (_actor->_entryTblPtr) {
702 		linkedActor->_flags |= Illusions::ACTOR_FLAG_80;
703 		linkedActor->_entryTblPtr = _actor->_entryTblPtr;
704 		linkedActor->_notifyThreadId2 = _actor->_notifyThreadId2;
705 		linkedActor->_seqCodeValue1 = _actor->_seqCodeValue1;
706 		linkedActor->_seqCodeValue3 = _actor->_seqCodeValue3;
707 		_actor->_flags &= ~Illusions::ACTOR_FLAG_80;
708 		_actor->_entryTblPtr = 0;
709 		_actor->_notifyThreadId1 = 0;
710 		_actor->_notifyThreadId2 = 0;
711 	}
712 	if (notifyThreadId2) {
713 		Thread *talkThread = _vm->_threads->findThread(notifyThreadId2);
714 		talkThread->sendMessage(kMsgClearSequenceId2, 0);
715 	}
716 }
717 
startMoveActor(uint32 sequenceId,Common::Point destPt,uint32 callerThreadId1,uint32 callerThreadId2)718 void Control::startMoveActor(uint32 sequenceId, Common::Point destPt, uint32 callerThreadId1, uint32 callerThreadId2) {
719 
720 	PointArray *pathNode;
721 	ActorType *actorType = _vm->_dict->findActorType(_actorTypeId);
722 
723 	_actor->_pathAngle = 0;
724 	_actor->_pathFlag50 = false;
725 	_actor->_seqCodeValue3 = 0;
726 	_actor->_seqCodeValue1 = 0;
727 	_actor->_pathInitialPosFlag = true;
728 
729 	uint newFacing;
730 	if (_vm->calcPointDirection(_actor->_position, destPt, newFacing))
731 		faceActor(newFacing);
732 
733 	if (actorType->_value1E)
734 		_actor->_pathCtrY = actorType->_value1E;
735 	else
736 		_actor->_pathCtrY = 140;
737 
738 	pathNode = createPath(destPt);
739 
740 	if (pathNode->size() == 1 &&
741 		_actor->_position.x == (*pathNode)[0].x &&
742 		_actor->_position.y == (*pathNode)[0].y) {
743 		delete pathNode;
744 		_vm->notifyThreadId(callerThreadId2);
745 	} else {
746 		_actor->_posXShl = _actor->_position.x << 16;
747 		_actor->_posYShl = _actor->_position.y << 16;
748 		startSequenceActor(sequenceId, 1, 0);
749 		_actor->_pathNode = pathNode;
750 		_actor->_pathPointsCount = pathNode->size();
751 		_actor->_pathPoints = pathNode->size();
752 		_actor->_flags |= Illusions::ACTOR_FLAG_400;
753 		_actor->_walkCallerThreadId1 = callerThreadId1;
754 		_vm->notifyThreadId(_actor->_notifyId3C);
755 		_actor->_notifyId3C = callerThreadId2;
756 		_actor->_pathPointIndex = 0;
757 		_vm->_input->discardEvent(kEventSkip);
758 	}
759 
760 }
761 
createPath(Common::Point destPt)762 PointArray *Control::createPath(Common::Point destPt) {
763 	PointArray *walkPoints = (_actor->_flags & Illusions::ACTOR_FLAG_HAS_WALK_POINTS) ? _actor->_pathWalkPoints->_points : 0;
764 	PathLines *walkRects = (_actor->_flags & Illusions::ACTOR_FLAG_HAS_WALK_RECTS) ? _actor->_pathWalkRects->_rects : 0;
765 	PathFinder pathFinder;
766 	WidthHeight bgDimensions = _vm->_backgroundInstances->getMasterBgDimensions();
767 	PointArray *path = pathFinder.findPath(_vm->_camera, _actor->_position, destPt, walkPoints, walkRects, bgDimensions);
768 	return path;
769 }
770 
updateActorMovement(uint32 deltaTime)771 void Control::updateActorMovement(uint32 deltaTime) {
772 	// TODO This needs some cleanup
773 
774 	static const int16 kAngleTbl[] = {60, 0, 120, 0, 60, 0, 120, 0};
775 	bool fastWalked = false;
776 
777 	do {
778 
779 		if (!fastWalked && _vm->testMainActorFastWalk(this)) {
780 			fastWalked = true;
781 			disappearActor();
782 			_actor->_flags |= Illusions::ACTOR_FLAG_8000;
783 			_actor->_seqCodeIp = 0;
784 			deltaTime = 2;
785 		}
786 
787 		if (_vm->testMainActorCollision(this))
788 			break;
789 
790 		Common::Point prevPt;
791 		if (_actor->_pathPointIndex == 0) {
792 			if (_actor->_pathInitialPosFlag) {
793 				_actor->_pathCtrX = 0;
794 				_actor->_pathInitialPos = _actor->_position;
795 				_actor->_pathInitialPosFlag = false;
796 			}
797 			prevPt = _actor->_pathInitialPos;
798 		} else {
799 			prevPt = (*_actor->_pathNode)[_actor->_pathPointIndex - 1];
800 		}
801 
802 		Common::Point currPt = (*_actor->_pathNode)[_actor->_pathPointIndex];
803 
804 		int16 deltaX = currPt.x - prevPt.x;
805 		int16 deltaY = currPt.y - prevPt.y;
806 
807 		if (!_actor->_pathFlag50) {
808 
809 			FixedPoint16 angle;
810 			if (currPt.x == prevPt.x) {
811 				if (prevPt.y >= currPt.y)
812 					angle = fixedMul(-0x5A0000, 0x478);
813 				else
814 					angle = fixedMul(0x5A0000, 0x478);
815 			} else {
816 				angle = fixedAtan(fixedDiv(deltaY << 16, deltaX << 16));
817 			}
818 			_actor->_pathAngle = angle;
819 
820 			int16 v13 = (fixedTrunc(fixedMul(angle, 0x394BB8)) + 360) % 360; // 0x394BB8 is 180 / pi
821 			if (deltaX >= 0)
822 				v13 += 180;
823 			v13 = (v13 + 90) % 360;
824 			int16 v15 = kAngleTbl[0] / -2;
825 			uint newFacing = 1;
826 			for (uint i = 0; i < 8; ++i) {
827 				v15 += kAngleTbl[i];
828 				if (v13 < v15) {
829 					newFacing = 1 << i;
830 					break;
831 				}
832 			}
833 			if (newFacing != _actor->_facing) {
834 				refreshSequenceCode();
835 				faceActor(newFacing);
836 			}
837 
838 			_actor->_pathFlag50 = true;
839 
840 		}
841 
842 		FixedPoint16 deltaX24, deltaY24;
843 
844 		if (_actor->_flags & Illusions::ACTOR_FLAG_400) {
845 
846 			FixedPoint16 v20 = fixedMul((deltaTime + _actor->_pathCtrX) << 16, _actor->_pathCtrY << 16);
847 			FixedPoint16 v21 = fixedDiv(v20, 100 << 16);
848 			FixedPoint16 v22 = fixedMul(v21, _actor->_scale << 16);
849 			FixedPoint16 v23 = fixedDiv(v22, 100 << 16);
850 			_actor->_seqCodeValue1 = 100 * _actor->_pathCtrY * deltaTime / 100;
851 			if (v23) {
852 				FixedPoint16 prevDistance = fixedDistance(prevPt.x << 16, prevPt.y << 16, _actor->_posXShl, _actor->_posYShl);
853 				FixedPoint16 distance = prevDistance + v23;
854 				if (prevPt.x > currPt.x)
855 					distance = -distance;
856 				deltaX24 = fixedMul(fixedCos(_actor->_pathAngle), distance);
857 				deltaY24 = fixedMul(fixedSin(_actor->_pathAngle), distance);
858 			} else {
859 				deltaX24 = _actor->_posXShl - (prevPt.x << 16);
860 				deltaY24 = _actor->_posYShl - (prevPt.y << 16);
861 			}
862 		} else {
863 			if (100 * (int)deltaTime <= _actor->_seqCodeValue2)
864 				break;
865 			deltaX24 = deltaX << 16;
866 			deltaY24 = deltaY << 16;
867 		}
868 
869 		if (ABS(deltaX24) < ABS(deltaX << 16) ||
870 			ABS(deltaY24) < ABS(deltaY << 16)) {
871 			FixedPoint16 newX = (prevPt.x << 16) + deltaX24;
872 			FixedPoint16 newY = (prevPt.y << 16) + deltaY24;
873 			if (newX == _actor->_posXShl &&	newY == _actor->_posYShl) {
874 				_actor->_pathCtrX += deltaTime;
875 			} else {
876 				_actor->_pathCtrX = 0;
877 				_actor->_posXShl = newX;
878 				_actor->_posYShl = newY;
879 				_actor->_position.x = fixedTrunc(_actor->_posXShl);
880 				_actor->_position.y = fixedTrunc(_actor->_posYShl);
881 			}
882 		} else {
883 			_actor->_position = currPt;
884 			_actor->_posXShl = _actor->_position.x << 16;
885 			_actor->_posYShl = _actor->_position.y << 16;
886 			--_actor->_pathPointsCount;
887 			++_actor->_pathPointIndex;
888 			++_actor->_pathPoints;
889 			_actor->_pathInitialPosFlag = true;
890 			if (_actor->_pathPointsCount == 0) {
891 				if (_actor->_flags & Illusions::ACTOR_FLAG_400) {
892 					delete _actor->_pathNode;
893 					_actor->_flags &= ~Illusions::ACTOR_FLAG_400;
894 				}
895 				_actor->_pathNode = 0;
896 				_actor->_pathPoints = 0;
897 				_actor->_pathPointsCount = 0;
898 				_actor->_pathPointIndex = 0;
899 				if (_actor->_notifyId3C) {
900 					_vm->notifyThreadId(_actor->_notifyId3C);
901 					_actor->_walkCallerThreadId1 = 0;
902 				}
903 				fastWalked = false;
904 			}
905 			_actor->_pathFlag50 = false;
906 		}
907 
908 	} while (fastWalked);
909 
910 }
911 
refreshSequenceCode()912 void Control::refreshSequenceCode() {
913 	Sequence *sequence = _vm->_dict->findSequence(_actor->_sequenceId);
914 	_actor->_seqCodeIp = sequence->_sequenceCode;
915 }
916 
getActorFrameDimensions(WidthHeight & dimensions)917 void Control::getActorFrameDimensions(WidthHeight &dimensions) {
918 	dimensions._width = _actor->_surface->w;
919 	dimensions._height = _actor->_surface->h;
920 }
921 
drawActorRect(const Common::Rect r,byte color)922 void Control::drawActorRect(const Common::Rect r, byte color) {
923 	_vm->_screen->fillSurfaceRect(_actor->_surface, r, color);
924 	_actor->_flags |= Illusions::ACTOR_FLAG_4000;
925 }
926 
fillActor(byte color)927 void Control::fillActor(byte color) {
928 	_vm->_screen->fillSurface(_actor->_surface, color);
929 	_actor->_flags |= Illusions::ACTOR_FLAG_4000;
930 }
931 
isPixelCollision(Common::Point & pt)932 bool Control::isPixelCollision(Common::Point &pt) {
933 	Frame *frame = &(*_actor->_frames)[_actor->_frameIndex - 1];
934 	return _vm->_screen->isSpritePixelSolid(pt, _position, _actor->_position,
935 		_actor->_surfInfo, _actor->_scale, frame->_flags, frame->_compressedPixels);
936 }
937 
startSequenceActorIntern(uint32 sequenceId,int value,byte * entryTblPtr,uint32 notifyThreadId)938 void Control::startSequenceActorIntern(uint32 sequenceId, int value, byte *entryTblPtr, uint32 notifyThreadId) {
939 	stopActor();
940 
941 	_actor->_flags &= ~Illusions::ACTOR_FLAG_80;
942 	_actor->_flags &= ~Illusions::ACTOR_FLAG_400;
943 	_actor->_flags |= Illusions::ACTOR_FLAG_100;
944 
945 	sequenceId = _actor->_defaultSequences.use(sequenceId);
946 
947 	_actor->_sequenceId = sequenceId;
948 	_actor->_notifyThreadId1 = notifyThreadId;
949 	_actor->_notifyId3C = 0;
950 	_actor->_walkCallerThreadId1 = 0;
951 	_actor->_entryTblPtr = 0;
952 
953 	Sequence *sequence = _vm->_dict->findSequence(sequenceId);
954 
955 	if (!sequence && _vm->getGameId() == kGameIdDuckman) {
956 		//debug(1, "Load external sequence...");
957 		_vm->_resSys->loadResource(0x00060000 | (sequenceId & 0xFFFF), _vm->getCurrentScene(), 0);
958 		sequence = _vm->_dict->findSequence(sequenceId);
959 		_actor->_flags |= Illusions::ACTOR_FLAG_800;
960 	}
961 
962 	_actor->_seqCodeIp = sequence->_sequenceCode;
963 	_actor->_frames = _vm->findActorSequenceFrames(sequence);
964 
965 	_actor->_seqCodeValue3 = 0;
966 	_actor->_seqCodeValue1 = 0;
967 
968 	if (_vm->getGameId() == kGameIdBBDOU) {
969 		_actor->_seqCodeValue2 = value == 1 ? 350 : 600;
970 	} else if (_vm->getGameId() == kGameIdDuckman) {
971 		_actor->_seqCodeValue2 = value == 1 ? 350 : 750;
972 	}
973 
974 	_actor->initSequenceStack();
975 
976 	if (_vm->getGameId() == kGameIdBBDOU)
977 		stopSequenceActor();
978 
979 	_actor->_linkIndex2 = 0;
980 
981 	if (entryTblPtr) {
982 		_actor->_flags |= Illusions::ACTOR_FLAG_80;
983 		_actor->_entryTblPtr = entryTblPtr;
984 		if (_vm->getGameId() == kGameIdBBDOU) {
985 			_actor->_notifyThreadId1 = 0;
986 			_actor->_notifyThreadId2 = notifyThreadId;
987 		}
988 	}
989 
990 	if (_vm->getGameId() == kGameIdBBDOU)
991 		sequenceActor();
992 
993 }
994 
execSequenceOpcode(OpCall & opCall)995 void Control::execSequenceOpcode(OpCall &opCall) {
996 	_vm->_controls->_sequenceOpcodes->execOpcode(this, opCall);
997 }
998 
999 // Controls
1000 
Controls(IllusionsEngine * vm)1001 Controls::Controls(IllusionsEngine *vm)
1002 	: _vm(vm) {
1003 	_sequenceOpcodes = new SequenceOpcodes(_vm);
1004 	_nextTempObjectId = 0;
1005 }
1006 
~Controls()1007 Controls::~Controls() {
1008 	delete _sequenceOpcodes;
1009 	destroyControls();
1010 }
1011 
placeBackgroundObject(BackgroundObject * backgroundObject)1012 void Controls::placeBackgroundObject(BackgroundObject *backgroundObject) {
1013 	Control *control = newControl();
1014 	control->_objectId = backgroundObject->_objectId;
1015 	control->_flags = backgroundObject->_flags;
1016 	control->_priority = backgroundObject->_priority;
1017 	control->readPointsConfig(backgroundObject->_pointsConfig);
1018 	control->activateObject();
1019 	_controls.push_front(control);
1020 	_vm->_dict->setObjectControl(control->_objectId, control);
1021 	debug(0, "Added background control. objectId: %08X", control->_objectId);
1022 }
1023 
placeActor(uint32 actorTypeId,Common::Point placePt,uint32 sequenceId,uint32 objectId,uint32 notifyThreadId)1024 void Controls::placeActor(uint32 actorTypeId, Common::Point placePt, uint32 sequenceId, uint32 objectId, uint32 notifyThreadId) {
1025 	Control *control = newControl();
1026 	Actor *actor = newActor();
1027 	ActorType *actorType = _vm->_dict->findActorType(actorTypeId);
1028 
1029 	control->_objectId = objectId;
1030 	control->_flags = actorType->_flags;
1031 	control->_priority = actorType->_priority;
1032 	control->readPointsConfig(actorType->_pointsConfig);
1033 	control->_actorTypeId = actorTypeId;
1034 	control->_actor = actor;
1035 
1036 	if (_vm->isCursorObject(actorTypeId, objectId))
1037 		_vm->setCursorControlRoutine(control);
1038 
1039 	if (actorType->_surfInfo._dimensions._width > 0 || actorType->_surfInfo._dimensions._height > 0) {
1040 		actor->createSurface(actorType->_surfInfo);
1041 	} else {
1042 		actor->_flags |= Illusions::ACTOR_FLAG_200;
1043 	}
1044 
1045 	actor->_position = placePt;
1046 	actor->_position2 = placePt;
1047 	Common::Point currPan = _vm->_camera->getCurrentPan();
1048 	if (!_vm->calcPointDirection(placePt, currPan, actor->_facing))
1049 		actor->_facing = 64;
1050 	actor->_scale = actorType->_scale;
1051 	actor->_namedPoints = &actorType->_namedPoints;
1052 
1053 	BackgroundResource *bgRes = _vm->_backgroundInstances->getActiveBgResource();
1054 	if (actorType->_pathWalkPointsIndex) {
1055 		actor->_pathWalkPoints = bgRes->getPathWalkPoints(actorType->_pathWalkPointsIndex - 1);
1056 		actor->_flags |= Illusions::ACTOR_FLAG_HAS_WALK_POINTS;
1057 	}
1058 
1059 	if (actorType->_scaleLayerIndex) {
1060 		actor->_scaleLayer = bgRes->getScaleLayer(actorType->_scaleLayerIndex - 1);
1061 		actor->_flags |= Illusions::ACTOR_FLAG_SCALED;
1062 	}
1063 
1064 	if (actorType->_pathWalkRectIndex) {
1065 		actor->_pathWalkRects = bgRes->getPathWalkRects(actorType->_pathWalkRectIndex - 1);
1066 		actor->_flags |= Illusions::ACTOR_FLAG_HAS_WALK_RECTS;
1067 	}
1068 
1069 	if (actorType->_priorityLayerIndex) {
1070 		actor->_priorityLayer = bgRes->getPriorityLayer(actorType->_priorityLayerIndex - 1);
1071 		actor->_flags |= Illusions::ACTOR_FLAG_PRIORITY;
1072 	}
1073 
1074 	if (actorType->_regionLayerIndex) {
1075 		actor->_regionLayer = bgRes->getRegionLayer(actorType->_regionLayerIndex - 1);
1076 		actor->_flags |= Illusions::ACTOR_FLAG_REGION;
1077 	}
1078 
1079 	actor->_pathCtrY = 140;
1080 
1081 	_controls.push_front(control);
1082 	_vm->_dict->setObjectControl(objectId, control);
1083 
1084 	if (_vm->getGameId() == kGameIdDuckman) {
1085 		control->appearActor();
1086 	} else if (_vm->getGameId() == kGameIdBBDOU) {
1087 		control->_flags |= 0x01;
1088 		actor->_flags |= Illusions::ACTOR_FLAG_1000;
1089 	}
1090 
1091 	if (_vm->isCursorObject(actorTypeId, objectId))
1092 		_vm->placeCursorControl(control, sequenceId);
1093 
1094 	// TODO HACK at least we should restrict this to the sequenceId
1095 	control->setActorIndex(1);
1096 
1097 	control->startSequenceActor(sequenceId, 2, notifyThreadId);
1098 }
1099 
placeSequenceLessActor(uint32 objectId,Common::Point placePt,WidthHeight dimensions,int16 priority)1100 void Controls::placeSequenceLessActor(uint32 objectId, Common::Point placePt, WidthHeight dimensions, int16 priority) {
1101 	Control *control = newControl();
1102 	Actor *actor = newActor();
1103 	control->_flags = 0;
1104 	control->_priority = priority;
1105 	control->_objectId = objectId;
1106 	control->_bounds._topLeft.x = 0;
1107 	control->_bounds._topLeft.y = 0;
1108 	control->_bounds._bottomRight.x = dimensions._width - 1;
1109 	control->_bounds._bottomRight.y = dimensions._height - 1;
1110 	control->_feetPt.x = dimensions._width / 2;
1111 	control->_feetPt.y = dimensions._height / 2;
1112 	control->_position.x = 0;
1113 	control->_position.y = 0;
1114 	control->_actorTypeId = 0x50004;
1115 	control->_actor = actor;
1116 	actor->setControlRoutine(0);
1117 	actor->_surfInfo._pixelSize = dimensions._width * dimensions._height;
1118 	actor->_surfInfo._dimensions = dimensions;
1119 	actor->createSurface(actor->_surfInfo);
1120 	actor->_position = placePt;
1121 	actor->_position2 = placePt;
1122 	actor->_facing = 64;
1123 	actor->_scale = 100;
1124 	actor->_namedPoints = 0;
1125 	actor->_pathCtrY = 140;
1126 
1127 	_controls.push_front(control);
1128 	_vm->_dict->setObjectControl(objectId, control);
1129 	control->appearActor();
1130 }
1131 
placeActorLessObject(uint32 objectId,Common::Point feetPt,Common::Point pt,int16 priority,uint flags)1132 void Controls::placeActorLessObject(uint32 objectId, Common::Point feetPt, Common::Point pt, int16 priority, uint flags) {
1133 	Control *control = newControl();
1134 	control->_flags = flags;
1135 	control->_feetPt = feetPt;
1136 	control->_priority = priority;
1137 	control->_objectId = objectId;
1138 	control->_bounds._topLeft = feetPt;
1139 	control->_bounds._bottomRight = pt;
1140 	control->_position.x = 0;
1141 	control->_position.y = 0;
1142 	control->_actorTypeId = 0;
1143 	control->_actor = 0;
1144 	_controls.push_front(control);
1145 	_vm->_dict->setObjectControl(objectId, control);
1146 }
1147 
placeSubActor(uint32 objectId,int linkIndex,uint32 actorTypeId,uint32 sequenceId)1148 void Controls::placeSubActor(uint32 objectId, int linkIndex, uint32 actorTypeId, uint32 sequenceId) {
1149 	Control *parentControl = _vm->_dict->getObjectControl(objectId);
1150 	uint32 tempObjectId = newTempObjectId();
1151 	placeActor(actorTypeId, Common::Point(0, 0), sequenceId, tempObjectId, 0);
1152 	parentControl->_actor->_subobjects[linkIndex - 1] = tempObjectId;
1153 	Actor *subActor = _vm->_dict->getObjectControl(tempObjectId)->_actor;
1154 	subActor->_flags |= Illusions::ACTOR_FLAG_40;
1155 	subActor->_parentObjectId = parentControl->_objectId;
1156 	subActor->_linkIndex = linkIndex;
1157 }
1158 
placeDialogItem(uint16 objectNum,uint32 actorTypeId,uint32 sequenceId,Common::Point placePt,int16 choiceJumpOffs)1159 void Controls::placeDialogItem(uint16 objectNum, uint32 actorTypeId, uint32 sequenceId, Common::Point placePt, int16 choiceJumpOffs) {
1160 	Control *control = newControl();
1161 	Actor *actor = newActor();
1162 	ActorType *actorType = _vm->_dict->findActorType(actorTypeId);
1163 	control->_flags = 0xC;
1164 	control->_priority = actorType->_priority;
1165 	control->_objectId = objectNum | 0x40000;
1166 	control->readPointsConfig(actorType->_pointsConfig);
1167 	control->_actorTypeId = actorTypeId;
1168 	control->_actor = actor;
1169 	actor->setControlRoutine(new Common::Functor2Mem<Control*, uint32, void, Controls>(this, &Controls::dialogItemControlRoutine));
1170 	actor->_choiceJumpOffs = choiceJumpOffs;
1171 	actor->createSurface(actorType->_surfInfo);
1172 	actor->_position = placePt;
1173 	actor->_position2 = placePt;
1174 	actor->_scale = actorType->_scale;
1175 	actor->_color = actorType->_color;
1176 	_controls.push_front(control);
1177 	control->appearActor();
1178 	control->startSequenceActor(sequenceId, 2, 0);
1179 	control->setActorIndex(1);
1180 }
1181 
destroyControls()1182 void Controls::destroyControls() {
1183 	ItemsIterator it = _controls.begin();
1184 	while (it != _controls.end()) {
1185 		destroyControlInternal(*it);
1186 		it = _controls.erase(it);
1187 	}
1188 }
1189 
destroyActiveControls()1190 void Controls::destroyActiveControls() {
1191 	ItemsIterator it = _controls.begin();
1192 	while (it != _controls.end()) {
1193 		if ((*it)->_pauseCtr <= 0) {
1194 			destroyControlInternal(*it);
1195 			it = _controls.erase(it);
1196 		} else
1197 			++it;
1198 	}
1199 }
1200 
destroyControlsBySceneId(uint32 sceneId)1201 void Controls::destroyControlsBySceneId(uint32 sceneId) {
1202 	ItemsIterator it = _controls.begin();
1203 	while (it != _controls.end()) {
1204 		if ((*it)->_sceneId == sceneId) {
1205 			destroyControlInternal(*it);
1206 			it = _controls.erase(it);
1207 		} else
1208 			++it;
1209 	}
1210 }
1211 
destroyDialogItems()1212 void Controls::destroyDialogItems() {
1213 	ItemsIterator it = _controls.begin();
1214 	while (it != _controls.end()) {
1215 		if (((*it)->_pauseCtr == 0) && ((*it)->_flags & 4)) {
1216 			destroyControlInternal(*it);
1217 			it = _controls.erase(it);
1218 		} else
1219 			++it;
1220 	}
1221 }
1222 
threadIsDead(uint32 threadId)1223 void Controls::threadIsDead(uint32 threadId) {
1224 	for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
1225 		Control *control = *it;
1226 		if (control->_actor &&
1227 			(control->_actor->_notifyThreadId1 == threadId || control->_actor->_notifyId3C == threadId)) {
1228 			control->_actor->_notifyThreadId1 = 0;
1229 			control->_actor->_notifyId3C = 0;
1230 		}
1231 	}
1232 }
1233 
pauseControls()1234 void Controls::pauseControls() {
1235 	for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
1236 		Control *control = *it;
1237 		++control->_pauseCtr;
1238 		if (control->_pauseCtr == 1)
1239 			control->pause();
1240 	}
1241 }
1242 
unpauseControls()1243 void Controls::unpauseControls() {
1244 	for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
1245 		Control *control = *it;
1246 		--control->_pauseCtr;
1247 		if (control->_pauseCtr == 0)
1248 			control->unpause();
1249 	}
1250 }
1251 
pauseControlsBySceneId(uint32 sceneId)1252 void Controls::pauseControlsBySceneId(uint32 sceneId) {
1253 	for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
1254 		Control *control = *it;
1255 		if (control->_sceneId == sceneId) {
1256 			++control->_pauseCtr;
1257 			if (control->_pauseCtr == 1)
1258 				control->pause();
1259 		}
1260 	}
1261 }
1262 
unpauseControlsBySceneId(uint32 sceneId)1263 void Controls::unpauseControlsBySceneId(uint32 sceneId) {
1264 	for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
1265 		Control *control = *it;
1266 		if (control->_sceneId == sceneId) {
1267 			--control->_pauseCtr;
1268 			if (control->_pauseCtr == 0)
1269 				control->unpause();
1270 		}
1271 	}
1272 }
1273 
getOverlappedObject(Control * control,Common::Point pt,Control ** outOverlappedControl,int minPriority)1274 bool Controls::getOverlappedObject(Control *control, Common::Point pt, Control **outOverlappedControl, int minPriority) {
1275 	Control *foundControl = 0;
1276 	uint32 foundPriority = 0;
1277 	uint32 minPriorityExt = _vm->getPriorityFromBase(minPriority);
1278 
1279 	for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
1280 		Control *testControl = *it;
1281 		if (testControl != control && testControl->_pauseCtr == 0 &&
1282 			(testControl->_flags & 1) && !(testControl->_flags & 0x10) &&
1283 			(!testControl->_actor || (testControl->_actor->_flags & Illusions::ACTOR_FLAG_IS_VISIBLE))) {
1284 			Common::Rect collisionRect;
1285 			testControl->getCollisionRect(collisionRect);
1286 			if (!collisionRect.isEmpty() && collisionRect.contains(pt)) {
1287 				uint32 testPriority = testControl->getOverlapPriority();
1288 				if ((!foundControl || foundPriority < testPriority) &&
1289 					testPriority >= minPriorityExt) {
1290 					foundControl = testControl;
1291 					foundPriority = testPriority;
1292 				}
1293 			}
1294 		}
1295 	}
1296 
1297 	if (foundControl) {
1298 		if (foundControl->_actor && foundControl->_actor->_parentObjectId && (foundControl->_actor->_flags & Illusions::ACTOR_FLAG_40)) {
1299 			uint32 parentObjectId = foundControl->getSubActorParent();
1300 			foundControl = _vm->_dict->getObjectControl(parentObjectId);
1301 		}
1302 		*outOverlappedControl = foundControl;
1303 	}
1304 
1305 	return foundControl != 0;
1306 }
1307 
getOverlappedObjectAccurate(Control * control,Common::Point pt,Control ** outOverlappedControl,int minPriority)1308 bool Controls::getOverlappedObjectAccurate(Control *control, Common::Point pt, Control **outOverlappedControl, int minPriority) {
1309 	Control *foundControl = 0;
1310 	uint32 foundPriority = 0;
1311 	uint32 minPriorityExt = _vm->getPriorityFromBase(minPriority);
1312 
1313 	for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
1314 		Control *testControl = *it;
1315 		if (testControl != control && testControl->_pauseCtr == 0 &&
1316 			(testControl->_flags & 1) && !(testControl->_flags & 0x10) &&
1317 			(!testControl->_actor || (testControl->_actor->_flags & Illusions::ACTOR_FLAG_IS_VISIBLE))) {
1318 			Common::Rect collisionRect;
1319 			testControl->getCollisionRectAccurate(collisionRect);
1320 			if (!collisionRect.isEmpty() && collisionRect.contains(pt) &&
1321 				(!testControl->_actor || testControl->isPixelCollision(pt))) {
1322 				uint32 testPriority = testControl->getOverlapPriority();
1323 				if ((!foundControl || foundPriority < testPriority) &&
1324 					testPriority >= minPriorityExt) {
1325 					foundControl = testControl;
1326 					foundPriority = testPriority;
1327 				}
1328 			}
1329 		}
1330 	}
1331 
1332 	if (foundControl) {
1333 		if (foundControl->_actor && foundControl->_actor->_parentObjectId && (foundControl->_actor->_flags & Illusions::ACTOR_FLAG_40)) {
1334 			uint32 parentObjectId = foundControl->getSubActorParent();
1335 			foundControl = _vm->_dict->getObjectControl(parentObjectId);
1336 		}
1337 		*outOverlappedControl = foundControl;
1338 	}
1339 
1340 	return foundControl != 0;
1341 }
1342 
getDialogItemAtPos(Control * control,Common::Point pt,Control ** outOverlappedControl)1343 bool Controls::getDialogItemAtPos(Control *control, Common::Point pt, Control **outOverlappedControl) {
1344 	Control *foundControl = 0;
1345 	for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
1346 		Control *testControl = *it;
1347 		if (testControl != control && testControl->_pauseCtr == 0 &&
1348 			(testControl->_flags & 1) && (testControl->_flags & 4)) {
1349 			Common::Rect collisionRect;
1350 			testControl->getCollisionRect(collisionRect);
1351 			if (!collisionRect.isEmpty() && collisionRect.contains(pt) &&
1352 				(!foundControl || foundControl->_priority < testControl->_priority))
1353 				foundControl = testControl;
1354 		}
1355 	}
1356 	*outOverlappedControl = foundControl;
1357 	return foundControl != 0;
1358 }
1359 
getOverlappedWalkObject(Control * control,Common::Point pt,Control ** outOverlappedControl)1360 bool Controls::getOverlappedWalkObject(Control *control, Common::Point pt, Control **outOverlappedControl) {
1361 	Control *foundControl = 0;
1362 	for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
1363 		Control *testControl = *it;
1364 		if (testControl != control && testControl->_pauseCtr == 0 &&
1365 			(testControl->_flags & 1)) {
1366 			Common::Rect collisionRect;
1367 			testControl->getCollisionRect(collisionRect);
1368 			if (!collisionRect.isEmpty() && collisionRect.contains(pt) &&
1369 				(!foundControl || foundControl->_priority < testControl->_priority))
1370 				foundControl = testControl;
1371 		}
1372 	}
1373 	if (foundControl)
1374 		*outOverlappedControl = foundControl;
1375 	return foundControl != 0;
1376 }
1377 
destroyControl(Control * control)1378 void Controls::destroyControl(Control *control) {
1379 	_controls.remove(control);
1380 	destroyControlInternal(control);
1381 }
1382 
findNamedPoint(uint32 namedPointId,Common::Point & pt)1383 bool Controls::findNamedPoint(uint32 namedPointId, Common::Point &pt) {
1384 	for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
1385 		Control *control = *it;
1386 		if (control->_pauseCtr == 0 && control->_actor && control->_actor->findNamedPoint(namedPointId, pt))
1387 			return true;
1388 	}
1389 	return false;
1390 }
1391 
actorControlRoutine(Control * control,uint32 deltaTime)1392 void Controls::actorControlRoutine(Control *control, uint32 deltaTime) {
1393 
1394 	Actor *actor = control->_actor;
1395 
1396 	if (actor->_pauseCtr > 0)
1397 		return;
1398 
1399 	if (control->_actor->_pathNode) {
1400 		control->updateActorMovement(deltaTime);
1401 	} else {
1402 		actor->_seqCodeValue1 = 100 * deltaTime;
1403 	}
1404 
1405 	if (actor->_flags & Illusions::ACTOR_FLAG_SCALED) {
1406 		int scale = actor->_scaleLayer->getScale(actor->_position);
1407 		control->setActorScale(scale);
1408 	}
1409 
1410 	if (actor->_flags & Illusions::ACTOR_FLAG_PRIORITY) {
1411 		int16 priority = actor->_priorityLayer->getPriority(actor->_position);
1412 		if (priority)
1413 			control->setPriority(priority + 1);
1414 	}
1415 
1416 	if (actor->_flags & Illusions::ACTOR_FLAG_REGION) {
1417 		// Update transition sequence
1418 		int regionIndex = actor->_regionLayer->getRegionIndex(actor->_position);
1419 		if (actor->_regionIndex != regionIndex) {
1420 			if (regionIndex) {
1421 				uint32 savedSequenceId = actor->_sequenceId;
1422 				byte *savedSeqCodeIp = actor->_seqCodeIp;
1423 				int savedSeqCodeValue1 = actor->_seqCodeValue1;
1424 				int savedSeqCodeValue3 = actor->_seqCodeValue3;
1425 				uint32 regionSequenceId = actor->_regionLayer->getRegionSequenceId(regionIndex);
1426 				//debug(1, "Running transition sequence %08X", regionSequenceId);
1427 				Sequence *sequence = _vm->_dict->findSequence(regionSequenceId);
1428 				actor->_sequenceId = regionSequenceId;
1429 				actor->_seqCodeIp = sequence->_sequenceCode;
1430 				actor->_seqCodeValue3 = 0;
1431 				control->sequenceActor();
1432 				actor->_sequenceId = savedSequenceId;
1433 				actor->_seqCodeIp = savedSeqCodeIp;
1434 				actor->_seqCodeValue3 = savedSeqCodeValue3;
1435 				actor->_seqCodeValue1 = savedSeqCodeValue1;
1436 			}
1437 			actor->_regionIndex = regionIndex;
1438 		}
1439 	}
1440 
1441 }
1442 
dialogItemControlRoutine(Control * control,uint32 deltaTime)1443 void Controls::dialogItemControlRoutine(Control *control, uint32 deltaTime) {
1444 	Actor *actor = control->_actor;
1445 	if (actor->_pauseCtr <= 0)
1446 		actor->_seqCodeValue1 = 100 * deltaTime;
1447 }
1448 
newActor()1449 Actor *Controls::newActor() {
1450 	return new Actor(_vm);
1451 }
1452 
newControl()1453 Control *Controls::newControl() {
1454 	return new Control(_vm);
1455 }
1456 
newTempObjectId()1457 uint32 Controls::newTempObjectId() {
1458 	uint32 nextTempObjectId1 = _nextTempObjectId;
1459 	uint32 nextTempObjectId2 = _nextTempObjectId + 0x1000;
1460 	if (nextTempObjectId2 > 0xFFFF) {
1461 		nextTempObjectId1 = 0;
1462 		nextTempObjectId2 = 0x1000;
1463 	}
1464 	_nextTempObjectId = nextTempObjectId1 + 1;
1465 	return nextTempObjectId2 | 0x40000;
1466 }
1467 
destroyControlInternal(Control * control)1468 void Controls::destroyControlInternal(Control *control) {
1469 
1470 	if ((_vm->getGameId() == kGameIdBBDOU || !(control->_flags & 4)) && control->_pauseCtr <= 0)
1471 		_vm->_dict->setObjectControl(control->_objectId, 0);
1472 
1473 	if ((_vm->getGameId() == kGameIdBBDOU || !(control->_flags & 4)) && control->_objectId == Illusions::CURSOR_OBJECT_ID && control->_pauseCtr <= 0)
1474 		_vm->setCursorControl(0);
1475 
1476 	if (control->_actor) {
1477 		if (control->_actor->_pathNode && (control->_actor->_flags & Illusions::ACTOR_FLAG_400))
1478 			delete control->_actor->_pathNode;
1479 		if (!(control->_actor->_flags & Illusions::ACTOR_FLAG_200))
1480 			control->_actor->destroySurface();
1481 		delete control->_actor;
1482 		control->_actor = 0;
1483 	}
1484 
1485 	delete control;
1486 }
1487 
disappearActors()1488 void Controls::disappearActors() {
1489 	for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
1490 		Control *control = *it;
1491 		if (control->_flags & 4 && control->_pauseCtr == 0) {
1492 			control->disappearActor();
1493 		}
1494 	}
1495 	Control *control = _vm->_dict->getObjectControl(0x40148);
1496 	if (control) {
1497 		control->disappearActor();
1498 	}
1499 }
1500 
appearActors()1501 void Controls::appearActors() {
1502 	for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
1503 		Control *control = *it;
1504 		if (control->_flags & 4 && control->_pauseCtr == 0) {
1505 			control->appearActor();
1506 		}
1507 	}
1508 	Control *control = _vm->_dict->getObjectControl(0x40148);
1509 	if (control) {
1510 		control->appearActor();
1511 	}
1512 }
1513 
pauseActors(uint32 objectId)1514 void Controls::pauseActors(uint32 objectId) {
1515 	for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
1516 		Control *control = *it;
1517 		if (control->_actor && control->_objectId != objectId) {
1518 			control->_actor->pause();
1519 		}
1520 	}
1521 }
1522 
unpauseActors(uint32 objectId)1523 void Controls::unpauseActors(uint32 objectId) {
1524 	for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
1525 		Control *control = *it;
1526 		if (control->_actor && control->_objectId != objectId) {
1527 			control->_actor->unpause();
1528 		}
1529 	}
1530 	_vm->_unpauseControlActorFlag = true;
1531 }
1532 
1533 
1534 } // End of namespace Illusions
1535