mirror of
https://github.com/libretro/scummvm.git
synced 2024-11-30 21:00:39 +00:00
SCUMM: (V1/2) - fix bug no. 15273
(Walking animation when turning not correct) Also match v1/2 walk code more to the orginal behavior in general, to eliminate accuracy glitches. Also, get rid of memory leaks in resetScumm().
This commit is contained in:
parent
261e37a340
commit
8d88e7b4d5
@ -581,8 +581,11 @@ int Actor::calcMovementFactor(const Common::Point& next) {
|
||||
int Actor_v3::calcMovementFactor(const Common::Point& next) {
|
||||
int32 deltaXFactor, deltaYFactor;
|
||||
|
||||
if (_pos == next)
|
||||
if (_pos == next) {
|
||||
if (_vm->_game.version == 2)
|
||||
_moving |= MF_IN_LEG;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int diffX = next.x - _pos.x;
|
||||
int diffY = next.y - _pos.y;
|
||||
@ -611,14 +614,23 @@ int Actor_v3::calcMovementFactor(const Common::Point& next) {
|
||||
_walkdata.next = next;
|
||||
_walkdata.deltaXFactor = deltaXFactor;
|
||||
_walkdata.deltaYFactor = deltaYFactor;
|
||||
_walkdata.facing = diffX >= 0 ? (diffY >= 0 ? 1 : 0) : (diffY >= 0 ? 2 : 3);
|
||||
|
||||
// The x/y distance ratio which determines whether to face up/down instead of left/right is different for SCUMM1/2 and SCUMM3.
|
||||
_targetFacing = oldDirToNewDir(((ABS(diffY) * _facingXYratio) > ABS(diffX)) ? 3 - (diffY >= 0 ? 1 : 0) : (diffX >= 0 ? 1 : 0));
|
||||
|
||||
if (_vm->_game.version <= 2 && _facing != updateActorDirection(true))
|
||||
if (_vm->_game.version > 2)
|
||||
return actorWalkStep();
|
||||
|
||||
_moving &= ~MF_IN_LEG;
|
||||
if (_facing != _targetFacing)
|
||||
_moving |= MF_TURN;
|
||||
|
||||
return actorWalkStep();
|
||||
|
||||
if (_walkFrame != _frame || _facing != _targetFacing)
|
||||
startWalkAnim(1, _facing);
|
||||
|
||||
return (_moving & MF_TURN) ? 0 : actorWalkStep();
|
||||
}
|
||||
|
||||
int Actor::actorWalkStep() {
|
||||
@ -672,39 +684,9 @@ int Actor::actorWalkStep() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Actor_v3::actorWalkStep() {
|
||||
int Actor_v2::actorWalkStep() {
|
||||
_needRedraw = true;
|
||||
|
||||
int nextFacing = updateActorDirection(true);
|
||||
if (!(_moving & MF_IN_LEG) || _facing != nextFacing) {
|
||||
if (_walkFrame != _frame || _facing != nextFacing)
|
||||
startWalkAnim(1, nextFacing);
|
||||
|
||||
_moving |= MF_IN_LEG;
|
||||
// The next two lines fix bug #12278 for ZAK FM-TOWNS (SCUMM3). They are alse required for SCUMM 1/2 to prevent movement while
|
||||
// turning, but only if the character has to make a turn. The correct behavior for v1/2 can be tested by letting Zak (only v1/2
|
||||
// versions) walk in the starting room from the torn wallpaper to the desk drawer: Zak should first turn around clockwise by
|
||||
// 180°, then walk one step to the left, then turn clockwise 90°. For ZAK FM-TOWNS (SCUMM3) this part will look quite different
|
||||
// (and a bit weird), but I have confirmed the correctness with the FM-Towns emulator, too.
|
||||
if (_vm->_game.version == 3 || (_vm->_game.version <= 2 && (_moving & MF_TURN)))
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (_vm->_game.version == 3) {
|
||||
if (_walkdata.next.x - (int)_stepX <= _pos.x && _walkdata.next.x + (int)_stepX >= _pos.x)
|
||||
_pos.x = _walkdata.next.x;
|
||||
if (_walkdata.next.y - (int)_speedy <= _pos.y && _walkdata.next.y + (int)_speedy >= _pos.y)
|
||||
_pos.y = _walkdata.next.y;
|
||||
|
||||
if (_walkbox != _walkdata.curbox && _vm->checkXYInBoxBounds(_walkdata.curbox, _pos.x, _pos.y))
|
||||
setBox(_walkdata.curbox);
|
||||
|
||||
if (_pos == _walkdata.next) {
|
||||
_moving &= ~MF_IN_LEG;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((_walkdata.xfrac += _walkdata.xAdd) >= _stepThreshold) {
|
||||
if (_pos.x != _walkdata.next.x)
|
||||
_pos.x += _walkdata.deltaXFactor;
|
||||
@ -716,11 +698,49 @@ int Actor_v3::actorWalkStep() {
|
||||
_walkdata.yfrac -= _stepThreshold;
|
||||
}
|
||||
|
||||
if (_vm->_game.version <= 2 && _pos == _walkdata.next) {
|
||||
if (_pos == _walkdata.next)
|
||||
_moving |= MF_IN_LEG;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Actor_v3::actorWalkStep() {
|
||||
_needRedraw = true;
|
||||
|
||||
int nextFacing = updateActorDirection(true);
|
||||
if (!(_moving & MF_IN_LEG) || _facing != nextFacing) {
|
||||
if (_walkFrame != _frame || _facing != nextFacing)
|
||||
startWalkAnim(1, nextFacing);
|
||||
|
||||
_moving |= MF_IN_LEG;
|
||||
// The next line fixes bug #12278 for ZAK FM-TOWNS (SCUMM3).
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (_walkdata.next.x - (int)_stepX <= _pos.x && _walkdata.next.x + (int)_stepX >= _pos.x)
|
||||
_pos.x = _walkdata.next.x;
|
||||
if (_walkdata.next.y - (int)_speedy <= _pos.y && _walkdata.next.y + (int)_speedy >= _pos.y)
|
||||
_pos.y = _walkdata.next.y;
|
||||
|
||||
if (_walkbox != _walkdata.curbox && _vm->checkXYInBoxBounds(_walkdata.curbox, _pos.x, _pos.y))
|
||||
setBox(_walkdata.curbox);
|
||||
|
||||
if (_pos == _walkdata.next) {
|
||||
_moving &= ~MF_IN_LEG;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((_walkdata.xfrac += _walkdata.xAdd) >= _stepThreshold) {
|
||||
if (_pos.x != _walkdata.next.x)
|
||||
_pos.x += _walkdata.deltaXFactor;
|
||||
_walkdata.xfrac -= _stepThreshold;
|
||||
}
|
||||
if ((_walkdata.yfrac += _walkdata.yAdd) >= _stepThreshold) {
|
||||
if (_pos.y != _walkdata.next.y)
|
||||
_pos.y += _walkdata.deltaYFactor;
|
||||
_walkdata.yfrac -= _stepThreshold;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -892,7 +912,7 @@ void Actor::startWalkActor(int destX, int destY, int dir) {
|
||||
((Actor_v0 *)this)->walkBoxQueuePrepare();
|
||||
|
||||
} else if (_vm->_game.version <= 2) {
|
||||
_moving = (_moving & ~(MF_LAST_LEG | MF_IN_LEG)) | MF_NEW_LEG;
|
||||
_moving = (_moving & ~MF_LAST_LEG) | MF_IN_LEG | MF_NEW_LEG;
|
||||
} else {
|
||||
_moving = (_moving & MF_IN_LEG) | MF_NEW_LEG;
|
||||
}
|
||||
@ -1230,50 +1250,46 @@ UpdateActorDirection:;
|
||||
}
|
||||
|
||||
void Actor_v2::walkActor() {
|
||||
Common::Point foundPath, tmp;
|
||||
int new_dir, next_box;
|
||||
|
||||
if (_moving & MF_TURN) {
|
||||
new_dir = updateActorDirection(false);
|
||||
if (_facing != new_dir) {
|
||||
setDirection(new_dir);
|
||||
} else {
|
||||
int newDir = updateActorDirection(false);
|
||||
if (_targetFacing == newDir)
|
||||
_moving &= ~MF_TURN;
|
||||
}
|
||||
setDirection(newDir);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_moving)
|
||||
if (!(_moving & MF_NEW_LEG))
|
||||
return;
|
||||
|
||||
if (_moving & MF_IN_LEG) {
|
||||
if (!(_moving & MF_IN_LEG)) {
|
||||
actorWalkStep();
|
||||
} else {
|
||||
if (_moving & MF_LAST_LEG) {
|
||||
_moving = MF_TURN;
|
||||
startAnimActor(_standFrame);
|
||||
if (_targetFacing != _walkdata.destdir)
|
||||
if (_walkdata.destdir != -1)
|
||||
turnToDirection(_walkdata.destdir);
|
||||
} else {
|
||||
Common::Point foundPath, tmp;
|
||||
setBox(_walkdata.curbox);
|
||||
if (_walkbox == _walkdata.destbox) {
|
||||
foundPath = _walkdata.dest;
|
||||
_moving |= MF_LAST_LEG;
|
||||
} else {
|
||||
next_box = _vm->getNextBox(_walkbox, _walkdata.destbox);
|
||||
if (next_box < 0) {
|
||||
int nextBox = _vm->getNextBox(_walkbox, _walkdata.destbox);
|
||||
if (nextBox < 0) {
|
||||
_moving |= MF_LAST_LEG;
|
||||
return;
|
||||
}
|
||||
|
||||
// Can't walk through locked boxes
|
||||
int flags = _vm->getBoxFlags(next_box);
|
||||
int flags = _vm->getBoxFlags(nextBox);
|
||||
if ((flags & kBoxLocked) && !((flags & kBoxPlayerOnly) && !isPlayer())) {
|
||||
_moving |= MF_LAST_LEG;
|
||||
//_walkdata.destdir = -1;
|
||||
_walkdata.destdir = -1;
|
||||
}
|
||||
|
||||
_walkdata.curbox = next_box;
|
||||
_walkdata.curbox = nextBox;
|
||||
|
||||
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);
|
||||
@ -1495,6 +1511,39 @@ int Actor::remapDirection(int dir, bool is_walking) {
|
||||
return dir;
|
||||
}
|
||||
|
||||
int Actor_v2::remapDirection(int dir, bool is_walking) {
|
||||
if (_vm->_game.version == 0)
|
||||
return Actor::remapDirection(dir, is_walking);
|
||||
|
||||
static const byte remapTable1[] = {
|
||||
0x04, 0x01, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00,
|
||||
0x06, 0x01, 0x03, 0x00, 0x01, 0x02, 0x03, 0x00,
|
||||
0x07, 0x00, 0x03, 0x00, 0x01, 0x02, 0x03, 0x00,
|
||||
0x05, 0x00, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00
|
||||
};
|
||||
|
||||
static const byte remapTable2[] = {
|
||||
0x00, 0x01, 0x03, 0x02, 0x03, 0x00, 0x02, 0x00,
|
||||
0x00, 0x01, 0x03, 0x02, 0x01, 0x03, 0x01, 0x02,
|
||||
0x00, 0x01, 0x03, 0x02, 0x01, 0x00, 0x02, 0x02,
|
||||
0x00, 0x01, 0x03, 0x02, 0x03, 0x03, 0x01, 0x01
|
||||
};
|
||||
|
||||
static const byte remapTable3[] = {
|
||||
0x00, 0x00, 0x02, 0x00, 0x01, 0x03, 0x02, 0x00,
|
||||
0x01, 0x01, 0x02, 0x00, 0x01, 0x03, 0x02, 0x00,
|
||||
0x02, 0x01, 0x02, 0x00, 0x01, 0x03, 0x02, 0x00,
|
||||
0x03, 0x00, 0x03, 0x00, 0x01, 0x03, 0x02, 0x00
|
||||
};
|
||||
|
||||
if (_moving & ~MF_TURN)
|
||||
_targetFacing = oldDirToNewDir(remapTable2[newDirToOldDir(dir) * 8 + remapTable1[_walkdata.facing * 8 + (_vm->getBoxFlags(_walkbox) & 7)]]);
|
||||
else
|
||||
_targetFacing = oldDirToNewDir(remapTable3[newDirToOldDir(dir) * 8 + (_vm->getBoxFlags(_walkbox) & 7)]);
|
||||
|
||||
return _targetFacing | 0x400;
|
||||
}
|
||||
|
||||
int Actor::updateActorDirection(bool is_walking) {
|
||||
static const uint8 actorTurnInterpolateTable[] = { 0, 2, 2, 3, 2, 1, 2, 3, 0, 1, 2, 1, 0, 1, 0, 3 };
|
||||
|
||||
|
@ -223,8 +223,8 @@ public:
|
||||
void setActorWalkSpeed(uint newSpeedX, uint newSpeedY);
|
||||
protected:
|
||||
virtual int calcMovementFactor(const Common::Point& next);
|
||||
int actorWalkStep();
|
||||
int remapDirection(int dir, bool is_walking);
|
||||
virtual int actorWalkStep();
|
||||
virtual int remapDirection(int dir, bool is_walking);
|
||||
virtual void setupActorScale();
|
||||
|
||||
void setBox(int box);
|
||||
@ -362,13 +362,12 @@ public:
|
||||
|
||||
protected:
|
||||
int calcMovementFactor(const Common::Point& next) override;
|
||||
int actorWalkStep();
|
||||
|
||||
void setupActorScale() override;
|
||||
void findPathTowardsOld(byte box, byte box2, byte box3, Common::Point &p2, Common::Point &p3);
|
||||
|
||||
uint _stepThreshold;
|
||||
private:
|
||||
uint _stepX, _stepThreshold;
|
||||
virtual int actorWalkStep();
|
||||
uint _stepX;
|
||||
const int _facingXYratio;
|
||||
};
|
||||
|
||||
@ -383,6 +382,9 @@ public:
|
||||
protected:
|
||||
bool isPlayer() override;
|
||||
void prepareDrawActorCostume(BaseCostumeRenderer *bcr) override;
|
||||
private:
|
||||
int actorWalkStep() override;
|
||||
int remapDirection(int dir, bool is_walking) override;
|
||||
};
|
||||
|
||||
class Actor_v7 final : public Actor {
|
||||
|
@ -1760,6 +1760,13 @@ void ScummEngine::resetScumm() {
|
||||
setShake(0);
|
||||
_cursor.animate = 1;
|
||||
|
||||
if (_actors) {
|
||||
for (i = 0; i < _numActors; ++i)
|
||||
delete _actors[i];
|
||||
delete[] _actors;
|
||||
}
|
||||
delete[] _sortedActors;
|
||||
|
||||
// Allocate and Initialize actors
|
||||
Actor::kInvalidBox = ((_game.features & GF_SMALL_HEADER) ? kOldInvalidBox : kNewInvalidBox);
|
||||
_actors = new Actor * [_numActors];
|
||||
|
Loading…
Reference in New Issue
Block a user