scummvm/engines/illusions/actor.cpp
2018-07-20 06:43:33 +00:00

1555 lines
45 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "illusions/illusions.h"
#include "illusions/actor.h"
#include "illusions/camera.h"
#include "illusions/cursor.h"
#include "illusions/dictionary.h"
#include "illusions/fixedpoint.h"
#include "illusions/input.h"
#include "illusions/screen.h"
#include "illusions/scriptopcodes.h"
#include "illusions/sequenceopcodes.h"
#include "illusions/thread.h"
#include "illusions/threads/talkthread.h"
namespace Illusions {
// DefaultSequences
uint32 DefaultSequences::use(uint32 sequenceId) {
ItemsIterator it = Common::find_if(_items.begin(), _items.end(), DefaultSequenceEqual(sequenceId));
return it != _items.end() ? (*it)._newSequenceId : sequenceId;
}
void DefaultSequences::set(uint32 sequenceId, uint32 newSequenceId) {
ItemsIterator it = Common::find_if(_items.begin(), _items.end(), DefaultSequenceEqual(sequenceId));
if (it == _items.end())
_items.push_back(DefaultSequence(sequenceId, newSequenceId));
else if (sequenceId == newSequenceId)
_items.remove_at(it - _items.begin());
else
(*it)._newSequenceId = newSequenceId;
}
// Actor
Actor::Actor(IllusionsEngine *vm)
: _vm(vm), _pauseCtr(0) {
_pauseCtr = 0;
_spriteFlags = 0;
_drawFlags = 0;
_flags = 0;
_scale = 100;
_frameIndex = 0;
_newFrameIndex = 0;
_surfInfo._pixelSize = 0;
_surfInfo._dimensions._width = 0;
_surfInfo._dimensions._height = 0;
_surface = 0;
_frames = 0;
_scaleLayer = 0;
_priorityLayer = 0;
_regionLayer = 0;
_pathWalkPoints = 0;
_pathWalkRects = 0;
_position.x = 0;
_position.y = 0;
_position2.x = 0;
_position2.y = 0;
_facing = 64;
_regionIndex = 0;
_fontId = 0;
_actorIndex = 0;
_parentObjectId = 0;
_linkIndex = 0;
_linkIndex2 = 0;
for (uint i = 0; i < kSubObjectsCount; ++i) {
_subobjects[i] = 0;
}
_notifyThreadId1 = 0;
_notifyThreadId2 = 0;
_surfaceTextFlag = 0;
_entryTblPtr = 0;
_seqCodeIp = 0;
_sequenceId = 0;
_seqCodeValue1 = 0;
_seqCodeValue2 = 600;
_seqCodeValue3 = 0;
_notifyId3C = 0;
_controlRoutine = 0;
setControlRoutine(new Common::Functor2Mem<Control*, uint32, void, Controls>(_vm->_controls, &Controls::actorControlRoutine));
_walkCallerThreadId1 = 0;
_pathAngle = 0;
_pathFlag50 = false;
_pathCtrX = 0;
_pathCtrY = 0;
_pathInitialPosFlag = true;
_pathInitialPos.x = 0;
_pathInitialPos.y = 0;
_pathPoints = 0;
_pathPointIndex = 0;
_pathPointsCount = 0;
_pathNode = 0;
#if 0 // TODO
_field2 = 0;
_field164 = 0;
_field18C = 0;
_field190 = 0;
_field192 = 0;
_field198 = 0;
#endif
}
Actor::~Actor() {
delete _controlRoutine;
}
void Actor::pause() {
++_pauseCtr;
}
void Actor::unpause() {
--_pauseCtr;
}
void Actor::createSurface(SurfInfo &surfInfo) {
_surface = _vm->_screen->allocSurface(surfInfo);
if (_frameIndex) {
if (_surfaceTextFlag) {
/* TODO
Font *font = _vm->findFont(_fontId);
_surface->fillRect(Common::Rect(surfInfo._dimensions._width, surfInfo._dimensions._height), 0);
gfx_sub_40CA70(_surface, font, _field18C, _surfInfo._dimensions, _field198);
*/
_flags |= Illusions::ACTOR_FLAG_4000;
}
else {
_flags |= Illusions::ACTOR_FLAG_2000;
_flags |= Illusions::ACTOR_FLAG_4000;
}
}
}
void Actor::destroySurface() {
if (_surface) {
_surface->free();
delete _surface;
_surface = 0;
}
}
void Actor::initSequenceStack() {
_seqStackCount = 0;
}
void Actor::pushSequenceStack(int16 value) {
_seqStack[_seqStackCount++] = value;
}
int16 Actor::popSequenceStack() {
return _seqStack[--_seqStackCount];
}
void Actor::setControlRoutine(ActorControlRoutine *controlRoutine) {
delete _controlRoutine;
_controlRoutine = controlRoutine;
}
void Actor::runControlRoutine(Control *control, uint32 deltaTime) {
if (_controlRoutine)
(*_controlRoutine)(control, deltaTime);
}
bool Actor::findNamedPoint(uint32 namedPointId, Common::Point &pt) {
if (_namedPoints->findNamedPoint(namedPointId, pt)) {
pt.x += _position.x;
pt.y += _position.y;
return true;
}
return false;
}
// Control
Control::Control(IllusionsEngine *vm)
: _vm(vm) {
_flags = 0;
_pauseCtr = 0;
_priority = 0;
_objectId = 0;
_unkPt.x = 0;
_unkPt.y = 0;
_pt.x = 0;
_pt.y = 0;
_feetPt.x = 0;
_feetPt.y = 0;
_position.x = 0;
_position.y = 0;
_actorTypeId = 0;
_actor = 0;
_sceneId = _vm->getCurrentScene();
}
Control::~Control() {
}
void Control::pause() {
_vm->_dict->setObjectControl(_objectId, 0);
if (_objectId == Illusions::CURSOR_OBJECT_ID)
_vm->setCursorControl(0);
if (_actor && !(_actor->_flags & Illusions::ACTOR_FLAG_200))
_actor->destroySurface();
}
void Control::unpause() {
_vm->_dict->setObjectControl(_objectId, this);
if (_objectId == Illusions::CURSOR_OBJECT_ID)
_vm->setCursorControl(this);
if (_actor && !(_actor->_flags & Illusions::ACTOR_FLAG_200)) {
SurfInfo surfInfo;
ActorType *actorType = _vm->_dict->findActorType(_actorTypeId);
if (actorType)
surfInfo = actorType->_surfInfo;
else
surfInfo = _actor->_surfInfo;
_actor->createSurface(surfInfo);
}
}
void Control::appearActor() {
if (_vm->getGameId() == kGameIdDuckman) {
_flags |= 1;
_actor->_flags |= Illusions::ACTOR_FLAG_IS_VISIBLE;
if (_objectId == Illusions::CURSOR_OBJECT_ID) {
if (_actor->_frameIndex) {
_actor->_flags |= Illusions::ACTOR_FLAG_2000;
_actor->_flags |= Illusions::ACTOR_FLAG_4000;
}
_vm->_input->discardAllEvents();
}
} else {
if (_objectId == Illusions::CURSOR_OBJECT_ID) {
_vm->showCursor();
} else {
if (_actor->_frameIndex || _actorTypeId == 0x50004) {
_actor->_flags |= Illusions::ACTOR_FLAG_IS_VISIBLE;
} else {
_actor->_flags |= Illusions::ACTOR_FLAG_1000;
}
for (uint i = 0; i < kSubObjectsCount; ++i) {
if (_actor->_subobjects[i]) {
Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[i]);
subControl->appearActor();
}
}
}
}
}
void Control::disappearActor() {
if (_vm->getGameId() == kGameIdDuckman) {
_flags &= ~1;
_actor->_flags &= ~Illusions::ACTOR_FLAG_IS_VISIBLE;
} else {
if (_objectId == Illusions::CURSOR_OBJECT_ID) {
_vm->hideCursor();
} else {
_actor->_flags &= ~Illusions::ACTOR_FLAG_IS_VISIBLE;
_actor->_flags &= ~Illusions::ACTOR_FLAG_1000;
for (uint i = 0; i < kSubObjectsCount; ++i) {
if (_actor->_subobjects[i]) {
Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[i]);
subControl->disappearActor();
}
}
}
}
}
bool Control::isActorVisible() {
return (_actor->_flags & Illusions::ACTOR_FLAG_IS_VISIBLE) != 0;
}
void Control::activateObject() {
_flags |= 1;
if (_actor) {
for (uint i = 0; i < kSubObjectsCount; ++i) {
if (_actor->_subobjects[i]) {
Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[i]);
subControl->activateObject();
}
}
}
}
void Control::deactivateObject() {
_flags &= ~1;
if (_actor) {
for (uint i = 0; i < kSubObjectsCount; ++i) {
if (_actor->_subobjects[i]) {
Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[i]);
subControl->deactivateObject();
}
}
}
}
void Control::readPointsConfig(byte *pointsConfig) {
_unkPt.x = READ_LE_UINT16(pointsConfig + 0);
_unkPt.y = READ_LE_UINT16(pointsConfig + 2);
pointsConfig += 4;
_pt.x = READ_LE_UINT16(pointsConfig + 0);
_pt.y = READ_LE_UINT16(pointsConfig + 2);
pointsConfig += 4;
_feetPt.x = READ_LE_UINT16(pointsConfig + 0);
_feetPt.y = READ_LE_UINT16(pointsConfig + 2);
pointsConfig += 4;
_position.x = READ_LE_UINT16(pointsConfig + 0);
_position.y = READ_LE_UINT16(pointsConfig + 2);
pointsConfig += 4;
for (uint i = 0; i < kSubObjectsCount; ++i) {
_subobjectsPos[i].x = READ_LE_UINT16(pointsConfig + 0);
_subobjectsPos[i].y = READ_LE_UINT16(pointsConfig + 2);
pointsConfig += 4;
}
}
void Control::setActorPosition(Common::Point position) {
_actor->_position = position;
}
Common::Point Control::getActorPosition() {
if (_actor)
return _actor->_position;
return _position;
}
void Control::setActorScale(int scale) {
_actor->_scale = scale;
for (uint i = 0; i < kSubObjectsCount; ++i) {
if (_actor->_subobjects[i]) {
Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[i]);
subControl->setActorScale(scale);
}
}
}
void Control::faceActor(uint facing) {
_actor->_facing = facing;
for (uint i = 0; i < kSubObjectsCount; ++i) {
if (_actor->_subobjects[i]) {
Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[i]);
subControl->faceActor(facing);
}
}
}
void Control::linkToObject(uint32 parentObjectId, uint32 linkedObjectValue) {
_actor->_parentObjectId = parentObjectId;
_actor->_linkIndex = linkedObjectValue;
}
void Control::unlinkObject() {
_actor->_parentObjectId = 0;
_actor->_linkIndex = 0;
}
void Control::clearNotifyThreadId1() {
_actor->_notifyThreadId1 = 0;
}
void Control::clearNotifyThreadId2() {
for (uint i = 0; i < kSubObjectsCount; ++i) {
if (_actor->_subobjects[i]) {
Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[i]);
subControl->_actor->_flags &= ~Illusions::ACTOR_FLAG_80;
subControl->_actor->_entryTblPtr = 0;
subControl->_actor->_notifyThreadId2 = 0;
}
}
_actor->_flags &= ~Illusions::ACTOR_FLAG_80;
_actor->_entryTblPtr = 0;
_actor->_notifyThreadId2 = 0;
}
void Control::setPriority(int16 priority) {
_priority = priority;
}
uint32 Control::getPriority() {
uint32 objectId;
int16 positionY, priority, priority1;
if (_actor) {
if (_actor->_parentObjectId && (_actor->_flags & Illusions::ACTOR_FLAG_40)) {
uint32 parentObjectId = getSubActorParent();
Control *parentControl = _vm->_dict->getObjectControl(parentObjectId);
objectId = parentControl->_objectId;
priority = parentControl->_priority;
positionY = parentControl->_actor->_position.y;
priority1 = _priority;
} else {
objectId = _objectId;
positionY = _actor->_position.y;
priority = _priority;
priority1 = 50;
}
} else {
positionY = _position.y;
objectId = _objectId;
priority = _priority;
priority1 = 1;
}
priority -= 1;
uint32 p = 50 * priority1 / 100;
if (p)
--p;
positionY = CLIP<int16>(positionY, -5000, 5000);
return p + 50 * ((objectId & 0x3F) + ((10000 * priority + positionY + 5000) << 6));
}
uint32 Control::getOverlapPriority() {
if (_vm->getGameId() == kGameIdBBDOU)
return getPriority();
return _priority;
}
uint32 Control::getDrawPriority() {
if (_vm->getGameId() == kGameIdBBDOU)
return getPriority();
return (_actor->_position.y + 32768) | (_priority << 16);
}
Common::Point Control::calcPosition(Common::Point posDelta) {
Common::Point pos;
if (_actor->_parentObjectId) {
int16 accuX = 0, accuY = 0;
Actor *actor = _actor;
while (actor->_parentObjectId) {
Control *parentControl = _vm->_dict->getObjectControl(actor->_parentObjectId);
accuX += parentControl->_subobjectsPos[actor->_linkIndex - 1].x;
accuY += parentControl->_subobjectsPos[actor->_linkIndex - 1].y;
actor = parentControl->_actor;
}
pos = actor->_position;
pos.x += accuX * actor->_scale / 100;
pos.y += accuY * actor->_scale / 100;
_actor->_position = pos;
if (!(_flags & 8)) {
pos.x -= posDelta.x;
pos.y -= posDelta.y;
}
} else {
pos = _actor->_position;
if (!(_flags & 8)) {
pos.x -= posDelta.x;
pos.y -= posDelta.y;
}
}
return pos;
}
uint32 Control::getSubActorParent() {
uint32 parentObjectId = _objectId;
while (1) {
Actor *actor = _vm->_dict->getObjectControl(parentObjectId)->_actor;
if (actor->_parentObjectId && (actor->_flags & Illusions::ACTOR_FLAG_40))
parentObjectId = actor->_parentObjectId;
else
break;
}
return parentObjectId;
}
void Control::getCollisionRectAccurate(Common::Rect &collisionRect) {
if (_actor && _actor->_frameIndex) {
collisionRect = Common::Rect(-_position.x, -_position.y,
-_position.x + _actor->_surfInfo._dimensions._width - 1,
-_position.y + _actor->_surfInfo._dimensions._height - 1);
} else {
collisionRect = Common::Rect(_unkPt.x, _unkPt.y, _pt.x, _pt.y);
}
if (_actor) {
if (_actor->_scale != 100) {
collisionRect.left = collisionRect.left * _actor->_scale / 100;
collisionRect.top = collisionRect.top * _actor->_scale / 100;
collisionRect.right = collisionRect.right * _actor->_scale / 100;
collisionRect.bottom = collisionRect.bottom * _actor->_scale / 100;
}
collisionRect.translate(_actor->_position.x, _actor->_position.y);
}
if (_flags & 8) {
Common::Point screenOffs = _vm->_camera->getScreenOffset();
collisionRect.translate(screenOffs.x, screenOffs.y);
}
}
void Control::getCollisionRect(Common::Rect &collisionRect) {
collisionRect = Common::Rect(_unkPt.x, _unkPt.y, _pt.x, _pt.y);
if (_actor) {
if (_actor->_scale != 100) {
collisionRect.left = collisionRect.left * _actor->_scale / 100;
collisionRect.top = collisionRect.top * _actor->_scale / 100;
collisionRect.right = collisionRect.right * _actor->_scale / 100;
collisionRect.bottom = collisionRect.bottom * _actor->_scale / 100;
}
collisionRect.translate(_actor->_position.x, _actor->_position.y);
}
if (_flags & 8) {
Common::Point screenOffs = _vm->_camera->getScreenOffset();
collisionRect.translate(screenOffs.x, screenOffs.y);
}
}
void Control::setActorUsePan(int usePan) {
if (usePan == 1)
_flags &= ~8;
else
_flags |= 8;
}
void Control::setActorFrameIndex(int16 frameIndex) {
if (frameIndex) {
_actor->_frameIndex = frameIndex;
const Frame &frame = (*_actor->_frames)[frameIndex - 1];
_actor->_surfInfo = frame._surfInfo;
readPointsConfig(frame._pointsConfig);
_actor->_flags |= Illusions::ACTOR_FLAG_2000;
_actor->_flags |= Illusions::ACTOR_FLAG_4000;
_actor->_newFrameIndex = 0;
}
}
void Control::stopActor() {
_actor->_seqCodeIp = 0;
if (_actor->_pathNode) {
if (_actor->_flags & Illusions::ACTOR_FLAG_400) {
delete _actor->_pathNode;
_actor->_flags &= ~Illusions::ACTOR_FLAG_400;
}
_actor->_pathNode = 0;
_actor->_pathPoints = 0;
_actor->_pathPointsCount = 0;
_actor->_pathPointIndex = 0;
_actor->_walkCallerThreadId1 = 0;
}
if (_vm->getGameId() == kGameIdBBDOU) {
_vm->notifyThreadId(_actor->_notifyId3C);
_vm->notifyThreadId(_actor->_notifyThreadId1);
}
}
void Control::startSequenceActor(uint32 sequenceId, int value, uint32 notifyThreadId) {
startSequenceActorIntern(sequenceId, value, 0, notifyThreadId);
}
void Control::stopSequenceActor() {
if (_actor->_flags & Illusions::ACTOR_FLAG_40) {
stopActor();
_actor->_frameIndex = 0;
if ((_actor->_flags & Illusions::ACTOR_FLAG_IS_VISIBLE) || (_actor->_flags & Illusions::ACTOR_FLAG_1000)) {
_actor->_flags &= ~Illusions::ACTOR_FLAG_IS_VISIBLE;
_actor->_flags |= Illusions::ACTOR_FLAG_1000;
}
}
for (uint i = 0; i < kSubObjectsCount; ++i) {
if (_actor->_subobjects[i]) {
Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[i]);
subControl->stopSequenceActor();
}
}
}
void Control::startTalkActor(uint32 sequenceId, byte *entryTblPtr, uint32 threadId) {
bool doSeq = true;
if (_actor->_linkIndex2) {
Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[_actor->_linkIndex2 - 1]);
if (subControl->_actor->_flags & Illusions::ACTOR_FLAG_IS_VISIBLE) {
if (_actor->_pathNode) {
doSeq = false;
subControl->_actor->_notifyThreadId2 = threadId;
subControl->_actor->_entryTblPtr = entryTblPtr;
subControl->_actor->_flags |= Illusions::ACTOR_FLAG_80;
Thread *thread = _vm->_threads->findThread(threadId);
thread->sendMessage(kMsgClearSequenceId2, 0);
}
}
}
if (doSeq)
startSequenceActorIntern(sequenceId, 2, entryTblPtr, threadId);
}
void Control::sequenceActor() {
if (_actor->_pauseCtr > 0)
return;
OpCall opCall;
bool sequenceFinished = false;
opCall._result = 0;
_actor->_seqCodeValue3 -= _actor->_seqCodeValue1;
while (_actor->_seqCodeValue3 <= 0 && !sequenceFinished) {
bool breakInner = false;
while (!breakInner) {
//debug(1, "[%08X] SEQ[%08X] op: %08X", _objectId, _actor->_sequenceId, _actor->_seqCodeIp[0]);
opCall._op = _actor->_seqCodeIp[0] & 0x7F;
opCall._opSize = _actor->_seqCodeIp[1];
opCall._code = _actor->_seqCodeIp + 2;
opCall._deltaOfs = opCall._opSize;
if (_actor->_seqCodeIp[0] & 0x80)
breakInner = true;
execSequenceOpcode(opCall);
if (opCall._result == 1) {
sequenceFinished = true;
breakInner = true;
} else if (opCall._result == 2) {
breakInner = true;
}
_actor->_seqCodeIp += opCall._deltaOfs;
}
_actor->_seqCodeValue3 += _actor->_seqCodeValue2;
}
if (_actor->_newFrameIndex != 0) {
//debug(1, "New frame %d", _actor->_newFrameIndex);
setActorFrameIndex(_actor->_newFrameIndex);
if (_vm->getGameId() == kGameIdBBDOU &&
!(_actor->_flags & Illusions::ACTOR_FLAG_IS_VISIBLE) && (_actor->_flags & Illusions::ACTOR_FLAG_1000) && (_objectId != Illusions::CURSOR_OBJECT_ID)) {
appearActor();
_actor->_flags &= ~Illusions::ACTOR_FLAG_1000;
}
//debug(1, "New frame OK");
}
if (sequenceFinished) {
//debug(1, "Sequence has finished");
_actor->_seqCodeIp = 0;
}
}
void Control::setActorIndex(int actorIndex) {
_actor->_actorIndex = actorIndex;
}
void Control::setActorIndexTo1() {
_actor->_actorIndex = 1;
}
void Control::setActorIndexTo2() {
_actor->_actorIndex = 2;
}
void Control::startSubSequence(int linkIndex, uint32 sequenceId) {
Control *linkedControl = _vm->_dict->getObjectControl(_actor->_subobjects[linkIndex - 1]);
Actor *linkedActor = linkedControl->_actor;
if (!linkedActor->_entryTblPtr)
linkedActor->_flags &= ~Illusions::ACTOR_FLAG_80;
linkedActor->_flags &= ~Illusions::ACTOR_FLAG_400;
linkedActor->_flags |= Illusions::ACTOR_FLAG_100;
linkedActor->_sequenceId = sequenceId;
linkedActor->_notifyThreadId1 = 0;
linkedActor->_notifyId3C = 0;
linkedActor->_walkCallerThreadId1 = 0;
Sequence *sequence = _vm->_dict->findSequence(sequenceId);
linkedActor->_seqCodeIp = sequence->_sequenceCode;
linkedActor->_frames = _vm->findActorSequenceFrames(sequence);
linkedActor->_seqCodeValue3 = 0;
linkedActor->_seqCodeValue1 = 0;
linkedActor->_seqCodeValue2 = 600;
linkedActor->initSequenceStack();
linkedControl->sequenceActor();
linkedControl->appearActor();
}
void Control::stopSubSequence(int linkIndex) {
Control *linkedControl = _vm->_dict->getObjectControl(_actor->_subobjects[linkIndex - 1]);
Actor *linkedActor = linkedControl->_actor;
uint32 notifyThreadId2 = _actor->_notifyThreadId2;
_actor->_linkIndex2 = linkIndex;
if (_actor->_entryTblPtr) {
linkedActor->_flags |= Illusions::ACTOR_FLAG_80;
linkedActor->_entryTblPtr = _actor->_entryTblPtr;
linkedActor->_notifyThreadId2 = _actor->_notifyThreadId2;
linkedActor->_seqCodeValue1 = _actor->_seqCodeValue1;
linkedActor->_seqCodeValue3 = _actor->_seqCodeValue3;
_actor->_flags &= ~Illusions::ACTOR_FLAG_80;
_actor->_entryTblPtr = 0;
_actor->_notifyThreadId1 = 0;
_actor->_notifyThreadId2 = 0;
}
if (notifyThreadId2) {
Thread *talkThread = _vm->_threads->findThread(notifyThreadId2);
talkThread->sendMessage(kMsgClearSequenceId2, 0);
}
}
void Control::startMoveActor(uint32 sequenceId, Common::Point destPt, uint32 callerThreadId1, uint32 callerThreadId2) {
PointArray *pathNode;
ActorType *actorType = _vm->_dict->findActorType(_actorTypeId);
_actor->_pathAngle = 0;
_actor->_pathFlag50 = false;
_actor->_seqCodeValue3 = 0;
_actor->_seqCodeValue1 = 0;
// TODO _actor->_field_BC = _actor->_position.x;
// TODO _actor->_field_BE = _actor->_position.x;
_actor->_pathInitialPosFlag = true;
// TODO _actor->_field_C0 = destPt.x;
// TODO _actor->_field_C2 = destPt.y;
uint newFacing;
if (_vm->calcPointDirection(_actor->_position, destPt, newFacing))
faceActor(newFacing);
if (actorType->_value1E)
_actor->_pathCtrY = actorType->_value1E;
else
_actor->_pathCtrY = 140;
pathNode = createPath(destPt);
if (pathNode->size() == 1 &&
_actor->_position.x == (*pathNode)[0].x &&
_actor->_position.y == (*pathNode)[0].y) {
delete pathNode;
_vm->notifyThreadId(callerThreadId2);
} else {
_actor->_posXShl = _actor->_position.x << 16;
_actor->_posYShl = _actor->_position.y << 16;
startSequenceActor(sequenceId, 1, 0);
_actor->_pathNode = pathNode;
_actor->_pathPointsCount = pathNode->size();
_actor->_pathPoints = pathNode->size();
_actor->_flags |= Illusions::ACTOR_FLAG_400;
_actor->_walkCallerThreadId1 = callerThreadId1;
_vm->notifyThreadId(_actor->_notifyId3C);
_actor->_notifyId3C = callerThreadId2;
_actor->_pathPointIndex = 0;
_vm->_input->discardEvent(kEventSkip);
}
}
PointArray *Control::createPath(Common::Point destPt) {
PointArray *walkPoints = (_actor->_flags & Illusions::ACTOR_FLAG_HAS_WALK_POINTS) ? _actor->_pathWalkPoints->_points : 0;
PathLines *walkRects = (_actor->_flags & Illusions::ACTOR_FLAG_HAS_WALK_RECTS) ? _actor->_pathWalkRects->_rects : 0;
PathFinder pathFinder;
WidthHeight bgDimensions = _vm->_backgroundInstances->getMasterBgDimensions();
PointArray *path = pathFinder.findPath(_vm->_camera, _actor->_position, destPt, walkPoints, walkRects, bgDimensions);
return path;
}
void Control::updateActorMovement(uint32 deltaTime) {
// TODO This needs some cleanup
// TODO Move while loop to caller
static const int16 kAngleTbl[] = {60, 0, 120, 0, 60, 0, 120, 0};
bool fastWalked = false;
do {
if (!fastWalked && _vm->testMainActorFastWalk(this)) {
fastWalked = true;
disappearActor();
_actor->_flags |= Illusions::ACTOR_FLAG_8000;
_actor->_seqCodeIp = 0;
deltaTime = 2;
}
if (_vm->testMainActorCollision(this))
break;
Common::Point prevPt;
if (_actor->_pathPointIndex == 0) {
if (_actor->_pathInitialPosFlag) {
_actor->_pathCtrX = 0;
_actor->_pathInitialPos = _actor->_position;
_actor->_pathInitialPosFlag = false;
}
prevPt = _actor->_pathInitialPos;
} else {
prevPt = (*_actor->_pathNode)[_actor->_pathPointIndex - 1];
}
Common::Point currPt = (*_actor->_pathNode)[_actor->_pathPointIndex];
int16 deltaX = currPt.x - prevPt.x;
int16 deltaY = currPt.y - prevPt.y;
if (!_actor->_pathFlag50) {
// TODO Move to own function
FixedPoint16 angle;
if (currPt.x == prevPt.x) {
if (prevPt.y >= currPt.y)
angle = fixedMul(-0x5A0000, 0x478);
else
angle = fixedMul(0x5A0000, 0x478);
} else {
angle = fixedAtan(fixedDiv(deltaY << 16, deltaX << 16));
}
_actor->_pathAngle = angle;
// TODO Move to own function
int16 v13 = (fixedTrunc(fixedMul(angle, 0x394BB8)) + 360) % 360; // 0x394BB8 is 180 / pi
if (deltaX >= 0)
v13 += 180;
v13 = (v13 + 90) % 360;
int16 v15 = kAngleTbl[0] / -2;
uint newFacing = 1;
for (uint i = 0; i < 8; ++i) {
v15 += kAngleTbl[i];
if (v13 < v15) {
newFacing = 1 << i;
break;
}
}
if (newFacing != _actor->_facing) {
refreshSequenceCode();
faceActor(newFacing);
}
_actor->_pathFlag50 = true;
}
FixedPoint16 deltaX24, deltaY24;
if (_actor->_flags & Illusions::ACTOR_FLAG_400) {
FixedPoint16 v20 = fixedMul((deltaTime + _actor->_pathCtrX) << 16, _actor->_pathCtrY << 16);
FixedPoint16 v21 = fixedDiv(v20, 100 << 16);
FixedPoint16 v22 = fixedMul(v21, _actor->_scale << 16);
FixedPoint16 v23 = fixedDiv(v22, 100 << 16);
_actor->_seqCodeValue1 = 100 * _actor->_pathCtrY * deltaTime / 100;
if (v23) {
FixedPoint16 prevDistance = fixedDistance(prevPt.x << 16, prevPt.y << 16, _actor->_posXShl, _actor->_posYShl);
FixedPoint16 distance = prevDistance + v23;
if (prevPt.x > currPt.x)
distance = -distance;
deltaX24 = fixedMul(fixedCos(_actor->_pathAngle), distance);
deltaY24 = fixedMul(fixedSin(_actor->_pathAngle), distance);
} else {
deltaX24 = _actor->_posXShl - (prevPt.x << 16);
deltaY24 = _actor->_posYShl - (prevPt.y << 16);
}
} else {
if (100 * (int)deltaTime <= _actor->_seqCodeValue2)
break;
deltaX24 = deltaX << 16;
deltaY24 = deltaY << 16;
}
if (ABS(deltaX24) < ABS(deltaX << 16) ||
ABS(deltaY24) < ABS(deltaY << 16)) {
FixedPoint16 newX = (prevPt.x << 16) + deltaX24;
FixedPoint16 newY = (prevPt.y << 16) + deltaY24;
if (newX == _actor->_posXShl && newY == _actor->_posYShl) {
_actor->_pathCtrX += deltaTime;
} else {
_actor->_pathCtrX = 0;
_actor->_posXShl = newX;
_actor->_posYShl = newY;
_actor->_position.x = fixedTrunc(_actor->_posXShl);
_actor->_position.y = fixedTrunc(_actor->_posYShl);
}
} else {
_actor->_position = currPt;
_actor->_posXShl = _actor->_position.x << 16;
_actor->_posYShl = _actor->_position.y << 16;
--_actor->_pathPointsCount;
++_actor->_pathPointIndex;
++_actor->_pathPoints;
_actor->_pathInitialPosFlag = true;
if (_actor->_pathPointsCount == 0) {
if (_actor->_flags & Illusions::ACTOR_FLAG_400) {
delete _actor->_pathNode;
_actor->_flags &= ~Illusions::ACTOR_FLAG_400;
}
_actor->_pathNode = 0;
_actor->_pathPoints = 0;
_actor->_pathPointsCount = 0;
_actor->_pathPointIndex = 0;
if (_actor->_notifyId3C) {
_vm->notifyThreadId(_actor->_notifyId3C);
_actor->_walkCallerThreadId1 = 0;
}
fastWalked = false;
}
_actor->_pathFlag50 = false;
}
} while (fastWalked);
}
void Control::refreshSequenceCode() {
Sequence *sequence = _vm->_dict->findSequence(_actor->_sequenceId);
_actor->_seqCodeIp = sequence->_sequenceCode;
}
void Control::getActorFrameDimensions(WidthHeight &dimensions) {
dimensions._width = _actor->_surface->w;
dimensions._height = _actor->_surface->h;
}
void Control::drawActorRect(const Common::Rect r, byte color) {
_actor->_surface->fillRect(r, color);
_actor->_flags |= Illusions::ACTOR_FLAG_4000;
}
void Control::fillActor(byte color) {
_vm->_screen->fillSurface(_actor->_surface, color);
_actor->_flags |= Illusions::ACTOR_FLAG_4000;
}
bool Control::isPixelCollision(Common::Point &pt) {
Frame *frame = &(*_actor->_frames)[_actor->_frameIndex - 1];
return _vm->_screen->isSpritePixelSolid(pt, _position, _actor->_position,
_actor->_surfInfo, _actor->_scale, frame->_flags, frame->_compressedPixels);
}
void Control::startSequenceActorIntern(uint32 sequenceId, int value, byte *entryTblPtr, uint32 notifyThreadId) {
stopActor();
_actor->_flags &= ~Illusions::ACTOR_FLAG_80;
_actor->_flags &= ~Illusions::ACTOR_FLAG_400;
_actor->_flags |= Illusions::ACTOR_FLAG_100;
sequenceId = _actor->_defaultSequences.use(sequenceId);
_actor->_sequenceId = sequenceId;
_actor->_notifyThreadId1 = notifyThreadId;
_actor->_notifyId3C = 0;
_actor->_walkCallerThreadId1 = 0;
_actor->_entryTblPtr = 0;
Sequence *sequence = _vm->_dict->findSequence(sequenceId);
if (!sequence && _vm->getGameId() == kGameIdDuckman) {
//debug(1, "Load external sequence...");
_vm->_resSys->loadResource(0x00060000 | (sequenceId & 0xFFFF), _vm->getCurrentScene(), 0);
sequence = _vm->_dict->findSequence(sequenceId);
_actor->_flags |= Illusions::ACTOR_FLAG_800;
}
_actor->_seqCodeIp = sequence->_sequenceCode;
_actor->_frames = _vm->findActorSequenceFrames(sequence);
_actor->_seqCodeValue3 = 0;
_actor->_seqCodeValue1 = 0;
if (_vm->getGameId() == kGameIdBBDOU) {
_actor->_seqCodeValue2 = value == 1 ? 350 : 600;
} else if (_vm->getGameId() == kGameIdDuckman) {
_actor->_seqCodeValue2 = value == 1 ? 350 : 750;
}
_actor->initSequenceStack();
if (_vm->getGameId() == kGameIdBBDOU)
stopSequenceActor();
_actor->_linkIndex2 = 0;
if (entryTblPtr) {
_actor->_flags |= Illusions::ACTOR_FLAG_80;
_actor->_entryTblPtr = entryTblPtr;
if (_vm->getGameId() == kGameIdBBDOU) {
_actor->_notifyThreadId1 = 0;
_actor->_notifyThreadId2 = notifyThreadId;
}
}
if (_vm->getGameId() == kGameIdBBDOU)
sequenceActor();
}
void Control::execSequenceOpcode(OpCall &opCall) {
// TODO Clean this up
_vm->_controls->_sequenceOpcodes->execOpcode(this, opCall);
}
// Controls
Controls::Controls(IllusionsEngine *vm)
: _vm(vm) {
_sequenceOpcodes = new SequenceOpcodes(_vm);
_nextTempObjectId = 0;
}
Controls::~Controls() {
delete _sequenceOpcodes;
}
void Controls::placeBackgroundObject(BackgroundObject *backgroundObject) {
Control *control = newControl();
control->_objectId = backgroundObject->_objectId;
control->_flags = backgroundObject->_flags;
control->_priority = backgroundObject->_priority;
control->readPointsConfig(backgroundObject->_pointsConfig);
control->activateObject();
_controls.push_front(control);
_vm->_dict->setObjectControl(control->_objectId, control);
debug(0, "Added background control. objectId: %08X", control->_objectId);
}
void Controls::placeActor(uint32 actorTypeId, Common::Point placePt, uint32 sequenceId, uint32 objectId, uint32 notifyThreadId) {
Control *control = newControl();
Actor *actor = newActor();
ActorType *actorType = _vm->_dict->findActorType(actorTypeId);
control->_objectId = objectId;
control->_flags = actorType->_flags;
control->_priority = actorType->_priority;
control->readPointsConfig(actorType->_pointsConfig);
control->_actorTypeId = actorTypeId;
control->_actor = actor;
if (_vm->isCursorObject(actorTypeId, objectId))
_vm->setCursorControlRoutine(control);
if (actorType->_surfInfo._dimensions._width > 0 || actorType->_surfInfo._dimensions._height > 0) {
actor->createSurface(actorType->_surfInfo);
} else {
actor->_flags |= Illusions::ACTOR_FLAG_200;
}
actor->_position = placePt;
actor->_position2 = placePt;
Common::Point currPan = _vm->_camera->getCurrentPan();
if (!_vm->calcPointDirection(placePt, currPan, actor->_facing))
actor->_facing = 64;
actor->_scale = actorType->_scale;
actor->_namedPoints = &actorType->_namedPoints;
BackgroundResource *bgRes = _vm->_backgroundInstances->getActiveBgResource();
if (actorType->_pathWalkPointsIndex) {
actor->_pathWalkPoints = bgRes->getPathWalkPoints(actorType->_pathWalkPointsIndex - 1);
actor->_flags |= Illusions::ACTOR_FLAG_HAS_WALK_POINTS;
}
if (actorType->_scaleLayerIndex) {
actor->_scaleLayer = bgRes->getScaleLayer(actorType->_scaleLayerIndex - 1);
actor->_flags |= Illusions::ACTOR_FLAG_SCALED;
}
if (actorType->_pathWalkRectIndex) {
actor->_pathWalkRects = bgRes->getPathWalkRects(actorType->_pathWalkRectIndex - 1);
actor->_flags |= Illusions::ACTOR_FLAG_HAS_WALK_RECTS;
}
if (actorType->_priorityLayerIndex) {
actor->_priorityLayer = bgRes->getPriorityLayer(actorType->_priorityLayerIndex - 1);
actor->_flags |= Illusions::ACTOR_FLAG_PRIORITY;
}
if (actorType->_regionLayerIndex) {
actor->_regionLayer = bgRes->getRegionLayer(actorType->_regionLayerIndex - 1);
actor->_flags |= Illusions::ACTOR_FLAG_REGION;
}
actor->_pathCtrY = 140;
_controls.push_front(control);
_vm->_dict->setObjectControl(objectId, control);
if (_vm->getGameId() == kGameIdDuckman) {
control->appearActor();
} else if (_vm->getGameId() == kGameIdBBDOU) {
control->_flags |= 0x01;
actor->_flags |= Illusions::ACTOR_FLAG_1000;
}
if (_vm->isCursorObject(actorTypeId, objectId))
_vm->placeCursorControl(control, sequenceId);
// TODO HACK at least we should restrict this to the sequenceId
control->setActorIndex(1);
control->startSequenceActor(sequenceId, 2, notifyThreadId);
}
void Controls::placeSequenceLessActor(uint32 objectId, Common::Point placePt, WidthHeight dimensions, int16 priority) {
Control *control = newControl();
Actor *actor = newActor();
control->_flags = 0;
control->_priority = priority;
control->_objectId = objectId;
control->_unkPt.x = 0;
control->_unkPt.y = 0;
control->_pt.y = dimensions._height - 1;
control->_pt.x = dimensions._width - 1;
control->_feetPt.x = dimensions._width / 2;
control->_feetPt.y = dimensions._height / 2;
control->_position.x = 0;
control->_position.y = 0;
control->_actorTypeId = 0x50004;
control->_actor = actor;
actor->setControlRoutine(0);
actor->_surfInfo._pixelSize = dimensions._width * dimensions._height;
actor->_surfInfo._dimensions = dimensions;
actor->createSurface(actor->_surfInfo);
actor->_position = placePt;
actor->_position2 = placePt;
actor->_facing = 64;
actor->_scale = 100;
actor->_namedPoints = 0;
actor->_pathCtrY = 140;
_controls.push_front(control);
_vm->_dict->setObjectControl(objectId, control);
control->appearActor();
}
void Controls::placeActorLessObject(uint32 objectId, Common::Point feetPt, Common::Point pt, int16 priority, uint flags) {
Control *control = newControl();
control->_flags = flags;
control->_unkPt = feetPt;
control->_feetPt = feetPt;
control->_priority = priority;
control->_objectId = objectId;
control->_pt = pt;
control->_position.x = 0;
control->_position.y = 0;
control->_actorTypeId = 0;
control->_actor = 0;
_controls.push_front(control);
_vm->_dict->setObjectControl(objectId, control);
}
void Controls::placeSubActor(uint32 objectId, int linkIndex, uint32 actorTypeId, uint32 sequenceId) {
Control *parentControl = _vm->_dict->getObjectControl(objectId);
uint32 tempObjectId = newTempObjectId();
placeActor(actorTypeId, Common::Point(0, 0), sequenceId, tempObjectId, 0);
parentControl->_actor->_subobjects[linkIndex - 1] = tempObjectId;
Actor *subActor = _vm->_dict->getObjectControl(tempObjectId)->_actor;
subActor->_flags |= Illusions::ACTOR_FLAG_40;
subActor->_parentObjectId = parentControl->_objectId;
subActor->_linkIndex = linkIndex;
}
void Controls::placeDialogItem(uint16 objectNum, uint32 actorTypeId, uint32 sequenceId, Common::Point placePt, int16 choiceJumpOffs) {
Control *control = newControl();
Actor *actor = newActor();
ActorType *actorType = _vm->_dict->findActorType(actorTypeId);
control->_flags = 0xC;
control->_priority = actorType->_priority;
control->_objectId = objectNum | 0x40000;
control->readPointsConfig(actorType->_pointsConfig);
control->_actorTypeId = actorTypeId;
control->_actor = actor;
actor->setControlRoutine(new Common::Functor2Mem<Control*, uint32, void, Controls>(this, &Controls::dialogItemControlRoutine));
actor->_choiceJumpOffs = choiceJumpOffs;
actor->createSurface(actorType->_surfInfo);
actor->_position = placePt;
actor->_position2 = placePt;
actor->_scale = actorType->_scale;
actor->_color = actorType->_color;
_controls.push_front(control);
control->appearActor();
control->startSequenceActor(sequenceId, 2, 0);
control->setActorIndex(1);
}
void Controls::destroyControls() {
ItemsIterator it = _controls.begin();
while (it != _controls.end()) {
destroyControlInternal(*it);
it = _controls.erase(it);
}
}
void Controls::destroyActiveControls() {
ItemsIterator it = _controls.begin();
while (it != _controls.end()) {
if ((*it)->_pauseCtr <= 0) {
destroyControlInternal(*it);
it = _controls.erase(it);
} else
++it;
}
}
void Controls::destroyControlsBySceneId(uint32 sceneId) {
ItemsIterator it = _controls.begin();
while (it != _controls.end()) {
if ((*it)->_sceneId == sceneId) {
destroyControlInternal(*it);
it = _controls.erase(it);
} else
++it;
}
}
void Controls::destroyDialogItems() {
ItemsIterator it = _controls.begin();
while (it != _controls.end()) {
if (((*it)->_pauseCtr == 0) && ((*it)->_flags & 4)) {
destroyControlInternal(*it);
it = _controls.erase(it);
} else
++it;
}
}
void Controls::threadIsDead(uint32 threadId) {
for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
Control *control = *it;
if (control->_actor &&
(control->_actor->_notifyThreadId1 == threadId || control->_actor->_notifyId3C == threadId)) {
control->_actor->_notifyThreadId1 = 0;
control->_actor->_notifyId3C = 0;
}
}
}
void Controls::pauseControls() {
for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
Control *control = *it;
++control->_pauseCtr;
if (control->_pauseCtr == 1)
control->pause();
}
}
void Controls::unpauseControls() {
for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
Control *control = *it;
--control->_pauseCtr;
if (control->_pauseCtr == 0)
control->unpause();
}
}
void Controls::pauseControlsBySceneId(uint32 sceneId) {
for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
Control *control = *it;
if (control->_sceneId == sceneId) {
++control->_pauseCtr;
if (control->_pauseCtr == 1)
control->pause();
}
}
}
void Controls::unpauseControlsBySceneId(uint32 sceneId) {
for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
Control *control = *it;
if (control->_sceneId == sceneId) {
--control->_pauseCtr;
if (control->_pauseCtr == 0)
control->unpause();
}
}
}
bool Controls::getOverlappedObject(Control *control, Common::Point pt, Control **outOverlappedControl, int minPriority) {
Control *foundControl = 0;
uint32 foundPriority = 0;
uint32 minPriorityExt = _vm->getPriorityFromBase(minPriority);
for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
Control *testControl = *it;
if (testControl != control && testControl->_pauseCtr == 0 &&
(testControl->_flags & 1) && !(testControl->_flags & 0x10) &&
(!testControl->_actor || (testControl->_actor->_flags & Illusions::ACTOR_FLAG_IS_VISIBLE))) {
Common::Rect collisionRect;
testControl->getCollisionRect(collisionRect);
if (!collisionRect.isEmpty() && collisionRect.contains(pt)) {
uint32 testPriority = testControl->getOverlapPriority();
if ((!foundControl || foundPriority < testPriority) &&
testPriority >= minPriorityExt) {
foundControl = testControl;
foundPriority = testPriority;
}
}
}
}
if (foundControl) {
if (foundControl->_actor && foundControl->_actor->_parentObjectId && (foundControl->_actor->_flags & Illusions::ACTOR_FLAG_40)) {
uint32 parentObjectId = foundControl->getSubActorParent();
foundControl = _vm->_dict->getObjectControl(parentObjectId);
}
*outOverlappedControl = foundControl;
}
return foundControl != 0;
}
bool Controls::getOverlappedObjectAccurate(Control *control, Common::Point pt, Control **outOverlappedControl, int minPriority) {
Control *foundControl = 0;
uint32 foundPriority = 0;
uint32 minPriorityExt = _vm->getPriorityFromBase(minPriority);
for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
Control *testControl = *it;
if (testControl != control && testControl->_pauseCtr == 0 &&
(testControl->_flags & 1) && !(testControl->_flags & 0x10) &&
(!testControl->_actor || (testControl->_actor->_flags & Illusions::ACTOR_FLAG_IS_VISIBLE))) {
Common::Rect collisionRect;
testControl->getCollisionRectAccurate(collisionRect);
if (!collisionRect.isEmpty() && collisionRect.contains(pt) &&
(!testControl->_actor || testControl->isPixelCollision(pt))) {
uint32 testPriority = testControl->getOverlapPriority();
if ((!foundControl || foundPriority < testPriority) &&
testPriority >= minPriorityExt) {
foundControl = testControl;
foundPriority = testPriority;
}
}
}
}
if (foundControl) {
if (foundControl->_actor && foundControl->_actor->_parentObjectId && (foundControl->_actor->_flags & Illusions::ACTOR_FLAG_40)) {
uint32 parentObjectId = foundControl->getSubActorParent();
foundControl = _vm->_dict->getObjectControl(parentObjectId);
}
*outOverlappedControl = foundControl;
}
return foundControl != 0;
}
bool Controls::getDialogItemAtPos(Control *control, Common::Point pt, Control **outOverlappedControl) {
Control *foundControl = 0;
for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
Control *testControl = *it;
if (testControl != control && testControl->_pauseCtr == 0 &&
(testControl->_flags & 1) && (testControl->_flags & 4)) {
Common::Rect collisionRect;
testControl->getCollisionRect(collisionRect);
if (!collisionRect.isEmpty() && collisionRect.contains(pt) &&
(!foundControl || foundControl->_priority < testControl->_priority))
foundControl = testControl;
}
}
*outOverlappedControl = foundControl;
return foundControl != 0;
}
bool Controls::getOverlappedWalkObject(Control *control, Common::Point pt, Control **outOverlappedControl) {
Control *foundControl = 0;
for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
Control *testControl = *it;
if (testControl != control && testControl->_pauseCtr == 0 &&
(testControl->_flags & 1)) {
Common::Rect collisionRect;
testControl->getCollisionRect(collisionRect);
if (!collisionRect.isEmpty() && collisionRect.contains(pt) &&
(!foundControl || foundControl->_priority < testControl->_priority))
foundControl = testControl;
}
}
if (foundControl)
*outOverlappedControl = foundControl;
return foundControl != 0;
}
void Controls::destroyControl(Control *control) {
_controls.remove(control);
destroyControlInternal(control);
}
bool Controls::findNamedPoint(uint32 namedPointId, Common::Point &pt) {
for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
Control *control = *it;
if (control->_pauseCtr == 0 && control->_actor && control->_actor->findNamedPoint(namedPointId, pt))
return true;
}
return false;
}
void Controls::actorControlRoutine(Control *control, uint32 deltaTime) {
Actor *actor = control->_actor;
if (actor->_pauseCtr > 0)
return;
if (control->_actor->_pathNode) {
control->updateActorMovement(deltaTime);
} else {
actor->_seqCodeValue1 = 100 * deltaTime;
}
if (actor->_flags & Illusions::ACTOR_FLAG_SCALED) {
int scale = actor->_scaleLayer->getScale(actor->_position);
control->setActorScale(scale);
}
if (actor->_flags & Illusions::ACTOR_FLAG_PRIORITY) {
int16 priority = actor->_priorityLayer->getPriority(actor->_position);
if (priority)
control->setPriority(priority + 1);
}
if (actor->_flags & Illusions::ACTOR_FLAG_REGION) {
// Update transition sequence
int regionIndex = actor->_regionLayer->getRegionIndex(actor->_position);
if (actor->_regionIndex != regionIndex) {
if (regionIndex) {
uint32 savedSequenceId = actor->_sequenceId;
byte *savedSeqCodeIp = actor->_seqCodeIp;
int savedSeqCodeValue1 = actor->_seqCodeValue1;
int savedSeqCodeValue3 = actor->_seqCodeValue3;
uint32 regionSequenceId = actor->_regionLayer->getRegionSequenceId(regionIndex);
//debug(1, "Running transition sequence %08X", regionSequenceId);
Sequence *sequence = _vm->_dict->findSequence(regionSequenceId);
actor->_sequenceId = regionSequenceId;
actor->_seqCodeIp = sequence->_sequenceCode;
actor->_seqCodeValue3 = 0;
control->sequenceActor();
actor->_sequenceId = savedSequenceId;
actor->_seqCodeIp = savedSeqCodeIp;
actor->_seqCodeValue3 = savedSeqCodeValue3;
actor->_seqCodeValue1 = savedSeqCodeValue1;
}
actor->_regionIndex = regionIndex;
}
}
}
void Controls::dialogItemControlRoutine(Control *control, uint32 deltaTime) {
Actor *actor = control->_actor;
if (actor->_pauseCtr <= 0)
actor->_seqCodeValue1 = 100 * deltaTime;
}
Actor *Controls::newActor() {
return new Actor(_vm);
}
Control *Controls::newControl() {
return new Control(_vm);
}
uint32 Controls::newTempObjectId() {
uint32 nextTempObjectId1 = _nextTempObjectId;
uint32 nextTempObjectId2 = _nextTempObjectId + 0x1000;
if (nextTempObjectId2 > 0xFFFF) {
nextTempObjectId1 = 0;
nextTempObjectId2 = 0x1000;
}
_nextTempObjectId = nextTempObjectId1 + 1;
return nextTempObjectId2 | 0x40000;
}
void Controls::destroyControlInternal(Control *control) {
if (!(control->_flags & 4) && control->_pauseCtr <= 0)
_vm->_dict->setObjectControl(control->_objectId, 0);
if (!(control->_flags & 4) && control->_objectId == Illusions::CURSOR_OBJECT_ID && control->_pauseCtr <= 0)
_vm->setCursorControl(0);
if (control->_actor) {
if (control->_actor->_pathNode && (control->_actor->_flags & Illusions::ACTOR_FLAG_400))
delete control->_actor->_pathNode;
if (!(control->_actor->_flags & Illusions::ACTOR_FLAG_200))
control->_actor->destroySurface();
/* TODO
if (control->_actor->_field2)
largeObj_sub_4061E0();
*/
delete control->_actor;
control->_actor = 0;
}
delete control;
}
void Controls::disappearActors() {
for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
Control *control = *it;
if (control->_flags & 4 && control->_pauseCtr == 0) {
control->disappearActor();
}
}
Control *control = _vm->_dict->getObjectControl(0x40148);
if (control) {
control->disappearActor();
}
}
void Controls::appearActors() {
for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
Control *control = *it;
if (control->_flags & 4 && control->_pauseCtr == 0) {
control->appearActor();
}
}
Control *control = _vm->_dict->getObjectControl(0x40148);
if (control) {
control->appearActor();
}
}
void Controls::pauseActors(uint32 objectId) {
for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
Control *control = *it;
if (control->_actor && control->_objectId != objectId) {
control->_actor->pause();
}
}
}
void Controls::unpauseActors(uint32 objectId) {
for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
Control *control = *it;
if (control->_actor && control->_objectId != objectId) {
control->_actor->unpause();
}
}
}
} // End of namespace Illusions