aboutsummaryrefslogtreecommitdiff
path: root/engines/scumm
diff options
context:
space:
mode:
authorKirben2014-12-07 15:09:36 +1100
committerKirben2014-12-07 15:09:36 +1100
commitdcd0f597e6026e248ff6e2db0224f3f60626cdca (patch)
treef616b8ed6ae0b0ce56f7c81dd65ad4af84754ded /engines/scumm
parentd8af639dfcbdae3c99f72c4c4ec4f07410d5915c (diff)
parent4b1b9ec66f5889fd20d88f8f7f565e8448ac8389 (diff)
downloadscummvm-rg350-dcd0f597e6026e248ff6e2db0224f3f60626cdca.tar.gz
scummvm-rg350-dcd0f597e6026e248ff6e2db0224f3f60626cdca.tar.bz2
scummvm-rg350-dcd0f597e6026e248ff6e2db0224f3f60626cdca.zip
Merge pull request #539 from segrax/master
SCUMM: Maniac V0: Original Walk Code Implementation
Diffstat (limited to 'engines/scumm')
-rw-r--r--engines/scumm/actor.cpp589
-rw-r--r--engines/scumm/actor.h49
-rw-r--r--engines/scumm/boxes.cpp24
-rw-r--r--engines/scumm/saveload.h2
-rw-r--r--engines/scumm/script.cpp6
-rw-r--r--engines/scumm/script_v0.cpp7
-rw-r--r--engines/scumm/script_v5.cpp4
-rw-r--r--engines/scumm/scumm_v0.h4
-rw-r--r--engines/scumm/verbs.cpp2
9 files changed, 562 insertions, 125 deletions
diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp
index 116a953b0b..90ee5bf368 100644
--- a/engines/scumm/actor.cpp
+++ b/engines/scumm/actor.cpp
@@ -33,6 +33,7 @@
#include "scumm/resource.h"
#include "scumm/saveload.h"
#include "scumm/scumm_v7.h"
+#include "scumm/scumm_v0.h"
#include "scumm/he/sound_he.h"
#include "scumm/he/sprite_he.h"
#include "scumm/usage_bits.h"
@@ -50,6 +51,12 @@ static const byte v0ActorTalkArray[0x19] = {
0xC0, 0xC0, 0x00, 0x06, 0x06
};
+static const byte v0WalkboxSlantedModifier[0x16] = {
+ 0x00,0x01,0x02,0x03,0x03,0x04,0x05,0x06,
+ 0x06,0x07,0x08,0x09,0x09,0x0A,0x0B,
+ 0x0C,0x0C,0x0D,0x0E,0x0F,0x10,0x10
+};
+
Actor::Actor(ScummEngine *scumm, int id) :
_vm(scumm), _number(id) {
assert(_vm != 0);
@@ -182,6 +189,20 @@ void Actor_v0::initActor(int mode) {
_costCommand = 0xFF;
_miscflags = 0;
_speaking = 0;
+
+ _walkCountModulo = 0;
+ _newWalkBoxEntered = false;
+ _walkDirX = 0;
+ _walkDirY = 0;
+ _walkYCountGreaterThanXCount = 0;
+ _walkXCount = 0;
+ _walkXCountInc = 0;
+ _walkYCount = 0;
+ _walkYCountInc = 0;
+ _walkMaxXYCountInc = 0;
+
+ _tmp_WalkBox = 0;
+ _tmp_NewWalkBoxEntered = 0;
_animFrameRepeat = 0;
for (int i = 0; i < 8; ++i) {
@@ -249,9 +270,12 @@ void Actor::stopActorMoving() {
if (_walkScript)
_vm->stopScript(_walkScript);
- _moving = 0;
- if (_vm->_game.version == 0)
+ if (_vm->_game.version == 0) {
+ _moving = 2;
setDirection(_facing);
+ } else {
+ _moving = 0;
+ }
}
void Actor::setActorWalkSpeed(uint newSpeedX, uint newSpeedY) {
@@ -339,9 +363,6 @@ int Actor::actorWalkStep() {
int distX, distY;
int nextFacing;
- if (_vm->_game.version == 0)
- ((Actor_v0 *)this)->_animFrameRepeat = -1;
-
_needRedraw = true;
nextFacing = updateActorDirection(true);
@@ -350,10 +371,6 @@ int Actor::actorWalkStep() {
startWalkAnim(1, nextFacing);
}
_moving |= MF_IN_LEG;
-
- // V0: Don't move during the turn
- if (_vm->_game.version == 0)
- return 0;
}
if (_walkbox != _walkdata.curbox && _vm->checkXYInBoxBounds(_walkdata.curbox, _pos.x, _pos.y)) {
@@ -389,12 +406,113 @@ int Actor::actorWalkStep() {
return 0;
}
- if (_vm->_game.version == 0)
- ((Actor_v0 *)this)->animateActor(newDirToOldDir(_facing));
-
return 1;
}
+bool Actor_v0::calcWalkDistances() {
+ _walkDirX = 0;
+ _walkDirY = 0;
+ _walkYCountGreaterThanXCount = 0;
+ uint16 A = 0;
+
+ if (_CurrentWalkTo.x >= _tmp_Dest.x ) {
+ A = _CurrentWalkTo.x - _tmp_Dest.x;
+ _walkDirX = 1;
+ } else {
+ A = _tmp_Dest.x - _CurrentWalkTo.x;
+ }
+
+ _walkXCountInc = A;
+
+ if (_CurrentWalkTo.y >= _tmp_Dest.y ) {
+ A = _CurrentWalkTo.y - _tmp_Dest.y;
+ _walkDirY = 1;
+ } else {
+ A = _tmp_Dest.y - _CurrentWalkTo.y;
+ }
+
+ _walkYCountInc = A;
+ if ( !_walkXCountInc && !_walkYCountInc )
+ return true;
+
+ if( _walkXCountInc <= _walkYCountInc )
+ _walkYCountGreaterThanXCount = 1;
+
+ // 2FCC
+ A = _walkXCountInc;
+ if( A <= _walkYCountInc )
+ A = _walkYCountInc;
+
+ _walkMaxXYCountInc = A;
+ _walkXCount = _walkXCountInc;
+ _walkYCount = _walkYCountInc;
+ _walkCountModulo = _walkMaxXYCountInc;
+
+ return false;
+}
+
+byte Actor_v0::actorWalkX() {
+ byte A = _walkXCount;
+ A += _walkXCountInc;
+ if (A >= _walkCountModulo) {
+ if (!_walkDirX ) {
+ _tmp_Dest.x--;
+ } else {
+ _tmp_Dest.x++;
+ }
+
+ A -= _walkCountModulo;
+ }
+ // 2EAC
+ _walkXCount = A;
+ setTmpFromActor();
+ if (updateWalkbox() == kInvalidBox) {
+ // 2EB9
+ setActorFromTmp();
+
+ return 3;
+ }
+ // 2EBF
+ if (_tmp_Dest.x == _CurrentWalkTo.x)
+ return 1;
+
+ return 0;
+}
+
+byte Actor_v0::actorWalkY() {
+ byte A = _walkYCount;
+ A += _walkYCountInc;
+ if (A >= _walkCountModulo) {
+ if (!_walkDirY ) {
+ _tmp_Dest.y--;
+ } else {
+ _tmp_Dest.y++;
+ }
+
+ A -= _walkCountModulo;
+ }
+ // 2EEB
+ _walkYCount = A;
+ setTmpFromActor();
+ if (updateWalkbox() == kInvalidBox) {
+ // 2EF8
+ setActorFromTmp();
+ return 4;
+ }
+ // 2EFE
+ if (_walkYCountInc != 0) {
+ if (_walkYCountInc == 0xFF) {
+ setActorFromTmp();
+ return 4;
+ }
+ }
+ // 2F0D
+ if (_CurrentWalkTo.y == _tmp_Dest.y)
+ return 1;
+
+ return 0;
+}
+
void Actor::startWalkActor(int destX, int destY, int dir) {
AdjustBoxResult abr;
@@ -447,10 +565,14 @@ void Actor::startWalkActor(int destX, int destY, int dir) {
_walkdata.dest.y = abr.y;
_walkdata.destbox = abr.box;
_walkdata.destdir = dir;
- _moving = (_moving & MF_IN_LEG) | MF_NEW_LEG;
_walkdata.point3.x = 32000;
-
_walkdata.curbox = _walkbox;
+
+ if(_vm->_game.version == 0 ) {
+ ((Actor_v0*)this)->_newWalkBoxEntered = true;
+ } else {
+ _moving = (_moving & MF_IN_LEG) | MF_NEW_LEG;
+ }
}
void Actor::startWalkAnim(int cmd, int angle) {
@@ -567,88 +689,206 @@ void Actor::walkActor() {
calcMovementFactor(_walkdata.dest);
}
-bool Actor_v2::checkWalkboxesHaveDirectPath(Common::Point &foundPath) {
- // only MM v0 supports walking in direct line between walkboxes.
- // MM v1 already does not support it anymore.
- return false;
-}
+void Actor_v0::walkActor() {
+ actorSetWalkTo();
-bool Actor_v0::intersectLineSegments(const Common::Point &line1Start, const Common::Point &line1End,
- const Common::Point &line2Start, const Common::Point &line2End, Common::Point &result)
-{
- const Common::Point v1 = line1End - line1Start; // line1(n1) = line1Start + n1 * v1
- const Common::Point v2 = line2End - line2Start; // line2(n2) = line2Start + n2 * v2
+ _needRedraw = true;
+ if (_NewWalkTo != _CurrentWalkTo) {
+ _CurrentWalkTo = _NewWalkTo;
- double det = v2.x * v1.y - v1.x * v2.y;
- if (det == 0)
- return false;
+L2A33:;
+ _moving &= 0xF0;
+ _tmp_Dest = _pos;
- double n1 = ((double)v2.x * (line2Start.y - line1Start.y) -
- (double)v2.y * (line2Start.x - line1Start.x)) / det;
- double n2 = ((double)v1.x * (line2Start.y - line1Start.y) -
- (double)v1.y * (line2Start.x - line1Start.x)) / det;
+ byte tmp = calcWalkDistances();
+ _moving &= 0xF0;
+ _moving |= tmp;
- // both coefficients have to be in [0, 1], otherwise the intersection is
- // not inside of at least one of the two line segments
- if (n1 < 0.0 || n1 > 1.0 || n2 < 0.0 || n2 > 1.0)
- return false;
+ if (!_walkYCountGreaterThanXCount) {
+ if (_walkDirX) {
+ _targetFacing = getAngleFromPos(V12_X_MULTIPLIER*1, V12_Y_MULTIPLIER*0, false);
+ } else {
+ _targetFacing = getAngleFromPos(V12_X_MULTIPLIER*-1, V12_Y_MULTIPLIER*0, false);
+ }
+ } else {
+ if (_walkDirY) {
+ _targetFacing = getAngleFromPos(V12_X_MULTIPLIER*0, V12_Y_MULTIPLIER*1, false);
+ } else {
+ _targetFacing = getAngleFromPos(V12_X_MULTIPLIER*0, V12_Y_MULTIPLIER*-1, false);
+ }
+ }
- result.x = line1Start.x + (int)(n1 * v1.x);
- result.y = line1Start.y + (int)(n1 * v1.y);
- return true;
-}
+ directionUpdate();
+
+ if (_moving & 0x80)
+ return;
-/*
- * MM v0 allows the actor to walk in a direct line between boxes to the target
- * if actor and target share a horizontal or vertical corridor.
- * If such a corridor is found the actor is not forced to go horizontally or
- * vertically from one box to the next but can also walk diagonally.
- *
- * Note: the original v0 interpreter sets the target destination for diagonal
- * walking only once and then rechecks whenever the actor reaches a new box if the
- * walk destination is still suitable for the current box.
- * ScummVM does not perform such a check, so it is possible to leave the walkboxes
- * in some cases, for example L-shaped rooms like the swimming pool (actor walks over water)
- * or the medical room (actor walks over examination table).
- * To solve this we intersect the new walk destination with the actor's walkbox borders,
- * so a recheck is done when the actor leaves his box. This is done by the
- * intersectLineSegments() routine calls.
- */
-bool Actor_v0::checkWalkboxesHaveDirectPath(Common::Point &foundPath) {
- BoxCoords boxCoords = _vm->getBoxCoordinates(_walkbox);
- BoxCoords curBoxCoords = _vm->getBoxCoordinates(_walkdata.curbox);
-
- // check if next walkbox is left or right to actor's box
- if (boxCoords.ll.x > curBoxCoords.lr.x || boxCoords.lr.x < curBoxCoords.ll.x) {
- // determine horizontal corridor gates
- int gateUpper = MAX(boxCoords.ul.y, curBoxCoords.ul.y);
- int gateLower = MIN(boxCoords.ll.y, curBoxCoords.ll.y);
-
- // check if actor and target are in the same horizontal corridor between the boxes
- if ((_pos.y >= gateUpper && _pos.y <= gateLower) &&
- (_walkdata.dest.y >= gateUpper && _walkdata.dest.y <= gateLower)) {
- if (boxCoords.ll.x > curBoxCoords.lr.x) // next box is left
- return intersectLineSegments(_pos, _walkdata.dest, boxCoords.ll, boxCoords.ul, foundPath);
- else // next box is right
- return intersectLineSegments(_pos, _walkdata.dest, boxCoords.lr, boxCoords.ur, foundPath);
- }
- // check if next walkbox is above or below actor's box
- } else if (boxCoords.ul.y > curBoxCoords.ll.y || boxCoords.ll.y < curBoxCoords.ul.y) {
- // determine vertical corridor gates
- int gateLeft = MAX(boxCoords.ll.x, curBoxCoords.ll.x);
- int gateRight = MIN(boxCoords.lr.x, curBoxCoords.lr.x);
-
- // check if actor and target are in the same vertical corridor between the boxes
- if ((_pos.x >= gateLeft && _pos.x <= gateRight) &&
- (_walkdata.dest.x >= gateLeft && _walkdata.dest.x <= gateRight)) {
- if (boxCoords.ul.y > curBoxCoords.ll.y) // next box is above
- return intersectLineSegments(_pos, _walkdata.dest, boxCoords.ul, boxCoords.ur, foundPath);
- else // next box is below
- return intersectLineSegments(_pos, _walkdata.dest, boxCoords.ll, boxCoords.lr, foundPath);
+ animateActor(newDirToOldDir(_facing));
+
+ } else {
+ // 2A0A
+ if ((_moving & 0x7F) != 1) {
+
+ if (_NewWalkTo == _pos)
+ return;
}
}
- return false;
+ // 2A9A
+ if (_moving == 2)
+ return;
+
+ if ((_moving & 0x0F) == 1)
+ return stopActorMoving();
+
+ // 2AAD
+ if (_moving & 0x80) {
+ directionUpdate();
+
+ if (_moving & 0x80)
+ return;
+
+ animateActor(newDirToOldDir(_facing));
+ }
+
+ if ((_moving & 0x0F) == 3 ) {
+L2C36:;
+ setTmpFromActor();
+
+ if (!_walkDirX) {
+ _pos.x--;
+ } else {
+ _pos.x++;
+ }
+
+ // 2C51
+ if (updateWalkbox() != kInvalidBox) {
+
+ setActorFromTmp();
+ goto L2A33;
+ }
+
+ setActorFromTmp();
+
+ if (_CurrentWalkTo.y == _tmp_Dest.y) {
+ stopActorMoving();
+ return;
+ }
+
+ if (!_walkDirY) {
+ _tmp_Dest.y--;
+ } else {
+ _tmp_Dest.y++;
+ }
+
+ setTmpFromActor();
+
+ byte A = updateWalkbox();
+ if (A == 0xFF) {
+ setActorFromTmp();
+ stopActorMoving();
+ return;
+ }
+ // 2C98: Yes, an exact copy of what just occured.. the original does this, so im doing it...
+ // Just to keep me sane when going over it :)
+ if (A == 0xFF) {
+ setActorFromTmp();
+ stopActorMoving();
+ return;
+ }
+ return;
+ }
+
+ // 2ADA
+ if ((_moving & 0x0F) == 4) {
+L2CA3:;
+ setTmpFromActor();
+
+ if (!_walkDirY) {
+ _pos.y--;
+ } else {
+ _pos.y++;
+ }
+ if (updateWalkbox() == kInvalidBox) {
+ // 2CC7
+ setActorFromTmp();
+ if( _CurrentWalkTo.x == _tmp_Dest.x) {
+ stopActorMoving();
+ return;
+ }
+
+ if (!_walkDirX) {
+ _tmp_Dest.x--;
+ } else {
+ _tmp_Dest.x++;
+ }
+ setTmpFromActor();
+
+ if (updateWalkbox() == kInvalidBox) {
+ setActorFromTmp();
+ stopActorMoving();
+ }
+
+ return;
+ } else {
+ setActorFromTmp();
+ goto L2A33;
+ }
+ }
+
+ if ((_moving & 0x0F) == 0) {
+ // 2AE8
+ byte A = actorWalkX();
+
+ if (A == 1) {
+ A = actorWalkY();
+ if (A == 1) {
+ _moving &= 0xF0;
+ _moving |= A;
+ } else {
+ if (A == 4)
+ stopActorMoving();
+ }
+
+ return;
+
+ } else {
+ // 2B0C
+ if (A == 3) {
+ _moving &= 0xF0;
+ _moving |= A;
+
+ if (_walkDirY) {
+ _targetFacing = getAngleFromPos(V12_X_MULTIPLIER*0, V12_Y_MULTIPLIER*1, false);
+ } else {
+ _targetFacing = getAngleFromPos(V12_X_MULTIPLIER*0, V12_Y_MULTIPLIER*-1, false);
+ }
+
+ directionUpdate();
+ animateActor(newDirToOldDir(_facing));
+ goto L2C36;
+
+ } else {
+ // 2B39
+ A = actorWalkY();
+ if (A != 4)
+ return;
+
+ _moving &= 0xF0;
+ _moving |= A;
+
+ if (_walkDirX) {
+ _targetFacing = getAngleFromPos(V12_X_MULTIPLIER*1, V12_Y_MULTIPLIER*0, false);
+ } else {
+ _targetFacing = getAngleFromPos(V12_X_MULTIPLIER*-1, V12_Y_MULTIPLIER*0, false);
+ }
+
+ directionUpdate();
+ animateActor(newDirToOldDir(_facing));
+ goto L2CA3;
+ }
+ }
+ }
}
void Actor_v2::walkActor() {
@@ -697,10 +937,8 @@ void Actor_v2::walkActor() {
_walkdata.curbox = next_box;
- if (!checkWalkboxesHaveDirectPath(foundPath)) {
- getClosestPtOnBox(_vm->getBoxCoordinates(_walkdata.curbox), _pos.x, _pos.y, tmp.x, tmp.y);
- getClosestPtOnBox(_vm->getBoxCoordinates(_walkbox), tmp.x, tmp.y, foundPath.x, foundPath.y);
- }
+ getClosestPtOnBox(_vm->getBoxCoordinates(_walkdata.curbox), _pos.x, _pos.y, tmp.x, tmp.y);
+ getClosestPtOnBox(_vm->getBoxCoordinates(_walkbox), tmp.x, tmp.y, foundPath.x, foundPath.y);
}
calcMovementFactor(foundPath);
}
@@ -985,18 +1223,16 @@ void Actor_v0::setDirection(int direction) {
break;
case 2:
- res = 6; // Face Away
+ res = 6; // Face Camera
break;
default:
- res = 7; // Face Camera
+ res = 7; // Face Away
break;
}
_animFrameRepeat = -1;
animateActor(res);
- if (_moving)
- animateCostume();
}
void Actor::faceToObject(int obj) {
@@ -1017,8 +1253,14 @@ void Actor::turnToDirection(int newdir) {
return;
if (_vm->_game.version <= 6) {
- _moving = MF_TURN;
_targetFacing = newdir;
+
+ if (_vm->_game.version == 0 ) {
+ setDirection( newdir );
+ return;
+ }
+ _moving = MF_TURN;
+
} else {
_moving &= ~MF_TURN;
if (newdir != _facing) {
@@ -1085,8 +1327,14 @@ void Actor::putActor(int dstX, int dstY, int newRoom) {
}
// V0 always sets the actor to face the camera upon entering a room
- if (_vm->_game.version == 0)
+ if (_vm->_game.version == 0) {
+ _walkdata.dest = _pos;
+
+ ((Actor_v0*)this)->_newWalkBoxEntered = true;
+ ((Actor_v0*)this)->_CurrentWalkTo = _pos;
+
setDirection(oldDirToNewDir(2));
+ }
}
static bool inBoxQuickReject(const BoxCoords &box, int x, int y, int threshold) {
@@ -1200,6 +1448,59 @@ static int checkXYInBoxBounds(int boxnum, int x, int y, int &destX, int &destY)
return dist;
}
+AdjustBoxResult Actor_v0::adjustPosInBorderWalkbox(AdjustBoxResult box) {
+ AdjustBoxResult Result = box;
+ BoxCoords BoxCoord = _vm->getBoxCoordinates(box.box);
+
+ byte boxMask = _vm->getMaskFromBox(box.box);
+ if (!(boxMask & 0x80))
+ return Result;
+
+ char A;
+ boxMask &= 0x7C;
+ if (boxMask == 0x0C)
+ A = 2;
+ else {
+ if (boxMask != 0x08)
+ return Result;
+
+ A = 1;
+ }
+
+ // 1BC6
+ byte Modifier = box.y - BoxCoord.ul.y;
+ assert(Modifier < 0x16);
+
+ if (A == 1) {
+ // 1BCF
+ A = BoxCoord.ur.x - v0WalkboxSlantedModifier[ Modifier ];
+ if (A < box.x)
+ return box;
+
+ if (A < 0xA0 || A == 0xA0)
+ A = 0;
+
+ Result.x = A;
+ } else {
+ // 1BED
+ A = BoxCoord.ul.x + v0WalkboxSlantedModifier[ Modifier ];
+
+ if (A < box.x || A == box.x)
+ Result.x = A;
+ }
+
+ return Result;
+}
+
+AdjustBoxResult Actor_v0::adjustXYToBeInBox(int dstX, int dstY) {
+ AdjustBoxResult Result = Actor_v2::adjustXYToBeInBox(dstX, dstY);
+
+ if( Result.box == kInvalidBox )
+ return Result;
+
+ return adjustPosInBorderWalkbox(Result);
+}
+
AdjustBoxResult Actor_v2::adjustXYToBeInBox(const int dstX, const int dstY) {
AdjustBoxResult abr;
@@ -1410,6 +1711,7 @@ void Actor::showActor() {
Actor_v0 *a = ((Actor_v0 *)this);
a->_costCommand = a->_costCommandNew = 0xFF;
+ _walkdata.dest = a->_CurrentWalkTo;
for (int i = 0; i < 8; ++i) {
a->_limbFrameRepeat[i] = 0;
@@ -1642,7 +1944,7 @@ void ScummEngine::processActors() {
continue;
// Sound
- if (a0->_moving && _currentRoom != 1 && _currentRoom != 44) {
+ if (a0->_moving != 2 && _currentRoom != 1 && _currentRoom != 44) {
if (a0->_cost.soundPos == 0)
a0->_cost.soundCounter++;
@@ -1659,8 +1961,17 @@ void ScummEngine::processActors() {
// would hence cause regressions. See also the other big
// comment further up in this method for some details.
if (a->_costume) {
- a->drawActorCostume();
- a->animateCostume();
+
+ // Unfortunately in V0, the 'animateCostume' call happens right after the call to 'walkActor' (which is before drawing the actor)...
+ // doing it the other way with V0, causes animation glitches (when beginnning to walk, as the costume hasnt been updated).
+ // Updating the costume directly after 'walkActor' and again, after drawing... causes frame skipping
+ if (_game.version == 0) {
+ a->animateCostume();
+ a->drawActorCostume();
+ } else {
+ a->drawActorCostume();
+ a->animateCostume();
+ }
}
}
}
@@ -2897,6 +3208,70 @@ void Actor_v0::animateActor(int anim) {
}
}
+byte Actor_v0::updateWalkbox() {
+ if( _vm->checkXYInBoxBounds( _walkbox, _pos.x, _pos.y ) )
+ return 0;
+
+ int numBoxes = _vm->getNumBoxes() - 1;
+ for (int i = 0; i <= numBoxes; i++) {
+ if (_vm->checkXYInBoxBounds( i, _pos.x, _pos.y ) == true ) {
+ if (_walkdata.curbox == i) {
+ setBox(i);
+ directionUpdate();
+
+ _newWalkBoxEntered = true;
+ return i;
+ }
+ }
+ }
+
+ return kInvalidBox;
+}
+
+void Actor_v0::directionUpdate() {
+
+ int nextFacing = updateActorDirection(true);
+ if (_facing != nextFacing) {
+ // 2A89
+ setDirection(nextFacing);
+
+ // Still need to turn?
+ if (_facing != _targetFacing) {
+ _moving |= 0x80;
+ return;
+ }
+ }
+
+ _moving &= ~0x80;
+}
+
+void Actor_v0::setTmpFromActor() {
+ _tmp_Pos = _pos;
+ _pos = _tmp_Dest;
+ _tmp_WalkBox = _walkbox;
+ _tmp_NewWalkBoxEntered = _newWalkBoxEntered;
+}
+
+void Actor_v0::setActorFromTmp() {
+ _pos = _tmp_Pos;
+ _tmp_Dest = _tmp_Pos;
+ _walkbox = _tmp_WalkBox;
+ _newWalkBoxEntered = _tmp_NewWalkBoxEntered;
+}
+
+void Actor_v0::actorSetWalkTo() {
+
+ if (_newWalkBoxEntered == false)
+ return;
+
+ _newWalkBoxEntered = false;
+
+ int nextBox = ((ScummEngine_v0*)_vm)->walkboxFindTarget(this, _walkdata.destbox, _walkdata.dest);
+ if (nextBox != kInvalidBox) {
+ _walkdata.curbox = nextBox;
+ }
+}
+
void Actor_v0::saveLoadWithSerializer(Serializer *ser) {
Actor::saveLoadWithSerializer(ser);
@@ -2910,6 +3285,20 @@ void Actor_v0::saveLoadWithSerializer(Serializer *ser) {
MKLINE(Actor_v0, _animFrameRepeat, sleByte, VER(89)),
MKARRAY(Actor_v0, _limbFrameRepeatNew[0], sleInt8, 8, VER(89)),
MKARRAY(Actor_v0, _limbFrameRepeat[0], sleInt8, 8, VER(90)),
+ MKLINE(Actor_v0, _CurrentWalkTo.x, sleInt16, VER(97)),
+ MKLINE(Actor_v0, _CurrentWalkTo.y, sleInt16, VER(97)),
+ MKLINE(Actor_v0, _NewWalkTo.x, sleInt16, VER(97)),
+ MKLINE(Actor_v0, _NewWalkTo.y, sleInt16, VER(97)),
+ MKLINE(Actor_v0, _walkCountModulo, sleInt8, VER(97)),
+ MKLINE(Actor_v0, _newWalkBoxEntered, sleByte, VER(97)),
+ MKLINE(Actor_v0, _walkDirX, sleByte, VER(97)),
+ MKLINE(Actor_v0, _walkDirY, sleByte, VER(97)),
+ MKLINE(Actor_v0, _walkYCountGreaterThanXCount, sleByte, VER(97)),
+ MKLINE(Actor_v0, _walkXCount, sleByte, VER(97)),
+ MKLINE(Actor_v0, _walkXCountInc, sleByte, VER(97)),
+ MKLINE(Actor_v0, _walkYCount, sleByte, VER(97)),
+ MKLINE(Actor_v0, _walkYCountInc, sleByte, VER(97)),
+ MKLINE(Actor_v0, _walkMaxXYCountInc, sleByte, VER(97)),
MKEND()
};
diff --git a/engines/scumm/actor.h b/engines/scumm/actor.h
index 46dc7d0295..c1a3f23318 100644
--- a/engines/scumm/actor.h
+++ b/engines/scumm/actor.h
@@ -333,7 +333,6 @@ public:
protected:
virtual bool isPlayer();
virtual void prepareDrawActorCostume(BaseCostumeRenderer *bcr);
- virtual bool checkWalkboxesHaveDirectPath(Common::Point &foundPath);
};
enum ActorV0MiscFlags {
@@ -349,11 +348,32 @@ enum ActorV0MiscFlags {
class Actor_v0 : public Actor_v2 {
public:
+ Common::Point _CurrentWalkTo, _NewWalkTo;
+
byte _costCommandNew;
byte _costCommand;
byte _miscflags;
byte _speaking;
+ byte _walkCountModulo;
+ bool _newWalkBoxEntered;
+
+ byte _walkDirX;
+ byte _walkDirY;
+
+ byte _walkYCountGreaterThanXCount;
+ byte _walkXCount;
+ byte _walkXCountInc;
+ byte _walkYCount;
+ byte _walkYCountInc;
+
+ byte _walkMaxXYCountInc;
+
+ Common::Point _tmp_Pos;
+ Common::Point _tmp_Dest;
+ byte _tmp_WalkBox;
+ bool _tmp_NewWalkBoxEntered;
+
int8 _animFrameRepeat;
int8 _limbFrameRepeatNew[8];
int8 _limbFrameRepeat[8];
@@ -363,23 +383,32 @@ public:
public:
Actor_v0(ScummEngine *scumm, int id) : Actor_v2(scumm, id) {}
- virtual void initActor(int mode);
- virtual void animateActor(int anim);
- virtual void animateCostume();
+ void initActor(int mode);
+ void animateActor(int anim);
+ void animateCostume();
void limbFrameCheck(int limb);
+ void directionUpdate();
void speakCheck();
- virtual void setDirection(int direction);
+ void setDirection(int direction);
void startAnimActor(int f);
+ bool calcWalkDistances();
+ void walkActor();
+ void actorSetWalkTo();
+ byte actorWalkX();
+ byte actorWalkY();
+ byte updateWalkbox();
+
+ AdjustBoxResult adjustXYToBeInBox(int dstX, int dstY);
+ AdjustBoxResult adjustPosInBorderWalkbox(AdjustBoxResult box);
+
+ void setTmpFromActor();
+ void setActorFromTmp();
+
// Used by the save/load system:
virtual void saveLoadWithSerializer(Serializer *ser);
-
-protected:
- bool intersectLineSegments(const Common::Point &line1Start, const Common::Point &line1End,
- const Common::Point &line2Start, const Common::Point &line2End, Common::Point &result);
- virtual bool checkWalkboxesHaveDirectPath(Common::Point &foundPath);
};
diff --git a/engines/scumm/boxes.cpp b/engines/scumm/boxes.cpp
index 70c8f2e032..087d8425ac 100644
--- a/engines/scumm/boxes.cpp
+++ b/engines/scumm/boxes.cpp
@@ -1158,6 +1158,30 @@ bool ScummEngine::areBoxesNeighbors(int box1nr, int box2nr) {
return false;
}
+byte ScummEngine_v0::walkboxFindTarget(Actor *a, int destbox, Common::Point walkdest) {
+ Actor_v0 *Actor = (Actor_v0*)a;
+
+ byte nextBox = getNextBox(a->_walkbox, destbox);
+
+ if (nextBox != 0xFF && nextBox == destbox && areBoxesNeighbors(a->_walkbox, nextBox)) {
+
+ Actor->_NewWalkTo = walkdest;
+ return nextBox;
+ }
+
+ if (nextBox != 0xFF && nextBox != a->_walkbox) {
+
+ getClosestPtOnBox(getBoxCoordinates(nextBox), a->getPos().x, a->getPos().y, Actor->_NewWalkTo.x, Actor->_NewWalkTo.y);
+
+ } else {
+ if (walkdest.x == -1)
+ Actor->_NewWalkTo = Actor->_CurrentWalkTo;
+ else
+ Actor->_NewWalkTo = walkdest;
+ }
+ return nextBox;
+}
+
bool ScummEngine_v0::areBoxesNeighbors(int box1nr, int box2nr) {
int i;
const int numOfBoxes = getNumBoxes();
diff --git a/engines/scumm/saveload.h b/engines/scumm/saveload.h
index 01ed21ece5..753287e217 100644
--- a/engines/scumm/saveload.h
+++ b/engines/scumm/saveload.h
@@ -47,7 +47,7 @@ namespace Scumm {
* only saves/loads those which are valid for the version of the savegame
* which is being loaded/saved currently.
*/
-#define CURRENT_VER 96
+#define CURRENT_VER 97
/**
* An auxillary macro, used to specify savegame versions. We use this instead
diff --git a/engines/scumm/script.cpp b/engines/scumm/script.cpp
index 2fe5333bfc..c9b37d43b1 100644
--- a/engines/scumm/script.cpp
+++ b/engines/scumm/script.cpp
@@ -1164,8 +1164,10 @@ void ScummEngine_v0::walkToActorOrObject(int object) {
VAR(7) = y;
// actor must not move if frozen
- if (a->_miscflags & kActorMiscFlagFreeze)
+ if (a->_miscflags & kActorMiscFlagFreeze) {
a->stopActorMoving();
+ a->_newWalkBoxEntered = false;
+ }
}
bool ScummEngine_v0::checkPendingWalkAction() {
@@ -1179,7 +1181,7 @@ bool ScummEngine_v0::checkPendingWalkAction() {
Actor_v0 *a = (Actor_v0 *)derefActor(actor, "checkPendingWalkAction");
// wait until walking or turning action is finished
- if (a->_moving)
+ if (a->_moving != 2)
return true;
// after walking and turning finally execute the script
diff --git a/engines/scumm/script_v0.cpp b/engines/scumm/script_v0.cpp
index af39fdaad8..90291535fd 100644
--- a/engines/scumm/script_v0.cpp
+++ b/engines/scumm/script_v0.cpp
@@ -707,17 +707,14 @@ void ScummEngine_v0::o_animateActor() {
}
a->animateActor(anim);
- a->animateCostume();
}
void ScummEngine_v0::o_getActorMoving() {
getResultPos();
int act = getVarOrDirectByte(PARAM_1);
Actor *a = derefActor(act, "o_getActorMoving");
- if (a->_moving)
- setResult(1);
- else
- setResult(2);
+
+ setResult(a->_moving);
}
void ScummEngine_v0::o_putActorAtObject() {
diff --git a/engines/scumm/script_v5.cpp b/engines/scumm/script_v5.cpp
index 91afa859a9..4a53ca3fed 100644
--- a/engines/scumm/script_v5.cpp
+++ b/engines/scumm/script_v5.cpp
@@ -2497,10 +2497,6 @@ void ScummEngine_v5::walkActorToActor(int actor, int toActor, int dist) {
y = abr.y;
}
a->startWalkActor(x, y, -1);
-
- // WORKAROUND: See bug #2971126 for details on why this is here.
- if (_game.version == 0)
- o5_breakHere();
}
void ScummEngine_v5::o5_walkActorToActor() {
diff --git a/engines/scumm/scumm_v0.h b/engines/scumm/scumm_v0.h
index 80d047ab9f..83e0e32e15 100644
--- a/engines/scumm/scumm_v0.h
+++ b/engines/scumm/scumm_v0.h
@@ -67,6 +67,8 @@ public:
virtual void resetScumm();
+ byte walkboxFindTarget(Actor *a, int destbox, Common::Point walkdest);
+
protected:
virtual void resetRoomObject(ObjectData *od, const byte *room, const byte *searchptr = NULL);
@@ -116,7 +118,7 @@ protected:
void resetSentence();
- virtual bool areBoxesNeighbors(int box1nr, int box2nr);
+ bool areBoxesNeighbors(int box1nr, int box2nr);
bool ifEqualActiveObject2Common(bool checkType);
diff --git a/engines/scumm/verbs.cpp b/engines/scumm/verbs.cpp
index fdb98a8019..bf0a693467 100644
--- a/engines/scumm/verbs.cpp
+++ b/engines/scumm/verbs.cpp
@@ -708,7 +708,6 @@ void ScummEngine_v0::verbExec() {
Actor_v0 *a = (Actor_v0 *)derefActor(VAR(VAR_EGO), "verbExec");
int x = _virtualMouse.x / V12_X_MULTIPLIER;
int y = _virtualMouse.y / V12_Y_MULTIPLIER;
- //actorSetPosInBox();
// 0xB31
VAR(6) = x;
@@ -717,7 +716,6 @@ void ScummEngine_v0::verbExec() {
if (a->_miscflags & kActorMiscFlagFreeze)
return;
- a->stopActorMoving();
a->startWalkActor(VAR(6), VAR(7), -1);
}