aboutsummaryrefslogtreecommitdiff
path: root/engines/scumm/actor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/scumm/actor.cpp')
-rw-r--r--engines/scumm/actor.cpp725
1 files changed, 579 insertions, 146 deletions
diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp
index 116a953b0b..0d7ea39ec2 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"
@@ -42,12 +43,66 @@ namespace Scumm {
byte Actor::kInvalidBox = 0;
-static const byte v0ActorTalkArray[0x19] = {
- 0x00, 0x06, 0x06, 0x06, 0x06,
- 0x06, 0x06, 0x00, 0x46, 0x06,
- 0x06, 0x06, 0x06, 0xFF, 0xFF,
- 0x06, 0xC0, 0x06, 0x06, 0x00,
- 0xC0, 0xC0, 0x00, 0x06, 0x06
+static const byte v0ActorDemoTalk[25] = {
+ 0x00,
+ 0x06, // Syd
+ 0x06, // Razor
+ 0x06, // Dave
+ 0x06, // Michael
+ 0x06, // Bernard
+ 0x06, // Wendy
+ 0x00, // Jeff
+ 0x46, // Radiation Suit
+ 0x06, // Dr Fred
+ 0x06, // Nurse Edna
+ 0x06, // Weird Ed
+ 0x06, // Dead Cousin Ted
+ 0xE2, // Purple Tentacle
+ 0xE2, // Green Tentacle
+ 0x06, // Meteor police
+ 0xC0, // Meteor
+ 0x06, // Mark Eteer
+ 0x06, // Talkshow Host
+ 0x00, // Plant
+ 0xC0, // Meteor Radiation
+ 0xC0, // Edsel (small, outro)
+ 0x00, // Meteor (small, intro)
+ 0x06, // Sandy (Lab)
+ 0x06, // Sandy (Cut-Scene)
+};
+
+static const byte v0ActorTalk[25] = {
+ 0x00,
+ 0x06, // Syd
+ 0x06, // Razor
+ 0x06, // Dave
+ 0x06, // Michael
+ 0x06, // Bernard
+ 0x06, // Wendy
+ 0x00, // Jeff
+ 0x46, // Radiation Suit
+ 0x06, // Dr Fred
+ 0x06, // Nurse Edna
+ 0x06, // Weird Ed
+ 0x06, // Dead Cousin Ted
+ 0xFF, // Purple Tentacle
+ 0xFF, // Green Tentacle
+ 0x06, // Meteor police
+ 0xC0, // Meteor
+ 0x06, // Mark Eteer
+ 0x06, // Talkshow Host
+ 0x00, // Plant
+ 0xC0, // Meteor Radiation
+ 0xC0, // Edsel (small, outro)
+ 0x00, // Meteor (small, intro)
+ 0x06, // Sandy (Lab)
+ 0x06, // Sandy (Cut-Scene)
+};
+
+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) :
@@ -182,6 +237,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) {
@@ -189,6 +258,12 @@ void Actor_v0::initActor(int mode) {
_limbFrameRepeat[i] = 0;
_limb_flipped[i] = false;
}
+
+ if (_vm->_game.features & GF_DEMO) {
+ _sound[0] = v0ActorDemoTalk[_number];
+ } else {
+ _sound[0] = v0ActorTalk[_number];
+ }
}
void Actor::setBox(int box) {
@@ -249,9 +324,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 +417,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 +425,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)) {
@@ -368,13 +439,28 @@ int Actor::actorWalkStep() {
return 0;
}
- tmpX = (_pos.x << 16) + _walkdata.xfrac + (_walkdata.deltaXFactor >> 8) * _scalex;
- _walkdata.xfrac = (uint16)tmpX;
- _pos.x = (tmpX >> 16);
+ if (_vm->_game.version <= 2) {
+ if (_walkdata.deltaXFactor != 0) {
+ if (_walkdata.deltaXFactor > 0)
+ _pos.x += 1;
+ else
+ _pos.x -= 1;
+ }
+ if (_walkdata.deltaYFactor != 0) {
+ if (_walkdata.deltaYFactor > 0)
+ _pos.y += 1;
+ else
+ _pos.y -= 1;
+ }
+ } else {
+ tmpX = (_pos.x << 16) + _walkdata.xfrac + (_walkdata.deltaXFactor >> 8) * _scalex;
+ _walkdata.xfrac = (uint16)tmpX;
+ _pos.x = (tmpX >> 16);
- tmpY = (_pos.y << 16) + _walkdata.yfrac + (_walkdata.deltaYFactor >> 8) * _scaley;
- _walkdata.yfrac = (uint16)tmpY;
- _pos.y = (tmpY >> 16);
+ tmpY = (_pos.y << 16) + _walkdata.yfrac + (_walkdata.deltaYFactor >> 8) * _scaley;
+ _walkdata.yfrac = (uint16)tmpY;
+ _pos.y = (tmpY >> 16);
+ }
if (ABS(_pos.x - _walkdata.cur.x) > distX) {
_pos.x = _walkdata.next.x;
@@ -384,17 +470,118 @@ int Actor::actorWalkStep() {
_pos.y = _walkdata.next.y;
}
- if (_vm->_game.version >= 4 && _vm->_game.version <= 6 && _pos == _walkdata.next) {
+ if ((_vm->_game.version <= 2 || (_vm->_game.version >= 4 && _vm->_game.version <= 6)) && _pos == _walkdata.next) {
_moving &= ~MF_IN_LEG;
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,9 +634,16 @@ 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;
+
+ if (_vm->_game.version == 0) {
+ ((Actor_v0*)this)->_newWalkBoxEntered = true;
+ } else if (_vm->_game.version <= 2) {
+ _moving = (_moving & ~(MF_LAST_LEG | MF_IN_LEG)) | MF_NEW_LEG;
+ } else {
+ _moving = (_moving & MF_IN_LEG) | MF_NEW_LEG;
+ }
+ _walkdata.point3.x = 32000;
_walkdata.curbox = _walkbox;
}
@@ -567,88 +761,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 +1009,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);
}
@@ -972,7 +1282,7 @@ void Actor::setDirection(int direction) {
}
void Actor_v0::setDirection(int direction) {
- int dir = newDirToOldDir( direction );
+ int dir = newDirToOldDir(direction);
int res = 0;
switch (dir) {
@@ -985,18 +1295,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 +1325,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 +1399,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 +1520,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;
+
+ int16 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 +1783,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;
@@ -1451,34 +1825,6 @@ void ScummEngine::showActors() {
}
}
-// bits 0..5: sound, bit 6: ???
-static const byte v0ActorSounds[24] = {
- 0x06, // Syd
- 0x06, // Razor
- 0x06, // Dave
- 0x06, // Michael
- 0x06, // Bernard
- 0x06, // Wendy
- 0x00, // Jeff
- 0x46, // Radiation Suit
- 0x06, // Dr Fred
- 0x06, // Nurse Edna
- 0x06, // Weird Ed
- 0x06, // Dead Cousin Ted
- 0xFF, // Purple Tentacle
- 0xFF, // Green Tentacle
- 0x06, // Meteor police
- 0xC0, // Meteor
- 0x06, // Mark Eteer
- 0x06, // Talkshow Host
- 0x00, // Plant
- 0xC0, // Meteor Radiation
- 0xC0, // Edsel (small, outro)
- 0x00, // Meteor (small, intro)
- 0x06, // Sandy (Lab)
- 0x06, // Sandy (Cut-Scene)
-};
-
/* Used in Scumm v5 only. Play sounds associated with actors */
void ScummEngine::playActorSounds() {
int i, j;
@@ -1488,7 +1834,7 @@ void ScummEngine::playActorSounds() {
if (_actors[i]->_cost.soundCounter && _actors[i]->isInCurrentRoom()) {
_currentScript = 0xFF;
if (_game.version == 0) {
- sound = v0ActorSounds[i - 1] & 0x3F;
+ sound = _actors[i]->_sound[0] & 0x3F;
} else {
sound = _actors[i]->_sound[0];
}
@@ -1642,13 +1988,13 @@ 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++;
// Is this the correct location?
// 0x073C
- if (v0ActorTalkArray[a0->_number] & 0x3F)
+ if (a0->_sound[0] & 0x3F)
a0->_cost.soundPos = (a0->_cost.soundPos + 1) % 3;
}
}
@@ -1659,8 +2005,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();
+ }
}
}
}
@@ -1948,7 +2303,7 @@ void Actor::startAnimActor(int f) {
void Actor_v0::startAnimActor(int f) {
if (f == _talkStartFrame) {
- if (v0ActorTalkArray[_number] & 0x40)
+ if (_sound[0] & 0x40)
return;
_speaking = 1;
@@ -2054,7 +2409,7 @@ void Actor_v0::animateCostume() {
}
void Actor_v0::speakCheck() {
- if (v0ActorTalkArray[_number] & 0x80)
+ if (_sound[0] & 0x80)
return;
int cmd = newDirToOldDir(_facing);
@@ -2897,6 +3252,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 +3329,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()
};