diff options
Diffstat (limited to 'engines')
-rw-r--r-- | engines/mads/game.cpp | 9 | ||||
-rw-r--r-- | engines/mads/msurface.cpp | 14 | ||||
-rw-r--r-- | engines/mads/msurface.h | 4 | ||||
-rw-r--r-- | engines/mads/nebular/game_nebular.cpp | 2 | ||||
-rw-r--r-- | engines/mads/player.cpp | 637 | ||||
-rw-r--r-- | engines/mads/player.h | 75 | ||||
-rw-r--r-- | engines/mads/scene_data.cpp | 81 | ||||
-rw-r--r-- | engines/mads/scene_data.h | 8 | ||||
-rw-r--r-- | engines/mads/user_interface.cpp | 4 |
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 ¤tNode = 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 |