aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/mads/game.cpp9
-rw-r--r--engines/mads/msurface.cpp14
-rw-r--r--engines/mads/msurface.h4
-rw-r--r--engines/mads/nebular/game_nebular.cpp2
-rw-r--r--engines/mads/player.cpp637
-rw-r--r--engines/mads/player.h75
-rw-r--r--engines/mads/scene_data.cpp81
-rw-r--r--engines/mads/scene_data.h8
-rw-r--r--engines/mads/user_interface.cpp4
9 files changed, 814 insertions, 20 deletions
diff --git a/engines/mads/game.cpp b/engines/mads/game.cpp
index 5c034bf8bf..af23998b74 100644
--- a/engines/mads/game.cpp
+++ b/engines/mads/game.cpp
@@ -179,11 +179,18 @@ void Game::sectionLoop() {
_vm->_palette->_paletteUsage.load(3, 0xF0, 0xF1, 0xF2);
+ if (!_player._spritesLoaded && _v3) {
+ if (_player.loadSprites(""))
+ _vm->quitGame();
+ _playerSpritesFlag = true;
+ }
+
_scene.loadScene(_scene._nextSceneId, _aaName, 0);
_vm->_sound->pauseNewCommands();
if (!_player._spritesLoaded) {
- _player.loadSprites("");
+ if (_player.loadSprites(""))
+ _vm->quitGame();
_playerSpritesFlag = false;
}
diff --git a/engines/mads/msurface.cpp b/engines/mads/msurface.cpp
index 62807e5543..65858f520e 100644
--- a/engines/mads/msurface.cpp
+++ b/engines/mads/msurface.cpp
@@ -521,4 +521,18 @@ int DepthSurface::getDepth(const Common::Point &pt) {
}
}
+int DepthSurface::getDepthHighBit(const Common::Point &pt) {
+ if (_vm->_game->_scene._sceneInfo->_depthStyle == 2) {
+ int bits = (3 - (pt.x % 4)) * 2;
+ byte v = *getBasePtr(pt.x >> 2, pt.y);
+ return (v >> bits) & 2;
+ } else {
+ if (pt.x < 0 || pt.y < 0 || pt.x >= this->w || pt.y >= this->h)
+ return 0;
+
+ return *getBasePtr(pt.x, pt.y) & 0x80;
+ }
+}
+
+
} // End of namespace MADS
diff --git a/engines/mads/msurface.h b/engines/mads/msurface.h
index 37ab305fb0..7cf2bbe15b 100644
--- a/engines/mads/msurface.h
+++ b/engines/mads/msurface.h
@@ -223,6 +223,10 @@ public:
* Returns the depth at a given position
*/
int getDepth(const Common::Point &pt);
+
+ /**
+ */
+ int getDepthHighBit(const Common::Point &pt);
};
} // End of namespace MADS
diff --git a/engines/mads/nebular/game_nebular.cpp b/engines/mads/nebular/game_nebular.cpp
index 1476620f9d..91c10a50ee 100644
--- a/engines/mads/nebular/game_nebular.cpp
+++ b/engines/mads/nebular/game_nebular.cpp
@@ -35,7 +35,7 @@ namespace MADS {
namespace Nebular {
GameNebular::GameNebular(MADSEngine *vm): Game(vm) {
- _surface = new MSurface(MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT - MADS_INTERFACE_HEIGHT);
+ _surface = new MSurface(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT);
_storyMode = STORYMODE_NAUGHTY;
}
diff --git a/engines/mads/player.cpp b/engines/mads/player.cpp
index 73b8ce06ba..fe1065cbed 100644
--- a/engines/mads/player.cpp
+++ b/engines/mads/player.cpp
@@ -26,21 +26,47 @@
namespace MADS {
+#define PLAYER_SEQ_INDEX -2
+
+const int Player::_directionListIndexes[32] = {
+ 0, 7, 4, 3, 6, 0, 2, 5, 0, 1, 9, 4, 1, 2, 7, 9, 3, 8, 9, 6, 7, 2, 3, 6, 1, 7, 9, 4, 7, 8, 0, 0
+};
+
Player::Player(MADSEngine *vm): _vm(vm) {
_action = nullptr;
_direction = 8;
_newDirection = 8;
_destFacing = 0;
_spritesLoaded = false;
- _spritesStart = _numSprites = 0;
+ _spritesStart = 0;
+ _spritesIdx = 0;
+ _numSprites = 0;
_stepEnabled = false;
_visible = false;
+ _priorVisible = false;
_visible3 = false;
_special = 0;
_ticksAmount = 0;
_priorTimer = 0;
_unk3 = _unk4 = 0;
_forceRefresh = false;
+ _highSprites = false;
+ _currentDepth = 0;
+ _currentScale = 0;
+ _frameOffset = 0;
+ _frameNum = 0;
+ _yScale = 0;
+ _frameCount = 0;
+ _unk1 = 0;
+ _unk2 = 0;
+ _unk3 = 0;
+ _frameListIndex = 0;
+ _actionIndex = 0;
+ _hypotenuse = 0;
+
+ Common::fill(&_actionList[0], &_actionList[12], 0);
+ Common::fill(&_actionList2[0], &_actionList2[12], 0);
+ Common::fill(&_spriteSetsPresent[0], &_spriteSetsPresent[PLAYER_SPRITES_FILE_COUNT], false);
}
void Player::reset() {
@@ -49,7 +75,7 @@ void Player::reset() {
_destFacing = 5;
_newDirection = _direction;
_moving = false;
- _v844C0 = _v844BE = 0;
+ _newSceneId = _v844BE = 0;
_next = 0;
_routeCount = 0;
@@ -58,8 +84,49 @@ void Player::reset() {
_action->_walkFlag = false;
}
-void Player::loadSprites(const Common::String &prefix) {
- warning("TODO: Player::loadSprites");
+bool Player::loadSprites(const Common::String &prefix) {
+ Common::String suffixList = "89632741";
+
+ Common::String newPrefix;
+ if (prefix.empty()) {
+ newPrefix = _spritesPrefix;
+ } else {
+ _spritesPrefix = prefix;
+ newPrefix = prefix;
+ }
+
+ _numSprites = 0;
+ if (!_spritesPrefix.empty()) {
+ for (int fileIndex = 0; fileIndex < PLAYER_SPRITES_FILE_COUNT; ++fileIndex) {
+ Common::String setName = Common::String::format("*%s_%c.SS",
+ newPrefix.c_str(), suffixList[fileIndex]);
+ if (fileIndex >= 5)
+ _highSprites = true;
+
+ _spriteSetsPresent[fileIndex] = true;
+ int setIndex = _vm->_game->_scene._sprites.addSprites(setName, 4);
+ if (setIndex >= 0) {
+ ++_numSprites;
+ } else if (fileIndex >= 5) {
+ _highSprites = 0;
+ return true;
+ } else {
+ _spriteSetsPresent[fileIndex] = false;
+ }
+
+ if (fileIndex == 0)
+ _spritesStart = setIndex;
+ }
+
+ _spritesLoaded = true;
+ _spritesChanged = false;
+ _highSprites = false;
+ return false;
+ } else {
+ Common::fill(&_spriteSetsPresent[0], &_spriteSetsPresent[PLAYER_SPRITES_FILE_COUNT], false);
+ _highSprites = false;
+ return true;
+ }
}
void Player::turnToDestFacing() {
@@ -67,30 +134,227 @@ void Player::turnToDestFacing() {
_newDirection = _destFacing;
}
+void Player::dirChanged() {
+ int dirIndex = 0, dirIndex2 = 0;
+ int newDir = 0, newDir2 = 0;
+
+ if (_direction != _newDirection) {
+ // Find the index for the given direction in the player direction list
+ int tempDir = _direction;
+ do {
+ ++dirIndex;
+ newDir += tempDir;
+ tempDir = _directionListIndexes[tempDir + 10];
+ } while (tempDir != _newDirection);
+ }
+
+
+ if (_direction != _newDirection) {
+ // Find the index for the given direction in the player direction list
+ int tempDir = _direction;
+ do {
+ ++dirIndex2;
+ newDir2 += tempDir;
+ tempDir = _directionListIndexes[tempDir + 20];
+ } while (tempDir != _newDirection);
+ }
+
+ int diff = dirIndex - dirIndex2;
+ if (diff == 0)
+ diff = newDir - newDir2;
+
+ _direction = (diff >= 0) ? _directionListIndexes[_direction + 20] : _directionListIndexes[_direction + 10];
+ setupFrame();
+ if ((_direction == _newDirection) && !_moving)
+ updateFrame();
+
+ _priorTimer += 1;
+}
+
void Player::moveComplete() {
reset();
_action->_inProgress = false;
}
void Player::setupFrame() {
+ Scene &scene = _vm->_game->_scene;
+
resetActionList();
- warning("TODO: Player::setupFrame");
+ _frameOffset = 0;
+ _spritesIdx = _directionListIndexes[_direction];
+ if (!_spriteSetsPresent[_spritesIdx]) {
+ // Direction isn't present, so use alternate direction, with entries flipped
+ _spritesIdx -= 4;
+ _frameOffset = 0x8000;
+ }
+
+ SpriteAsset &spriteSet = *scene._sprites[_spritesStart + _spritesIdx];
+ assert(spriteSet._charInfo);
+ _unk1 = MAX(spriteSet._charInfo->_unk1, 100);
+ setTicksAmount();
+
+ _frameCount = spriteSet._charInfo->_totalFrames;
+ if (_frameCount == 0)
+ _frameCount = spriteSet.getCount();
+
+ _yScale = spriteSet._charInfo->_yScale;
+
+ if ((_frameNum <= 0) || (_frameNum > _frameCount))
+ _frameNum = 1;
+ _forceRefresh = true;
}
void Player::updateFrame() {
- warning("TODO: Player::updateFrame");
+ Scene &scene = _vm->_game->_scene;
+ SpriteAsset &spriteSet = *scene._sprites[_spritesStart + _spritesIdx];
+ assert(spriteSet._charInfo);
+
+ if (!spriteSet._charInfo->_numEntries) {
+ _frameNum = 1;
+ } else {
+ _frameListIndex = _actionList[_actionIndex];
+
+ if (!_visible) {
+ _unk2 = 0;
+ }
+ else {
+ _unk2 = _actionList2[_actionIndex];
+
+ if (_actionIndex > 0)
+ --_actionIndex;
+ }
+
+ // Set the player frame number
+ int frameIndex = ABS(_frameListIndex);
+ _frameNum = (_frameListIndex <= 0) ? spriteSet._charInfo->_frameList[frameIndex] :
+ spriteSet._charInfo->_frameList2[frameIndex];
+
+ // Set next waiting period in ticks
+ if (frameIndex == 0) {
+ setTicksAmount();
+ } else {
+ _ticksAmount = spriteSet._charInfo->_ticksList[frameIndex];
+ }
+ }
}
void Player::update() {
- warning("TODO: Player::update");
+ Scene &scene = _vm->_game->_scene;
+
+ if (_forceRefresh || (_visible != _priorVisible)) {
+ int slotIndex = getSpriteSlot();
+ if (slotIndex >= 0)
+ scene._spriteSlots[slotIndex]._spriteType = ST_EXPIRED;
+
+ int newDepth = 1;
+ int yp = MAX(_playerPos.y, (int16)(MADS_SCENE_HEIGHT - 1));
+
+ for (int idx = 1; idx < 15; ++idx) {
+ if (scene._sceneInfo->_depthList[newDepth] >= yp)
+ newDepth = idx + 1;
+ }
+ _currentDepth = newDepth;
+
+ // Get the scale
+ int newScale = getScale(_playerPos.y);
+ _currentScale = MIN(newScale, 100);
+
+ if (_visible) {
+ // Player sprite needs to be rendered
+ SpriteSlot slot;
+ slot._spriteType = ST_FOREGROUND;
+ slot._seqIndex = PLAYER_SEQ_INDEX;
+ slot._spritesIndex = _spritesStart + _spritesIdx;
+ slot._frameNumber = _frameOffset + _frameNum;
+ slot._position.x = _playerPos.x;
+ slot._position.y = _playerPos.y + (_yScale * newScale) / 100;
+ slot._depth = newDepth;
+ slot._scale = newScale;
+
+ if (slotIndex >= 0) {
+ // Check if the existing player slot has the same details, and can be re-used
+ SpriteSlot &s2 = scene._spriteSlots[slotIndex];
+ bool equal = (s2._seqIndex == slot._seqIndex)
+ && (s2._spritesIndex == slot._spritesIndex)
+ && (s2._frameNumber == slot._frameNumber)
+ && (s2._position == slot._position)
+ && (s2._depth == slot._depth)
+ && (s2._scale == slot._scale);
+
+ if (equal)
+ // Undo the prior expiry of the player sprite
+ s2._spriteType = ST_NONE;
+ else
+ slotIndex = -1;
+ }
+
+ if (slotIndex < 0) {
+ // New slot needed, so allocate one and copy the slot data
+ slotIndex = scene._spriteSlots.add();
+ scene._spriteSlots[slotIndex] = slot;
+ }
+
+ // If changing a scene, check to change the scene when the player
+ // has moved off-screen
+ if (_newSceneId) {
+ SpriteAsset *asset = scene._sprites[slot._spritesIndex];
+ MSprite *frame = asset->getFrame(_frameNum - 1);
+ int xScale = frame->w * newScale / 200;
+ int yScale = frame->h * newScale / 100;
+ int playerX = slot._position.x;
+ int playerY = slot._position.y;
+
+ if ((playerX + xScale) < 0 || (playerX + xScale) >= MADS_SCREEN_WIDTH ||
+ playerY < 0 || (playerY + yScale) >= MADS_SCENE_HEIGHT) {
+ scene._nextSceneId = _newSceneId;
+ _newSceneId = 0;
+ _vm->_game->_v4 = 0;
+ }
+ }
+
+ }
+ }
+
+ _visible3 = _visible;
+ _priorVisible = _visible;
+ _forceRefresh = false;
}
void Player::resetActionList() {
- warning("TODO: Player::resetActionList");
+ _actionList[0] = 0;
+ _actionList2[0] = 0;
+ _actionIndex = 0;
+ _unk2 = 0;
+ _unk3 = 0;
}
void Player::setDest(const Common::Point &pt, int facing) {
- warning("TODO: Player::setDest");
+ Scene &scene = _vm->_game->_scene;
+
+ resetActionList();
+ setTicksAmount();
+ _moving = true;
+ _destFacing = facing;
+
+ scene._sceneInfo->setRouteNode(scene._sceneInfo->_nodes.size() - 2,
+ _playerPos, scene._depthSurface);
+ scene._sceneInfo->setRouteNode(scene._sceneInfo->_nodes.size() - 1,
+ pt, scene._depthSurface);
+
+ bool v = scene._depthSurface.getDepthHighBit(pt);
+ setupRoute(v);
+ _next = 0;
+
+ if (_routeCount > 0) {
+ Common::Point srcPos = _playerPos;
+ for (int routeCtr = _routeCount - 1; (routeCtr >= 0) && (_next == 0); --routeCtr) {
+ int idx = _routeIndexes[routeCtr];
+ const Common::Point &pt =scene._sceneInfo->_nodes[idx]._walkPos;
+
+ _next = scanPath(scene._depthSurface, srcPos, pt);
+ srcPos = pt;
+ }
+ }
}
void Player::nextFrame() {
@@ -111,15 +375,364 @@ void Player::nextFrame() {
}
void Player::move() {
- warning("TODO: Player::move");
+ Scene &scene = _vm->_game->_scene;
+ bool routeFlag = false;
+
+ if (_moving) {
+ int idx = _routeCount;
+ while (!_newSceneId && (_destPos.x == _playerPos.x) && (_destPos.y == _playerPos.y)) {
+ if (idx != 0) {
+ --idx;
+ SceneNode &node = scene._sceneInfo->_nodes[_routeIndexes[idx]];
+ _destPos = node._walkPos;
+ routeFlag = true;
+ }
+ else if (_v844BE == idx) {
+ // End of walking path
+ _routeCount = 0;
+ _moving = false;
+ turnToDestFacing();
+ routeFlag = true;
+ idx = _routeCount;
+ }
+ else {
+ _newSceneId = _v844BE;
+ _v844BC = true;
+ _v844BE = 0;
+ _stepEnabled = true;
+ routeFlag = false;
+ }
+
+ if (!_moving)
+ break;
+ }
+ _routeCount = idx;
+ }
+
+ if (routeFlag && _moving)
+ startMovement();
+
+ if (_newDirection != _direction)
+ dirChanged();
+ else if (!_moving)
+ updateFrame();
+
+ int var1 = _unk1;
+ if (_unk4 && (_hypotenuse > 0)) {
+ int v1 = -(_currentScale - 100) * (_posDiff.x - 1) / _hypotenuse + _currentScale;
+ var1 = MAX(1, 10000 / (v1 * _currentScale * var1));
+ }
+
+ if (!_moving || (_direction != _newDirection))
+ return;
+
+ Common::Point newPos = _playerPos;
+
+ if (_v8452E < var1) {
+ do {
+ if (_v8452C < _posDiff.x)
+ _v8452C += _posDiff.y;
+ if (_v8452C >= _posDiff.x) {
+ if ((_posChange.y > 0) || (_newSceneId != 0))
+ newPos.y += _yDirection;
+ --_posChange.y;
+ _v8452C -= _posDiff.x;
+ }
+
+ if (_v8452C < _posDiff.x) {
+ if ((_posChange.x > 0) || (_newSceneId != 0))
+ newPos.x += _xDirection;
+ --_posChange.x;
+ }
+
+ if ((_v844BC == 0) && (_newSceneId == 0) && (_v844BE == 0)) {
+ routeFlag = scene._depthSurface.getDepthHighBit(newPos);
+
+ if (_special == 0)
+ _special = scene.getDepthHighBits(newPos);
+ }
+
+ _v8452E += _v84530;
+
+ } while ((_v8452E < var1) && !routeFlag && ((_posChange.x > 0) || (_posChange.y > 0) || (_newSceneId != 0)));
+ }
+
+ _v8452E -= var1;
+
+ if (routeFlag)
+ moveComplete();
+ else {
+ if (!_newSceneId) {
+ // If the move is complete, make sure the position is exactly on the given destination
+ if (_posChange.x == 0)
+ newPos.x = _destPos.x;
+ if (_posChange.y == 0)
+ newPos.y = _destPos.y;
+ }
+
+ _playerPos = newPos;
+ }
}
void Player::idle() {
- warning("TODO: Player::idle");
+ Scene &scene = _vm->_game->_scene;
+
+ if (_direction != _newDirection) {
+ // The direction has changed, so reset for new direction
+ dirChanged();
+ return;
+ }
+
+ SpriteAsset &spriteSet = *scene._sprites[_spritesStart + _spritesIdx];
+ assert(spriteSet._charInfo);
+ if (spriteSet._charInfo->_numEntries == 0)
+ // No entries, so exit immediately
+ return;
+
+ int frameIndex = ABS(_frameListIndex);
+ int direction = (_frameListIndex < 0) ? -1 : 1;
+
+ if (frameIndex >= spriteSet._charInfo->_numEntries)
+ // Reset back to the start of the list
+ _frameListIndex = 0;
+ else {
+ _frameNum += direction;
+ _forceRefresh = true;
+
+ if (spriteSet._charInfo->_frameList2[frameIndex] < _frameNum) {
+ _unk3 = _unk2;
+ updateFrame();
+ }
+ if (spriteSet._charInfo->_frameList[frameIndex] < _frameNum) {
+ _unk3 = _unk2;
+ updateFrame();
+ }
+ }
}
void Player::postUpdate() {
- warning("TODO: Player::postUpdate");
+ if (_moving) {
+ if (++_frameNum > _frameCount)
+ _frameNum = 1;
+ _forceRefresh = true;
+ } else {
+ if (!_forceRefresh)
+ idle();
+ }
+}
+
+int Player::getSpriteSlot() {
+ SpriteSlots &spriteSlots = _vm->_game->_scene._spriteSlots;
+
+ for (uint idx = 0; idx < spriteSlots.size(); ++idx) {
+ if (spriteSlots[idx]._seqIndex == PLAYER_SEQ_INDEX &&
+ spriteSlots[idx]._spriteType >= ST_NONE)
+ return idx;
+ }
+
+ return - 1;
+}
+
+int Player::getScale(int yp) {
+ Scene &scene = _vm->_game->_scene;
+
+ int scale = (scene._bandsRange == 0) ? scene._sceneInfo->_maxScale :
+ (yp - scene._sceneInfo->_yBandsStart) * scene._scaleRange / scene._bandsRange +
+ scene._sceneInfo->_minScale;
+
+ return MIN(scale, 100);
+}
+
+void Player::setTicksAmount() {
+ Scene &scene = _vm->_game->_scene;
+
+ SpriteAsset &spriteSet = *scene._sprites[_spritesStart + _spritesIdx];
+ assert(spriteSet._charInfo);
+
+ _ticksAmount = spriteSet._charInfo->_ticksAmount;
+ if (_ticksAmount == 0)
+ _ticksAmount = 6;
+}
+
+void Player::setupRoute(bool bitFlag) {
+ Scene &scene = _vm->_game->_scene;
+
+ // Reset the flag set of nodes in use
+ SceneNodeList &nodes = scene._sceneInfo->_nodes;
+ for (uint i = 0; i < nodes.size(); ++i)
+ nodes[i]._active = false;
+
+ // Start constructing route node list
+ _routeLength = 0x3FFF;
+ _routeCount = 0;
+
+ setupRouteNode(_tempRoute, nodes.size() - 1, bitFlag ? 0xC000 : 0x8000, 0);
+}
+
+void Player::setupRouteNode(int *routeIndexP, int nodeIndex, int flags, int routeLength) {
+ Scene &scene = _vm->_game->_scene;
+ SceneNodeList &nodes = scene._sceneInfo->_nodes;
+ SceneNode &currentNode = nodes[nodeIndex];
+ currentNode._active = true;
+
+ *routeIndexP++ = nodeIndex;
+
+ int subIndex = nodes.size() - 2;
+ int indexVal = nodes[nodeIndex]._indexes[subIndex];
+ if (indexVal & flags) {
+ routeLength += indexVal & 0x3FFF;
+ if (routeLength < _routeLength) {
+ // Found a new shorter route to destination, so set up the route with the found one
+ Common::copy(_tempRoute, routeIndexP, _routeIndexes);
+ _routeCount = routeIndexP - _tempRoute;
+ _routeLength = indexVal & 0x3FFF;
+ }
+ } else {
+ for (int idx = nodes.size() - 2; idx > 0; --idx) {
+ int nodePos = idx - 1;
+ if (!nodes[nodePos]._active && ((currentNode._indexes[nodePos] & flags) != 0))
+ setupRouteNode(routeIndexP, nodePos, 0x8000, indexVal & 0x3fff);
+ }
+ }
+
+ currentNode._active = false;
+}
+
+int Player::scanPath(MSurface &depthSurface, const Common::Point &srcPos, const Common::Point &destPos) {
+ Scene &scene = _vm->_game->_scene;
+
+ // For compressed depth surfaces, always return 0
+ if (scene._sceneInfo->_depthStyle != 2)
+ return 0;
+
+ int yDiff = destPos.y - srcPos.y;
+ int yAmount = MADS_SCREEN_WIDTH;
+
+ if (yDiff < 0) {
+ yDiff = -yDiff;
+ yAmount = -yAmount;
+ }
+
+ int xDiff = destPos.x - srcPos.y;
+ int xDirection = 1;
+ int xAmount = 0;
+ if (xDiff < 0) {
+ xDiff = -xDiff;
+ xDirection = -xDirection;
+ xAmount = MIN(yDiff, xDiff);
+ }
+
+ ++xDiff;
+ ++yDiff;
+
+ const byte *srcP = depthSurface.getBasePtr(srcPos.x, srcPos.y);
+ int index = xAmount;
+
+ // Outer horizontal movement loop
+ for (int yIndex = 0; yIndex < yDiff; ++yIndex) {
+ index += yDiff;
+ int v = (*srcP & 0x7F) >> 4;
+ if (v)
+ return v;
+
+ // Inner loop for handling vertical movement
+ while (index >= xDiff) {
+ index -= xDiff;
+
+ v = (*srcP & 0x7F) >> 4;
+ if (v)
+ return v;
+
+ srcP += yAmount;
+ }
+
+ srcP += xDirection;
+ }
+
+ return 0;
+}
+
+void Player::startMovement() {
+ int xDiff = _destPos.x - _playerPos.x;
+ int yDiff = _destPos.y - _playerPos.y;
+ int srcScale = getScale(_playerPos.y);
+ int destScale = getScale(_destPos.y);
+
+ // Sets the X direction
+ if (xDiff > 0)
+ _xDirection = 1;
+ else if (xDiff < 0)
+ _xDirection = -1;
+ else
+ _xDirection = 0;
+
+ // Sets the Y direction
+ if (yDiff > 0)
+ _yDirection = 1;
+ else if (yDiff < 0)
+ _yDirection = -1;
+ else
+ _yDirection = 0;
+
+ xDiff = ABS(xDiff);
+ yDiff = ABS(yDiff);
+ int scaleDiff = ABS(srcScale - destScale);
+
+ int xAmt100 = xDiff * 100;
+ int yAmt100 = yDiff * 100;
+ int xAmt33 = xDiff * 33;
+
+ int scaleAmount = (_unk4 ? scaleDiff * 3 : 0) + 100 * yDiff / 100;
+ int scaleAmount100 = scaleAmount * 100;
+
+ // Figure out direction that will need to be moved in
+ int majorDir;
+ if (xDiff == 0)
+ majorDir = 1;
+ else if (yDiff == 0)
+ majorDir = 3;
+ else {
+ if ((scaleAmount < xDiff) && ((xAmt33 / scaleAmount) >= 141))
+ majorDir = 3;
+ else if (yDiff <= xDiff)
+ majorDir = 2;
+ else if ((scaleAmount100 / xDiff) >= 141)
+ majorDir = 1;
+ else
+ majorDir = 2;
+ }
+
+ switch (majorDir) {
+ case 1:
+ _newDirection = (_yDirection <= 0) ? 8 : 2;
+ break;
+ case 2: {
+ _newDirection = ((_yDirection <= 0) ? 9 : 3) - ((_xDirection <= 0) ? 2 : 0);
+ break;
+ }
+ case 3:
+ _newDirection = (_xDirection <= 0) ? 4 : 6;
+ break;
+ default:
+ break;
+ }
+
+ _hypotenuse = sqrt((double)(xAmt100 * xAmt100 + yAmt100 * yAmt100));
+ _posDiff.x = xDiff + 1;
+ _posDiff.y = yDiff + 1;
+ _posChange.x = xDiff;
+ _posChange.y = yDiff;
+
+ int majorChange = MAX(xDiff, yDiff);
+ _v84530 = (majorChange == 0) ? 0 : _hypotenuse / majorChange;
+
+ if (_playerPos.x > _destPos.x)
+ _v8452C = MAX(_posChange.x, _posChange.y);
+ else
+ _v8452C = 0;
+
+ _hypotenuse /= 100;
+ _v8452E = -_v84530;
}
} // End of namespace MADS
diff --git a/engines/mads/player.h b/engines/mads/player.h
index 92e28896c4..9a615e544f 100644
--- a/engines/mads/player.h
+++ b/engines/mads/player.h
@@ -31,10 +31,32 @@ namespace MADS {
class MADSEngine;
class Action;
+#define PLAYER_SPRITES_FILE_COUNT 8
+
class Player {
private:
+ static const int _directionListIndexes[32];
+private:
MADSEngine *_vm;
MADSAction *_action;
+ bool _highSprites;
+ bool _spriteSetsPresent[PLAYER_SPRITES_FILE_COUNT];
+ int _currentDepth;
+ int _currentScale;
+ int _frameOffset;
+ int _frameNum;
+ int _yScale;
+ int _frameCount;
+ int _frameListIndex;
+ int _actionIndex;
+ bool _v844BC;
+ int _v8452E;
+ int _v8452C;
+ int _v84530;
+ int _routeLength;
+ int _actionList[12];
+ int _actionList2[12];
+ int _hypotenuse;
void reset();
@@ -43,33 +65,78 @@ private:
void move();
void postUpdate();
+
+ /**
+ * Get the sprite slot index for the player
+ */
+ int getSpriteSlot();
+
+ /**
+ * Get the scale for the player at the given Y position
+ */
+ int getScale(int yp);
+
+ void setTicksAmount();
+
+ void setupRoute();
+
+ void setupRoute(bool bitFlag);
+
+ void setupRouteNode(int *routeIndexP, int nodeIndex, int flags, int routeLength);
+
+ /**
+ * Scans along an edge connecting two points within the depths/walk surface, and returns the information of the first
+ * pixel high nibble encountered with a non-zero value
+ */
+ int scanPath(MSurface &depthSurface, const Common::Point &srcPos, const Common::Point &destPos);
+
+ /**
+ * Starts a player moving to a given destination
+ */
+ void startMovement();
+
+ void dirChanged();
public:
int _direction;
int _newDirection;
+ int _xDirection, _yDirection;
int _destFacing;
bool _spritesLoaded;
int _spritesStart;
+ int _spritesIdx;
int _numSprites;
bool _stepEnabled;
bool _spritesChanged;
bool _visible;
+ bool _priorVisible;
bool _visible3;
Common::Point _playerPos;
Common::Point _destPos;
+ Common::Point _posChange;
+ Common::Point _posDiff;
bool _moving;
- int _v844C0, _v844BE;
+ int _newSceneId, _v844BE;
int _next;
- int _routeCount;
int _special;
int _ticksAmount;
uint32 _priorTimer;
- int _unk3, _unk4;
+ int _unk1;
+ int _unk2;
+ int _unk3;
+ bool _unk4;
bool _forceRefresh;
Common::String _spritesPrefix;
+ int _routeCount;
+ int _routeOffset;
+ int _tempRoute[MAX_ROUTE_NODES];
+ int _routeIndexes[MAX_ROUTE_NODES];
public:
Player(MADSEngine *vm);
- void loadSprites(const Common::String &prefix);
+ /**
+ * Load sprites for the player
+ */
+ bool loadSprites(const Common::String &prefix);
void turnToDestFacing();
diff --git a/engines/mads/scene_data.cpp b/engines/mads/scene_data.cpp
index aa3670ee41..04dfc4be44 100644
--- a/engines/mads/scene_data.cpp
+++ b/engines/mads/scene_data.cpp
@@ -394,6 +394,87 @@ void SceneInfo::SpriteInfo::load(Common::SeekableReadStream *f) {
_scale = f->readByte();
}
+void SceneInfo::setRouteNode(int nodeIndex, const Common::Point &pt, MSurface &depthSurface) {
+ int flags, hypotenuse;
+
+ _nodes[nodeIndex]._walkPos = pt;
+
+ // Recalculate inter-node lengths
+ for (uint idx = 0; idx < _nodes.size(); ++idx) {
+ int entry;
+ if (idx == (uint)nodeIndex) {
+ entry = 0x3FFF;
+ }
+ else {
+ // Process the node
+ flags = getRouteFlags(pt, _nodes[idx]._walkPos, depthSurface);
+
+ int xDiff = ABS(_nodes[idx]._walkPos.x - pt.x);
+ int yDiff = ABS(_nodes[idx]._walkPos.y - pt.y);
+ hypotenuse = sqrt((double)(xDiff * xDiff + yDiff * yDiff));
+
+ if (hypotenuse >= 0x3FFF)
+ // Shouldn't ever be this large
+ hypotenuse = 0x3FFF;
+
+ entry = hypotenuse | flags;
+ _nodes[idx]._indexes[nodeIndex] = entry;
+ _nodes[nodeIndex]._indexes[idx] = entry;
+ }
+ }
+}
+
+int SceneInfo::getRouteFlags(const Common::Point &src, const Common::Point &dest,
+ MSurface &depthSurface) {
+ int result = 0x8000;
+ bool flag = false;
+
+ int xDiff = ABS(dest.x - src.x);
+ int yDiff = ABS(dest.y - src.y);
+ int xDirection = dest.x >= src.x ? 1 : -1;
+ int yDirection = dest.y >= src.y ? depthSurface.w : -depthSurface.w;
+ int majorDiff = 0;
+ if (dest.x < src.x)
+ majorDiff = MAX(xDiff, yDiff);
+ ++xDiff;
+ ++yDiff;
+
+ byte *srcP = depthSurface.getBasePtr(src.x, src.y);
+
+ int totalCtr = majorDiff;
+ for (int xCtr = 0; xCtr < xDiff; ++xCtr, srcP += xDirection) {
+ totalCtr += yDiff;
+
+ if ((*srcP & 0x80) == 0)
+ flag = false;
+ else if (!flag) {
+ flag = true;
+ result -= 0x4000;
+ if (result == 0)
+ break;
+ }
+
+ while (totalCtr >= xDiff) {
+ totalCtr -= xDiff;
+
+ if ((*srcP & 0x80) == 0)
+ flag = false;
+ else if (!flag) {
+ flag = true;
+ result -= 0x4000;
+ if (result == 0)
+ break;
+ }
+
+ srcP += yDirection;
+ }
+ if (result == 0)
+ break;
+ }
+
+ return result;
+}
+
/*------------------------------------------------------------------------*/
SceneInfo *SceneInfo::init(MADSEngine *vm) {
diff --git a/engines/mads/scene_data.h b/engines/mads/scene_data.h
index ffea369166..00edefbf91 100644
--- a/engines/mads/scene_data.h
+++ b/engines/mads/scene_data.h
@@ -251,6 +251,9 @@ class SceneInfo {
void load(Common::SeekableReadStream *f);
};
+
+
+ int getRouteFlags(const Common::Point &src, const Common::Point &dest, MSurface &depthSurface);
protected:
MADSEngine *_vm;
@@ -301,6 +304,11 @@ public:
*/
void load(int sceneId, int flags, const Common::String &resName, int v3,
MSurface &depthSurface, MSurface &bgSurface);
+
+ /**
+ * Set up a route node
+ */
+ void setRouteNode(int nodeIndex, const Common::Point &pt, MSurface &depthSurface);
};
} // End of namespace MADS
diff --git a/engines/mads/user_interface.cpp b/engines/mads/user_interface.cpp
index cbd4573eb4..3b3fc9379a 100644
--- a/engines/mads/user_interface.cpp
+++ b/engines/mads/user_interface.cpp
@@ -42,7 +42,7 @@ UserInterface::UserInterface(MADSEngine *vm) : _vm(vm) {
_inventoryTopIndex = 0;
_objectY = 0;
- byte *pData = _vm->_screen.getBasePtr(0, MADS_SCREEN_HEIGHT - MADS_INTERFACE_HEIGHT);
+ byte *pData = _vm->_screen.getBasePtr(0, MADS_SCENE_HEIGHT);
setPixels(pData, MADS_SCREEN_WIDTH, MADS_INTERFACE_HEIGHT);
}
@@ -270,7 +270,7 @@ bool UserInterface::getBounds(ScrCategory category, int v, Common::Rect &bounds)
}
void UserInterface::moveRect(Common::Rect &bounds) {
- bounds.translate(0, MADS_SCREEN_HEIGHT - MADS_INTERFACE_HEIGHT);
+ bounds.translate(0, MADS_SCENE_HEIGHT);
}
} // End of namespace MADS