From 1a880c748c5cfb5ed64ca220ff332bc353726345 Mon Sep 17 00:00:00 2001 From: Robert Crossfield Date: Fri, 15 Jul 2016 20:40:17 +1000 Subject: SCUMM: Maniac V0: Clear the text area of the screen on fade out --- engines/scumm/gfx.cpp | 5 +++++ engines/scumm/gfx.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'engines/scumm') diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp index 1d1b6b4f13..5dc96eceb9 100644 --- a/engines/scumm/gfx.cpp +++ b/engines/scumm/gfx.cpp @@ -3795,6 +3795,11 @@ void ScummEngine::fadeOut(int effect) { _textSurface.fillRect(Common::Rect(0, vs->topline * _textSurfaceMultiplier, _textSurface.pitch, (vs->topline + vs->h) * _textSurfaceMultiplier), 0); #endif + // V0 wipes the text area before fading out + if (_game.version == 0) { + updateDirtyScreen( kTextVirtScreen ); + } + // TheDig can disable fadeIn(), and may call fadeOut() several times // successively. Disabling the _screenEffectFlag check forces the screen // to get cleared. This fixes glitches, at least, in the first cutscenes diff --git a/engines/scumm/gfx.h b/engines/scumm/gfx.h index 42844daf30..86913f9e2e 100644 --- a/engines/scumm/gfx.h +++ b/engines/scumm/gfx.h @@ -58,7 +58,7 @@ struct CameraData { /** Virtual screen identifiers */ enum VirtScreenNumber { kMainVirtScreen = 0, // The 'stage' - kTextVirtScreen = 1, // In V1-V3 games: the area where text is printed + kTextVirtScreen = 1, // In V0-V3 games: the area where text is printed kVerbVirtScreen = 2, // The verb area kUnkVirtScreen = 3 // ?? Not sure what this one is good for... }; -- cgit v1.2.3 From 44000ba8262a470612f1c83e2879b8b6f3d8a0b2 Mon Sep 17 00:00:00 2001 From: Robert Crossfield Date: Sat, 16 Jul 2016 17:18:11 +1000 Subject: SCUMM: Maniac V0: Implement original walkbox queue, Cleanup actor walk code --- engines/scumm/actor.cpp | 178 +++++++++++++++++++++++++++++++++++++++++------ engines/scumm/actor.h | 14 ++++ engines/scumm/boxes.cpp | 55 +++++++++++---- engines/scumm/saveload.h | 2 +- engines/scumm/scumm.h | 2 + 5 files changed, 215 insertions(+), 36 deletions(-) (limited to 'engines/scumm') diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp index cd54c175cc..6cb5ce5708 100644 --- a/engines/scumm/actor.cpp +++ b/engines/scumm/actor.cpp @@ -259,6 +259,8 @@ void Actor_v0::initActor(int mode) { _limb_flipped[i] = false; } + walkBoxQueueReset(); + if (_vm->_game.features & GF_DEMO) { _sound[0] = v0ActorDemoTalk[_number]; } else { @@ -266,6 +268,116 @@ void Actor_v0::initActor(int mode) { } } +void Actor_v0::walkBoxQueueReset() { + _walkboxHistory.clear(); + _walkboxQueueIndex = 0; + + for (uint i = 0; i < ARRAYSIZE( _walkboxQueue ); ++i) { + _walkboxQueue[i] = kInvalidBox; + } +} + +bool Actor_v0::walkBoxQueueAdd(int box) { + + if (_walkboxQueueIndex == ARRAYSIZE( _walkboxQueue )) + return false; + + _walkboxQueue[_walkboxQueueIndex++] = box ; + _walkboxHistory.push_back( box ); + return true; +} + +void Actor_v0::walkboxQueueReverse() { + int j = ARRAYSIZE( _walkboxQueue ) - 1; + + while (_walkboxQueue[j] == kInvalidBox && j >= 1) + --j; + + if (j <= 1) + return; + + for (int i = 1; i < j && j >= 1 ; ++i, --j) { + + byte tmp = _walkboxQueue[i]; + + _walkboxQueue[i] = _walkboxQueue[j]; + _walkboxQueue[j] = tmp; + } +} + +bool Actor_v0::walkBoxQueueFind(int box) { + + for (uint i = 0; i < _walkboxHistory.size(); ++i) { + if (box == _walkboxHistory[i]) + return true; + } + + return false; +} + +bool Actor_v0::walkBoxQueuePrepare() { + walkBoxQueueReset(); + int BoxFound = _walkbox; + + if (BoxFound == _walkdata.destbox) { + + _newWalkBoxEntered = true; + return true; + } + + // Build a series of walkboxes from our current position, to the target + do { + // Add the current box to the queue + if (!walkBoxQueueAdd( BoxFound )) + return false; + + // Loop until we find a walkbox which hasn't been tested + while (_walkboxQueueIndex > 0) { + + // Check if the dest box is a direct neighbour + if ((BoxFound = _vm->getNextBox( BoxFound, _walkdata.destbox )) == kInvalidBox) { + + // Its not, start hunting through this boxes immediate connections + byte* boxm = _vm->getBoxConnectionBase( _walkboxQueue[_walkboxQueueIndex - 1] ); + + // Attempt to find one, which we havn't already used + for (; *boxm != kInvalidBox; ++boxm) { + if (walkBoxQueueFind( *boxm ) != true) + break; + } + + BoxFound = *boxm; + } + + // Found one? + if (BoxFound != kInvalidBox) { + + // Did we find a connection to the final walkbox + if (BoxFound == _walkdata.destbox) { + + _newWalkBoxEntered = true; + + walkBoxQueueAdd( BoxFound ); + + walkboxQueueReverse(); + return true; + } + + // Nope, check the next box + break; + } + + // Drop this box, its useless to us + _walkboxQueue[--_walkboxQueueIndex] = kInvalidBox; + + BoxFound = _walkboxQueue[_walkboxQueueIndex - 1]; + } + + } while (_walkboxQueueIndex > 0); + + return false; +} + void Actor::setBox(int box) { _walkbox = box; setupActorScale(); @@ -634,17 +746,18 @@ void Actor::startWalkActor(int destX, int destY, int dir) { _walkdata.dest.y = abr.y; _walkdata.destbox = abr.box; _walkdata.destdir = dir; - + _walkdata.point3.x = 32000; + _walkdata.curbox = _walkbox; + if (_vm->_game.version == 0) { - ((Actor_v0*)this)->_newWalkBoxEntered = true; + ((Actor_v0*)this)->walkBoxQueuePrepare(); + } 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; } void Actor::startWalkAnim(int cmd, int angle) { @@ -861,13 +974,7 @@ L2C36:; stopActorMoving(); return; } - // 2C98: Yes, an exact copy of what just occurred.. the original does this, so im doing it... - // Just to keep me sane when going over it :) - if (A == 0xFF) { - setActorFromTmp(); - stopActorMoving(); - return; - } + return; } @@ -1398,13 +1505,13 @@ void Actor::putActor(int dstX, int dstY, int newRoom) { showActor(); } - // V0 always sets the actor to face the camera upon entering a room if (_vm->_game.version == 0) { - _walkdata.dest = _pos; - ((Actor_v0*)this)->_newWalkBoxEntered = true; + ((Actor_v0*)this)->_newWalkBoxEntered = false; ((Actor_v0*)this)->_CurrentWalkTo = _pos; + ((Actor_v0*)this)->_NewWalkTo = _pos; + // V0 always sets the actor to face the camera upon entering a room setDirection(oldDirToNewDir(2)); } } @@ -1549,7 +1656,7 @@ AdjustBoxResult Actor_v0::adjustPosInBorderWalkbox(AdjustBoxResult box) { if (A < box.x) return box; - if (A < 0xA0 || A == 0xA0) + if (A <= 0xA0) A = 0; Result.x = A; @@ -1980,9 +2087,10 @@ void ScummEngine::processActors() { if (_game.version == 0) { // 0x057B Actor_v0 *a0 = (Actor_v0*) a; - if (a0->_speaking & 1) + if (a0->_speaking & 1) { a0->_speaking ^= 0xFE; - + ++_V0Delay._actorRedrawCount; + } // 0x22B5 if (a0->_miscflags & kActorMiscFlagHide) continue; @@ -2404,8 +2512,13 @@ void Actor_v0::limbFrameCheck(int limb) { void Actor_v0::animateCostume() { speakCheck(); - if (_vm->_costumeLoader->increaseAnims(this)) + byte count = _vm->_costumeLoader->increaseAnims( this ); + + if (count) { + _vm->_V0Delay._actorLimbRedrawDrawCount += count; + _needRedraw = true; + } } void Actor_v0::speakCheck() { @@ -3254,7 +3367,7 @@ void Actor_v0::animateActor(int anim) { } else { - if (anim > 4 && anim <= 7) + if (anim >= 4 && anim <= 7) _facing = normalizeAngle(oldDirToNewDir(dir)); } } @@ -3311,7 +3424,7 @@ void Actor_v0::setActorFromTmp() { } void Actor_v0::actorSetWalkTo() { - + if (_newWalkBoxEntered == false) return; @@ -3350,10 +3463,33 @@ void Actor_v0::saveLoadWithSerializer(Serializer *ser) { MKLINE(Actor_v0, _walkYCount, sleByte, VER(97)), MKLINE(Actor_v0, _walkYCountInc, sleByte, VER(97)), MKLINE(Actor_v0, _walkMaxXYCountInc, sleByte, VER(97)), + + MKARRAY(Actor_v0, _walkboxQueue[0], sleByte, 16, VER(98)), + MKLINE(Actor_v0, _walkboxQueueIndex, sleByte, VER(98)), MKEND() }; ser->saveLoadEntries(this, actorEntries); + + if (ser->isLoading()) { + if (_costCommand != 0xFF ) { + + if (_walkboxQueueIndex < 1) { + + _costCommand = 0xFF; + setDirection( _facing ); + speakCheck(); + } + else { + //_costCommandNew = _costCommand; + //_costCommand = 0xFF; + //animateActor( _costCommandNew ); + _facing = 0; + directionUpdate(); + animateActor( newDirToOldDir( _facing ) ); + } + } + } } void Actor::saveLoadWithSerializer(Serializer *ser) { @@ -3496,6 +3632,8 @@ void Actor::saveLoadWithSerializer(Serializer *ser) { _walkdata.point3.x >>= V12_X_SHIFT; _walkdata.point3.y >>= V12_Y_SHIFT; } + + setDirection( _facing ); } } diff --git a/engines/scumm/actor.h b/engines/scumm/actor.h index c1a3f23318..3bc301fddb 100644 --- a/engines/scumm/actor.h +++ b/engines/scumm/actor.h @@ -350,6 +350,11 @@ class Actor_v0 : public Actor_v2 { public: Common::Point _CurrentWalkTo, _NewWalkTo; + Common::Array _walkboxHistory; + + byte _walkboxQueue[0x10]; + byte _walkboxQueueIndex; + byte _costCommandNew; byte _costCommand; byte _miscflags; @@ -380,6 +385,12 @@ public: bool _limb_flipped[8]; +private: + + bool walkBoxQueueAdd( int box ); + bool walkBoxQueueFind( int box ); + void walkboxQueueReverse(); + public: Actor_v0(ScummEngine *scumm, int id) : Actor_v2(scumm, id) {} @@ -401,6 +412,9 @@ public: byte actorWalkY(); byte updateWalkbox(); + void walkBoxQueueReset(); + bool walkBoxQueuePrepare(); + AdjustBoxResult adjustXYToBeInBox(int dstX, int dstY); AdjustBoxResult adjustPosInBorderWalkbox(AdjustBoxResult box); diff --git a/engines/scumm/boxes.cpp b/engines/scumm/boxes.cpp index 087d8425ac..108f227ec2 100644 --- a/engines/scumm/boxes.cpp +++ b/engines/scumm/boxes.cpp @@ -692,6 +692,22 @@ byte *ScummEngine::getBoxMatrixBaseAddr() { return ptr; } +byte *ScummEngine::getBoxConnectionBase( int box ) { + byte *boxm = getBoxMatrixBaseAddr(); + + int boxIndex = 0; + + for (; boxIndex != box; ++boxIndex) { + + while ( *boxm != 0xFF) { + ++boxm; + } + + ++boxm; + } + + return boxm; +} /** * Compute if there is a way that connects box 'from' with box 'to'. * Returns the number of a box adjacent to 'from' that is the next on the @@ -719,21 +735,18 @@ int ScummEngine::getNextBox(byte from, byte to) { boxm = getBoxMatrixBaseAddr(); if (_game.version == 0) { - // calculate shortest paths - byte *itineraryMatrix = (byte *)malloc(numOfBoxes * numOfBoxes); - calcItineraryMatrix(itineraryMatrix, numOfBoxes); - dest = to; - do { - dest = itineraryMatrix[numOfBoxes * from + dest]; - } while (dest != Actor::kInvalidBox && !areBoxesNeighbors(from, dest)); + boxm = getBoxConnectionBase( from ); + + for (; *boxm != 0xFF; ++boxm) { + if (*boxm == to) + break; + } - if (dest == Actor::kInvalidBox) - dest = -1; + return *boxm; - free(itineraryMatrix); - return dest; - } else if (_game.version <= 2) { + } + else if (_game.version <= 2) { // The v2 box matrix is a real matrix with numOfBoxes rows and columns. // The first numOfBoxes bytes contain indices to the start of the corresponding // row (although that seems unnecessary to me - the value is easily computable. @@ -967,6 +980,7 @@ void ScummEngine::calcItineraryMatrix(byte *itineraryMatrix, int num) { // 255 (= infinity) to all other boxes. for (i = 0; i < num; i++) { for (j = 0; j < num; j++) { + if (i == j) { adjacentMatrix[i * boxSize + j] = 0; itineraryMatrix[i * boxSize + j] = j; @@ -1160,20 +1174,31 @@ bool ScummEngine::areBoxesNeighbors(int box1nr, int box2nr) { byte ScummEngine_v0::walkboxFindTarget(Actor *a, int destbox, Common::Point walkdest) { Actor_v0 *Actor = (Actor_v0*)a; + byte nextBox = kOldInvalidBox; - byte nextBox = getNextBox(a->_walkbox, destbox); + // Do we have a walkbox queue to process + if (Actor->_walkboxQueueIndex > 1) { + nextBox = Actor->_walkboxQueue[--Actor->_walkboxQueueIndex]; - if (nextBox != 0xFF && nextBox == destbox && areBoxesNeighbors(a->_walkbox, nextBox)) { + if (Actor->_walkboxQueueIndex <= 1) { + Actor->walkBoxQueueReset(); + } + } + + // Target box reached? + if (nextBox != Actor::kInvalidBox && nextBox == destbox && areBoxesNeighbors(a->_walkbox, nextBox)) { Actor->_NewWalkTo = walkdest; return nextBox; } - if (nextBox != 0xFF && nextBox != a->_walkbox) { + // Next box reached + if (nextBox != Actor::kInvalidBox && 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 diff --git a/engines/scumm/saveload.h b/engines/scumm/saveload.h index 753287e217..fb2d45df8c 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 97 +#define CURRENT_VER 98 /** * An auxillary macro, used to specify savegame versions. We use this instead diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h index f9758aec33..5a653d0970 100644 --- a/engines/scumm/scumm.h +++ b/engines/scumm/scumm.h @@ -1131,6 +1131,8 @@ public: byte getNumBoxes(); byte *getBoxMatrixBaseAddr(); + byte *getBoxConnectionBase( int box ); + int getNextBox(byte from, byte to); void setBoxFlags(int box, int val); -- cgit v1.2.3 From 67071b42bc3ada8a1d1b49243ae4fbff9b7ef27c Mon Sep 17 00:00:00 2001 From: Robert Crossfield Date: Tue, 19 Jul 2016 18:55:27 +1000 Subject: SCUMM: Maniac V0: Implement 'simulator' for CPU lag (as the original engine occasionally ran at less than 60Hz). Fix call to 'getClosestPtOnBox', whcih was being passed X * V12_X_MULTIPLIER and Y * V12_Y_MULTIPLIER, but the box coordinates, where not --- engines/scumm/actor.cpp | 57 ++++++++++++++++++++++++++---------------------- engines/scumm/actor.h | 4 ++-- engines/scumm/boxes.cpp | 10 ++++----- engines/scumm/gfx.cpp | 2 +- engines/scumm/object.cpp | 2 ++ engines/scumm/scumm.cpp | 50 ++++++++++++++++++++++++++++++++++++++---- engines/scumm/scumm.h | 11 +++++++++- engines/scumm/scumm_v0.h | 4 ++++ 8 files changed, 101 insertions(+), 39 deletions(-) (limited to 'engines/scumm') diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp index 6cb5ce5708..b3e7926015 100644 --- a/engines/scumm/actor.cpp +++ b/engines/scumm/actor.cpp @@ -272,23 +272,23 @@ void Actor_v0::walkBoxQueueReset() { _walkboxHistory.clear(); _walkboxQueueIndex = 0; - for (uint i = 0; i < ARRAYSIZE( _walkboxQueue ); ++i) { + for (uint i = 0; i < ARRAYSIZE(_walkboxQueue); ++i) { _walkboxQueue[i] = kInvalidBox; } } bool Actor_v0::walkBoxQueueAdd(int box) { - if (_walkboxQueueIndex == ARRAYSIZE( _walkboxQueue )) + if (_walkboxQueueIndex == ARRAYSIZE(_walkboxQueue)) return false; - _walkboxQueue[_walkboxQueueIndex++] = box ; - _walkboxHistory.push_back( box ); + _walkboxQueue[_walkboxQueueIndex++] = box; + _walkboxHistory.push_back(box); return true; } void Actor_v0::walkboxQueueReverse() { - int j = ARRAYSIZE( _walkboxQueue ) - 1; + int j = ARRAYSIZE(_walkboxQueue) - 1; while (_walkboxQueue[j] == kInvalidBox && j >= 1) --j; @@ -328,21 +328,21 @@ bool Actor_v0::walkBoxQueuePrepare() { // Build a series of walkboxes from our current position, to the target do { // Add the current box to the queue - if (!walkBoxQueueAdd( BoxFound )) + if (!walkBoxQueueAdd(BoxFound)) return false; // Loop until we find a walkbox which hasn't been tested while (_walkboxQueueIndex > 0) { // Check if the dest box is a direct neighbour - if ((BoxFound = _vm->getNextBox( BoxFound, _walkdata.destbox )) == kInvalidBox) { + if ((BoxFound = _vm->getNextBox(BoxFound, _walkdata.destbox)) == kInvalidBox) { // Its not, start hunting through this boxes immediate connections - byte* boxm = _vm->getBoxConnectionBase( _walkboxQueue[_walkboxQueueIndex - 1] ); + byte* boxm = _vm->getBoxConnectionBase(_walkboxQueue[_walkboxQueueIndex - 1]); // Attempt to find one, which we havn't already used for (; *boxm != kInvalidBox; ++boxm) { - if (walkBoxQueueFind( *boxm ) != true) + if (walkBoxQueueFind(*boxm) != true) break; } @@ -357,7 +357,7 @@ bool Actor_v0::walkBoxQueuePrepare() { _newWalkBoxEntered = true; - walkBoxQueueAdd( BoxFound ); + walkBoxQueueAdd(BoxFound); walkboxQueueReverse(); return true; @@ -750,7 +750,7 @@ void Actor::startWalkActor(int destX, int destY, int dir) { _walkdata.curbox = _walkbox; if (_vm->_game.version == 0) { - ((Actor_v0*)this)->walkBoxQueuePrepare(); + ((Actor_v0 *)this)->walkBoxQueuePrepare(); } else if (_vm->_game.version <= 2) { _moving = (_moving & ~(MF_LAST_LEG | MF_IN_LEG)) | MF_NEW_LEG; @@ -1507,9 +1507,9 @@ void Actor::putActor(int dstX, int dstY, int newRoom) { if (_vm->_game.version == 0) { - ((Actor_v0*)this)->_newWalkBoxEntered = false; - ((Actor_v0*)this)->_CurrentWalkTo = _pos; - ((Actor_v0*)this)->_NewWalkTo = _pos; + ((Actor_v0 *)this)->_newWalkBoxEntered = false; + ((Actor_v0 *)this)->_CurrentWalkTo = _pos; + ((Actor_v0 *)this)->_NewWalkTo = _pos; // V0 always sets the actor to face the camera upon entering a room setDirection(oldDirToNewDir(2)); @@ -2512,7 +2512,7 @@ void Actor_v0::limbFrameCheck(int limb) { void Actor_v0::animateCostume() { speakCheck(); - byte count = _vm->_costumeLoader->increaseAnims( this ); + byte count = _vm->_costumeLoader->increaseAnims(this); if (count) { _vm->_V0Delay._actorLimbRedrawDrawCount += count; @@ -3430,7 +3430,7 @@ void Actor_v0::actorSetWalkTo() { _newWalkBoxEntered = false; - int nextBox = ((ScummEngine_v0*)_vm)->walkboxFindTarget(this, _walkdata.destbox, _walkdata.dest); + int nextBox = ((ScummEngine_v0 *)_vm)->walkboxFindTarget(this, _walkdata.destbox, _walkdata.dest); if (nextBox != kInvalidBox) { _walkdata.curbox = nextBox; } @@ -3471,22 +3471,27 @@ void Actor_v0::saveLoadWithSerializer(Serializer *ser) { ser->saveLoadEntries(this, actorEntries); + // When loading, we need to ensure the limbs are restarted if (ser->isLoading()) { - if (_costCommand != 0xFF ) { + + // valid costume command? + if (_costCommand != 0xFF) { + // Do we have a walkbox queue? if (_walkboxQueueIndex < 1) { - _costCommand = 0xFF; - setDirection( _facing ); + + // Standing Still + setDirection(_facing); speakCheck(); - } - else { - //_costCommandNew = _costCommand; - //_costCommand = 0xFF; - //animateActor( _costCommandNew ); + + } else { + // Force limb direction update _facing = 0; directionUpdate(); - animateActor( newDirToOldDir( _facing ) ); + + // Begin walking + animateActor(newDirToOldDir(_facing)); } } } @@ -3633,7 +3638,7 @@ void Actor::saveLoadWithSerializer(Serializer *ser) { _walkdata.point3.y >>= V12_Y_SHIFT; } - setDirection( _facing ); + setDirection(_facing); } } diff --git a/engines/scumm/actor.h b/engines/scumm/actor.h index 3bc301fddb..62ba161f4e 100644 --- a/engines/scumm/actor.h +++ b/engines/scumm/actor.h @@ -387,8 +387,8 @@ public: private: - bool walkBoxQueueAdd( int box ); - bool walkBoxQueueFind( int box ); + bool walkBoxQueueAdd(int box); + bool walkBoxQueueFind(int box); void walkboxQueueReverse(); public: diff --git a/engines/scumm/boxes.cpp b/engines/scumm/boxes.cpp index 108f227ec2..b5caec3c4f 100644 --- a/engines/scumm/boxes.cpp +++ b/engines/scumm/boxes.cpp @@ -692,14 +692,14 @@ byte *ScummEngine::getBoxMatrixBaseAddr() { return ptr; } -byte *ScummEngine::getBoxConnectionBase( int box ) { +byte *ScummEngine::getBoxConnectionBase(int box) { byte *boxm = getBoxMatrixBaseAddr(); int boxIndex = 0; for (; boxIndex != box; ++boxIndex) { - while ( *boxm != 0xFF) { + while (*boxm != 0xFF) { ++boxm; } @@ -736,7 +736,7 @@ int ScummEngine::getNextBox(byte from, byte to) { if (_game.version == 0) { - boxm = getBoxConnectionBase( from ); + boxm = getBoxConnectionBase(from); for (; *boxm != 0xFF; ++boxm) { if (*boxm == to) @@ -1173,7 +1173,7 @@ bool ScummEngine::areBoxesNeighbors(int box1nr, int box2nr) { } byte ScummEngine_v0::walkboxFindTarget(Actor *a, int destbox, Common::Point walkdest) { - Actor_v0 *Actor = (Actor_v0*)a; + Actor_v0 *Actor = (Actor_v0 *)a; byte nextBox = kOldInvalidBox; // Do we have a walkbox queue to process @@ -1195,7 +1195,7 @@ byte ScummEngine_v0::walkboxFindTarget(Actor *a, int destbox, Common::Point walk // Next box reached if (nextBox != Actor::kInvalidBox && nextBox != a->_walkbox) { - getClosestPtOnBox(getBoxCoordinates(nextBox), a->getPos().x, a->getPos().y, Actor->_NewWalkTo.x, Actor->_NewWalkTo.y); + getClosestPtOnBox(getBoxCoordinates(nextBox), a->getRealPos().x, a->getRealPos().y, Actor->_NewWalkTo.x, Actor->_NewWalkTo.y); } else { diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp index 5dc96eceb9..48818b8abf 100644 --- a/engines/scumm/gfx.cpp +++ b/engines/scumm/gfx.cpp @@ -3797,7 +3797,7 @@ void ScummEngine::fadeOut(int effect) { // V0 wipes the text area before fading out if (_game.version == 0) { - updateDirtyScreen( kTextVirtScreen ); + updateDirtyScreen(kTextVirtScreen); } // TheDig can disable fadeIn(), and may call fadeOut() several times diff --git a/engines/scumm/object.cpp b/engines/scumm/object.cpp index db836467ef..da94a34baf 100644 --- a/engines/scumm/object.cpp +++ b/engines/scumm/object.cpp @@ -1126,6 +1126,7 @@ void ScummEngine_v80he::clearDrawQueues() { */ void ScummEngine::markObjectRectAsDirty(int obj) { int i, strip; + ++_V0Delay._objectRedrawCount; for (i = 1; i < _numLocalObjects; i++) { if (_objs[i].obj_nr == (uint16)obj) { @@ -1133,6 +1134,7 @@ void ScummEngine::markObjectRectAsDirty(int obj) { const int minStrip = MAX(_screenStartStrip, _objs[i].x_pos / 8); const int maxStrip = MIN(_screenEndStrip+1, _objs[i].x_pos / 8 + _objs[i].width / 8); for (strip = minStrip; strip < maxStrip; strip++) { + ++_V0Delay._objectStripRedrawCount; setGfxUsageBit(strip, USAGE_BIT_DIRTY); } } diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index 3b7dea194b..3c617470fe 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -732,11 +732,40 @@ ScummEngine_v0::ScummEngine_v0(OSystem *syst, const DetectorResult &dr) VAR_ACTIVE_OBJECT2 = 0xFF; VAR_IS_SOUND_RUNNING = 0xFF; VAR_ACTIVE_VERB = 0xFF; + + DelayReset(); if (strcmp(dr.fp.pattern, "maniacdemo.d64") == 0 ) _game.features |= GF_DEMO; } +void ScummEngine_v0::DelayReset() { + _V0Delay._screenScroll = false; + _V0Delay._objectRedrawCount = 0; + _V0Delay._objectStripRedrawCount = 0; + _V0Delay._actorRedrawCount = 0; + _V0Delay._actorLimbRedrawDrawCount = 0; +} + +int ScummEngine_v0::DelayCalculateDelta() { + float Time = 0; + + // These values are made up, based on trial/error with visual inspection against WinVice + // If anyone feels inclined, the routines in the original engine could be profiled + // and these values changed accordindly. + Time += _V0Delay._objectRedrawCount * 7; + Time += _V0Delay._objectStripRedrawCount * 0.6; + Time += _V0Delay._actorRedrawCount * 2.0; + Time += _V0Delay._actorLimbRedrawDrawCount * 0.3; + + if (_V0Delay._screenScroll) + Time += 3.6f; + + DelayReset(); + + return roundf(Time); +} + ScummEngine_v6::ScummEngine_v6(OSystem *syst, const DetectorResult &dr) : ScummEngine(syst, dr) { _blastObjectQueuePos = 0; @@ -2079,13 +2108,24 @@ Common::Error ScummEngine::go() { if (delta < 1) // Ensure we don't get into an endless loop delta = 1; // by not decreasing sleepers. - // WORKAROUND: walking speed in the original v0/v1 interpreter + // WORKAROUND: Unfortunately the MOS 6502 wasn't always fast enough for MM + // a number of situations can lead to the engine running at less than 60 ticks per second, without this drop + // - A single kid is able to escape via the Dungeon Door (after pushing the brick) + // - During the intro, calls to 'SetState08' are made for the lights on the mansion, with a 'breakHere' + // in between each, the reduction in ticks then occurs while affected stripes are being redrawn. + // The music buildup is then out of sync with the text "A Lucasfilm Games Production". + // Each call to 'breakHere' has been replaced with calls to 'Delay' in the V1/V2 versions of the game + if (_game.version == 0) { + delta += ((ScummEngine_v0 *)this)->DelayCalculateDelta(); + } + + // WORKAROUND: walking speed in the original v1 interpreter // is sometimes slower (e.g. during scrolling) than in ScummVM. // This is important for the door-closing action in the dungeon, // otherwise (delta < 6) a single kid is able to escape. - if ((_game.version == 0 && isScriptRunning(132)) || - (_game.version == 1 && isScriptRunning(137))) - delta = 6; + if (_game.version == 1 && isScriptRunning(137)) { + delta = 6; + } // Wait... waitForTimer(delta * 1000 / 60 - diff); @@ -2452,6 +2492,8 @@ void ScummEngine_v8::scummLoop_handleSaveLoad() { void ScummEngine::scummLoop_handleDrawing() { if (camera._cur != camera._last || _bgNeedsRedraw || _fullRedraw) { + _V0Delay._screenScroll = true; + redrawBGAreas(); } diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h index 5a653d0970..2906fc71f5 100644 --- a/engines/scumm/scumm.h +++ b/engines/scumm/scumm.h @@ -298,7 +298,14 @@ struct StringTab : StringSlot { } }; +struct ScummEngine_v0_Delays { + bool _screenScroll; + uint _objectRedrawCount; + uint _objectStripRedrawCount; + uint _actorRedrawCount; + uint _actorLimbRedrawDrawCount; +}; enum WhereIsObject { WIO_NOT_FOUND = -1, @@ -1097,6 +1104,8 @@ public: // Indy4 Amiga specific byte *_verbPalette; + ScummEngine_v0_Delays _V0Delay; + protected: int _shadowPaletteSize; byte _currentPalette[3 * 256]; @@ -1131,7 +1140,7 @@ public: byte getNumBoxes(); byte *getBoxMatrixBaseAddr(); - byte *getBoxConnectionBase( int box ); + byte *getBoxConnectionBase(int box); int getNextBox(byte from, byte to); diff --git a/engines/scumm/scumm_v0.h b/engines/scumm/scumm_v0.h index 4098d639c4..5f40940166 100644 --- a/engines/scumm/scumm_v0.h +++ b/engines/scumm/scumm_v0.h @@ -70,6 +70,10 @@ public: byte walkboxFindTarget(Actor *a, int destbox, Common::Point walkdest); + /* Delay calculation */ + void DelayReset(); + int DelayCalculateDelta(); + protected: virtual void resetRoomObject(ObjectData *od, const byte *room, const byte *searchptr = NULL); -- cgit v1.2.3