diff options
-rw-r--r-- | engines/parallaction/parallaction.cpp | 56 | ||||
-rw-r--r-- | engines/parallaction/parallaction.h | 10 | ||||
-rw-r--r-- | engines/parallaction/parallaction_ns.cpp | 2 | ||||
-rw-r--r-- | engines/parallaction/walk.cpp | 133 |
4 files changed, 107 insertions, 94 deletions
diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index d03d61fc59..3cde21b49c 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -503,6 +503,34 @@ void Parallaction::freeZones() { } +enum { + WALK_LEFT = 0, + WALK_RIGHT = 1, + WALK_DOWN = 2, + WALK_UP = 3 +}; + +struct WalkFrames { + int16 stillFrame[4]; + int16 firstWalkFrame[4]; + int16 numWalkFrames[4]; + int16 frameRepeat[4]; +}; + +WalkFrames _char20WalkFrames = { + { 0, 7, 14, 17 }, + { 1, 8, 15, 18 }, + { 6, 6, 2, 2 }, + { 2, 2, 4, 4 } +}; + +WalkFrames _char24WalkFrames = { + { 0, 9, 18, 21 }, + { 1, 10, 19, 22 }, + { 8, 8, 2, 2 }, + { 2, 2, 4, 4 } +}; + const char Character::_prefixMini[] = "mini"; const char Character::_suffixTras[] = "tras"; const char Character::_empty[] = "\0"; @@ -513,6 +541,9 @@ Character::Character(Parallaction *vm) : _vm(vm), _ani(new Animation), _builder( _head = NULL; _objs = NULL; + _direction = WALK_DOWN; + _step = 0; + _dummy = false; _ani->_left = 150; @@ -633,4 +664,29 @@ void Parallaction::scheduleLocationSwitch(const char *location) { } + + + +void Character::updateDirection(const Common::Point& pos, const Common::Point& to) { + + Common::Point dist(to.x - pos.x, to.y - pos.y); + WalkFrames *frames = (_ani->getFrameNum() == 20) ? &_char20WalkFrames : &_char24WalkFrames; + + _step++; + + if (dist.x == 0 && dist.y == 0) { + _ani->_frame = frames->stillFrame[_direction]; + return; + } + + if (dist.x < 0) + dist.x = -dist.x; + if (dist.y < 0) + dist.y = -dist.y; + + _direction = (dist.x > dist.y) ? ((to.x > pos.x) ? WALK_LEFT : WALK_RIGHT) : ((to.y > pos.y) ? WALK_DOWN : WALK_UP); + _ani->_frame = frames->firstWalkFrame[_direction] + (_step / frames->frameRepeat[_direction]) % frames->numWalkFrames[_direction]; +} + + } // namespace Parallaction diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index 2d0a201686..ef2dad9884 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -229,12 +229,17 @@ protected: static const char _suffixTras[]; static const char _empty[]; + int16 _direction, _step; + public: void setName(const char *name); const char *getName() const; const char *getBaseName() const; const char *getFullName() const; bool dummy() const; + + void updateDirection(const Common::Point& pos, const Common::Point& to); + }; @@ -263,7 +268,7 @@ public: void finalizeWalk(Character &character); int16 selectWalkFrame(Character &character, const Common::Point& pos, const WalkNodePtr to); - void clipMove(Common::Point& pos, const WalkNodePtr to); + void clipMove(Common::Point& pos, const Common::Point& to); ZonePtr findZone(const char *name); ZonePtr hitZone(uint32 type, uint16 x, uint16 y); @@ -357,7 +362,7 @@ protected: // members void displayComment(ExamineData *data); - void checkDoor(Character &character); + void checkDoor(const Common::Point &foot); void freeCharacter(); @@ -384,6 +389,7 @@ public: void beep(); + ZonePtr _zoneTrap; public: // const char **_zoneFlagNamesRes; diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp index 850123de97..d1b25f189a 100644 --- a/engines/parallaction/parallaction_ns.cpp +++ b/engines/parallaction/parallaction_ns.cpp @@ -305,6 +305,8 @@ void Parallaction_ns::changeLocation(char *location) { _gfx->hideFloatingLabel(); _gfx->freeLabels(); + _zoneTrap = nullZonePtr; + _input->stopHovering(); if (_engineFlags & kEngineBlockInput) { setArrowCursor(); diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp index 7a16960cbf..40dfddb903 100644 --- a/engines/parallaction/walk.cpp +++ b/engines/parallaction/walk.cpp @@ -27,14 +27,6 @@ namespace Parallaction { -// should be reset on location switch -static uint16 _doorData1 = 1000; -static ZonePtr _zoneTrap; - -// should be reset on character switch -static uint16 walkData1 = 0; -static uint16 walkData2 = 0; // next walk frame - inline byte PathBuffer::getValue(uint16 x, uint16 y) { byte m = data[(x >> 3) + y * internalWidth]; @@ -261,99 +253,43 @@ uint16 PathBuilder::walkFunc1(int16 x, int16 y, WalkNodePtr Node) { return 1; } -void Parallaction::clipMove(Common::Point& pos, const WalkNodePtr to) { +void Parallaction::clipMove(Common::Point& pos, const Common::Point& to) { - if ((pos.x < to->_x) && (pos.x < _pathBuffer->w) && (_pathBuffer->getValue(pos.x + 2, pos.y) != 0)) { - pos.x = (pos.x + 2 < to->_x) ? pos.x + 2 : to->_x; + if ((pos.x < to.x) && (pos.x < _pathBuffer->w) && (_pathBuffer->getValue(pos.x + 2, pos.y) != 0)) { + pos.x = (pos.x + 2 < to.x) ? pos.x + 2 : to.x; } - if ((pos.x > to->_x) && (pos.x > 0) && (_pathBuffer->getValue(pos.x - 2, pos.y) != 0)) { - pos.x = (pos.x - 2 > to->_x) ? pos.x - 2 : to->_x; + if ((pos.x > to.x) && (pos.x > 0) && (_pathBuffer->getValue(pos.x - 2, pos.y) != 0)) { + pos.x = (pos.x - 2 > to.x) ? pos.x - 2 : to.x; } - if ((pos.y < to->_y) && (pos.y < _pathBuffer->h) && (_pathBuffer->getValue(pos.x, pos.y + 2) != 0)) { - pos.y = (pos.y + 2 <= to->_y) ? pos.y + 2 : to->_y; + if ((pos.y < to.y) && (pos.y < _pathBuffer->h) && (_pathBuffer->getValue(pos.x, pos.y + 2) != 0)) { + pos.y = (pos.y + 2 <= to.y) ? pos.y + 2 : to.y; } - if ((pos.y > to->_y) && (pos.y > 0) && (_pathBuffer->getValue(pos.x, pos.y - 2) != 0)) { - pos.y = (pos.y - 2 >= to->_y) ? pos.y - 2 : to->_y; + if ((pos.y > to.y) && (pos.y > 0) && (_pathBuffer->getValue(pos.x, pos.y - 2) != 0)) { + pos.y = (pos.y - 2 >= to.y) ? pos.y - 2 : to.y; } return; } -int16 Parallaction::selectWalkFrame(Character &character, const Common::Point& pos, const WalkNodePtr to) { - - Common::Point dist(to->_x - pos.x, to->_y - pos.y); - - if (dist.x < 0) - dist.x = -dist.x; - if (dist.y < 0) - dist.y = -dist.y; - - walkData1++; - - // walk frame selection - int16 v16; - if (character._ani->getFrameNum() == 20) { - - if (dist.x > dist.y) { - walkData2 = (to->_x > pos.x) ? 0 : 7; - walkData1 %= 12; - v16 = walkData1 / 2; - } else { - walkData2 = (to->_y > pos.y) ? 14 : 17; - walkData1 %= 8; - v16 = walkData1 / 4; - } - - } else { - - if (dist.x > dist.y) { - walkData2 = (to->_x > pos.x) ? 0 : 9; - walkData1 %= 16; - v16 = walkData1 / 2; - } else { - walkData2 = (to->_y > pos.y) ? 18 : 21; - walkData1 %= 8; - v16 = walkData1 / 4; - } - - } - - return v16; -} - -void Parallaction::checkDoor(Character &character) { - if (_currentLocationIndex != _doorData1) { - _doorData1 = _currentLocationIndex; - _zoneTrap = nullZonePtr; - } - - _engineFlags &= ~kEngineWalking; - Common::Point foot; +void Parallaction::checkDoor(const Common::Point &foot) { - character.getFoot(foot); ZonePtr z = hitZone(kZoneDoor, foot.x, foot.y); - if (z) { - if ((z->_flags & kFlagsClosed) == 0) { _location._startPosition = z->u.door->_startPos; _location._startFrame = z->u.door->_startFrame; - scheduleLocationSwitch(z->u.door->_location); _zoneTrap = nullZonePtr; - } else { _cmdExec->run(z->_commands, z); } } - character.getFoot(foot); z = hitZone(kZoneTrap, foot.x, foot.y); - if (z) { setLocationFlags(kFlagsEnter); _cmdExec->run(z->_commands, z); @@ -371,11 +307,14 @@ void Parallaction::checkDoor(Character &character) { void Parallaction::finalizeWalk(Character &character) { - checkDoor(character); + _engineFlags &= ~kEngineWalking; + + Common::Point foot; + character.getFoot(foot); + checkDoor(foot); + delete character._walkPath; character._walkPath = 0; - - character._ani->_frame = walkData2; } void Parallaction_ns::walk(Character &character) { @@ -386,35 +325,45 @@ void Parallaction_ns::walk(Character &character) { Common::Point curPos; character.getFoot(curPos); + // update target, if previous was reached WalkNodeList::iterator it = character._walkPath->begin(); - if (it != character._walkPath->end()) { if ((*it)->_x == curPos.x && (*it)->_y == curPos.y) { debugC(1, kDebugWalk, "walk reached node (%i, %i)", (*it)->_x, (*it)->_y); it = character._walkPath->erase(it); } } + + // advance character towards the target + Common::Point targetPos; if (it == character._walkPath->end()) { debugC(1, kDebugWalk, "walk reached last node"); finalizeWalk(character); - return; - } - - // selectWalkFrame must be performed before position is changed by clipMove - int16 walkFrame = selectWalkFrame(character, curPos, *it); + targetPos = curPos; + } else { + if (*it) { + // targetPos is saved to help setting character direction + targetPos.x = (*it)->_x; + targetPos.y = (*it)->_y; + } - Common::Point newPos(curPos); - clipMove(newPos, *it); - character.setFoot(newPos); + Common::Point newPos(curPos); + clipMove(newPos, targetPos); + character.setFoot(newPos); - if (newPos == curPos) { - debugC(1, kDebugWalk, "walk was blocked by an unforeseen obstacle"); - finalizeWalk(character); - } else { - character._ani->_frame = walkFrame + walkData2 + 1; + if (newPos == curPos) { + debugC(1, kDebugWalk, "walk was blocked by an unforeseen obstacle"); + finalizeWalk(character); + } } - return; + // targetPos is used to select the direction (and the walkFrame) of a character, + // since it doesn't cause the sudden changes in orientation that newPos would. + // Since newPos is 'adjusted' according to walkable areas, an imaginary line drawn + // from curPos to newPos is prone to abrutply change in direction, thus making the + // code select 'too different' frames when walking diagonally against obstacles, + // and yielding an annoying shaking effect in the character. + character.updateDirection(curPos, targetPos); } |