mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-14 21:59:17 +00:00
d57ae26179
- Add remaining screen shake effects - Implement Chinese dialog puzzle in Duckman
1446 lines
40 KiB
C++
1446 lines
40 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/scriptman.h"
|
|
#include "illusions/scriptopcodes.h"
|
|
#include "illusions/sequenceopcodes.h"
|
|
#include "illusions/talkthread.h"
|
|
#include "illusions/thread.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 |= 0x4000;
|
|
}
|
|
else {
|
|
_flags |= 0x2000;
|
|
_flags |= 0x4000;
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
_tag = _vm->getCurrentScene();
|
|
}
|
|
|
|
Control::~Control() {
|
|
}
|
|
|
|
void Control::pause() {
|
|
|
|
_vm->_dict->setObjectControl(_objectId, 0);
|
|
|
|
if (_objectId == 0x40004)
|
|
_vm->setCursorControl(0);
|
|
|
|
if (_actor && !(_actor->_flags & 0x0200))
|
|
_actor->destroySurface();
|
|
|
|
}
|
|
|
|
void Control::unpause() {
|
|
|
|
_vm->_dict->setObjectControl(_objectId, this);
|
|
|
|
if (_objectId == 0x40004)
|
|
_vm->setCursorControl(this);
|
|
|
|
if (_actor && !(_actor->_flags & 0x0200)) {
|
|
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 |= 1;
|
|
if (_objectId == 0x40004) {
|
|
if (_actor->_frameIndex) {
|
|
_actor->_flags |= 0x2000;
|
|
_actor->_flags |= 0x4000;
|
|
}
|
|
_vm->_input->discardButtons(0xFFFF);
|
|
}
|
|
} else {
|
|
if (_objectId == 0x40004) {
|
|
_vm->showCursor();
|
|
} else {
|
|
if (_actor->_frameIndex || _actorTypeId == 0x50004)
|
|
_actor->_flags |= 1;
|
|
else
|
|
_actor->_flags |= 0x1000;
|
|
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 &= ~1;
|
|
} else {
|
|
if (_objectId == 0x40004) {
|
|
_vm->hideCursor();
|
|
} else {
|
|
_actor->_flags &= ~1;
|
|
_actor->_flags &= ~0x1000;
|
|
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 & 1) != 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 &= ~0x80;
|
|
subControl->_actor->_entryTblPtr = 0;
|
|
subControl->_actor->_notifyThreadId2 = 0;
|
|
}
|
|
_actor->_flags &= ~0x80;
|
|
_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 & 0x40)) {
|
|
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));;
|
|
}
|
|
|
|
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 & 0x40))
|
|
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) {
|
|
// scaledValue = value * scale div 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) {
|
|
// scaledValue = value * scale div 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 |= 0x2000;
|
|
_actor->_flags |= 0x4000;
|
|
_actor->_newFrameIndex = 0;
|
|
}
|
|
}
|
|
|
|
void Control::stopActor() {
|
|
_actor->_seqCodeIp = 0;
|
|
if (_actor->_pathNode) {
|
|
if (_actor->_flags & 0x0400) {
|
|
delete _actor->_pathNode;
|
|
_actor->_flags &= ~0x0400;
|
|
}
|
|
_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 & 0x40) {
|
|
stopActor();
|
|
_actor->_frameIndex = 0;
|
|
if ((_actor->_flags & 1) || (_actor->_flags & 0x1000)) {
|
|
_actor->_flags &= ~1;
|
|
_actor->_flags |= 0x1000;
|
|
}
|
|
}
|
|
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 & 1) {
|
|
if (_actor->_pathNode) {
|
|
doSeq = false;
|
|
subControl->_actor->_notifyThreadId2 = threadId;
|
|
subControl->_actor->_entryTblPtr = entryTblPtr;
|
|
subControl->_actor->_flags |= 0x80;
|
|
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 & 1) && (_actor->_flags & 0x1000) && (_objectId != 0x40004)) {
|
|
appearActor();
|
|
_actor->_flags &= ~0x1000;
|
|
}
|
|
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 &= ~0x80;
|
|
linkedActor->_flags &= ~0x400;
|
|
linkedActor->_flags |= 0x100;
|
|
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->_actorItems->findSequenceFrames(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 |= 0x80;
|
|
linkedActor->_entryTblPtr = _actor->_entryTblPtr;
|
|
linkedActor->_notifyThreadId2 = _actor->_notifyThreadId2;
|
|
linkedActor->_seqCodeValue1 = _actor->_seqCodeValue1;
|
|
linkedActor->_seqCodeValue3 = _actor->_seqCodeValue3;
|
|
_actor->_flags &= ~0x80;
|
|
_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 |= 0x0400;
|
|
_actor->_walkCallerThreadId1 = callerThreadId1;
|
|
_vm->notifyThreadId(_actor->_notifyId3C);
|
|
_actor->_notifyId3C = callerThreadId2;
|
|
_actor->_pathPointIndex = 0;
|
|
|
|
if (_vm->getGameId() == kGameIdBBDOU) {
|
|
_vm->_input->discardButtons(0x10);
|
|
} else if (_vm->getGameId() == kGameIdDuckman) {
|
|
_vm->_input->discardButtons(0x20);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PointArray *Control::createPath(Common::Point destPt) {
|
|
// TODO Implement actual pathfinding
|
|
PointArray *walkPoints = (_actor->_flags & 2) ? _actor->_pathWalkPoints->_points : 0;
|
|
PathLines *walkRects = (_actor->_flags & 0x10) ? _actor->_pathWalkRects->_rects : 0;
|
|
PathFinder pathFinder;
|
|
WidthHeight bgDimensions = _vm->_backgroundItems->getMasterBgDimensions();
|
|
PointArray *path = pathFinder.findPath(_actor->_position, destPt, walkPoints, walkRects, bgDimensions);
|
|
for (uint i = 0; i < path->size(); ++i) {
|
|
debug(0, "Path(%d) (%d, %d)", i, (*path)[i].x, (*path)[i].y);
|
|
}
|
|
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 again = false;
|
|
|
|
while (1) {
|
|
|
|
if (!again && _vm->testMainActorFastWalk(this)) {
|
|
again = true;
|
|
disappearActor();
|
|
_actor->_flags |= 0x8000;
|
|
_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
|
|
FP16 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;
|
|
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;
|
|
|
|
}
|
|
|
|
FP16 deltaX24, deltaY24;
|
|
|
|
if (_actor->_flags & 0x0400) {
|
|
|
|
FP16 v20 = fixedMul((deltaTime + _actor->_pathCtrX) << 16, _actor->_pathCtrY << 16);
|
|
FP16 v21 = fixedDiv(v20, 100 << 16);
|
|
FP16 v22 = fixedMul(v21, _actor->_scale << 16);
|
|
FP16 v23 = fixedDiv(v22, 100 << 16);
|
|
_actor->_seqCodeValue1 = 100 * _actor->_pathCtrY * deltaTime / 100;
|
|
if (v23) {
|
|
FP16 prevDistance = fixedDistance(prevPt.x << 16, prevPt.y << 16, _actor->_posXShl, _actor->_posYShl);
|
|
FP16 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)) {
|
|
FP16 newX = (prevPt.x << 16) + deltaX24;
|
|
FP16 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 & 0x0400) {
|
|
delete _actor->_pathNode;
|
|
_actor->_flags &= ~0x0400;
|
|
}
|
|
_actor->_pathNode = 0;
|
|
_actor->_pathPoints = 0;
|
|
_actor->_pathPointsCount = 0;
|
|
_actor->_pathPointIndex = 0;
|
|
if (_actor->_notifyId3C) {
|
|
_vm->notifyThreadId(_actor->_notifyId3C);
|
|
_actor->_walkCallerThreadId1 = 0;
|
|
}
|
|
again = false;
|
|
}
|
|
_actor->_pathFlag50 = false;
|
|
}
|
|
|
|
if (!again)
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void Control::refreshSequenceCode() {
|
|
Sequence *sequence = _vm->_dict->findSequence(_actor->_sequenceId);
|
|
_actor->_seqCodeIp = sequence->_sequenceCode;
|
|
}
|
|
|
|
void Control::startSequenceActorIntern(uint32 sequenceId, int value, byte *entryTblPtr, uint32 notifyThreadId) {
|
|
stopActor();
|
|
|
|
_actor->_flags &= ~0x80;
|
|
_actor->_flags &= ~0x0400;
|
|
_actor->_flags |= 0x0100;
|
|
|
|
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("Load external sequence...");
|
|
_vm->_resSys->loadResource(0x00060000 | (sequenceId & 0xFFFF), _vm->getCurrentScene(), 0);
|
|
sequence = _vm->_dict->findSequence(sequenceId);
|
|
_actor->_flags |= 0x800;
|
|
}
|
|
|
|
_actor->_seqCodeIp = sequence->_sequenceCode;
|
|
_actor->_frames = _vm->_actorItems->findSequenceFrames(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 |= 0x80;
|
|
_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_back(control);
|
|
_vm->_dict->setObjectControl(control->_objectId, control);
|
|
}
|
|
|
|
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 |= 0x0200;
|
|
}
|
|
|
|
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->_backgroundItems->getActiveBgResource();
|
|
if (actorType->_pathWalkPointsIndex) {
|
|
actor->_pathWalkPoints = bgRes->getPathWalkPoints(actorType->_pathWalkPointsIndex - 1);
|
|
actor->_flags |= 0x02;
|
|
}
|
|
|
|
if (actorType->_scaleLayerIndex) {
|
|
actor->_scaleLayer = bgRes->getScaleLayer(actorType->_scaleLayerIndex - 1);
|
|
actor->_flags |= 0x04;
|
|
}
|
|
|
|
if (actorType->_pathWalkRectIndex) {
|
|
actor->_pathWalkRects = bgRes->getPathWalkRects(actorType->_pathWalkRectIndex - 1);
|
|
actor->_flags |= 0x10;
|
|
}
|
|
|
|
if (actorType->_priorityLayerIndex) {
|
|
actor->_priorityLayer = bgRes->getPriorityLayer(actorType->_priorityLayerIndex - 1);
|
|
actor->_flags |= 0x08;
|
|
}
|
|
|
|
if (actorType->_regionLayerIndex) {
|
|
actor->_regionLayer = bgRes->getRegionLayer(actorType->_regionLayerIndex - 1);
|
|
actor->_flags |= 0x20;
|
|
}
|
|
|
|
actor->_pathCtrY = 140;
|
|
|
|
_controls.push_back(control);
|
|
_vm->_dict->setObjectControl(objectId, control);
|
|
|
|
if (_vm->getGameId() == kGameIdDuckman) {
|
|
control->appearActor();
|
|
} else if (_vm->getGameId() == kGameIdBBDOU) {
|
|
control->_flags |= 0x01;
|
|
actor->_flags |= 0x1000;
|
|
}
|
|
|
|
if (_vm->isCursorObject(actorTypeId, objectId))
|
|
_vm->placeCursorControl(control, sequenceId);
|
|
|
|
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_back(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_back(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 |= 0x40;
|
|
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_back(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::destroyControlsByTag(uint32 tag) {
|
|
ItemsIterator it = _controls.begin();
|
|
while (it != _controls.end()) {
|
|
if ((*it)->_tag == tag) {
|
|
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::pauseControlsByTag(uint32 tag) {
|
|
for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
|
|
Control *control = *it;
|
|
if (control->_tag == tag) {
|
|
++control->_pauseCtr;
|
|
if (control->_pauseCtr == 1)
|
|
control->pause();
|
|
}
|
|
}
|
|
}
|
|
|
|
void Controls::unpauseControlsByTag(uint32 tag) {
|
|
for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
|
|
Control *control = *it;
|
|
if (control->_tag == tag) {
|
|
--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 & 1))) {
|
|
Common::Rect collisionRect;
|
|
testControl->getCollisionRect(collisionRect);
|
|
if (!collisionRect.isEmpty() && collisionRect.contains(pt)) {
|
|
uint32 testPriority = testControl->getPriority();
|
|
if ((!foundControl || foundPriority < testPriority) &&
|
|
testPriority >= minPriorityExt) {
|
|
foundControl = testControl;
|
|
foundPriority = testPriority;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (foundControl) {
|
|
if (foundControl->_actor && foundControl->_actor->_parentObjectId && (foundControl->_actor->_flags & 0x40)) {
|
|
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 & 4) {
|
|
int scale = actor->_scaleLayer->getScale(actor->_position);
|
|
control->setActorScale(scale);
|
|
}
|
|
|
|
if (actor->_flags & 8) {
|
|
int16 priority = actor->_priorityLayer->getPriority(actor->_position);
|
|
if (priority)
|
|
control->setPriority(priority + 1);
|
|
}
|
|
|
|
if (actor->_flags & 0x20) {
|
|
// 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("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 == 0x40004 && control->_pauseCtr <= 0)
|
|
_vm->setCursorControl(0);
|
|
|
|
if (control->_actor) {
|
|
if (control->_actor->_pathNode && (control->_actor->_flags & 0x400))
|
|
delete control->_actor->_pathNode;
|
|
if (!(control->_actor->_flags & 0x200))
|
|
control->_actor->destroySurface();
|
|
/* TODO
|
|
if (control->_actor->_field2)
|
|
largeObj_sub_4061E0();
|
|
*/
|
|
delete control->_actor;
|
|
control->_actor = 0;
|
|
}
|
|
|
|
delete control;
|
|
}
|
|
|
|
} // End of namespace Illusions
|