From 22ce3aa9e1ab6428484e90fdf51178ba895e150f Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sat, 15 Sep 2007 15:02:40 +0000 Subject: Slight cleanup of the actor class: moved all of the actor walk code in a new file and removed many unneeded includes svn-id: r28908 --- engines/saga/actor.cpp | 1960 +------------------------------------------ engines/saga/actor.h | 30 + engines/saga/actor_walk.cpp | 1942 ++++++++++++++++++++++++++++++++++++++++++ engines/saga/module.mk | 1 + 4 files changed, 1982 insertions(+), 1951 deletions(-) create mode 100644 engines/saga/actor_walk.cpp (limited to 'engines') diff --git a/engines/saga/actor.cpp b/engines/saga/actor.cpp index 8218f13555..cf69dea47a 100644 --- a/engines/saga/actor.cpp +++ b/engines/saga/actor.cpp @@ -29,18 +29,12 @@ #include "saga/animation.h" #include "saga/console.h" #include "saga/events.h" -#include "saga/gfx.h" -#include "saga/interface.h" #include "saga/isomap.h" -#include "saga/itedata.h" #include "saga/objectmap.h" #include "saga/sagaresnames.h" #include "saga/rscfile.h" #include "saga/script.h" #include "saga/sndres.h" -#include "saga/sprite.h" -#include "saga/stream.h" -#include "saga/font.h" #include "saga/sound.h" #include "saga/scene.h" @@ -48,24 +42,6 @@ namespace Saga { -enum ActorFrameIds { -//ITE - kFrameITEStand = 0, - kFrameITEWalk = 1, - kFrameITESpeak = 2, - kFrameITEGive = 3, - kFrameITEGesture = 4, - kFrameITEWait = 5, - kFrameITEPickUp = 6, - kFrameITELook = 7, -//IHNM - kFrameIHNMStand = 0, - kFrameIHNMSpeak = 1, - kFrameIHNMWait = 2, - kFrameIHNMGesture = 3, - kFrameIHNMWalk = 4 -}; - static int commonObjectCompare(const CommonObjectDataPointer& obj1, const CommonObjectDataPointer& obj2) { int p1 = obj1->_location.y - obj1->_location.z; int p2 = obj2->_location.y - obj2->_location.z; @@ -99,140 +75,6 @@ static int tileCommonObjectCompare(const CommonObjectDataPointer& obj1, const Co return 1; } -inline int16 int16Compare(int16 i1, int16 i2) { - return ((i1) > (i2) ? 1 : ((i1) < (i2) ? -1 : 0)); -} - -inline int16 quickDistance(const Point &point1, const Point &point2, int16 compressX) { - Point delta; - delta.x = ABS(point1.x - point2.x) / compressX; - delta.y = ABS(point1.y - point2.y); - return ((delta.x < delta.y) ? (delta.y + delta.x / 2) : (delta.x + delta.y / 2)); -} - -inline void calcDeltaS(const Point &point1, const Point &point2, Point &delta, Point &s) { - - delta.x = point2.x - point1.x; - if (delta.x == 0) { - s.x = 0; - } else { - if (delta.x > 0) { - s.x = 1; - } else { - s.x = -1; - delta.x = -delta.x; - } - } - - - delta.y = point2.y - point1.y; - if (delta.y == 0) { - s.y = 0; - } else { - if (delta.y > 0) { - s.y = 1; - } else { - s.y = -1; - delta.y = -delta.y; - } - } -} - -// Lookup table to convert 8 cardinal directions to 4 -static const int actorDirectectionsLUT[8] = { - ACTOR_DIRECTION_BACK, // kDirUp - ACTOR_DIRECTION_RIGHT, // kDirUpRight - ACTOR_DIRECTION_RIGHT, // kDirRight - ACTOR_DIRECTION_RIGHT, // kDirDownRight - ACTOR_DIRECTION_FORWARD,// kDirDown - ACTOR_DIRECTION_LEFT, // kDirDownLeft - ACTOR_DIRECTION_LEFT, // kDirLeft - ACTOR_DIRECTION_LEFT, // kDirUpLeft -}; - -static const PathDirectionData pathDirectionLUT[8][3] = { - { { 0, Point( 0, -1) }, { 7, Point(-1, -1) }, { 4, Point( 1, -1) } }, - { { 1, Point( 1, 0) }, { 4, Point( 1, -1) }, { 5, Point( 1, 1) } }, - { { 2, Point( 0, 1) }, { 5, Point( 1, 1) }, { 6, Point(-1, 1) } }, - { { 3, Point(-1, 0) }, { 6, Point(-1, 1) }, { 7, Point(-1, -1) } }, - { { 0, Point( 0, -1) }, { 1, Point( 1, 0) }, { 4, Point( 1, -1) } }, - { { 1, Point( 1, 0) }, { 2, Point( 0, 1) }, { 5, Point( 1, 1) } }, - { { 2, Point( 0, 1) }, { 3, Point(-1, 0) }, { 6, Point(-1, 1) } }, - { { 3, Point(-1, 0) }, { 0, Point( 0, -1) }, { 7, Point(-1, -1) } } -}; - -static const int pathDirectionLUT2[8][2] = { - { 0, -1 }, - { 1, 0 }, - { 0, 1 }, - { -1, 0 }, - { 1, -1 }, - { 1, 1 }, - { -1, 1 }, - { -1, -1 } -}; - -static const int angleLUT[16][2] = { - { 0, -256 }, - { 98, -237 }, - { 181, -181 }, - { 237, -98 }, - { 256, 0 }, - { 237, 98 }, - { 181, 181 }, - { 98, 237 }, - { 0, 256 }, - { -98, 237 }, - { -181, 181 }, - { -237, 98 }, - { -256, 0 }, - { -237, -98 }, - { -181, -181 }, - { -98, -237 } -}; - -static const int directionLUT[8][2] = { - { 0 * 2, -2 * 2 }, - { 2 * 2, -1 * 2 }, - { 3 * 2, 0 * 2 }, - { 2 * 2, 1 * 2 }, - { 0 * 2, 2 * 2 }, - { -2 * 2, 1 * 2 }, - { -4 * 2, 0 * 2 }, - { -2 * 2, -1 * 2 } -}; - -static const int tileDirectionLUT[8][2] = { - { 1, 1 }, - { 2, 0 }, - { 1, -1 }, - { 0, -2 }, - { -1, -1 }, - { -2, 0 }, - { -1, 1 }, - { 0, 2 } -}; - -struct DragonMove { - uint16 baseFrame; - int16 offset[4][2]; -}; - -static const DragonMove dragonMoveTable[12] = { - { 0, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } }, - { 0, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } }, - { 0, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } }, - { 0, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } }, - { 28, { { -0, 0 }, { -1, 6 }, { -5, 11 }, { -10, 15 } } }, - { 56, { { 0, 0 }, { 1, 6 }, { 5, 11 }, { 10, 15 } } }, - { 40, { { 0, 0 }, { 6, 1 }, { 11, 5 }, { 15, 10 } } }, - { 44, { { 0, 0 }, { 6, -1 }, { 11, -5 }, { 15, -10 } } }, - { 32, { { -0, -0 }, { -6, -1 }, { -11, -5 }, { -15, -10 } } }, - { 52, { { -0, 0 }, { -6, 1 }, { -11, 5 }, { -15, 10 } } }, - { 36, { { 0, -0 }, { 1, -6 }, { 5, -11 }, { 10, -15 } } }, - { 48, { { -0, -0 }, { -1, -6 }, { -5, -11 }, { -10, -15 } } } -}; - Actor::Actor(SagaEngine *vm) : _vm(vm) { int i; byte *stringsPointer; @@ -731,76 +573,6 @@ void Actor::stepZoneAction(ActorData *actor, const HitZone *hitZone, bool exit, } } -void Actor::realLocation(Location &location, uint16 objectId, uint16 walkFlags) { - int angle; - int distance; - ActorData *actor; - ObjectData *obj; - debug (8, "Actor::realLocation objectId=%i", objectId); - if (walkFlags & kWalkUseAngle) { - if (_vm->_scene->getFlags() & kSceneFlagISO) { - angle = (location.x + 2) & 15; - distance = location.y; - - location.u() = (angleLUT[angle][0] * distance) >> 8; - location.v() = -(angleLUT[angle][1] * distance) >> 8; - } else { - angle = location.x & 15; - distance = location.y; - - location.x = (angleLUT[angle][0] * distance) >> 6; - location.y = (angleLUT[angle][1] * distance) >> 6; - } - } - - if (objectId != ID_NOTHING) { - if (validActorId(objectId)) { - actor = getActor(objectId); - location.addXY(actor->_location); - } else if (validObjId(objectId)) { - obj = getObj(objectId); - location.addXY(obj->_location); - } - } -} - -void Actor::actorFaceTowardsPoint(uint16 actorId, const Location &toLocation) { - ActorData *actor; - Location delta; - //debug (8, "Actor::actorFaceTowardsPoint actorId=%i", actorId); - actor = getActor(actorId); - - toLocation.delta(actor->_location, delta); - - if (_vm->_scene->getFlags() & kSceneFlagISO) { - if (delta.u() > 0) { - actor->_facingDirection = (delta.v() > 0) ? kDirUp : kDirRight; - } else { - actor->_facingDirection = (delta.v() > 0) ? kDirLeft : kDirDown; - } - } else { - if (ABS(delta.y) > ABS(delta.x * 2)) { - actor->_facingDirection = (delta.y > 0) ? kDirDown : kDirUp; - } else { - actor->_facingDirection = (delta.x > 0) ? kDirRight : kDirLeft; - } - } -} - -void Actor::actorFaceTowardsObject(uint16 actorId, uint16 objectId) { - ActorData *actor; - ObjectData *obj; - - if (validActorId(objectId)) { - actor = getActor(objectId); - actorFaceTowardsPoint(actorId, actor->_location); - } else if (validObjId(objectId)) { - obj = getObj(objectId); - actorFaceTowardsPoint(actorId, obj->_location); - } -} - - ObjectData *Actor::getObj(uint16 objId) { ObjectData *obj; @@ -838,18 +610,6 @@ ActorData *Actor::getActor(uint16 actorId) { return actor; } -bool Actor::validFollowerLocation(const Location &location) { - Point point; - location.toScreenPointXY(point); - - if ((point.x < 5) || (point.x >= _vm->getDisplayWidth() - 5) || - (point.y < 0) || (point.y > _vm->_scene->getHeight())) { - return false; - } - - return (_vm->_scene->canWalk(point)); -} - void Actor::setProtagState(int state) { _protagState = state; @@ -863,149 +623,6 @@ void Actor::setProtagState(int state) { } } -void Actor::updateActorsScene(int actorsEntrance) { - int i, j; - int followerDirection; - ActorData *actor; - Location tempLocation; - Location possibleLocation; - Point delta; - const SceneEntry *sceneEntry; - - if (_vm->_scene->currentSceneNumber() == 0) { - error("Actor::updateActorsScene _vm->_scene->currentSceneNumber() == 0"); - } - - _vm->_sound->stopVoice(); - _activeSpeech.stringsCount = 0; - _activeSpeech.playing = false; - _protagonist = NULL; - - for (i = 0; i < _actorsCount; i++) { - actor = _actors[i]; - actor->_inScene = false; - actor->_spriteList.freeMem(); - if (actor->_disabled) { - continue; - } - if ((actor->_flags & (kProtagonist | kFollower)) || (i == 0)) { - if (actor->_flags & kProtagonist) { - actor->_finalTarget = actor->_location; - _centerActor = _protagonist = actor; - } else if (_vm->getGameType() == GType_ITE && - _vm->_scene->currentSceneResourceId() == RID_ITE_OVERMAP_SCENE) { - continue; - } - - actor->_sceneNumber = _vm->_scene->currentSceneNumber(); - } - if (actor->_sceneNumber == _vm->_scene->currentSceneNumber()) { - actor->_inScene = true; - actor->_actionCycle = (_vm->_rnd.getRandomNumber(7) & 0x7) * 4; // 1/8th chance - } - } - - // _protagonist can be null while loading a game from the command line - if (_protagonist == NULL) - return; - - if ((actorsEntrance >= 0) && (_vm->_scene->_entryList.entryListCount > 0)) { - if (_vm->_scene->_entryList.entryListCount <= actorsEntrance) { - actorsEntrance = 0; //OCEAN bug - } - - sceneEntry = _vm->_scene->_entryList.getEntry(actorsEntrance); - if (_vm->_scene->getFlags() & kSceneFlagISO) { - _protagonist->_location = sceneEntry->location; - } else { - _protagonist->_location.x = sceneEntry->location.x * ACTOR_LMULT; - _protagonist->_location.y = sceneEntry->location.y * ACTOR_LMULT; - _protagonist->_location.z = sceneEntry->location.z * ACTOR_LMULT; - } - // Workaround for bug #1328045: - // "When entering any of the houses at the start of the - // game if you click on anything inside the building you - // start walking through the door, turn around and leave." - // - // After stepping on an action zone, Rif is trying to exit. - // Shift Rif's entry position to a non action zone area. - if (_vm->getGameType() == GType_ITE) { - if ((_vm->_scene->currentSceneNumber() >= 53) && (_vm->_scene->currentSceneNumber() <= 66)) - _protagonist->_location.y += 10; - } - - _protagonist->_facingDirection = _protagonist->_actionDirection = sceneEntry->facing; - } - - _protagonist->_currentAction = kActionWait; - - if (_vm->_scene->getFlags() & kSceneFlagISO) { - //nothing? - } else { - _vm->_scene->initDoorsState(); //TODO: move to _scene - } - - followerDirection = _protagonist->_facingDirection + 3; - calcScreenPosition(_protagonist); - - for (i = 0; i < _actorsCount; i++) { - actor = _actors[i]; - if (actor->_flags & (kFollower)) { - actor->_facingDirection = actor->_actionDirection = _protagonist->_facingDirection; - actor->_currentAction = kActionWait; - actor->_walkStepsCount = actor->_walkStepIndex = 0; - actor->_location.z = _protagonist->_location.z; - - - if (_vm->_scene->getFlags() & kSceneFlagISO) { - _vm->_isoMap->placeOnTileMap(_protagonist->_location, actor->_location, 3, followerDirection & 0x07); - } else { - followerDirection &= 0x07; - - possibleLocation = _protagonist->_location; - - - delta.x = directionLUT[followerDirection][0]; - delta.y = directionLUT[followerDirection][1]; - - - for (j = 0; j < 30; j++) { - tempLocation = possibleLocation; - tempLocation.x += delta.x; - tempLocation.y += delta.y; - - if (validFollowerLocation(tempLocation)) { - possibleLocation = tempLocation; - } else { - tempLocation = possibleLocation; - tempLocation.x += delta.x; - if (validFollowerLocation(tempLocation)) { - possibleLocation = tempLocation; - } else { - tempLocation = possibleLocation; - tempLocation.y += delta.y; - if (validFollowerLocation(tempLocation)) { - possibleLocation = tempLocation; - } else { - break; - } - } - } - } - - actor->_location = possibleLocation; - } - followerDirection += 2; - } - - } - - handleActions(0, true); - if (_vm->_scene->getFlags() & kSceneFlagISO) { - _vm->_isoMap->adjustScroll(true); - } -} - int Actor::getFrameType(ActorFrameTypes frameType) { if (_vm->getGameType() == GType_ITE) { @@ -1243,416 +860,6 @@ void Actor::handleSpeech(int msec) { _activeSpeech.playing = true; } -void Actor::handleActions(int msec, bool setup) { - int i; - ActorData *actor; - ActorFrameRange *frameRange; - int state; - int speed; - int32 framesLeft; - Location delta; - Location addDelta; - int hitZoneIndex; - const HitZone *hitZone; - Point hitPoint; - Location pickLocation; - - for (i = 0; i < _actorsCount; i++) { - actor = _actors[i]; - if (!actor->_inScene) - continue; - - if ((_vm->getGameType() == GType_ITE) && (i == ACTOR_DRAGON_INDEX)) { - moveDragon(actor); - continue; - } - - switch (actor->_currentAction) { - case kActionWait: - if (!setup && (actor->_flags & kFollower)) { - followProtagonist(actor); - if (actor->_currentAction != kActionWait) - break; - } - - if (actor->_targetObject != ID_NOTHING) { - actorFaceTowardsObject(actor->_id, actor->_targetObject); - } - - if (actor->_flags & kCycle) { - frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameStand)); - if (frameRange->frameCount > 0) { - actor->_actionCycle++; - actor->_actionCycle = (actor->_actionCycle) % frameRange->frameCount; - } else { - actor->_actionCycle = 0; - } - actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle; - break; - } - - if ((actor->_actionCycle & 3) == 0) { - actor->cycleWrap(100); - - frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameWait)); - if ((frameRange->frameCount < 1 || actor->_actionCycle > 33)) - frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameStand)); - - if (frameRange->frameCount) { - actor->_frameNumber = frameRange->frameIndex + (uint16)_vm->_rnd.getRandomNumber(frameRange->frameCount - 1); - } else { - actor->_frameNumber = frameRange->frameIndex; - } - } - actor->_actionCycle++; - break; - - case kActionWalkToPoint: - case kActionWalkToLink: - if (_vm->_scene->getFlags() & kSceneFlagISO) { - actor->_partialTarget.delta(actor->_location, delta); - - while ((delta.u() == 0) && (delta.v() == 0)) { - - if ((actor == _protagonist) && (_vm->mouseButtonPressed())) { - _vm->_isoMap->screenPointToTileCoords(_vm->mousePos(), pickLocation); - - if (!actorWalkTo(_protagonist->_id, pickLocation)) { - break; - } - } else if (!_vm->_isoMap->nextTileTarget(actor) && !actorEndWalk(actor->_id, true)) { - break; - } - - actor->_partialTarget.delta(actor->_location, delta); - actor->_partialTarget.z = 0; - } - - if (actor->_flags & kFastest) { - speed = 8; - } else if (actor->_flags & kFaster) { - speed = 6; - } else { - speed = 4; - } - - if (_vm->_scene->currentSceneResourceId() == RID_ITE_OVERMAP_SCENE) { - speed = 2; - } - - if ((actor->_actionDirection == 2) || (actor->_actionDirection == 6)) { - speed = speed / 2; - } - - if (ABS(delta.v()) > ABS(delta.u())) { - addDelta.v() = clamp(-speed, delta.v(), speed); - if (addDelta.v() == delta.v()) { - addDelta.u() = delta.u(); - } else { - addDelta.u() = delta.u() * addDelta.v(); - addDelta.u() += (addDelta.u() > 0) ? (delta.v() / 2) : (-delta.v() / 2); - addDelta.u() /= delta.v(); - } - } else { - addDelta.u() = clamp(-speed, delta.u(), speed); - if (addDelta.u() == delta.u()) { - addDelta.v() = delta.v(); - } else { - addDelta.v() = delta.v() * addDelta.u(); - addDelta.v() += (addDelta.v() > 0) ? (delta.u() / 2) : (-delta.u() / 2); - addDelta.v() /= delta.u(); - } - } - - actor->_location.add(addDelta); - } else { - actor->_partialTarget.delta(actor->_location, delta); - - while ((delta.x == 0) && (delta.y == 0)) { - - if (actor->_walkStepIndex >= actor->_walkStepsCount) { - actorEndWalk(actor->_id, true); - break; - } - - actor->_partialTarget.fromScreenPoint(actor->_walkStepsPoints[actor->_walkStepIndex++]); - if (_vm->getGameType() == GType_ITE) { - if (actor->_partialTarget.x > 224 * 2 * ACTOR_LMULT) { - actor->_partialTarget.x -= 256 * 2 * ACTOR_LMULT; - } - } else { - if (actor->_partialTarget.x > 224 * 4 * ACTOR_LMULT) { - actor->_partialTarget.x -= 256 * 4 * ACTOR_LMULT; - } - } - - actor->_partialTarget.delta(actor->_location, delta); - - if (ABS(delta.y) > ABS(delta.x)) { - actor->_actionDirection = delta.y > 0 ? kDirDown : kDirUp; - } else { - actor->_actionDirection = delta.x > 0 ? kDirRight : kDirLeft; - } - } - - if(_vm->getGameType() == GType_ITE) - speed = (ACTOR_LMULT * 2 * actor->_screenScale + 63) / 256; - else - speed = (ACTOR_SPEED * actor->_screenScale + 128) >> 8; - - if (speed < 1) - speed = 1; - - if(_vm->getGameType() == GType_IHNM) - speed = speed / 2; - - if ((actor->_actionDirection == kDirUp) || (actor->_actionDirection == kDirDown)) { - addDelta.y = clamp(-speed, delta.y, speed); - if (addDelta.y == delta.y) { - addDelta.x = delta.x; - } else { - addDelta.x = delta.x * addDelta.y; - addDelta.x += (addDelta.x > 0) ? (delta.y / 2) : (-delta.y / 2); - addDelta.x /= delta.y; - actor->_facingDirection = actor->_actionDirection; - } - } else { - addDelta.x = clamp(-2 * speed, delta.x, 2 * speed); - if (addDelta.x == delta.x) { - addDelta.y = delta.y; - } else { - addDelta.y = delta.y * addDelta.x; - addDelta.y += (addDelta.y > 0) ? (delta.x / 2) : (-delta.x / 2); - addDelta.y /= delta.x; - actor->_facingDirection = actor->_actionDirection; - } - } - - actor->_location.add(addDelta); - } - - if (actor->_actorFlags & kActorBackwards) { - actor->_facingDirection = (actor->_actionDirection + 4) & 7; - actor->_actionCycle--; - } else { - actor->_actionCycle++; - } - - frameRange = getActorFrameRange(actor->_id, actor->_walkFrameSequence); - - if (actor->_actionCycle < 0) { - actor->_actionCycle = frameRange->frameCount - 1; - } else if (actor->_actionCycle >= frameRange->frameCount) { - actor->_actionCycle = 0; - } - - actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle; - break; - - case kActionWalkDir: - if (_vm->_scene->getFlags() & kSceneFlagISO) { - actor->_location.u() += tileDirectionLUT[actor->_actionDirection][0]; - actor->_location.v() += tileDirectionLUT[actor->_actionDirection][1]; - - frameRange = getActorFrameRange(actor->_id, actor->_walkFrameSequence); - - actor->_actionCycle++; - actor->cycleWrap(frameRange->frameCount); - actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle; - } else { - if (_vm->getGameType() == GType_ITE) { - actor->_location.x += directionLUT[actor->_actionDirection][0] * 2; - actor->_location.y += directionLUT[actor->_actionDirection][1] * 2; - } else { - // FIXME: The original does not multiply by 8 here, but we do - actor->_location.x += (directionLUT[actor->_actionDirection][0] * 8 * actor->_screenScale + 128) >> 8; - actor->_location.y += (directionLUT[actor->_actionDirection][1] * 8 * actor->_screenScale + 128) >> 8; - } - - frameRange = getActorFrameRange(actor->_id, actor->_walkFrameSequence); - actor->_actionCycle++; - actor->cycleWrap(frameRange->frameCount); - actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle; - } - break; - - case kActionSpeak: - actor->_actionCycle++; - actor->cycleWrap(64); - - frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameGesture)); - if (actor->_actionCycle >= frameRange->frameCount) { - if (actor->_actionCycle & 1) - break; - frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameSpeak)); - - state = (uint16)_vm->_rnd.getRandomNumber(frameRange->frameCount); - - if (state == 0) { - frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameStand)); - } else { - state--; - } - } else { - state = actor->_actionCycle; - } - - actor->_frameNumber = frameRange->frameIndex + state; - break; - - case kActionAccept: - case kActionStoop: - break; - - case kActionCycleFrames: - case kActionPongFrames: - if (actor->_cycleTimeCount > 0) { - actor->_cycleTimeCount--; - break; - } - - actor->_cycleTimeCount = actor->_cycleDelay; - actor->_actionCycle++; - - frameRange = getActorFrameRange(actor->_id, actor->_cycleFrameSequence); - - if (actor->_currentAction == kActionPongFrames) { - if (actor->_actionCycle >= frameRange->frameCount * 2 - 2) { - if (actor->_actorFlags & kActorContinuous) { - actor->_actionCycle = 0; - } else { - actor->_currentAction = kActionFreeze; - break; - } - } - - state = actor->_actionCycle; - if (state >= frameRange->frameCount) { - state = frameRange->frameCount * 2 - 2 - state; - } - } else { - if (actor->_actionCycle >= frameRange->frameCount) { - if (actor->_actorFlags & kActorContinuous) { - actor->_actionCycle = 0; - } else { - actor->_currentAction = kActionFreeze; - break; - } - } - state = actor->_actionCycle; - } - - if (frameRange->frameCount && (actor->_actorFlags & kActorRandom)) { - state = _vm->_rnd.getRandomNumber(frameRange->frameCount - 1); - } - - if (actor->_actorFlags & kActorBackwards) { - actor->_frameNumber = frameRange->frameIndex + frameRange->frameCount - 1 - state; - } else { - actor->_frameNumber = frameRange->frameIndex + state; - } - break; - - case kActionFall: - if (actor->_actionCycle > 0) { - framesLeft = actor->_actionCycle--; - actor->_finalTarget.delta(actor->_location, delta); - delta.x /= framesLeft; - delta.y /= framesLeft; - actor->_location.addXY(delta); - actor->_fallVelocity += actor->_fallAcceleration; - actor->_fallPosition += actor->_fallVelocity; - actor->_location.z = actor->_fallPosition >> 4; - } else { - actor->_location = actor->_finalTarget; - actor->_currentAction = kActionFreeze; - _vm->_script->wakeUpActorThread(kWaitTypeWalk, actor); - } - break; - - case kActionClimb: - actor->_cycleDelay++; - if (actor->_cycleDelay & 3) { - break; - } - - if (actor->_location.z >= actor->_finalTarget.z + ACTOR_CLIMB_SPEED) { - actor->_location.z -= ACTOR_CLIMB_SPEED; - actor->_actionCycle--; - } else if (actor->_location.z <= actor->_finalTarget.z - ACTOR_CLIMB_SPEED) { - actor->_location.z += ACTOR_CLIMB_SPEED; - actor->_actionCycle++; - } else { - actor->_location.z = actor->_finalTarget.z; - actor->_currentAction = kActionFreeze; - _vm->_script->wakeUpActorThread(kWaitTypeWalk, actor); - } - - frameRange = getActorFrameRange(actor->_id, actor->_cycleFrameSequence); - - if (actor->_actionCycle < 0) { - actor->_actionCycle = frameRange->frameCount - 1; - } - actor->cycleWrap(frameRange->frameCount); - actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle; - break; - } - - if ((actor->_currentAction >= kActionWalkToPoint) && (actor->_currentAction <= kActionWalkDir)) { - hitZone = NULL; - - if (_vm->_scene->getFlags() & kSceneFlagISO) { - actor->_location.toScreenPointUV(hitPoint); - } else { - actor->_location.toScreenPointXY(hitPoint); - } - hitZoneIndex = _vm->_scene->_actionMap->hitTest(hitPoint); - if (hitZoneIndex != -1) { - hitZone = _vm->_scene->_actionMap->getHitZone(hitZoneIndex); - } - - if (hitZone != actor->_lastZone) { - if (actor->_lastZone) - stepZoneAction(actor, actor->_lastZone, true, false); - actor->_lastZone = hitZone; - // WORKAROUND for graphics glitch in the rat caves. Don't do this step zone action in the rat caves - // (room 51) for hitzone 24577 (the door with the copy protection) to avoid the glitch. This glitch - // happens because the copy protection is supposed to kick in at this point, but it's bypassed - // (with permission from Wyrmkeep Entertainment) - if (hitZone && - !(_vm->getGameType() == GType_ITE && _vm->_scene->currentSceneNumber() == 51 && hitZone->getHitZoneId() == 24577)) - stepZoneAction(actor, hitZone, false, false); - } - } - } - // Update frameCount for sfWaitFrames in IHNM - _vm->_frameCount++; -} - -void Actor::direct(int msec) { - - if (_vm->_scene->_entryList.entryListCount == 0) { - return; - } - - if (_vm->_interface->_statusTextInput) { - return; - } - - // FIXME: HACK. This should be turned into cycle event. - _lastTickMsec += msec; - - if (_lastTickMsec > 1000 / _handleActionDiv) { - _lastTickMsec = 0; - //process actions - handleActions(msec, false); - } - -//process speech - handleSpeech(msec); -} - - bool Actor::calcScreenPosition(CommonObjectData *commonObjectData) { int beginSlope, endSlope, middle; bool result; @@ -1901,392 +1108,16 @@ void Actor::drawSpeech(void) { free(outputString); } -bool Actor::followProtagonist(ActorData *actor) { - Location protagonistLocation; - Location newLocation; - Location delta; - int protagonistBGMaskType; - Point prefer1; - Point prefer2; - Point prefer3; - int16 prefU; - int16 prefV; - int16 newU; - int16 newV; - - assert(_protagonist); - - actor->_flags &= ~(kFaster | kFastest); - protagonistLocation = _protagonist->_location; - calcScreenPosition(_protagonist); - - if (_vm->_scene->getFlags() & kSceneFlagISO) { - prefU = 60; - prefV = 60; - - - actor->_location.delta(protagonistLocation, delta); - - if (actor->_id == actorIndexToId(2)) { - prefU = prefV = 48; - } - - if ((delta.u() > prefU) || (delta.u() < -prefU) || (delta.v() > prefV) || (delta.v() < -prefV)) { +void Actor::actorSpeech(uint16 actorId, const char **strings, int stringsCount, int sampleResourceId, int speechFlags) { + ActorData *actor; + int i; + int16 dist; - if ((delta.u() > prefU * 2) || (delta.u() < -prefU * 2) || (delta.v() > prefV * 2) || (delta.v() < -prefV * 2)) { - actor->_flags |= kFaster; - - if ((delta.u() > prefU * 3) || (delta.u() < -prefU*3) || (delta.v() > prefV * 3) || (delta.v() < -prefV * 3)) { - actor->_flags |= kFastest; - } - } - - prefU /= 2; - prefV /= 2; - - newU = clamp(-prefU, delta.u(), prefU) + protagonistLocation.u(); - newV = clamp(-prefV, delta.v(), prefV) + protagonistLocation.v(); - - newLocation.u() = newU + _vm->_rnd.getRandomNumber(prefU - 1) - prefU / 2; - newLocation.v() = newV + _vm->_rnd.getRandomNumber(prefV - 1) - prefV / 2; - newLocation.z = 0; - - return actorWalkTo(actor->_id, newLocation); - } - - } else { - prefer1.x = (100 * _protagonist->_screenScale) >> 8; - prefer1.y = (50 * _protagonist->_screenScale) >> 8; - - if (_protagonist->_currentAction == kActionWalkDir) { - prefer1.x /= 2; - } - - if (prefer1.x < 8) { - prefer1.x = 8; - } - - if (prefer1.y < 8) { - prefer1.y = 8; - } - - prefer2.x = prefer1.x * 2; - prefer2.y = prefer1.y * 2; - prefer3.x = prefer1.x + prefer1.x / 2; - prefer3.y = prefer1.y + prefer1.y / 2; - - actor->_location.delta(protagonistLocation, delta); - - protagonistBGMaskType = 0; - if (_vm->_scene->isBGMaskPresent() && _vm->_scene->validBGMaskPoint(_protagonist->_screenPosition)) { - protagonistBGMaskType = _vm->_scene->getBGMaskType(_protagonist->_screenPosition); - } - - if ((_vm->_rnd.getRandomNumber(7) & 0x7) == 0) // 1/8th chance - actor->_actorFlags &= ~kActorNoFollow; - - if (actor->_actorFlags & kActorNoFollow) { - return false; - } - - if ((delta.x > prefer2.x) || (delta.x < -prefer2.x) || - (delta.y > prefer2.y) || (delta.y < -prefer2.y) || - ((_protagonist->_currentAction == kActionWait) && - (delta.x * 2 < prefer1.x) && (delta.x * 2 > -prefer1.x) && - (delta.y < prefer1.y) && (delta.y > -prefer1.y))) { - - if (ABS(delta.x) > ABS(delta.y)) { - - delta.x = (delta.x > 0) ? prefer3.x : -prefer3.x; - - newLocation.x = delta.x + protagonistLocation.x; - newLocation.y = clamp(-prefer2.y, delta.y, prefer2.y) + protagonistLocation.y; - } else { - delta.y = (delta.y > 0) ? prefer3.y : -prefer3.y; - - newLocation.x = clamp(-prefer2.x, delta.x, prefer2.x) + protagonistLocation.x; - newLocation.y = delta.y + protagonistLocation.y; - } - newLocation.z = 0; - - if (protagonistBGMaskType != 3) { - newLocation.x += _vm->_rnd.getRandomNumber(prefer1.x - 1) - prefer1.x / 2; - newLocation.y += _vm->_rnd.getRandomNumber(prefer1.y - 1) - prefer1.y / 2; - } - - newLocation.x = clamp(-31 * 4, newLocation.x, (_vm->getDisplayWidth() + 31) * 4); - - return actorWalkTo(actor->_id, newLocation); - } - } - return false; -} - -bool Actor::actorEndWalk(uint16 actorId, bool recurse) { - bool walkMore = false; - ActorData *actor; - const HitZone *hitZone; - int hitZoneIndex; - Point testPoint; - - actor = getActor(actorId); - actor->_actorFlags &= ~kActorBackwards; - - if (_vm->getGameType() == GType_ITE) { - - if (actor->_location.distance(actor->_finalTarget) > 8 && (actor->_flags & kProtagonist) && recurse && !(actor->_actorFlags & kActorNoCollide)) { - actor->_actorFlags |= kActorNoCollide; - return actorWalkTo(actorId, actor->_finalTarget); - } - } - - actor->_currentAction = kActionWait; - if (actor->_actorFlags & kActorFinalFace) { - actor->_facingDirection = actor->_actionDirection = (actor->_actorFlags >> 6) & 0x07; //? - } - - actor->_actorFlags &= ~(kActorNoCollide | kActorCollided | kActorFinalFace | kActorFacingMask); - actor->_flags &= ~(kFaster | kFastest); - - if (actor == _protagonist) { - _vm->_script->wakeUpActorThread(kWaitTypeWalk, actor); - if (_vm->_script->_pendingVerb == _vm->_script->getVerbType(kVerbWalkTo)) { - if (_vm->getGameType() == GType_ITE) - actor->_location.toScreenPointUV(testPoint); // it's wrong calculation, but it is used in ITE - else - actor->_location.toScreenPointXY(testPoint); - - hitZoneIndex = _vm->_scene->_actionMap->hitTest(testPoint); - if (hitZoneIndex != -1) { - hitZone = _vm->_scene->_actionMap->getHitZone(hitZoneIndex); - stepZoneAction(actor, hitZone, false, true); - } else { - _vm->_script->setNoPendingVerb(); - } - } else if (_vm->_script->_pendingVerb != _vm->_script->getVerbType(kVerbNone)) { - _vm->_script->doVerb(); - } - } else { - if (recurse && (actor->_flags & kFollower)) - walkMore = followProtagonist(actor); - - _vm->_script->wakeUpActorThread(kWaitTypeWalk, actor); - } - return walkMore; -} - -bool Actor::actorWalkTo(uint16 actorId, const Location &toLocation) { - ActorData *actor; - ActorData *anotherActor; - int i; - - Rect testBox; - Rect testBox2; - Point anotherActorScreenPosition; - Point collision; - Point pointFrom, pointTo, pointBest, pointAdd; - Point delta, bestDelta; - Point tempPoint; - bool extraStartNode; - bool extraEndNode; - - actor = getActor(actorId); - - if (actor == _protagonist) { - _vm->_scene->setDoorState(2, 0xff); - _vm->_scene->setDoorState(3, 0); - } else { - _vm->_scene->setDoorState(2, 0); - _vm->_scene->setDoorState(3, 0xff); - } - - if (_vm->_scene->getFlags() & kSceneFlagISO) { - - if ((_vm->getGameType() == GType_ITE) && (actor->_index == ACTOR_DRAGON_INDEX)) { - return false; - } - - actor->_finalTarget = toLocation; - actor->_walkStepsCount = 0; - _vm->_isoMap->findTilePath(actor, actor->_location, toLocation); - - - if ((actor->_walkStepsCount == 0) && (actor->_flags & kProtagonist)) { - actor->_actorFlags |= kActorNoCollide; - _vm->_isoMap->findTilePath(actor, actor->_location, toLocation); - } - - actor->_walkStepIndex = 0; - if (_vm->_isoMap->nextTileTarget(actor)) { - actor->_currentAction = kActionWalkToPoint; - actor->_walkFrameSequence = getFrameType(kFrameWalk); - } else { - actorEndWalk(actorId, false); - return false; - } - } else { - - actor->_location.toScreenPointXY(pointFrom); - pointFrom.x &= ~1; - - extraStartNode = _vm->_scene->offscreenPath(pointFrom); - - toLocation.toScreenPointXY(pointTo); - pointTo.x &= ~1; - - extraEndNode = _vm->_scene->offscreenPath(pointTo); - - if (_vm->_scene->isBGMaskPresent()) { - - if ((((actor->_currentAction >= kActionWalkToPoint) && - (actor->_currentAction <= kActionWalkDir)) || (actor == _protagonist)) && - !_vm->_scene->canWalk(pointFrom)) { - - int max = _vm->getGameType() == GType_ITE ? 8 : 4; - - for (i = 1; i < max; i++) { - pointAdd = pointFrom; - pointAdd.y += i; - if (_vm->_scene->canWalk(pointAdd)) { - pointFrom = pointAdd; - break; - } - pointAdd = pointFrom; - pointAdd.y -= i; - if (_vm->_scene->canWalk(pointAdd)) { - pointFrom = pointAdd; - break; - } - if (_vm->getGameType() == GType_ITE) { - pointAdd = pointFrom; - pointAdd.x += i; - if (_vm->_scene->canWalk(pointAdd)) { - pointFrom = pointAdd; - break; - } - pointAdd = pointFrom; - pointAdd.x -= i; - if (_vm->_scene->canWalk(pointAdd)) { - pointFrom = pointAdd; - break; - } - } - } - } - - _barrierCount = 0; - if (!(actor->_actorFlags & kActorNoCollide)) { - collision.x = ACTOR_COLLISION_WIDTH * actor->_screenScale / (256 * 2); - collision.y = ACTOR_COLLISION_HEIGHT * actor->_screenScale / (256 * 2); - - - for (i = 0; (i < _actorsCount) && (_barrierCount < ACTOR_BARRIERS_MAX); i++) { - anotherActor = _actors[i]; - if (!anotherActor->_inScene) - continue; - if (anotherActor == actor) - continue; - - anotherActorScreenPosition = anotherActor->_screenPosition; - testBox.left = (anotherActorScreenPosition.x - collision.x) & ~1; - testBox.right = (anotherActorScreenPosition.x + collision.x) & ~1 + 1; - testBox.top = anotherActorScreenPosition.y - collision.y; - testBox.bottom = anotherActorScreenPosition.y + collision.y + 1; - testBox2 = testBox; - testBox2.right += 2; - testBox2.left -= 2; - testBox2.top -= 1; - testBox2.bottom += 1; - - if (testBox2.contains(pointFrom)) { - if (pointFrom.x > anotherActorScreenPosition.x + 4) { - testBox.right = pointFrom.x - 1; - } else if (pointFrom.x < anotherActorScreenPosition.x - 4) { - testBox.left = pointFrom.x + 2; - } else if (pointFrom.y > anotherActorScreenPosition.y) { - testBox.bottom = pointFrom.y; - } else { - testBox.top = pointFrom.y + 1 ; - } - } - - if ((testBox.width() > 0) && (testBox.height() > 0)) { - _barrierList[_barrierCount++] = testBox; - } - } - } - - - pointBest = pointTo; - actor->_walkStepsCount = 0; - findActorPath(actor, pointFrom, pointTo); - - if (actor->_walkStepsCount == 0) { - error("actor->_walkStepsCount == 0"); - } - - if (extraStartNode) { - actor->_walkStepIndex = 0; - } else { - actor->_walkStepIndex = 1; - } - - if (extraEndNode) { - toLocation.toScreenPointXY(tempPoint); - actor->_walkStepsCount--; - actor->addWalkStepPoint(tempPoint); - } - - - pointBest = actor->_walkStepsPoints[actor->_walkStepsCount - 1]; - - pointBest.x &= ~1; - delta.x = ABS(pointFrom.x - pointTo.x); - delta.y = ABS(pointFrom.y - pointTo.y); - - bestDelta.x = ABS(pointBest.x - pointTo.x); - bestDelta.y = ABS(pointBest.y - pointTo.y); - - if ((delta.x + delta.y <= bestDelta.x + bestDelta.y) && (actor->_flags & kFollower)) { - actor->_actorFlags |= kActorNoFollow; - } - - if (pointBest == pointFrom) { - actor->_walkStepsCount = 0; - } - } else { - actor->_walkStepsCount = 0; - actor->addWalkStepPoint(pointTo); - actor->_walkStepIndex = 0; - } - - actor->_partialTarget = actor->_location; - actor->_finalTarget = toLocation; - if (actor->_walkStepsCount == 0) { - actorEndWalk(actorId, false); - return false; - } else { - if (actor->_flags & kProtagonist) { - _actors[1]->_actorFlags &= ~kActorNoFollow; // TODO: mark all actors with kFollower flag, not only 1 and 2 - _actors[2]->_actorFlags &= ~kActorNoFollow; - } - actor->_currentAction = (actor->_walkStepsCount >= ACTOR_MAX_STEPS_COUNT) ? kActionWalkToLink : kActionWalkToPoint; - actor->_walkFrameSequence = getFrameType(kFrameWalk); - } - } - return true; -} - -void Actor::actorSpeech(uint16 actorId, const char **strings, int stringsCount, int sampleResourceId, int speechFlags) { - ActorData *actor; - int i; - int16 dist; - - actor = getActor(actorId); - calcScreenPosition(actor); - for (i = 0; i < stringsCount; i++) { - _activeSpeech.strings[i] = strings[i]; - } + actor = getActor(actorId); + calcScreenPosition(actor); + for (i = 0; i < stringsCount; i++) { + _activeSpeech.strings[i] = strings[i]; + } _activeSpeech.stringsCount = stringsCount; _activeSpeech.speechFlags = speechFlags; @@ -2393,759 +1224,6 @@ void Actor::abortSpeech() { _activeSpeech.playingTime = 0; } -void Actor::moveDragon(ActorData *actor) { - int16 dir0, dir1, dir2, dir3; - int16 moveType; - Event event; - const DragonMove *dragonMove; - - if ((actor->_actionCycle < 0) || - ((actor->_actionCycle == 0) && (actor->_dragonMoveType >= ACTOR_DRAGON_TURN_MOVES))) { - - moveType = kDragonMoveInvalid; - if (actor->_location.distance(_protagonist->_location) < 24) { - if (_dragonHunt && (_protagonist->_currentAction != kActionFall)) { - event.type = kEvTOneshot; - event.code = kScriptEvent; - event.op = kEventExecNonBlocking; - event.time = 0; - event.param = _vm->_scene->getScriptModuleNumber(); // module number - event.param2 = ACTOR_EXP_KNOCK_RIF; // script entry point number - event.param3 = -1; // Action - event.param4 = -1; // Object - event.param5 = -1; // With Object - event.param6 = -1; // Actor - _vm->_events->queue(&event); - - _dragonHunt = false; - } - } else { - _dragonHunt = true; - } - - if (actor->_walkStepIndex + 2 > actor->_walkStepsCount) { - - _vm->_isoMap->findDragonTilePath(actor, actor->_location, _protagonist->_location, actor->_actionDirection); - - if (actor->_walkStepsCount == 0) { - _vm->_isoMap->findDragonTilePath(actor, actor->_location, _protagonist->_location, 0); - } - - if (actor->_walkStepsCount < 2) { - return; - } - - actor->_partialTarget = actor->_location; - actor->_finalTarget = _protagonist->_location; - actor->_walkStepIndex = 0; - } - - dir0 = actor->_actionDirection; - dir1 = actor->_tileDirections[actor->_walkStepIndex++]; - dir2 = actor->_tileDirections[actor->_walkStepIndex]; - dir3 = actor->_tileDirections[actor->_walkStepIndex + 1]; - - if (dir0 != dir1){ - actor->_actionDirection = dir0 = dir1; - } - - actor->_location = actor->_partialTarget; - - if ((dir1 != dir2) && (dir1 == dir3)) { - switch (dir1) { - case kDirUpLeft: - actor->_partialTarget.v() += 16; - moveType = kDragonMoveUpLeft; - break; - case kDirDownLeft: - actor->_partialTarget.u() -= 16; - moveType = kDragonMoveDownLeft; - break; - case kDirDownRight: - actor->_partialTarget.v() -= 16; - moveType = kDragonMoveDownRight; - break; - case kDirUpRight: - actor->_partialTarget.u() += 16; - moveType = kDragonMoveUpRight; - break; - } - - switch (dir2) { - case kDirUpLeft: - actor->_partialTarget.v() += 16; - break; - case kDirDownLeft: - actor->_partialTarget.u() -= 16; - break; - case kDirDownRight: - actor->_partialTarget.v() -= 16; - break; - case kDirUpRight: - actor->_partialTarget.u() += 16; - break; - } - - actor->_walkStepIndex++; - } else { - switch (dir1) { - case kDirUpLeft: - actor->_partialTarget.v() += 16; - switch (dir2) { - case kDirDownLeft: - moveType = kDragonMoveUpLeft_Left; - actor->_partialTarget.u() -= 16; - break; - case kDirUpLeft: - moveType = kDragonMoveUpLeft; - break; - case kDirUpRight: - actor->_partialTarget.u() += 16; - moveType = kDragonMoveUpLeft_Right; - break; - default: - actor->_actionDirection = dir1; - actor->_walkStepsCount = 0; - break; - } - break; - case kDirDownLeft: - actor->_partialTarget.u() -= 16; - switch (dir2) { - case kDirDownRight: - moveType = kDragonMoveDownLeft_Left; - actor->_partialTarget.v() -= 16; - break; - case kDirDownLeft: - moveType = kDragonMoveDownLeft; - break; - case kDirUpLeft: - moveType = kDragonMoveDownLeft_Right; - actor->_partialTarget.v() += 16; - break; - default: - actor->_actionDirection = dir1; - actor->_walkStepsCount = 0; - break; - } - break; - case kDirDownRight: - actor->_partialTarget.v() -= 16; - switch (dir2) { - case kDirUpRight: - moveType = kDragonMoveDownRight_Left; - actor->_partialTarget.u() += 16; - break; - case kDirDownRight: - moveType = kDragonMoveDownRight; - break; - case kDirDownLeft: - moveType = kDragonMoveDownRight_Right; - actor->_partialTarget.u() -= 16; - break; - default: - actor->_actionDirection = dir1; - actor->_walkStepsCount = 0; - break; - } - break; - case kDirUpRight: - actor->_partialTarget.u() += 16; - switch (dir2) { - case kDirUpLeft: - moveType = kDragonMoveUpRight_Left; - actor->_partialTarget.v() += 16; - break; - case kDirUpRight: - moveType = kDragonMoveUpRight; - break; - case kDirDownRight: - moveType = kDragonMoveUpRight_Right; - actor->_partialTarget.v() -= 16; - break; - default: - actor->_actionDirection = dir1; - actor->_walkStepsCount = 0; - break; - } - break; - - default: - actor->_actionDirection = dir1; - actor->_walkStepsCount = 0; - break; - } - } - - actor->_dragonMoveType = moveType; - - if (moveType >= ACTOR_DRAGON_TURN_MOVES) { - actor->_dragonStepCycle = 0; - actor->_actionCycle = 4; - actor->_walkStepIndex++; - } else { - actor->_actionCycle = 4; - } - } - - actor->_actionCycle--; - - if ((actor->_walkStepsCount < 1) || (actor->_actionCycle < 0)) { - return; - } - - if (actor->_dragonMoveType < ACTOR_DRAGON_TURN_MOVES) { - - actor->_dragonStepCycle++; - if (actor->_dragonStepCycle >= 7) { - actor->_dragonStepCycle = 0; - } - - actor->_dragonBaseFrame = actor->_dragonMoveType * 7; - - if (actor->_location.u() > actor->_partialTarget.u() + 3) { - actor->_location.u() -= 4; - } else if (actor->_location.u() < actor->_partialTarget.u() - 3) { - actor->_location.u() += 4; - } else { - actor->_location.u() = actor->_partialTarget.u(); - } - - if (actor->_location.v() > actor->_partialTarget.v() + 3) { - actor->_location.v() -= 4; - } else if (actor->_location.v() < actor->_partialTarget.v() - 3) { - actor->_location.v() += 4; - } else { - actor->_location.v() = actor->_partialTarget.v(); - } - } else { - dragonMove = &dragonMoveTable[actor->_dragonMoveType]; - actor->_dragonBaseFrame = dragonMove->baseFrame; - - - actor->_location.u() = actor->_partialTarget.u() - dragonMove->offset[actor->_actionCycle][0]; - actor->_location.v() = actor->_partialTarget.v() - dragonMove->offset[actor->_actionCycle][1]; - - actor->_dragonStepCycle++; - if (actor->_dragonStepCycle >= 3) { - actor->_dragonStepCycle = 3; - } - } - - actor->_frameNumber = actor->_dragonBaseFrame + actor->_dragonStepCycle; -} - -void Actor::findActorPath(ActorData *actor, const Point &fromPoint, const Point &toPoint) { - Point iteratorPoint; - Point bestPoint; - int maskType; - int i; - Rect intersect; - -#ifdef ACTOR_DEBUG - _debugPointsCount = 0; -#endif - - actor->_walkStepsCount = 0; - if (fromPoint == toPoint) { - actor->addWalkStepPoint(toPoint); - return; - } - - for (iteratorPoint.y = 0; iteratorPoint.y < _yCellCount; iteratorPoint.y++) { - for (iteratorPoint.x = 0; iteratorPoint.x < _xCellCount; iteratorPoint.x++) { - if (_vm->_scene->validBGMaskPoint(iteratorPoint)) { - maskType = _vm->_scene->getBGMaskType(iteratorPoint); - setPathCell(iteratorPoint, _vm->_scene->getDoorState(maskType) ? kPathCellBarrier : kPathCellEmpty); - } else { - setPathCell(iteratorPoint, kPathCellBarrier); - } - } - } - - for (i = 0; i < _barrierCount; i++) { - intersect.left = MAX(_pathRect.left, _barrierList[i].left); - intersect.top = MAX(_pathRect.top, _barrierList[i].top); - intersect.right = MIN(_pathRect.right, _barrierList[i].right); - intersect.bottom = MIN(_pathRect.bottom, _barrierList[i].bottom); - - for (iteratorPoint.y = intersect.top; iteratorPoint.y < intersect.bottom; iteratorPoint.y++) { - for (iteratorPoint.x = intersect.left; iteratorPoint.x < intersect.right; iteratorPoint.x++) { - setPathCell(iteratorPoint, kPathCellBarrier); - } - } - } - -#ifdef ACTOR_DEBUG - for (iteratorPoint.y = 0; iteratorPoint.y < _yCellCount; iteratorPoint.y++) { - for (iteratorPoint.x = 0; iteratorPoint.x < _xCellCount; iteratorPoint.x++) { - if (getPathCell(iteratorPoint) == kPathCellBarrier) { - addDebugPoint(iteratorPoint, 24); - } - } - } -#endif - - if (scanPathLine(fromPoint, toPoint)) { - actor->addWalkStepPoint(fromPoint); - actor->addWalkStepPoint(toPoint); - return; - } - - i = fillPathArray(fromPoint, toPoint, bestPoint); - - if (fromPoint == bestPoint) { - actor->addWalkStepPoint(bestPoint); - return; - } - - if (i == 0) { - error("fillPathArray returns zero"); - } - - setActorPath(actor, fromPoint, bestPoint); -} - -bool Actor::scanPathLine(const Point &point1, const Point &point2) { - Point point; - Point delta; - Point s; - Point fDelta; - int16 errterm; - - calcDeltaS(point1, point2, delta, s); - point = point1; - - fDelta.x = delta.x * 2; - fDelta.y = delta.y * 2; - - if (delta.y > delta.x) { - - errterm = fDelta.x - delta.y; - - while (delta.y > 0) { - while (errterm >= 0) { - point.x += s.x; - errterm -= fDelta.y; - } - - point.y += s.y; - errterm += fDelta.x; - - if (!validPathCellPoint(point)) { - return false; - } - if (getPathCell(point) == kPathCellBarrier) { - return false; - } - delta.y--; - } - } else { - - errterm = fDelta.y - delta.x; - - while (delta.x > 0) { - while (errterm >= 0) { - point.y += s.y; - errterm -= fDelta.x; - } - - point.x += s.x; - errterm += fDelta.y; - - if (!validPathCellPoint(point)) { - return false; - } - if (getPathCell(point) == kPathCellBarrier) { - return false; - } - delta.x--; - } - } - return true; -} - -int Actor::fillPathArray(const Point &fromPoint, const Point &toPoint, Point &bestPoint) { - int bestRating; - int currentRating; - int i; - Point bestPath; - int pointCounter; - int startDirection; - PathDirectionData *pathDirection; - PathDirectionData *newPathDirection; - const PathDirectionData *samplePathDirection; - Point nextPoint; - int directionCount; - int16 compressX = (_vm->getGameType() == GType_ITE) ? 2 : 1; - - _pathDirectionListCount = 0; - pointCounter = 0; - bestRating = quickDistance(fromPoint, toPoint, compressX); - bestPath = fromPoint; - - for (startDirection = 0; startDirection < 4; startDirection++) { - newPathDirection = addPathDirectionListData(); - newPathDirection->coord = fromPoint; - newPathDirection->direction = startDirection; - } - - if (validPathCellPoint(fromPoint)) { - setPathCell(fromPoint, kDirUp); - -#ifdef ACTOR_DEBUG - addDebugPoint(fromPoint, 24+36); -#endif - } - - i = 0; - - do { - pathDirection = &_pathDirectionList[i]; - for (directionCount = 0; directionCount < 3; directionCount++) { - samplePathDirection = &pathDirectionLUT[pathDirection->direction][directionCount]; - nextPoint = pathDirection->coord; - nextPoint.x += samplePathDirection->coord.x; - nextPoint.y += samplePathDirection->coord.y; - - if (!validPathCellPoint(nextPoint)) { - continue; - } - - if (getPathCell(nextPoint) != kPathCellEmpty) { - continue; - } - - setPathCell(nextPoint, samplePathDirection->direction); - -#ifdef ACTOR_DEBUG - addDebugPoint(nextPoint, samplePathDirection->direction + 96); -#endif - newPathDirection = addPathDirectionListData(); - newPathDirection->coord = nextPoint; - newPathDirection->direction = samplePathDirection->direction; - ++pointCounter; - if (nextPoint == toPoint) { - bestPoint = toPoint; - return pointCounter; - } - currentRating = quickDistance(nextPoint, toPoint, compressX); - if (currentRating < bestRating) { - bestRating = currentRating; - bestPath = nextPoint; - } - pathDirection = &_pathDirectionList[i]; - } - ++i; - } while (i < _pathDirectionListCount); - - bestPoint = bestPath; - return pointCounter; -} - -void Actor::setActorPath(ActorData *actor, const Point &fromPoint, const Point &toPoint) { - Point nextPoint; - int8 direction; - int i; - - _pathListIndex = -1; - addPathListPoint(toPoint); - nextPoint = toPoint; - - while (!(nextPoint == fromPoint)) { - direction = getPathCell(nextPoint); - if ((direction < 0) || (direction >= 8)) { - error("Actor::setActorPath error direction 0x%X", direction); - } - nextPoint.x -= pathDirectionLUT2[direction][0]; - nextPoint.y -= pathDirectionLUT2[direction][1]; - addPathListPoint(nextPoint); - -#ifdef ACTOR_DEBUG - addDebugPoint(nextPoint, 0x8a); -#endif - } - - pathToNode(); - removeNodes(); - nodeToPath(); - removePathPoints(); - - for (i = 0; i <= _pathNodeListIndex; i++) { - actor->addWalkStepPoint(_pathNodeList[i].point); - } -} - -void Actor::pathToNode() { - Point point1, point2, delta; - int direction; - int i; - Point *point; - - point= &_pathList[_pathListIndex]; - direction = 0; - - _pathNodeListIndex = -1; - addPathNodeListPoint(*point); - - for (i = _pathListIndex; i > 0; i--) { - point1 = *point; - --point; - point2 = *point; - if (direction == 0) { - delta.x = int16Compare(point2.x, point1.x); - delta.y = int16Compare(point2.y, point1.y); - direction++; - } - if ((point1.x + delta.x != point2.x) || (point1.y + delta.y != point2.y)) { - addPathNodeListPoint(point1); - direction--; - i++; - point++; - } - } - addPathNodeListPoint(*_pathList); -} - -int pathLine(Point *pointList, const Point &point1, const Point &point2) { - Point point; - Point delta; - Point tempPoint; - Point s; - int16 errterm; - int16 res; - - calcDeltaS(point1, point2, delta, s); - - point = point1; - - tempPoint.x = delta.x * 2; - tempPoint.y = delta.y * 2; - - if (delta.y > delta.x) { - - errterm = tempPoint.x - delta.y; - res = delta.y; - - while (delta.y > 0) { - while (errterm >= 0) { - point.x += s.x; - errterm -= tempPoint.y; - } - - point.y += s.y; - errterm += tempPoint.x; - - *pointList = point; - pointList++; - delta.y--; - } - } else { - - errterm = tempPoint.y - delta.x; - res = delta.x; - - while (delta.x > 0) { - while (errterm >= 0) { - point.y += s.y; - errterm -= tempPoint.x; - } - - point.x += s.x; - errterm += tempPoint.y; - - *pointList = point; - pointList++; - delta.x--; - } - } - return res; -} - -void Actor::nodeToPath() { - int i; - Point point1, point2; - PathNode *node; - Point *point; - - for (i = 0, point = _pathList; i < _pathListAlloced; i++, point++) { - point->x = point->y = PATH_NODE_EMPTY; - } - - _pathListIndex = 1; - _pathList[0] = _pathNodeList[0].point; - _pathNodeList[0].link = 0; - for (i = 0, node = _pathNodeList; i < _pathNodeListIndex; i++) { - point1 = node->point; - node++; - point2 = node->point; - _pathListIndex += pathLine(&_pathList[_pathListIndex], point1, point2); - node->link = _pathListIndex - 1; - } - _pathListIndex--; - _pathNodeList[_pathNodeListIndex].link = _pathListIndex; - -} - -void Actor::removeNodes() { - int i, j, k; - PathNode *iNode, *jNode, *kNode, *fNode; - fNode = &_pathNodeList[_pathNodeListIndex]; - - if (scanPathLine(_pathNodeList[0].point, fNode->point)) { - _pathNodeList[1] = *fNode; - _pathNodeListIndex = 1; - } - - if (_pathNodeListIndex < 4) { - return; - } - - for (i = _pathNodeListIndex - 1, iNode = fNode-1; i > 1 ; i--, iNode--) { - if (iNode->point.x == PATH_NODE_EMPTY) { - continue; - } - - if (scanPathLine(_pathNodeList[0].point, iNode->point)) { - for (j = 1, jNode = _pathNodeList + 1; j < i; j++, jNode++) { - jNode->point.x = PATH_NODE_EMPTY; - } - } - } - - for (i = 1, iNode = _pathNodeList + 1; i < _pathNodeListIndex - 1; i++, iNode++) { - if (iNode->point.x == PATH_NODE_EMPTY) { - continue; - } - - if (scanPathLine(fNode->point, iNode->point)) { - for (j = i + 1, jNode = iNode + 1; j < _pathNodeListIndex; j++, jNode++) { - jNode->point.x = PATH_NODE_EMPTY; - } - } - } - condenseNodeList(); - - for (i = 1, iNode = _pathNodeList + 1; i < _pathNodeListIndex - 1; i++, iNode++) { - if (iNode->point.x == PATH_NODE_EMPTY) { - continue; - } - for (j = i + 2, jNode = iNode + 2; j < _pathNodeListIndex; j++, jNode++) { - if (jNode->point.x == PATH_NODE_EMPTY) { - continue; - } - - if (scanPathLine(iNode->point, jNode->point)) { - for (k = i + 1,kNode = iNode + 1; k < j; k++, kNode++) { - kNode->point.x = PATH_NODE_EMPTY; - } - } - } - } - condenseNodeList(); -} - -void Actor::condenseNodeList() { - int i, j, count; - PathNode *iNode, *jNode; - - count = _pathNodeListIndex; - - for (i = 1, iNode = _pathNodeList + 1; i < _pathNodeListIndex; i++, iNode++) { - if (iNode->point.x == PATH_NODE_EMPTY) { - j = i + 1; - jNode = iNode + 1; - while (jNode->point.x == PATH_NODE_EMPTY) { - j++; - jNode++; - } - *iNode = *jNode; - count = i; - jNode->point.x = PATH_NODE_EMPTY; - if (j == _pathNodeListIndex) { - break; - } - } - } - _pathNodeListIndex = count; -} - -void Actor::removePathPoints() { - int i, j, k, l; - PathNode *node; - int start; - int end; - Point point1, point2; - - if (_pathNodeListIndex < 2) - return; - - _newPathNodeListIndex = -1; - addNewPathNodeListPoint(_pathNodeList[0]); - - for (i = 1, node = _pathNodeList + 1; i < _pathNodeListIndex; i++, node++) { - addNewPathNodeListPoint(*node); - - for (j = 5; j > 0; j--) { - start = node->link - j; - end = node->link + j; - - if (start < 0 || end > _pathListIndex) { - continue; - } - - point1 = _pathList[start]; - point2 = _pathList[end]; - if ((point1.x == PATH_NODE_EMPTY) || (point2.x == PATH_NODE_EMPTY)) { - continue; - } - - if (scanPathLine(point1, point2)) { - for (l = 1; l <= _newPathNodeListIndex; l++) { - if (start <= _newPathNodeList[l].link) { - _newPathNodeListIndex = l; - _newPathNodeList[_newPathNodeListIndex].point = point1; - _newPathNodeList[_newPathNodeListIndex].link = start; - incrementNewPathNodeListIndex(); - break; - } - } - _newPathNodeList[_newPathNodeListIndex].point = point2; - _newPathNodeList[_newPathNodeListIndex].link = end; - - for (k = start + 1; k < end; k++) { - _pathList[k].x = PATH_NODE_EMPTY; - } - break; - } - } - } - - addNewPathNodeListPoint(_pathNodeList[_pathNodeListIndex]); - - for (i = 0, j = 0; i <= _newPathNodeListIndex; i++) { - if (_newPathNodeListIndex == i || (_newPathNodeList[i].point != _newPathNodeList[i+1].point)) { - _pathNodeList[j++] = _newPathNodeList[i]; - } - } - _pathNodeListIndex = j - 1; -} - -void Actor::drawPathTest() { -#ifdef ACTOR_DEBUG - int i; - Surface *surface; - surface = _vm->_gfx->getBackBuffer(); - if (_debugPoints == NULL) { - return; - } - - for (i = 0; i < _debugPointsCount; i++) { - *((byte *)surface->pixels + (_debugPoints[i].point.y * surface->pitch) + _debugPoints[i].point.x) = _debugPoints[i].color; - } -#endif -} - void Actor::saveState(Common::OutSaveFile *out) { uint16 i; @@ -3188,24 +1266,4 @@ void Actor::loadState(Common::InSaveFile *in) { } } -// Console wrappers - must be safe to run - -void Actor::cmdActorWalkTo(int argc, const char **argv) { - uint16 actorId = (uint16) atoi(argv[1]); - Location location; - Point movePoint; - - movePoint.x = atoi(argv[2]); - movePoint.y = atoi(argv[3]); - - location.fromScreenPoint(movePoint); - - if (!validActorId(actorId)) { - _vm->_console->DebugPrintf("Actor::cmActorWalkTo Invalid actorId 0x%X.\n", actorId); - return; - } - - actorWalkTo(actorId, location); -} - } // End of namespace Saga diff --git a/engines/saga/actor.h b/engines/saga/actor.h index 971fe8f5be..7022ef1289 100644 --- a/engines/saga/actor.h +++ b/engines/saga/actor.h @@ -94,6 +94,24 @@ enum ActorActions { kActionClimb = 12 }; +enum ActorFrameIds { +//ITE + kFrameITEStand = 0, + kFrameITEWalk = 1, + kFrameITESpeak = 2, + kFrameITEGive = 3, + kFrameITEGesture = 4, + kFrameITEWait = 5, + kFrameITEPickUp = 6, + kFrameITELook = 7, +//IHNM + kFrameIHNMStand = 0, + kFrameIHNMSpeak = 1, + kFrameIHNMWait = 2, + kFrameIHNMGesture = 3, + kFrameIHNMWalk = 4 +}; + enum SpeechFlags { kSpeakNoAnimate = 1, kSpeakAsync = 2, @@ -112,6 +130,18 @@ enum ActorFrameTypes { kFrameLook }; +// Lookup table to convert 8 cardinal directions to 4 +static const int actorDirectectionsLUT[8] = { + ACTOR_DIRECTION_BACK, // kDirUp + ACTOR_DIRECTION_RIGHT, // kDirUpRight + ACTOR_DIRECTION_RIGHT, // kDirRight + ACTOR_DIRECTION_RIGHT, // kDirDownRight + ACTOR_DIRECTION_FORWARD,// kDirDown + ACTOR_DIRECTION_LEFT, // kDirDownLeft + ACTOR_DIRECTION_LEFT, // kDirLeft + ACTOR_DIRECTION_LEFT, // kDirUpLeft +}; + enum ActorFlagsEx { kActorNoCollide = (1 << 0), kActorNoFollow = (1 << 1), diff --git a/engines/saga/actor_walk.cpp b/engines/saga/actor_walk.cpp new file mode 100644 index 0000000000..f1f3b2edad --- /dev/null +++ b/engines/saga/actor_walk.cpp @@ -0,0 +1,1942 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "saga/saga.h" + +#include "saga/actor.h" +#include "saga/console.h" +#include "saga/events.h" +#include "saga/isomap.h" +#include "saga/objectmap.h" +#include "saga/sagaresnames.h" +#include "saga/script.h" +#include "saga/sound.h" +#include "saga/scene.h" + +namespace Saga { + +static const PathDirectionData pathDirectionLUT[8][3] = { + { { 0, Point( 0, -1) }, { 7, Point(-1, -1) }, { 4, Point( 1, -1) } }, + { { 1, Point( 1, 0) }, { 4, Point( 1, -1) }, { 5, Point( 1, 1) } }, + { { 2, Point( 0, 1) }, { 5, Point( 1, 1) }, { 6, Point(-1, 1) } }, + { { 3, Point(-1, 0) }, { 6, Point(-1, 1) }, { 7, Point(-1, -1) } }, + { { 0, Point( 0, -1) }, { 1, Point( 1, 0) }, { 4, Point( 1, -1) } }, + { { 1, Point( 1, 0) }, { 2, Point( 0, 1) }, { 5, Point( 1, 1) } }, + { { 2, Point( 0, 1) }, { 3, Point(-1, 0) }, { 6, Point(-1, 1) } }, + { { 3, Point(-1, 0) }, { 0, Point( 0, -1) }, { 7, Point(-1, -1) } } +}; + +static const int pathDirectionLUT2[8][2] = { + { 0, -1 }, + { 1, 0 }, + { 0, 1 }, + { -1, 0 }, + { 1, -1 }, + { 1, 1 }, + { -1, 1 }, + { -1, -1 } +}; + +static const int angleLUT[16][2] = { + { 0, -256 }, + { 98, -237 }, + { 181, -181 }, + { 237, -98 }, + { 256, 0 }, + { 237, 98 }, + { 181, 181 }, + { 98, 237 }, + { 0, 256 }, + { -98, 237 }, + { -181, 181 }, + { -237, 98 }, + { -256, 0 }, + { -237, -98 }, + { -181, -181 }, + { -98, -237 } +}; + +static const int directionLUT[8][2] = { + { 0 * 2, -2 * 2 }, + { 2 * 2, -1 * 2 }, + { 3 * 2, 0 * 2 }, + { 2 * 2, 1 * 2 }, + { 0 * 2, 2 * 2 }, + { -2 * 2, 1 * 2 }, + { -4 * 2, 0 * 2 }, + { -2 * 2, -1 * 2 } +}; + +static const int tileDirectionLUT[8][2] = { + { 1, 1 }, + { 2, 0 }, + { 1, -1 }, + { 0, -2 }, + { -1, -1 }, + { -2, 0 }, + { -1, 1 }, + { 0, 2 } +}; + +struct DragonMove { + uint16 baseFrame; + int16 offset[4][2]; +}; + +static const DragonMove dragonMoveTable[12] = { + { 0, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } }, + { 0, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } }, + { 0, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } }, + { 0, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } }, + { 28, { { -0, 0 }, { -1, 6 }, { -5, 11 }, { -10, 15 } } }, + { 56, { { 0, 0 }, { 1, 6 }, { 5, 11 }, { 10, 15 } } }, + { 40, { { 0, 0 }, { 6, 1 }, { 11, 5 }, { 15, 10 } } }, + { 44, { { 0, 0 }, { 6, -1 }, { 11, -5 }, { 15, -10 } } }, + { 32, { { -0, -0 }, { -6, -1 }, { -11, -5 }, { -15, -10 } } }, + { 52, { { -0, 0 }, { -6, 1 }, { -11, 5 }, { -15, 10 } } }, + { 36, { { 0, -0 }, { 1, -6 }, { 5, -11 }, { 10, -15 } } }, + { 48, { { -0, -0 }, { -1, -6 }, { -5, -11 }, { -10, -15 } } } +}; + +inline int16 quickDistance(const Point &point1, const Point &point2, int16 compressX) { + Point delta; + delta.x = ABS(point1.x - point2.x) / compressX; + delta.y = ABS(point1.y - point2.y); + return ((delta.x < delta.y) ? (delta.y + delta.x / 2) : (delta.x + delta.y / 2)); +} + +inline void calcDeltaS(const Point &point1, const Point &point2, Point &delta, Point &s) { + + delta.x = point2.x - point1.x; + if (delta.x == 0) { + s.x = 0; + } else { + if (delta.x > 0) { + s.x = 1; + } else { + s.x = -1; + delta.x = -delta.x; + } + } + + + delta.y = point2.y - point1.y; + if (delta.y == 0) { + s.y = 0; + } else { + if (delta.y > 0) { + s.y = 1; + } else { + s.y = -1; + delta.y = -delta.y; + } + } +} + +inline int16 int16Compare(int16 i1, int16 i2) { + return ((i1) > (i2) ? 1 : ((i1) < (i2) ? -1 : 0)); +} + +bool Actor::validFollowerLocation(const Location &location) { + Point point; + location.toScreenPointXY(point); + + if ((point.x < 5) || (point.x >= _vm->getDisplayWidth() - 5) || + (point.y < 0) || (point.y > _vm->_scene->getHeight())) { + return false; + } + + return (_vm->_scene->canWalk(point)); +} + +void Actor::realLocation(Location &location, uint16 objectId, uint16 walkFlags) { + int angle; + int distance; + ActorData *actor; + ObjectData *obj; + debug (8, "Actor::realLocation objectId=%i", objectId); + if (walkFlags & kWalkUseAngle) { + if (_vm->_scene->getFlags() & kSceneFlagISO) { + angle = (location.x + 2) & 15; + distance = location.y; + + location.u() = (angleLUT[angle][0] * distance) >> 8; + location.v() = -(angleLUT[angle][1] * distance) >> 8; + } else { + angle = location.x & 15; + distance = location.y; + + location.x = (angleLUT[angle][0] * distance) >> 6; + location.y = (angleLUT[angle][1] * distance) >> 6; + } + } + + if (objectId != ID_NOTHING) { + if (validActorId(objectId)) { + actor = getActor(objectId); + location.addXY(actor->_location); + } else if (validObjId(objectId)) { + obj = getObj(objectId); + location.addXY(obj->_location); + } + } +} + +void Actor::actorFaceTowardsObject(uint16 actorId, uint16 objectId) { + ActorData *actor; + ObjectData *obj; + + if (validActorId(objectId)) { + actor = getActor(objectId); + actorFaceTowardsPoint(actorId, actor->_location); + } else if (validObjId(objectId)) { + obj = getObj(objectId); + actorFaceTowardsPoint(actorId, obj->_location); + } +} + +void Actor::actorFaceTowardsPoint(uint16 actorId, const Location &toLocation) { + ActorData *actor; + Location delta; + //debug (8, "Actor::actorFaceTowardsPoint actorId=%i", actorId); + actor = getActor(actorId); + + toLocation.delta(actor->_location, delta); + + if (_vm->_scene->getFlags() & kSceneFlagISO) { + if (delta.u() > 0) { + actor->_facingDirection = (delta.v() > 0) ? kDirUp : kDirRight; + } else { + actor->_facingDirection = (delta.v() > 0) ? kDirLeft : kDirDown; + } + } else { + if (ABS(delta.y) > ABS(delta.x * 2)) { + actor->_facingDirection = (delta.y > 0) ? kDirDown : kDirUp; + } else { + actor->_facingDirection = (delta.x > 0) ? kDirRight : kDirLeft; + } + } +} + +void Actor::updateActorsScene(int actorsEntrance) { + int i, j; + int followerDirection; + ActorData *actor; + Location tempLocation; + Location possibleLocation; + Point delta; + const SceneEntry *sceneEntry; + + if (_vm->_scene->currentSceneNumber() == 0) { + error("Actor::updateActorsScene _vm->_scene->currentSceneNumber() == 0"); + } + + _vm->_sound->stopVoice(); + _activeSpeech.stringsCount = 0; + _activeSpeech.playing = false; + _protagonist = NULL; + + for (i = 0; i < _actorsCount; i++) { + actor = _actors[i]; + actor->_inScene = false; + actor->_spriteList.freeMem(); + if (actor->_disabled) { + continue; + } + if ((actor->_flags & (kProtagonist | kFollower)) || (i == 0)) { + if (actor->_flags & kProtagonist) { + actor->_finalTarget = actor->_location; + _centerActor = _protagonist = actor; + } else if (_vm->getGameType() == GType_ITE && + _vm->_scene->currentSceneResourceId() == RID_ITE_OVERMAP_SCENE) { + continue; + } + + actor->_sceneNumber = _vm->_scene->currentSceneNumber(); + } + if (actor->_sceneNumber == _vm->_scene->currentSceneNumber()) { + actor->_inScene = true; + actor->_actionCycle = (_vm->_rnd.getRandomNumber(7) & 0x7) * 4; // 1/8th chance + } + } + + // _protagonist can be null while loading a game from the command line + if (_protagonist == NULL) + return; + + if ((actorsEntrance >= 0) && (_vm->_scene->_entryList.entryListCount > 0)) { + if (_vm->_scene->_entryList.entryListCount <= actorsEntrance) { + actorsEntrance = 0; //OCEAN bug + } + + sceneEntry = _vm->_scene->_entryList.getEntry(actorsEntrance); + if (_vm->_scene->getFlags() & kSceneFlagISO) { + _protagonist->_location = sceneEntry->location; + } else { + _protagonist->_location.x = sceneEntry->location.x * ACTOR_LMULT; + _protagonist->_location.y = sceneEntry->location.y * ACTOR_LMULT; + _protagonist->_location.z = sceneEntry->location.z * ACTOR_LMULT; + } + // Workaround for bug #1328045: + // "When entering any of the houses at the start of the + // game if you click on anything inside the building you + // start walking through the door, turn around and leave." + // + // After stepping on an action zone, Rif is trying to exit. + // Shift Rif's entry position to a non action zone area. + if (_vm->getGameType() == GType_ITE) { + if ((_vm->_scene->currentSceneNumber() >= 53) && (_vm->_scene->currentSceneNumber() <= 66)) + _protagonist->_location.y += 10; + } + + _protagonist->_facingDirection = _protagonist->_actionDirection = sceneEntry->facing; + } + + _protagonist->_currentAction = kActionWait; + + if (_vm->_scene->getFlags() & kSceneFlagISO) { + //nothing? + } else { + _vm->_scene->initDoorsState(); //TODO: move to _scene + } + + followerDirection = _protagonist->_facingDirection + 3; + calcScreenPosition(_protagonist); + + for (i = 0; i < _actorsCount; i++) { + actor = _actors[i]; + if (actor->_flags & (kFollower)) { + actor->_facingDirection = actor->_actionDirection = _protagonist->_facingDirection; + actor->_currentAction = kActionWait; + actor->_walkStepsCount = actor->_walkStepIndex = 0; + actor->_location.z = _protagonist->_location.z; + + + if (_vm->_scene->getFlags() & kSceneFlagISO) { + _vm->_isoMap->placeOnTileMap(_protagonist->_location, actor->_location, 3, followerDirection & 0x07); + } else { + followerDirection &= 0x07; + + possibleLocation = _protagonist->_location; + + delta.x = directionLUT[followerDirection][0]; + delta.y = directionLUT[followerDirection][1]; + + for (j = 0; j < 30; j++) { + tempLocation = possibleLocation; + tempLocation.x += delta.x; + tempLocation.y += delta.y; + + if (validFollowerLocation(tempLocation)) { + possibleLocation = tempLocation; + } else { + tempLocation = possibleLocation; + tempLocation.x += delta.x; + if (validFollowerLocation(tempLocation)) { + possibleLocation = tempLocation; + } else { + tempLocation = possibleLocation; + tempLocation.y += delta.y; + if (validFollowerLocation(tempLocation)) { + possibleLocation = tempLocation; + } else { + break; + } + } + } + } + + actor->_location = possibleLocation; + } + followerDirection += 2; + } + + } + + handleActions(0, true); + if (_vm->_scene->getFlags() & kSceneFlagISO) { + _vm->_isoMap->adjustScroll(true); + } +} + +void Actor::handleActions(int msec, bool setup) { + int i; + ActorData *actor; + ActorFrameRange *frameRange; + int state; + int speed; + int32 framesLeft; + Location delta; + Location addDelta; + int hitZoneIndex; + const HitZone *hitZone; + Point hitPoint; + Location pickLocation; + + for (i = 0; i < _actorsCount; i++) { + actor = _actors[i]; + if (!actor->_inScene) + continue; + + if ((_vm->getGameType() == GType_ITE) && (i == ACTOR_DRAGON_INDEX)) { + moveDragon(actor); + continue; + } + + switch (actor->_currentAction) { + case kActionWait: + if (!setup && (actor->_flags & kFollower)) { + followProtagonist(actor); + if (actor->_currentAction != kActionWait) + break; + } + + if (actor->_targetObject != ID_NOTHING) { + actorFaceTowardsObject(actor->_id, actor->_targetObject); + } + + if (actor->_flags & kCycle) { + frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameStand)); + if (frameRange->frameCount > 0) { + actor->_actionCycle++; + actor->_actionCycle = (actor->_actionCycle) % frameRange->frameCount; + } else { + actor->_actionCycle = 0; + } + actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle; + break; + } + + if ((actor->_actionCycle & 3) == 0) { + actor->cycleWrap(100); + + frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameWait)); + if ((frameRange->frameCount < 1 || actor->_actionCycle > 33)) + frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameStand)); + + if (frameRange->frameCount) { + actor->_frameNumber = frameRange->frameIndex + (uint16)_vm->_rnd.getRandomNumber(frameRange->frameCount - 1); + } else { + actor->_frameNumber = frameRange->frameIndex; + } + } + actor->_actionCycle++; + break; + + case kActionWalkToPoint: + case kActionWalkToLink: + if (_vm->_scene->getFlags() & kSceneFlagISO) { + actor->_partialTarget.delta(actor->_location, delta); + + while ((delta.u() == 0) && (delta.v() == 0)) { + + if ((actor == _protagonist) && (_vm->mouseButtonPressed())) { + _vm->_isoMap->screenPointToTileCoords(_vm->mousePos(), pickLocation); + + if (!actorWalkTo(_protagonist->_id, pickLocation)) { + break; + } + } else if (!_vm->_isoMap->nextTileTarget(actor) && !actorEndWalk(actor->_id, true)) { + break; + } + + actor->_partialTarget.delta(actor->_location, delta); + actor->_partialTarget.z = 0; + } + + if (actor->_flags & kFastest) { + speed = 8; + } else if (actor->_flags & kFaster) { + speed = 6; + } else { + speed = 4; + } + + if (_vm->_scene->currentSceneResourceId() == RID_ITE_OVERMAP_SCENE) { + speed = 2; + } + + if ((actor->_actionDirection == 2) || (actor->_actionDirection == 6)) { + speed = speed / 2; + } + + if (ABS(delta.v()) > ABS(delta.u())) { + addDelta.v() = clamp(-speed, delta.v(), speed); + if (addDelta.v() == delta.v()) { + addDelta.u() = delta.u(); + } else { + addDelta.u() = delta.u() * addDelta.v(); + addDelta.u() += (addDelta.u() > 0) ? (delta.v() / 2) : (-delta.v() / 2); + addDelta.u() /= delta.v(); + } + } else { + addDelta.u() = clamp(-speed, delta.u(), speed); + if (addDelta.u() == delta.u()) { + addDelta.v() = delta.v(); + } else { + addDelta.v() = delta.v() * addDelta.u(); + addDelta.v() += (addDelta.v() > 0) ? (delta.u() / 2) : (-delta.u() / 2); + addDelta.v() /= delta.u(); + } + } + + actor->_location.add(addDelta); + } else { + actor->_partialTarget.delta(actor->_location, delta); + + while ((delta.x == 0) && (delta.y == 0)) { + + if (actor->_walkStepIndex >= actor->_walkStepsCount) { + actorEndWalk(actor->_id, true); + break; + } + + actor->_partialTarget.fromScreenPoint(actor->_walkStepsPoints[actor->_walkStepIndex++]); + if (_vm->getGameType() == GType_ITE) { + if (actor->_partialTarget.x > 224 * 2 * ACTOR_LMULT) { + actor->_partialTarget.x -= 256 * 2 * ACTOR_LMULT; + } + } else { + if (actor->_partialTarget.x > 224 * 4 * ACTOR_LMULT) { + actor->_partialTarget.x -= 256 * 4 * ACTOR_LMULT; + } + } + + actor->_partialTarget.delta(actor->_location, delta); + + if (ABS(delta.y) > ABS(delta.x)) { + actor->_actionDirection = delta.y > 0 ? kDirDown : kDirUp; + } else { + actor->_actionDirection = delta.x > 0 ? kDirRight : kDirLeft; + } + } + + if(_vm->getGameType() == GType_ITE) + speed = (ACTOR_LMULT * 2 * actor->_screenScale + 63) / 256; + else + speed = (ACTOR_SPEED * actor->_screenScale + 128) >> 8; + + if (speed < 1) + speed = 1; + + if(_vm->getGameType() == GType_IHNM) + speed = speed / 2; + + if ((actor->_actionDirection == kDirUp) || (actor->_actionDirection == kDirDown)) { + addDelta.y = clamp(-speed, delta.y, speed); + if (addDelta.y == delta.y) { + addDelta.x = delta.x; + } else { + addDelta.x = delta.x * addDelta.y; + addDelta.x += (addDelta.x > 0) ? (delta.y / 2) : (-delta.y / 2); + addDelta.x /= delta.y; + actor->_facingDirection = actor->_actionDirection; + } + } else { + addDelta.x = clamp(-2 * speed, delta.x, 2 * speed); + if (addDelta.x == delta.x) { + addDelta.y = delta.y; + } else { + addDelta.y = delta.y * addDelta.x; + addDelta.y += (addDelta.y > 0) ? (delta.x / 2) : (-delta.x / 2); + addDelta.y /= delta.x; + actor->_facingDirection = actor->_actionDirection; + } + } + + actor->_location.add(addDelta); + } + + if (actor->_actorFlags & kActorBackwards) { + actor->_facingDirection = (actor->_actionDirection + 4) & 7; + actor->_actionCycle--; + } else { + actor->_actionCycle++; + } + + frameRange = getActorFrameRange(actor->_id, actor->_walkFrameSequence); + + if (actor->_actionCycle < 0) { + actor->_actionCycle = frameRange->frameCount - 1; + } else if (actor->_actionCycle >= frameRange->frameCount) { + actor->_actionCycle = 0; + } + + actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle; + break; + + case kActionWalkDir: + if (_vm->_scene->getFlags() & kSceneFlagISO) { + actor->_location.u() += tileDirectionLUT[actor->_actionDirection][0]; + actor->_location.v() += tileDirectionLUT[actor->_actionDirection][1]; + + frameRange = getActorFrameRange(actor->_id, actor->_walkFrameSequence); + + actor->_actionCycle++; + actor->cycleWrap(frameRange->frameCount); + actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle; + } else { + if (_vm->getGameType() == GType_ITE) { + actor->_location.x += directionLUT[actor->_actionDirection][0] * 2; + actor->_location.y += directionLUT[actor->_actionDirection][1] * 2; + } else { + // FIXME: The original does not multiply by 8 here, but we do + actor->_location.x += (directionLUT[actor->_actionDirection][0] * 8 * actor->_screenScale + 128) >> 8; + actor->_location.y += (directionLUT[actor->_actionDirection][1] * 8 * actor->_screenScale + 128) >> 8; + } + + frameRange = getActorFrameRange(actor->_id, actor->_walkFrameSequence); + actor->_actionCycle++; + actor->cycleWrap(frameRange->frameCount); + actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle; + } + break; + + case kActionSpeak: + actor->_actionCycle++; + actor->cycleWrap(64); + + frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameGesture)); + if (actor->_actionCycle >= frameRange->frameCount) { + if (actor->_actionCycle & 1) + break; + frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameSpeak)); + + state = (uint16)_vm->_rnd.getRandomNumber(frameRange->frameCount); + + if (state == 0) { + frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameStand)); + } else { + state--; + } + } else { + state = actor->_actionCycle; + } + + actor->_frameNumber = frameRange->frameIndex + state; + break; + + case kActionAccept: + case kActionStoop: + break; + + case kActionCycleFrames: + case kActionPongFrames: + if (actor->_cycleTimeCount > 0) { + actor->_cycleTimeCount--; + break; + } + + actor->_cycleTimeCount = actor->_cycleDelay; + actor->_actionCycle++; + + frameRange = getActorFrameRange(actor->_id, actor->_cycleFrameSequence); + + if (actor->_currentAction == kActionPongFrames) { + if (actor->_actionCycle >= frameRange->frameCount * 2 - 2) { + if (actor->_actorFlags & kActorContinuous) { + actor->_actionCycle = 0; + } else { + actor->_currentAction = kActionFreeze; + break; + } + } + + state = actor->_actionCycle; + if (state >= frameRange->frameCount) { + state = frameRange->frameCount * 2 - 2 - state; + } + } else { + if (actor->_actionCycle >= frameRange->frameCount) { + if (actor->_actorFlags & kActorContinuous) { + actor->_actionCycle = 0; + } else { + actor->_currentAction = kActionFreeze; + break; + } + } + state = actor->_actionCycle; + } + + if (frameRange->frameCount && (actor->_actorFlags & kActorRandom)) { + state = _vm->_rnd.getRandomNumber(frameRange->frameCount - 1); + } + + if (actor->_actorFlags & kActorBackwards) { + actor->_frameNumber = frameRange->frameIndex + frameRange->frameCount - 1 - state; + } else { + actor->_frameNumber = frameRange->frameIndex + state; + } + break; + + case kActionFall: + if (actor->_actionCycle > 0) { + framesLeft = actor->_actionCycle--; + actor->_finalTarget.delta(actor->_location, delta); + delta.x /= framesLeft; + delta.y /= framesLeft; + actor->_location.addXY(delta); + actor->_fallVelocity += actor->_fallAcceleration; + actor->_fallPosition += actor->_fallVelocity; + actor->_location.z = actor->_fallPosition >> 4; + } else { + actor->_location = actor->_finalTarget; + actor->_currentAction = kActionFreeze; + _vm->_script->wakeUpActorThread(kWaitTypeWalk, actor); + } + break; + + case kActionClimb: + actor->_cycleDelay++; + if (actor->_cycleDelay & 3) { + break; + } + + if (actor->_location.z >= actor->_finalTarget.z + ACTOR_CLIMB_SPEED) { + actor->_location.z -= ACTOR_CLIMB_SPEED; + actor->_actionCycle--; + } else if (actor->_location.z <= actor->_finalTarget.z - ACTOR_CLIMB_SPEED) { + actor->_location.z += ACTOR_CLIMB_SPEED; + actor->_actionCycle++; + } else { + actor->_location.z = actor->_finalTarget.z; + actor->_currentAction = kActionFreeze; + _vm->_script->wakeUpActorThread(kWaitTypeWalk, actor); + } + + frameRange = getActorFrameRange(actor->_id, actor->_cycleFrameSequence); + + if (actor->_actionCycle < 0) { + actor->_actionCycle = frameRange->frameCount - 1; + } + actor->cycleWrap(frameRange->frameCount); + actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle; + break; + } + + if ((actor->_currentAction >= kActionWalkToPoint) && (actor->_currentAction <= kActionWalkDir)) { + hitZone = NULL; + + if (_vm->_scene->getFlags() & kSceneFlagISO) { + actor->_location.toScreenPointUV(hitPoint); + } else { + actor->_location.toScreenPointXY(hitPoint); + } + hitZoneIndex = _vm->_scene->_actionMap->hitTest(hitPoint); + if (hitZoneIndex != -1) { + hitZone = _vm->_scene->_actionMap->getHitZone(hitZoneIndex); + } + + if (hitZone != actor->_lastZone) { + if (actor->_lastZone) + stepZoneAction(actor, actor->_lastZone, true, false); + actor->_lastZone = hitZone; + // WORKAROUND for graphics glitch in the rat caves. Don't do this step zone action in the rat caves + // (room 51) for hitzone 24577 (the door with the copy protection) to avoid the glitch. This glitch + // happens because the copy protection is supposed to kick in at this point, but it's bypassed + // (with permission from Wyrmkeep Entertainment) + if (hitZone && + !(_vm->getGameType() == GType_ITE && _vm->_scene->currentSceneNumber() == 51 && hitZone->getHitZoneId() == 24577)) + stepZoneAction(actor, hitZone, false, false); + } + } + } + // Update frameCount for sfWaitFrames in IHNM + _vm->_frameCount++; +} + +void Actor::direct(int msec) { + + if (_vm->_scene->_entryList.entryListCount == 0) { + return; + } + + if (_vm->_interface->_statusTextInput) { + return; + } + + // FIXME: HACK. This should be turned into cycle event. + _lastTickMsec += msec; + + if (_lastTickMsec > 1000 / _handleActionDiv) { + _lastTickMsec = 0; + //process actions + handleActions(msec, false); + } + +//process speech + handleSpeech(msec); +} + +bool Actor::followProtagonist(ActorData *actor) { + Location protagonistLocation; + Location newLocation; + Location delta; + int protagonistBGMaskType; + Point prefer1; + Point prefer2; + Point prefer3; + int16 prefU; + int16 prefV; + int16 newU; + int16 newV; + + assert(_protagonist); + + actor->_flags &= ~(kFaster | kFastest); + protagonistLocation = _protagonist->_location; + calcScreenPosition(_protagonist); + + if (_vm->_scene->getFlags() & kSceneFlagISO) { + prefU = 60; + prefV = 60; + + + actor->_location.delta(protagonistLocation, delta); + + if (actor->_id == actorIndexToId(2)) { + prefU = prefV = 48; + } + + if ((delta.u() > prefU) || (delta.u() < -prefU) || (delta.v() > prefV) || (delta.v() < -prefV)) { + + if ((delta.u() > prefU * 2) || (delta.u() < -prefU * 2) || (delta.v() > prefV * 2) || (delta.v() < -prefV * 2)) { + actor->_flags |= kFaster; + + if ((delta.u() > prefU * 3) || (delta.u() < -prefU*3) || (delta.v() > prefV * 3) || (delta.v() < -prefV * 3)) { + actor->_flags |= kFastest; + } + } + + prefU /= 2; + prefV /= 2; + + newU = clamp(-prefU, delta.u(), prefU) + protagonistLocation.u(); + newV = clamp(-prefV, delta.v(), prefV) + protagonistLocation.v(); + + newLocation.u() = newU + _vm->_rnd.getRandomNumber(prefU - 1) - prefU / 2; + newLocation.v() = newV + _vm->_rnd.getRandomNumber(prefV - 1) - prefV / 2; + newLocation.z = 0; + + return actorWalkTo(actor->_id, newLocation); + } + + } else { + prefer1.x = (100 * _protagonist->_screenScale) >> 8; + prefer1.y = (50 * _protagonist->_screenScale) >> 8; + + if (_protagonist->_currentAction == kActionWalkDir) { + prefer1.x /= 2; + } + + if (prefer1.x < 8) { + prefer1.x = 8; + } + + if (prefer1.y < 8) { + prefer1.y = 8; + } + + prefer2.x = prefer1.x * 2; + prefer2.y = prefer1.y * 2; + prefer3.x = prefer1.x + prefer1.x / 2; + prefer3.y = prefer1.y + prefer1.y / 2; + + actor->_location.delta(protagonistLocation, delta); + + protagonistBGMaskType = 0; + if (_vm->_scene->isBGMaskPresent() && _vm->_scene->validBGMaskPoint(_protagonist->_screenPosition)) { + protagonistBGMaskType = _vm->_scene->getBGMaskType(_protagonist->_screenPosition); + } + + if ((_vm->_rnd.getRandomNumber(7) & 0x7) == 0) // 1/8th chance + actor->_actorFlags &= ~kActorNoFollow; + + if (actor->_actorFlags & kActorNoFollow) { + return false; + } + + if ((delta.x > prefer2.x) || (delta.x < -prefer2.x) || + (delta.y > prefer2.y) || (delta.y < -prefer2.y) || + ((_protagonist->_currentAction == kActionWait) && + (delta.x * 2 < prefer1.x) && (delta.x * 2 > -prefer1.x) && + (delta.y < prefer1.y) && (delta.y > -prefer1.y))) { + + if (ABS(delta.x) > ABS(delta.y)) { + + delta.x = (delta.x > 0) ? prefer3.x : -prefer3.x; + + newLocation.x = delta.x + protagonistLocation.x; + newLocation.y = clamp(-prefer2.y, delta.y, prefer2.y) + protagonistLocation.y; + } else { + delta.y = (delta.y > 0) ? prefer3.y : -prefer3.y; + + newLocation.x = clamp(-prefer2.x, delta.x, prefer2.x) + protagonistLocation.x; + newLocation.y = delta.y + protagonistLocation.y; + } + newLocation.z = 0; + + if (protagonistBGMaskType != 3) { + newLocation.x += _vm->_rnd.getRandomNumber(prefer1.x - 1) - prefer1.x / 2; + newLocation.y += _vm->_rnd.getRandomNumber(prefer1.y - 1) - prefer1.y / 2; + } + + newLocation.x = clamp(-31 * 4, newLocation.x, (_vm->getDisplayWidth() + 31) * 4); + + return actorWalkTo(actor->_id, newLocation); + } + } + return false; +} + +bool Actor::actorWalkTo(uint16 actorId, const Location &toLocation) { + ActorData *actor; + ActorData *anotherActor; + int i; + + Rect testBox; + Rect testBox2; + Point anotherActorScreenPosition; + Point collision; + Point pointFrom, pointTo, pointBest, pointAdd; + Point delta, bestDelta; + Point tempPoint; + bool extraStartNode; + bool extraEndNode; + + actor = getActor(actorId); + + if (actor == _protagonist) { + _vm->_scene->setDoorState(2, 0xff); + _vm->_scene->setDoorState(3, 0); + } else { + _vm->_scene->setDoorState(2, 0); + _vm->_scene->setDoorState(3, 0xff); + } + + if (_vm->_scene->getFlags() & kSceneFlagISO) { + + if ((_vm->getGameType() == GType_ITE) && (actor->_index == ACTOR_DRAGON_INDEX)) { + return false; + } + + actor->_finalTarget = toLocation; + actor->_walkStepsCount = 0; + _vm->_isoMap->findTilePath(actor, actor->_location, toLocation); + + + if ((actor->_walkStepsCount == 0) && (actor->_flags & kProtagonist)) { + actor->_actorFlags |= kActorNoCollide; + _vm->_isoMap->findTilePath(actor, actor->_location, toLocation); + } + + actor->_walkStepIndex = 0; + if (_vm->_isoMap->nextTileTarget(actor)) { + actor->_currentAction = kActionWalkToPoint; + actor->_walkFrameSequence = getFrameType(kFrameWalk); + } else { + actorEndWalk(actorId, false); + return false; + } + } else { + + actor->_location.toScreenPointXY(pointFrom); + pointFrom.x &= ~1; + + extraStartNode = _vm->_scene->offscreenPath(pointFrom); + + toLocation.toScreenPointXY(pointTo); + pointTo.x &= ~1; + + extraEndNode = _vm->_scene->offscreenPath(pointTo); + + if (_vm->_scene->isBGMaskPresent()) { + + if ((((actor->_currentAction >= kActionWalkToPoint) && + (actor->_currentAction <= kActionWalkDir)) || (actor == _protagonist)) && + !_vm->_scene->canWalk(pointFrom)) { + + int max = _vm->getGameType() == GType_ITE ? 8 : 4; + + for (i = 1; i < max; i++) { + pointAdd = pointFrom; + pointAdd.y += i; + if (_vm->_scene->canWalk(pointAdd)) { + pointFrom = pointAdd; + break; + } + pointAdd = pointFrom; + pointAdd.y -= i; + if (_vm->_scene->canWalk(pointAdd)) { + pointFrom = pointAdd; + break; + } + if (_vm->getGameType() == GType_ITE) { + pointAdd = pointFrom; + pointAdd.x += i; + if (_vm->_scene->canWalk(pointAdd)) { + pointFrom = pointAdd; + break; + } + pointAdd = pointFrom; + pointAdd.x -= i; + if (_vm->_scene->canWalk(pointAdd)) { + pointFrom = pointAdd; + break; + } + } + } + } + + _barrierCount = 0; + if (!(actor->_actorFlags & kActorNoCollide)) { + collision.x = ACTOR_COLLISION_WIDTH * actor->_screenScale / (256 * 2); + collision.y = ACTOR_COLLISION_HEIGHT * actor->_screenScale / (256 * 2); + + + for (i = 0; (i < _actorsCount) && (_barrierCount < ACTOR_BARRIERS_MAX); i++) { + anotherActor = _actors[i]; + if (!anotherActor->_inScene) + continue; + if (anotherActor == actor) + continue; + + anotherActorScreenPosition = anotherActor->_screenPosition; + testBox.left = (anotherActorScreenPosition.x - collision.x) & ~1; + testBox.right = (anotherActorScreenPosition.x + collision.x) & ~1 + 1; + testBox.top = anotherActorScreenPosition.y - collision.y; + testBox.bottom = anotherActorScreenPosition.y + collision.y + 1; + testBox2 = testBox; + testBox2.right += 2; + testBox2.left -= 2; + testBox2.top -= 1; + testBox2.bottom += 1; + + if (testBox2.contains(pointFrom)) { + if (pointFrom.x > anotherActorScreenPosition.x + 4) { + testBox.right = pointFrom.x - 1; + } else if (pointFrom.x < anotherActorScreenPosition.x - 4) { + testBox.left = pointFrom.x + 2; + } else if (pointFrom.y > anotherActorScreenPosition.y) { + testBox.bottom = pointFrom.y; + } else { + testBox.top = pointFrom.y + 1 ; + } + } + + if ((testBox.width() > 0) && (testBox.height() > 0)) { + _barrierList[_barrierCount++] = testBox; + } + } + } + + + pointBest = pointTo; + actor->_walkStepsCount = 0; + findActorPath(actor, pointFrom, pointTo); + + if (actor->_walkStepsCount == 0) { + error("actor->_walkStepsCount == 0"); + } + + if (extraStartNode) { + actor->_walkStepIndex = 0; + } else { + actor->_walkStepIndex = 1; + } + + if (extraEndNode) { + toLocation.toScreenPointXY(tempPoint); + actor->_walkStepsCount--; + actor->addWalkStepPoint(tempPoint); + } + + + pointBest = actor->_walkStepsPoints[actor->_walkStepsCount - 1]; + + pointBest.x &= ~1; + delta.x = ABS(pointFrom.x - pointTo.x); + delta.y = ABS(pointFrom.y - pointTo.y); + + bestDelta.x = ABS(pointBest.x - pointTo.x); + bestDelta.y = ABS(pointBest.y - pointTo.y); + + if ((delta.x + delta.y <= bestDelta.x + bestDelta.y) && (actor->_flags & kFollower)) { + actor->_actorFlags |= kActorNoFollow; + } + + if (pointBest == pointFrom) { + actor->_walkStepsCount = 0; + } + } else { + actor->_walkStepsCount = 0; + actor->addWalkStepPoint(pointTo); + actor->_walkStepIndex = 0; + } + + actor->_partialTarget = actor->_location; + actor->_finalTarget = toLocation; + if (actor->_walkStepsCount == 0) { + actorEndWalk(actorId, false); + return false; + } else { + if (actor->_flags & kProtagonist) { + _actors[1]->_actorFlags &= ~kActorNoFollow; // TODO: mark all actors with kFollower flag, not only 1 and 2 + _actors[2]->_actorFlags &= ~kActorNoFollow; + } + actor->_currentAction = (actor->_walkStepsCount >= ACTOR_MAX_STEPS_COUNT) ? kActionWalkToLink : kActionWalkToPoint; + actor->_walkFrameSequence = getFrameType(kFrameWalk); + } + } + return true; +} + +bool Actor::actorEndWalk(uint16 actorId, bool recurse) { + bool walkMore = false; + ActorData *actor; + const HitZone *hitZone; + int hitZoneIndex; + Point testPoint; + + actor = getActor(actorId); + actor->_actorFlags &= ~kActorBackwards; + + if (_vm->getGameType() == GType_ITE) { + + if (actor->_location.distance(actor->_finalTarget) > 8 && (actor->_flags & kProtagonist) && recurse && !(actor->_actorFlags & kActorNoCollide)) { + actor->_actorFlags |= kActorNoCollide; + return actorWalkTo(actorId, actor->_finalTarget); + } + } + + actor->_currentAction = kActionWait; + if (actor->_actorFlags & kActorFinalFace) { + actor->_facingDirection = actor->_actionDirection = (actor->_actorFlags >> 6) & 0x07; //? + } + + actor->_actorFlags &= ~(kActorNoCollide | kActorCollided | kActorFinalFace | kActorFacingMask); + actor->_flags &= ~(kFaster | kFastest); + + if (actor == _protagonist) { + _vm->_script->wakeUpActorThread(kWaitTypeWalk, actor); + if (_vm->_script->_pendingVerb == _vm->_script->getVerbType(kVerbWalkTo)) { + if (_vm->getGameType() == GType_ITE) + actor->_location.toScreenPointUV(testPoint); // it's wrong calculation, but it is used in ITE + else + actor->_location.toScreenPointXY(testPoint); + + hitZoneIndex = _vm->_scene->_actionMap->hitTest(testPoint); + if (hitZoneIndex != -1) { + hitZone = _vm->_scene->_actionMap->getHitZone(hitZoneIndex); + stepZoneAction(actor, hitZone, false, true); + } else { + _vm->_script->setNoPendingVerb(); + } + } else if (_vm->_script->_pendingVerb != _vm->_script->getVerbType(kVerbNone)) { + _vm->_script->doVerb(); + } + } else { + if (recurse && (actor->_flags & kFollower)) + walkMore = followProtagonist(actor); + + _vm->_script->wakeUpActorThread(kWaitTypeWalk, actor); + } + return walkMore; +} + +void Actor::moveDragon(ActorData *actor) { + int16 dir0, dir1, dir2, dir3; + int16 moveType; + Event event; + const DragonMove *dragonMove; + + if ((actor->_actionCycle < 0) || + ((actor->_actionCycle == 0) && (actor->_dragonMoveType >= ACTOR_DRAGON_TURN_MOVES))) { + + moveType = kDragonMoveInvalid; + if (actor->_location.distance(_protagonist->_location) < 24) { + if (_dragonHunt && (_protagonist->_currentAction != kActionFall)) { + event.type = kEvTOneshot; + event.code = kScriptEvent; + event.op = kEventExecNonBlocking; + event.time = 0; + event.param = _vm->_scene->getScriptModuleNumber(); // module number + event.param2 = ACTOR_EXP_KNOCK_RIF; // script entry point number + event.param3 = -1; // Action + event.param4 = -1; // Object + event.param5 = -1; // With Object + event.param6 = -1; // Actor + _vm->_events->queue(&event); + + _dragonHunt = false; + } + } else { + _dragonHunt = true; + } + + if (actor->_walkStepIndex + 2 > actor->_walkStepsCount) { + + _vm->_isoMap->findDragonTilePath(actor, actor->_location, _protagonist->_location, actor->_actionDirection); + + if (actor->_walkStepsCount == 0) { + _vm->_isoMap->findDragonTilePath(actor, actor->_location, _protagonist->_location, 0); + } + + if (actor->_walkStepsCount < 2) { + return; + } + + actor->_partialTarget = actor->_location; + actor->_finalTarget = _protagonist->_location; + actor->_walkStepIndex = 0; + } + + dir0 = actor->_actionDirection; + dir1 = actor->_tileDirections[actor->_walkStepIndex++]; + dir2 = actor->_tileDirections[actor->_walkStepIndex]; + dir3 = actor->_tileDirections[actor->_walkStepIndex + 1]; + + if (dir0 != dir1){ + actor->_actionDirection = dir0 = dir1; + } + + actor->_location = actor->_partialTarget; + + if ((dir1 != dir2) && (dir1 == dir3)) { + switch (dir1) { + case kDirUpLeft: + actor->_partialTarget.v() += 16; + moveType = kDragonMoveUpLeft; + break; + case kDirDownLeft: + actor->_partialTarget.u() -= 16; + moveType = kDragonMoveDownLeft; + break; + case kDirDownRight: + actor->_partialTarget.v() -= 16; + moveType = kDragonMoveDownRight; + break; + case kDirUpRight: + actor->_partialTarget.u() += 16; + moveType = kDragonMoveUpRight; + break; + } + + switch (dir2) { + case kDirUpLeft: + actor->_partialTarget.v() += 16; + break; + case kDirDownLeft: + actor->_partialTarget.u() -= 16; + break; + case kDirDownRight: + actor->_partialTarget.v() -= 16; + break; + case kDirUpRight: + actor->_partialTarget.u() += 16; + break; + } + + actor->_walkStepIndex++; + } else { + switch (dir1) { + case kDirUpLeft: + actor->_partialTarget.v() += 16; + switch (dir2) { + case kDirDownLeft: + moveType = kDragonMoveUpLeft_Left; + actor->_partialTarget.u() -= 16; + break; + case kDirUpLeft: + moveType = kDragonMoveUpLeft; + break; + case kDirUpRight: + actor->_partialTarget.u() += 16; + moveType = kDragonMoveUpLeft_Right; + break; + default: + actor->_actionDirection = dir1; + actor->_walkStepsCount = 0; + break; + } + break; + case kDirDownLeft: + actor->_partialTarget.u() -= 16; + switch (dir2) { + case kDirDownRight: + moveType = kDragonMoveDownLeft_Left; + actor->_partialTarget.v() -= 16; + break; + case kDirDownLeft: + moveType = kDragonMoveDownLeft; + break; + case kDirUpLeft: + moveType = kDragonMoveDownLeft_Right; + actor->_partialTarget.v() += 16; + break; + default: + actor->_actionDirection = dir1; + actor->_walkStepsCount = 0; + break; + } + break; + case kDirDownRight: + actor->_partialTarget.v() -= 16; + switch (dir2) { + case kDirUpRight: + moveType = kDragonMoveDownRight_Left; + actor->_partialTarget.u() += 16; + break; + case kDirDownRight: + moveType = kDragonMoveDownRight; + break; + case kDirDownLeft: + moveType = kDragonMoveDownRight_Right; + actor->_partialTarget.u() -= 16; + break; + default: + actor->_actionDirection = dir1; + actor->_walkStepsCount = 0; + break; + } + break; + case kDirUpRight: + actor->_partialTarget.u() += 16; + switch (dir2) { + case kDirUpLeft: + moveType = kDragonMoveUpRight_Left; + actor->_partialTarget.v() += 16; + break; + case kDirUpRight: + moveType = kDragonMoveUpRight; + break; + case kDirDownRight: + moveType = kDragonMoveUpRight_Right; + actor->_partialTarget.v() -= 16; + break; + default: + actor->_actionDirection = dir1; + actor->_walkStepsCount = 0; + break; + } + break; + + default: + actor->_actionDirection = dir1; + actor->_walkStepsCount = 0; + break; + } + } + + actor->_dragonMoveType = moveType; + + if (moveType >= ACTOR_DRAGON_TURN_MOVES) { + actor->_dragonStepCycle = 0; + actor->_actionCycle = 4; + actor->_walkStepIndex++; + } else { + actor->_actionCycle = 4; + } + } + + actor->_actionCycle--; + + if ((actor->_walkStepsCount < 1) || (actor->_actionCycle < 0)) { + return; + } + + if (actor->_dragonMoveType < ACTOR_DRAGON_TURN_MOVES) { + + actor->_dragonStepCycle++; + if (actor->_dragonStepCycle >= 7) { + actor->_dragonStepCycle = 0; + } + + actor->_dragonBaseFrame = actor->_dragonMoveType * 7; + + if (actor->_location.u() > actor->_partialTarget.u() + 3) { + actor->_location.u() -= 4; + } else if (actor->_location.u() < actor->_partialTarget.u() - 3) { + actor->_location.u() += 4; + } else { + actor->_location.u() = actor->_partialTarget.u(); + } + + if (actor->_location.v() > actor->_partialTarget.v() + 3) { + actor->_location.v() -= 4; + } else if (actor->_location.v() < actor->_partialTarget.v() - 3) { + actor->_location.v() += 4; + } else { + actor->_location.v() = actor->_partialTarget.v(); + } + } else { + dragonMove = &dragonMoveTable[actor->_dragonMoveType]; + actor->_dragonBaseFrame = dragonMove->baseFrame; + + + actor->_location.u() = actor->_partialTarget.u() - dragonMove->offset[actor->_actionCycle][0]; + actor->_location.v() = actor->_partialTarget.v() - dragonMove->offset[actor->_actionCycle][1]; + + actor->_dragonStepCycle++; + if (actor->_dragonStepCycle >= 3) { + actor->_dragonStepCycle = 3; + } + } + + actor->_frameNumber = actor->_dragonBaseFrame + actor->_dragonStepCycle; +} + +void Actor::findActorPath(ActorData *actor, const Point &fromPoint, const Point &toPoint) { + Point iteratorPoint; + Point bestPoint; + int maskType; + int i; + Rect intersect; + +#ifdef ACTOR_DEBUG + _debugPointsCount = 0; +#endif + + actor->_walkStepsCount = 0; + if (fromPoint == toPoint) { + actor->addWalkStepPoint(toPoint); + return; + } + + for (iteratorPoint.y = 0; iteratorPoint.y < _yCellCount; iteratorPoint.y++) { + for (iteratorPoint.x = 0; iteratorPoint.x < _xCellCount; iteratorPoint.x++) { + if (_vm->_scene->validBGMaskPoint(iteratorPoint)) { + maskType = _vm->_scene->getBGMaskType(iteratorPoint); + setPathCell(iteratorPoint, _vm->_scene->getDoorState(maskType) ? kPathCellBarrier : kPathCellEmpty); + } else { + setPathCell(iteratorPoint, kPathCellBarrier); + } + } + } + + for (i = 0; i < _barrierCount; i++) { + intersect.left = MAX(_pathRect.left, _barrierList[i].left); + intersect.top = MAX(_pathRect.top, _barrierList[i].top); + intersect.right = MIN(_pathRect.right, _barrierList[i].right); + intersect.bottom = MIN(_pathRect.bottom, _barrierList[i].bottom); + + for (iteratorPoint.y = intersect.top; iteratorPoint.y < intersect.bottom; iteratorPoint.y++) { + for (iteratorPoint.x = intersect.left; iteratorPoint.x < intersect.right; iteratorPoint.x++) { + setPathCell(iteratorPoint, kPathCellBarrier); + } + } + } + +#ifdef ACTOR_DEBUG + for (iteratorPoint.y = 0; iteratorPoint.y < _yCellCount; iteratorPoint.y++) { + for (iteratorPoint.x = 0; iteratorPoint.x < _xCellCount; iteratorPoint.x++) { + if (getPathCell(iteratorPoint) == kPathCellBarrier) { + addDebugPoint(iteratorPoint, 24); + } + } + } +#endif + + if (scanPathLine(fromPoint, toPoint)) { + actor->addWalkStepPoint(fromPoint); + actor->addWalkStepPoint(toPoint); + return; + } + + i = fillPathArray(fromPoint, toPoint, bestPoint); + + if (fromPoint == bestPoint) { + actor->addWalkStepPoint(bestPoint); + return; + } + + if (i == 0) { + error("fillPathArray returns zero"); + } + + setActorPath(actor, fromPoint, bestPoint); +} + +bool Actor::scanPathLine(const Point &point1, const Point &point2) { + Point point; + Point delta; + Point s; + Point fDelta; + int16 errterm; + + calcDeltaS(point1, point2, delta, s); + point = point1; + + fDelta.x = delta.x * 2; + fDelta.y = delta.y * 2; + + if (delta.y > delta.x) { + + errterm = fDelta.x - delta.y; + + while (delta.y > 0) { + while (errterm >= 0) { + point.x += s.x; + errterm -= fDelta.y; + } + + point.y += s.y; + errterm += fDelta.x; + + if (!validPathCellPoint(point)) { + return false; + } + if (getPathCell(point) == kPathCellBarrier) { + return false; + } + delta.y--; + } + } else { + + errterm = fDelta.y - delta.x; + + while (delta.x > 0) { + while (errterm >= 0) { + point.y += s.y; + errterm -= fDelta.x; + } + + point.x += s.x; + errterm += fDelta.y; + + if (!validPathCellPoint(point)) { + return false; + } + if (getPathCell(point) == kPathCellBarrier) { + return false; + } + delta.x--; + } + } + return true; +} + +int Actor::fillPathArray(const Point &fromPoint, const Point &toPoint, Point &bestPoint) { + int bestRating; + int currentRating; + int i; + Point bestPath; + int pointCounter; + int startDirection; + PathDirectionData *pathDirection; + PathDirectionData *newPathDirection; + const PathDirectionData *samplePathDirection; + Point nextPoint; + int directionCount; + int16 compressX = (_vm->getGameType() == GType_ITE) ? 2 : 1; + + _pathDirectionListCount = 0; + pointCounter = 0; + bestRating = quickDistance(fromPoint, toPoint, compressX); + bestPath = fromPoint; + + for (startDirection = 0; startDirection < 4; startDirection++) { + newPathDirection = addPathDirectionListData(); + newPathDirection->coord = fromPoint; + newPathDirection->direction = startDirection; + } + + if (validPathCellPoint(fromPoint)) { + setPathCell(fromPoint, kDirUp); + +#ifdef ACTOR_DEBUG + addDebugPoint(fromPoint, 24+36); +#endif + } + + i = 0; + + do { + pathDirection = &_pathDirectionList[i]; + for (directionCount = 0; directionCount < 3; directionCount++) { + samplePathDirection = &pathDirectionLUT[pathDirection->direction][directionCount]; + nextPoint = pathDirection->coord; + nextPoint.x += samplePathDirection->coord.x; + nextPoint.y += samplePathDirection->coord.y; + + if (!validPathCellPoint(nextPoint)) { + continue; + } + + if (getPathCell(nextPoint) != kPathCellEmpty) { + continue; + } + + setPathCell(nextPoint, samplePathDirection->direction); + +#ifdef ACTOR_DEBUG + addDebugPoint(nextPoint, samplePathDirection->direction + 96); +#endif + newPathDirection = addPathDirectionListData(); + newPathDirection->coord = nextPoint; + newPathDirection->direction = samplePathDirection->direction; + ++pointCounter; + if (nextPoint == toPoint) { + bestPoint = toPoint; + return pointCounter; + } + currentRating = quickDistance(nextPoint, toPoint, compressX); + if (currentRating < bestRating) { + bestRating = currentRating; + bestPath = nextPoint; + } + pathDirection = &_pathDirectionList[i]; + } + ++i; + } while (i < _pathDirectionListCount); + + bestPoint = bestPath; + return pointCounter; +} + +void Actor::setActorPath(ActorData *actor, const Point &fromPoint, const Point &toPoint) { + Point nextPoint; + int8 direction; + int i; + + _pathListIndex = -1; + addPathListPoint(toPoint); + nextPoint = toPoint; + + while (!(nextPoint == fromPoint)) { + direction = getPathCell(nextPoint); + if ((direction < 0) || (direction >= 8)) { + error("Actor::setActorPath error direction 0x%X", direction); + } + nextPoint.x -= pathDirectionLUT2[direction][0]; + nextPoint.y -= pathDirectionLUT2[direction][1]; + addPathListPoint(nextPoint); + +#ifdef ACTOR_DEBUG + addDebugPoint(nextPoint, 0x8a); +#endif + } + + pathToNode(); + removeNodes(); + nodeToPath(); + removePathPoints(); + + for (i = 0; i <= _pathNodeListIndex; i++) { + actor->addWalkStepPoint(_pathNodeList[i].point); + } +} + +void Actor::pathToNode() { + Point point1, point2, delta; + int direction; + int i; + Point *point; + + point= &_pathList[_pathListIndex]; + direction = 0; + + _pathNodeListIndex = -1; + addPathNodeListPoint(*point); + + for (i = _pathListIndex; i > 0; i--) { + point1 = *point; + --point; + point2 = *point; + if (direction == 0) { + delta.x = int16Compare(point2.x, point1.x); + delta.y = int16Compare(point2.y, point1.y); + direction++; + } + if ((point1.x + delta.x != point2.x) || (point1.y + delta.y != point2.y)) { + addPathNodeListPoint(point1); + direction--; + i++; + point++; + } + } + addPathNodeListPoint(*_pathList); +} + +int pathLine(Point *pointList, const Point &point1, const Point &point2) { + Point point; + Point delta; + Point tempPoint; + Point s; + int16 errterm; + int16 res; + + calcDeltaS(point1, point2, delta, s); + + point = point1; + + tempPoint.x = delta.x * 2; + tempPoint.y = delta.y * 2; + + if (delta.y > delta.x) { + + errterm = tempPoint.x - delta.y; + res = delta.y; + + while (delta.y > 0) { + while (errterm >= 0) { + point.x += s.x; + errterm -= tempPoint.y; + } + + point.y += s.y; + errterm += tempPoint.x; + + *pointList = point; + pointList++; + delta.y--; + } + } else { + + errterm = tempPoint.y - delta.x; + res = delta.x; + + while (delta.x > 0) { + while (errterm >= 0) { + point.y += s.y; + errterm -= tempPoint.x; + } + + point.x += s.x; + errterm += tempPoint.y; + + *pointList = point; + pointList++; + delta.x--; + } + } + return res; +} + +void Actor::nodeToPath() { + int i; + Point point1, point2; + PathNode *node; + Point *point; + + for (i = 0, point = _pathList; i < _pathListAlloced; i++, point++) { + point->x = point->y = PATH_NODE_EMPTY; + } + + _pathListIndex = 1; + _pathList[0] = _pathNodeList[0].point; + _pathNodeList[0].link = 0; + for (i = 0, node = _pathNodeList; i < _pathNodeListIndex; i++) { + point1 = node->point; + node++; + point2 = node->point; + _pathListIndex += pathLine(&_pathList[_pathListIndex], point1, point2); + node->link = _pathListIndex - 1; + } + _pathListIndex--; + _pathNodeList[_pathNodeListIndex].link = _pathListIndex; + +} + +void Actor::removeNodes() { + int i, j, k; + PathNode *iNode, *jNode, *kNode, *fNode; + fNode = &_pathNodeList[_pathNodeListIndex]; + + if (scanPathLine(_pathNodeList[0].point, fNode->point)) { + _pathNodeList[1] = *fNode; + _pathNodeListIndex = 1; + } + + if (_pathNodeListIndex < 4) { + return; + } + + for (i = _pathNodeListIndex - 1, iNode = fNode-1; i > 1 ; i--, iNode--) { + if (iNode->point.x == PATH_NODE_EMPTY) { + continue; + } + + if (scanPathLine(_pathNodeList[0].point, iNode->point)) { + for (j = 1, jNode = _pathNodeList + 1; j < i; j++, jNode++) { + jNode->point.x = PATH_NODE_EMPTY; + } + } + } + + for (i = 1, iNode = _pathNodeList + 1; i < _pathNodeListIndex - 1; i++, iNode++) { + if (iNode->point.x == PATH_NODE_EMPTY) { + continue; + } + + if (scanPathLine(fNode->point, iNode->point)) { + for (j = i + 1, jNode = iNode + 1; j < _pathNodeListIndex; j++, jNode++) { + jNode->point.x = PATH_NODE_EMPTY; + } + } + } + condenseNodeList(); + + for (i = 1, iNode = _pathNodeList + 1; i < _pathNodeListIndex - 1; i++, iNode++) { + if (iNode->point.x == PATH_NODE_EMPTY) { + continue; + } + for (j = i + 2, jNode = iNode + 2; j < _pathNodeListIndex; j++, jNode++) { + if (jNode->point.x == PATH_NODE_EMPTY) { + continue; + } + + if (scanPathLine(iNode->point, jNode->point)) { + for (k = i + 1,kNode = iNode + 1; k < j; k++, kNode++) { + kNode->point.x = PATH_NODE_EMPTY; + } + } + } + } + condenseNodeList(); +} + +void Actor::condenseNodeList() { + int i, j, count; + PathNode *iNode, *jNode; + + count = _pathNodeListIndex; + + for (i = 1, iNode = _pathNodeList + 1; i < _pathNodeListIndex; i++, iNode++) { + if (iNode->point.x == PATH_NODE_EMPTY) { + j = i + 1; + jNode = iNode + 1; + while (jNode->point.x == PATH_NODE_EMPTY) { + j++; + jNode++; + } + *iNode = *jNode; + count = i; + jNode->point.x = PATH_NODE_EMPTY; + if (j == _pathNodeListIndex) { + break; + } + } + } + _pathNodeListIndex = count; +} + +void Actor::removePathPoints() { + int i, j, k, l; + PathNode *node; + int start; + int end; + Point point1, point2; + + if (_pathNodeListIndex < 2) + return; + + _newPathNodeListIndex = -1; + addNewPathNodeListPoint(_pathNodeList[0]); + + for (i = 1, node = _pathNodeList + 1; i < _pathNodeListIndex; i++, node++) { + addNewPathNodeListPoint(*node); + + for (j = 5; j > 0; j--) { + start = node->link - j; + end = node->link + j; + + if (start < 0 || end > _pathListIndex) { + continue; + } + + point1 = _pathList[start]; + point2 = _pathList[end]; + if ((point1.x == PATH_NODE_EMPTY) || (point2.x == PATH_NODE_EMPTY)) { + continue; + } + + if (scanPathLine(point1, point2)) { + for (l = 1; l <= _newPathNodeListIndex; l++) { + if (start <= _newPathNodeList[l].link) { + _newPathNodeListIndex = l; + _newPathNodeList[_newPathNodeListIndex].point = point1; + _newPathNodeList[_newPathNodeListIndex].link = start; + incrementNewPathNodeListIndex(); + break; + } + } + _newPathNodeList[_newPathNodeListIndex].point = point2; + _newPathNodeList[_newPathNodeListIndex].link = end; + + for (k = start + 1; k < end; k++) { + _pathList[k].x = PATH_NODE_EMPTY; + } + break; + } + } + } + + addNewPathNodeListPoint(_pathNodeList[_pathNodeListIndex]); + + for (i = 0, j = 0; i <= _newPathNodeListIndex; i++) { + if (_newPathNodeListIndex == i || (_newPathNodeList[i].point != _newPathNodeList[i+1].point)) { + _pathNodeList[j++] = _newPathNodeList[i]; + } + } + _pathNodeListIndex = j - 1; +} + +void Actor::drawPathTest() { +#ifdef ACTOR_DEBUG + int i; + Surface *surface; + surface = _vm->_gfx->getBackBuffer(); + if (_debugPoints == NULL) { + return; + } + + for (i = 0; i < _debugPointsCount; i++) { + *((byte *)surface->pixels + (_debugPoints[i].point.y * surface->pitch) + _debugPoints[i].point.x) = _debugPoints[i].color; + } +#endif +} + +// Console wrappers - must be safe to run + +void Actor::cmdActorWalkTo(int argc, const char **argv) { + uint16 actorId = (uint16) atoi(argv[1]); + Location location; + Point movePoint; + + movePoint.x = atoi(argv[2]); + movePoint.y = atoi(argv[3]); + + location.fromScreenPoint(movePoint); + + if (!validActorId(actorId)) { + _vm->_console->DebugPrintf("Actor::cmActorWalkTo Invalid actorId 0x%X.\n", actorId); + return; + } + + actorWalkTo(actorId, location); +} + +} // End of namespace Saga \ No newline at end of file diff --git a/engines/saga/module.mk b/engines/saga/module.mk index 6c1812ad23..68cf91be32 100644 --- a/engines/saga/module.mk +++ b/engines/saga/module.mk @@ -2,6 +2,7 @@ MODULE := engines/saga MODULE_OBJS := \ actor.o \ + actor_walk.o \ animation.o \ console.o \ detection.o \ -- cgit v1.2.3