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