From 6334125d1c0264278f2907d13cff8e6ba418bcc8 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Tue, 24 Feb 2009 11:20:45 +0000 Subject: Implemented follower support, except that: * follower is forgotten when location changes (see freeLocation) * the final walking frame is screwed svn-id: r38838 --- engines/parallaction/exec_br.cpp | 5 + engines/parallaction/objects.h | 3 + engines/parallaction/parallaction.cpp | 3 + engines/parallaction/parallaction.h | 2 + engines/parallaction/parallaction_br.cpp | 24 +++- engines/parallaction/parser_br.cpp | 2 + engines/parallaction/walk.cpp | 187 +++++++++++++++---------------- engines/parallaction/walk.h | 8 +- 8 files changed, 130 insertions(+), 104 deletions(-) diff --git a/engines/parallaction/exec_br.cpp b/engines/parallaction/exec_br.cpp index 09d8043ab7..274e8187ff 100644 --- a/engines/parallaction/exec_br.cpp +++ b/engines/parallaction/exec_br.cpp @@ -116,6 +116,11 @@ void Parallaction_br::clearSubtitles() { DECLARE_COMMAND_OPCODE(location) { warning("Parallaction_br::cmdOp_location command not yet implemented"); + _vm->_location._startPosition = _ctxt.cmd->u._startPos; + _vm->_location._startFrame = 0; // TODO: verify this against the disassembly!f + _vm->_location._followerStartPosition = _ctxt.cmd->u._startPos2; + _vm->_location._followerStartFrame = 0; + // TODO: handle startPos and startPos2 _vm->scheduleLocationSwitch(_ctxt.cmd->u._string); } diff --git a/engines/parallaction/objects.h b/engines/parallaction/objects.h index aa11165b33..9effbf66fd 100644 --- a/engines/parallaction/objects.h +++ b/engines/parallaction/objects.h @@ -229,6 +229,9 @@ struct DoorData { GfxObj *gfxobj; Common::Point _startPos; uint16 _startFrame; + // BRA specific + Common::Point _startPos2; + uint16 _startFrame2; DoorData() { _location = NULL; diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index 6ab94d3c54..5193433eea 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -111,6 +111,9 @@ Common::Error Parallaction::init() { _location._startPosition.x = -1000; _location._startPosition.y = -1000; _location._startFrame = 0; + _location._followerStartPosition.x = -1000; + _location._followerStartPosition.y = -1000; + _location._followerStartFrame = 0; _objects = 0; _screenSize = _screenWidth * _screenHeight; diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index 55eeabfa85..e86485d036 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -153,6 +153,8 @@ struct Location { int _zeta1; int _zeta2; CommandList _escapeCommands; + Common::Point _followerStartPosition; + uint16 _followerStartFrame; protected: void freeAnimations(); diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp index 4cfada2bc7..cb81bf1646 100644 --- a/engines/parallaction/parallaction_br.cpp +++ b/engines/parallaction/parallaction_br.cpp @@ -202,6 +202,8 @@ void Parallaction_br::freeLocation(bool removeAll) { _gfx->freeLocationObjects(); + // TODO: avoid removing needed animations from 'common.slf' + // when cleaning up!!! _location._animations.remove(_char._ani); _location.cleanup(removeAll); _location._animations.push_front(_char._ani); @@ -261,15 +263,27 @@ void Parallaction_br::changeLocation(char *location) { // load new location parseLocation(location); - setFollower(_followerName); - if (_location._startPosition.x != -1000) { - _char.setFoot(_location._startPosition); + _char._ani->setFoot(_location._startPosition); _char._ani->setF(_location._startFrame); - _location._startPosition.y = -1000; - _location._startPosition.x = -1000; } + // re-link the follower animation + setFollower(_followerName); + if (_follower) { + Common::Point p = _location._followerStartPosition; + if (p.x == -1000) { + _char._ani->getFoot(p); + } + _follower->setFoot(p); + _follower->setF(_location._followerStartFrame); + } + + _location._startPosition.x = -1000; + _location._startPosition.y = -1000; + _location._followerStartPosition.x = -1000; + _location._followerStartPosition.y = -1000; + // kFlagsRemove is cleared because the character is visible by default. // Commands can hide the character, anyway. _char._ani->_flags &= ~kFlagsRemove; diff --git a/engines/parallaction/parser_br.cpp b/engines/parallaction/parser_br.cpp index d91c0b485c..eeaf132b9e 100644 --- a/engines/parallaction/parser_br.cpp +++ b/engines/parallaction/parser_br.cpp @@ -525,6 +525,8 @@ DECLARE_COMMAND_PARSER(location) { ctxt.cmd->u._string = strdup(_tokens[1]); ctxt.nextToken++; + ctxt.cmd->u._startPos.x = -1000; + ctxt.cmd->u._startPos2.x = -1000; if (_tokens[ctxt.nextToken][0] != '\0') { if (isdigit(_tokens[ctxt.nextToken][0]) || _tokens[ctxt.nextToken][0] == '-') { ctxt.cmd->u._startPos.x = atoi(_tokens[ctxt.nextToken]); diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp index 6807884c7a..a4f07f9bfc 100644 --- a/engines/parallaction/walk.cpp +++ b/engines/parallaction/walk.cpp @@ -368,15 +368,18 @@ bool PathWalker_BR::directPathExists(const Common::Point &from, const Common::Po void PathWalker_BR::setCharacterPath(AnimationPtr a, uint16 x, uint16 y) { _character._a = a; - _ch = _character; - buildPath(x, y); + _character._first = true; + _character._fieldC = 1; + buildPath(_character, x, y); _character._active = true; } void PathWalker_BR::setFollowerPath(AnimationPtr a, uint16 x, uint16 y) { _follower._a = a; - _ch = _follower; - buildPath(x, y); + _follower._first = true; + _follower._fieldC = 1; + _follower._walkDelay = 5; + buildPath(_follower, x - 50, y); _follower._active = true; } @@ -386,17 +389,17 @@ void PathWalker_BR::stopFollower() { } -void PathWalker_BR::buildPath(uint16 x, uint16 y) { +void PathWalker_BR::buildPath(State &s, uint16 x, uint16 y) { Common::Point foot; - _ch._a->getFoot(foot); + s._a->getFoot(foot); debugC(1, kDebugWalk, "buildPath: from (%i, %i) to (%i, %i)", foot.x, foot.y, x, y); - _ch._walkPath.clear(); + s._walkPath.clear(); // look for easy path first Common::Point dest(x, y); if (directPathExists(foot, dest)) { - _ch._walkPath.push_back(dest); + s._walkPath.push_back(dest); debugC(3, kDebugWalk, "buildPath: direct path found"); return; } @@ -404,13 +407,13 @@ void PathWalker_BR::buildPath(uint16 x, uint16 y) { // look for short circuit cases ZonePtr z0 = _vm->hitZone(kZonePath, x, y); if (!z0) { - _ch._walkPath.push_back(dest); + s._walkPath.push_back(dest); debugC(3, kDebugWalk, "buildPath: corner case 0"); return; } ZonePtr z1 = _vm->hitZone(kZonePath, foot.x, foot.y); if (!z1 || z1 == z0) { - _ch._walkPath.push_back(dest); + s._walkPath.push_back(dest); debugC(3, kDebugWalk, "buildPath: corner case 1"); return; } @@ -419,7 +422,7 @@ void PathWalker_BR::buildPath(uint16 x, uint16 y) { int id = atoi(z0->_name); if (z1->u.path->_lists[id].empty()) { - _ch._walkPath.clear(); + s._walkPath.clear(); debugC(3, kDebugWalk, "buildPath: no path"); return; } @@ -427,39 +430,34 @@ void PathWalker_BR::buildPath(uint16 x, uint16 y) { PointList::iterator b = z1->u.path->_lists[id].begin(); PointList::iterator e = z1->u.path->_lists[id].end(); for ( ; b != e; b++) { - _ch._walkPath.push_front(*b); + s._walkPath.push_front(*b); } - _ch._walkPath.push_back(dest); + s._walkPath.push_back(dest); debugC(3, kDebugWalk, "buildPath: complex path"); } -void PathWalker_BR::finalizeWalk() { +void PathWalker_BR::finalizeWalk(State &s) { _engineFlags &= ~kEngineWalking; - _ch._first = true; - _ch._fieldC = 1; Common::Point foot; - _ch._a->getFoot(foot); + _character._a->getFoot(foot); ZonePtr z = _vm->hitZone(kZoneDoor, foot.x, foot.y); if (z && ((z->_flags & kFlagsClosed) == 0)) { _vm->_location._startPosition = z->u.door->_startPos; // foot pos _vm->_location._startFrame = z->u.door->_startFrame; -#if 0 // TODO: implement working follower. Must find out a location in which the code is // used and which is stable enough. - _followerFootInit.x = -1; - if (_follower && z->u.door->startPos2.x != -1) { - _followerFootInit.x = z->u.door->startPos2.x; // foot pos - _followerFootInit.y = z->u.door->startPos2.y; // foot pos - } - _followerFootInit.z = -1; - if (_follower && z->u.door->startPos2.z != -1) { - _followerFootInit.z = z->u.door->startPos2.z; // foot pos + if (_follower._active) { + _vm->_location._followerStartPosition = z->u.door->_startPos2; // foot pos + _vm->_location._followerStartFrame = z->u.door->_startFrame2; + } else { + _vm->_location._followerStartPosition.x = -1000; + _vm->_location._followerStartPosition.y = -1000; + _vm->_location._followerStartFrame = 0; } -#endif _vm->scheduleLocationSwitch(z->u.door->_location); _vm->_cmdExec->run(z->_commands, z); @@ -467,8 +465,6 @@ void PathWalker_BR::finalizeWalk() { #if 0 // TODO: Input::walkTo must be extended to support destination frame in addition to coordinates - // TODO: the frame argument must be passed to PathWalker through PathBuilder, so probably - // a merge between the two Path managers is the right solution if (_engineFlags & FINAL_WALK_FRAME) { // this flag is set in readInput() _engineFlags &= ~FINAL_WALK_FRAME; _ch._a->_frame = _moveToF; // from readInput()... @@ -478,7 +474,7 @@ void PathWalker_BR::finalizeWalk() { _ch._a->setFoot(foot); #endif - _ch._a->setF(_ch._dirFrame); // temporary solution + s._a->setF(s._dirFrame); // temporary solution #if 0 // TODO: support scrolling ;) @@ -488,7 +484,7 @@ void PathWalker_BR::finalizeWalk() { if (foot.y < 80) _gfx->scrollUp(100); #endif - return; + s._active = false; } void PathWalker_BR::walk() { @@ -496,12 +492,12 @@ void PathWalker_BR::walk() { return; } - bool finalize = doWalk(_character); + debugC(3, kDebugWalk, "PathWalker_BR::walk()"); + + doWalk(_character); doWalk(_follower); - if (finalize) { - finalizeWalk(); - } + debugC(3, kDebugWalk, "PathWalker_BR::walk() -> done"); } void PathWalker_BR::checkTrap(const Common::Point &p) { @@ -530,12 +526,12 @@ void PathWalker_BR::checkTrap(const Common::Point &p) { _vm->_zoneTrap = z; } -bool PathWalker_BR::doWalk(State &s) { +void PathWalker_BR::doWalk(State &s) { if (!s._active) { - return false; + return; } - _ch = s; + debugC(3, kDebugWalk, "PathWalker_BR::doWalk(%s)", s._a->_name); #if 0 // TODO: support delays in walking. This requires extending Input::walkIo(). @@ -547,119 +543,122 @@ bool PathWalker_BR::doWalk(State &s) { Script *script = findScript(_ch._ani->_scriptName); script->_nextCommand = script->firstCommand; } - return false; + return; } #endif - if (_ch._fieldC == 0) { - _ch._walkPath.erase(_ch._walkPath.begin()); + if (s._fieldC == 0) { + s._walkPath.erase(s._walkPath.begin()); - if (_ch._walkPath.empty()) { - debugC(3, kDebugWalk, "PathWalker_BR::walk, case 0"); - return true; + if (s._walkPath.empty()) { + finalizeWalk(s); + debugC(3, kDebugWalk, "PathWalker_BR::doWalk, case 0"); + return; } else { - debugC(3, kDebugWalk, "PathWalker_BR::walk, moving to next node"); + debugC(3, kDebugWalk, "PathWalker_BR::doWalk, moving to next node"); } } - _ch._a->getFoot(_ch._startFoot); + s._a->getFoot(s._startFoot); - uint scale = _vm->_location.getScale(_ch._startFoot.y); + uint scale = _vm->_location.getScale(s._startFoot.y); int xStep = (scale * 16) / 100 + 1; int yStep = (scale * 10) / 100 + 1; debugC(9, kDebugWalk, "calculated step: (%i, %i)", xStep, yStep); - _ch._fieldC = 0; - _ch._step++; - _ch._step %= 8; + s._fieldC = 0; + s._step++; + s._step %= 8; int maxX = _vm->_gfx->_backgroundInfo->width; int minX = 0; int maxY = _vm->_gfx->_backgroundInfo->height; int minY = 0; - int walkFrame = _ch._step; - _ch._dirFrame = 0; - Common::Point newpos(_ch._startFoot), delta; + int walkFrame = s._step; + s._dirFrame = 0; + Common::Point newpos(s._startFoot), delta; - Common::Point p(*_ch._walkPath.begin()); + Common::Point p(*s._walkPath.begin()); - if (_ch._startFoot.y < p.y && _ch._startFoot.y < maxY && IS_PATH_CLEAR(_ch._startFoot.x, yStep + _ch._startFoot.y)) { - if (yStep + _ch._startFoot.y <= p.y) { - _ch._fieldC = 1; + if (s._startFoot.y < p.y && s._startFoot.y < maxY && IS_PATH_CLEAR(s._startFoot.x, yStep + s._startFoot.y)) { + if (yStep + s._startFoot.y <= p.y) { + s._fieldC = 1; delta.y = yStep; - newpos.y = yStep + _ch._startFoot.y; + newpos.y = yStep + s._startFoot.y; } else { - delta.y = p.y - _ch._startFoot.y; + delta.y = p.y - s._startFoot.y; newpos.y = p.y; } - _ch._dirFrame = 9; + s._dirFrame = 9; } else - if (_ch._startFoot.y > p.y && _ch._startFoot.y > minY && IS_PATH_CLEAR(_ch._startFoot.x, _ch._startFoot.y - yStep)) { - if (_ch._startFoot.y - yStep >= p.y) { - _ch._fieldC = 1; + if (s._startFoot.y > p.y && s._startFoot.y > minY && IS_PATH_CLEAR(s._startFoot.x, s._startFoot.y - yStep)) { + if (s._startFoot.y - yStep >= p.y) { + s._fieldC = 1; delta.y = yStep; - newpos.y = _ch._startFoot.y - yStep; + newpos.y = s._startFoot.y - yStep; } else { - delta.y = _ch._startFoot.y - p.y; + delta.y = s._startFoot.y - p.y; newpos.y = p.y; } - _ch._dirFrame = 0; + s._dirFrame = 0; } - if (_ch._startFoot.x < p.x && _ch._startFoot.x < maxX && IS_PATH_CLEAR(_ch._startFoot.x + xStep, _ch._startFoot.y)) { - if (_ch._startFoot.x + xStep <= p.x) { - _ch._fieldC = 1; + if (s._startFoot.x < p.x && s._startFoot.x < maxX && IS_PATH_CLEAR(s._startFoot.x + xStep, s._startFoot.y)) { + if (s._startFoot.x + xStep <= p.x) { + s._fieldC = 1; delta.x = xStep; - newpos.x = xStep + _ch._startFoot.x; + newpos.x = xStep + s._startFoot.x; } else { - delta.x = p.x - _ch._startFoot.x; + delta.x = p.x - s._startFoot.x; newpos.x = p.x; } if (delta.y < delta.x) { - _ch._dirFrame = 18; // right + s._dirFrame = 18; // right } } else - if (_ch._startFoot.x > p.x && _ch._startFoot.x > minX && IS_PATH_CLEAR(_ch._startFoot.x - xStep, _ch._startFoot.y)) { - if (_ch._startFoot.x - xStep >= p.x) { - _ch._fieldC = 1; + if (s._startFoot.x > p.x && s._startFoot.x > minX && IS_PATH_CLEAR(s._startFoot.x - xStep, s._startFoot.y)) { + if (s._startFoot.x - xStep >= p.x) { + s._fieldC = 1; delta.x = xStep; - newpos.x = _ch._startFoot.x - xStep; + newpos.x = s._startFoot.x - xStep; } else { - delta.x = _ch._startFoot.x - p.x; + delta.x = s._startFoot.x - p.x; newpos.x = p.x; } if (delta.y < delta.x) { - _ch._dirFrame = 27; // left + s._dirFrame = 27; // left } } - debugC(9, kDebugWalk, "foot (%i, %i) dest (%i, %i) deltas = %i/%i ", _ch._startFoot.x, _ch._startFoot.y, p.x, p.y, delta.x, delta.y); + debugC(9, kDebugWalk, "foot (%i, %i) dest (%i, %i) deltas = %i/%i ", s._startFoot.x, s._startFoot.y, p.x, p.y, delta.x, delta.y); - if (_ch._fieldC) { - debugC(9, kDebugWalk, "PathWalker_BR::walk, foot moved from (%i, %i) to (%i, %i)", _ch._startFoot.x, _ch._startFoot.y, newpos.x, newpos.y); - _ch._a->setF(walkFrame + _ch._dirFrame + 1); - _ch._startFoot.x = newpos.x; - _ch._startFoot.y = newpos.y; - _ch._a->setFoot(_ch._startFoot); - _ch._a->setZ(newpos.y); + if (s._fieldC) { + debugC(9, kDebugWalk, "PathWalker_BR::doWalk, foot moved from (%i, %i) to (%i, %i)", s._startFoot.x, s._startFoot.y, newpos.x, newpos.y); + s._a->setF(walkFrame + s._dirFrame + 1); + s._startFoot.x = newpos.x; + s._startFoot.y = newpos.y; + s._a->setFoot(s._startFoot); + s._a->setZ(newpos.y); } - if (_ch._fieldC || !_ch._walkPath.empty()) { + if (s._fieldC || !s._walkPath.empty()) { Common::Point p; - _ch._a->getFoot(p); + s._a->getFoot(p); checkTrap(p); - debugC(3, kDebugWalk, "PathWalker_BR::walk, case 1"); - return false; + debugC(3, kDebugWalk, "PathWalker_BR::doWalk, case 1"); + return; } - debugC(3, kDebugWalk, "PathWalker_BR::walk, case 2"); - return true; + debugC(3, kDebugWalk, "PathWalker_BR::doWalk, case 2"); + finalizeWalk(s); + return; } -PathWalker_BR::PathWalker_BR() : _ch(_character) { - +PathWalker_BR::PathWalker_BR() { + _character._active = false; + _follower._active = false; } diff --git a/engines/parallaction/walk.h b/engines/parallaction/walk.h index aebfea7975..d746fdec54 100644 --- a/engines/parallaction/walk.h +++ b/engines/parallaction/walk.h @@ -102,12 +102,10 @@ class PathWalker_BR { State _character; State _follower; - State &_ch; - - void finalizeWalk(); + void finalizeWalk(State &s); bool directPathExists(const Common::Point &from, const Common::Point &to); - void buildPath(uint16 x, uint16 y); - bool doWalk(State &s); + void buildPath(State &s, uint16 x, uint16 y); + void doWalk(State &s); void checkTrap(const Common::Point &p); public: -- cgit v1.2.3