From f796fd6cf39c322b7482faee771be666c217480e Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Wed, 14 Jul 2010 11:55:15 +0000 Subject: Preliminary implementation of lots of code related to player movement svn-id: r50882 --- engines/m4/mads_player.cpp | 317 +++++++++++++++++++++++++++++++++++++++++++-- engines/m4/mads_player.h | 26 ++++ engines/m4/mads_scene.cpp | 38 +++++- engines/m4/mads_scene.h | 12 +- engines/m4/rails.h | 2 + 5 files changed, 383 insertions(+), 12 deletions(-) diff --git a/engines/m4/mads_player.cpp b/engines/m4/mads_player.cpp index 8531a3ed44..a671854e88 100644 --- a/engines/m4/mads_player.cpp +++ b/engines/m4/mads_player.cpp @@ -35,20 +35,27 @@ const int MadsPlayer::_directionListIndexes[32] = { MadsPlayer::MadsPlayer() { _playerPos = Common::Point(160, 78); - _direction = 0; - _newDirection = 0; + _ticksAmount = 3; _forceRefresh = true; _stepEnabled = true; - _ticksAmount = 3; - _priorTimer = 0; _visible = true; - _priorVisible = false; - _visible3 = false; _yScale = 0; _moving = false; + _spriteListStart = 0; - _spriteListIdx = 0; + //TODO:unknown vars + _special = 0; + _next = 0; + _unk4 = false; + _spritesChanged = true; + + _direction = 0; + _newDirection = 0; + _priorTimer = 0; + _priorVisible = false; + _visible3 = false; + _spriteListIdx = 0; _currentScale = 0; strcpy(_spritesPrefix, ""); for (int idx = 0; idx < 8; ++idx) @@ -59,6 +66,8 @@ MadsPlayer::MadsPlayer() { _frameCount = 0; _frameListIndex = 0; _actionIndex = 0; + _routeCount = 0; + resetActionList(); } @@ -168,7 +177,7 @@ void MadsPlayer::update() { _madsVm->scene()->_spriteSlots[slotIndex] = slot; } - // TODO: Meaning of word_844c0 block + // TODO: Meaning of _v844c0 block } } @@ -325,6 +334,34 @@ void MadsPlayer::nextFrame() { } } +void MadsPlayer::setDest(int destX, int destY, int facing) { + resetActionList(); + setTicksAmount(); + _moving = true; + _destFacing = facing; + + _madsVm->scene()->getSceneResources().setRouteNode(_madsVm->scene()->getSceneResources()._nodes.size() - 2, + _playerPos, _madsVm->scene()->_depthSurface); + _madsVm->scene()->getSceneResources().setRouteNode(_madsVm->scene()->getSceneResources()._nodes.size() - 1, + Common::Point(destX, destY), _madsVm->scene()->_depthSurface); + + bool v = _madsVm->scene()->getDepthHighBit(Common::Point(destX, destY)); + 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 = _madsVm->scene()->getSceneResources()._nodes[idx].pt; + + _next = scanPath(_madsVm->scene()->_depthSurface, srcPos, pt); + srcPos = pt; + } + } +} + + int MadsPlayer::getScale(int yp) { MadsSceneResources &r = _madsVm->scene()->getSceneResources(); @@ -411,7 +448,98 @@ void MadsPlayer::idle() { } void MadsPlayer::move() { - // TODO: Handle player movement + bool routeFlag = false; + + if (_moving) { + int idx = _routeCount; + while (!_v844C0 && (_destPos.x == _playerPos.x) && (_destPos.y == _playerPos.y)) { + if (idx != 0) { + --idx; + SceneNode &node = _madsVm->scene()->getSceneResources()._nodes[_routeIndexes[idx]]; + _destPos = node.pt; + routeFlag = true; + } else if (_v844BE == idx) { + // End of walking path + _routeCount = 0; + _moving = false; + turnToDestFacing(); + routeFlag = true; + idx = _routeCount; + } else { + _v844C0 = _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) || (_v844C0 != 0)) + newPos.y += _yDirection; + --_posChange.y; + _v8452C -= _posDiff.x; + } + + if (_v8452C < _posDiff.x) { + if ((_posChange.x <= 0) || (_v844C0 != 0)) + newPos.x += _xDirection; + --_posChange.x; + } + + if ((_v844BC == 0) && (_v844C0 == 0) && (_v844BE == 0)) { + routeFlag = _madsVm->scene()->getDepthHighBit(newPos); + + if (_special == 0) + _special = _madsVm->scene()->getDepthHighBits(newPos); + } + + _v8452E += _v84530; + + } while ((_v8452E < var1) && !routeFlag && ((_posChange.x > 0) || (_posChange.y > 0))); + } + + if (routeFlag) + moveComplete(); + else { + if (!_v844C0) { + // 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 MadsPlayer::dirChanged() { @@ -451,4 +579,175 @@ void MadsPlayer::dirChanged() { _priorTimer += 1; } +void MadsPlayer::moveComplete() { + reset(); + //todo: Unknown flag +} + +void MadsPlayer::reset() { + _destPos = _playerPos; + _destFacing = 5; + _newDirection = _direction; + + _moving = false; + _v844BC = false; + _v844C0 = false; + _v844BE = 0; + _next = 0; + _routeCount = 0; +} + +/** + * 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 MadsPlayer::scanPath(M4Surface *depthSurface, const Common::Point &srcPos, const Common::Point &destPos) { + // For compressed depth surfaces, always return 0 + if (_madsVm->scene()->getSceneResources()._depthStyle != 2) + return 0; + + int yDiff = destPos.y - srcPos.y; + int yAmount = MADS_SURFACE_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; + + int v = (*srcP && 0x7F) >> 4; + if (v) + return v; + + srcP += yAmount; + } + + srcP += xDirection; + } + + return 0; +} + +/** + * Starts a player moving to a given destination + */ +void MadsPlayer::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 = SqrtF16(xAmt100 * xAmt100 + yAmt100 * yAmt100); + _posDiff.x = xDiff + 1; + _posDiff.y = yDiff + 1; + _posChange.x = xDiff; + _posChange.y = yDiff; + + scaleAmount = MAX(xDiff, yDiff); + _v84530 = (scaleAmount == 0) ? 0 : _hypotenuse / scaleAmount; + + if (_playerPos.x > _destPos.x) + _v8452C = MAX(_posChange.x, _posChange.y); + else + _v8452C = 0; + + _hypotenuse /= 100; + _v8452E = -_v84530; +} + +void MadsPlayer::turnToDestFacing() { + if (_destFacing != 5) + _newDirection = _destFacing; +} + +void MadsPlayer::setupRoute(bool bitFlag) { + // TODO: Properly Implement route setup + _routeIndexes[0] = _madsVm->scene()->getSceneResources()._nodes.size() - 1; + _routeCount = 1; +} + } // End of namespace M4 diff --git a/engines/m4/mads_player.h b/engines/m4/mads_player.h index 65ed9ef89c..2fbba70664 100644 --- a/engines/m4/mads_player.h +++ b/engines/m4/mads_player.h @@ -31,6 +31,7 @@ namespace M4 { #define PLAYER_SEQ_INDEX -2 +#define MAX_ROUTE_NODES 22 class MadsPlayer { private: @@ -42,12 +43,18 @@ private: void idle(); void move(); void dirChanged(); + void reset(); + int scanPath(M4Surface *depthSurface, const Common::Point &srcPos, const Common::Point &destPos); + void startMovement(); public: char _spritesPrefix[16]; int _spriteSetCount; bool _spriteSetsPresent[8]; Common::Point _playerPos; Common::Point _destPos; + Common::Point _posChange; + Common::Point _posDiff; + int _hypotenuse; uint32 _priorTimer; uint _ticksAmount; int16 _direction, _newDirection; @@ -70,6 +77,21 @@ public: int _actionList2[12]; int _unk2; int _unk3; + int _xDirection, _yDirection; + int _destFacing; + int _special; + int _next; + int _routeCount; + int _routeOffset; + int _tempRoute[MAX_ROUTE_NODES]; + int _routeIndexes[MAX_ROUTE_NODES]; + bool _unk4; + bool _v844BC; + int _v844BE; + bool _v844C0; + int _v8452E; + int _v8452C; + int _v84530; static const int _directionListIndexes[32]; public: @@ -81,6 +103,10 @@ public: void setupFrame(); void step(); void nextFrame(); + void setDest(int destX, int destY, int facing); + void turnToDestFacing(); + void setupRoute(bool bitFlag); + void moveComplete(); }; } // End of namespace M4 diff --git a/engines/m4/mads_scene.cpp b/engines/m4/mads_scene.cpp index e4f84aeb5a..ba2bbc07e2 100644 --- a/engines/m4/mads_scene.cpp +++ b/engines/m4/mads_scene.cpp @@ -48,6 +48,17 @@ static const int SCROLLER_DELAY = 200; //-------------------------------------------------------------------------- +void SceneNode::load(Common::SeekableReadStream *stream) { + // Get the next data block + uint8 obj[0x30]; + stream->read(obj, 0x30); + + pt.x = READ_LE_UINT16(&obj[0]); + pt.y = READ_LE_UINT16(&obj[2]); +} + +//-------------------------------------------------------------------------- + MadsScene::MadsScene(MadsEngine *vm): _sceneResources(), Scene(vm, &_sceneResources), MadsView(this) { _vm = vm; _activeAnimation = NULL; @@ -265,6 +276,10 @@ void MadsScene::leftClick(int x, int y) { statusText[0] = toupper(statusText[0]); // capitalize first letter setStatusText(statusText); } + + // **DEBUG** - being used for movement testing + _madsVm->_player.moveComplete(); + _madsVm->_player.setDest(x, y, 2); } void MadsScene::rightClick(int x, int y) { @@ -503,6 +518,22 @@ void MadsScene::loadAnimation(const Common::String &animName, int abortTimers) { _activeAnimation = anim; } +bool MadsScene::getDepthHighBit(const Common::Point &pt) { + const byte *p = _depthSurface->getBasePtr(pt.x, pt.y); + if (_sceneResources._depthStyle == 2) + return ((*p << 4) & 0x80) != 0; + + return (*p & 0x80) != 0; +} + +bool MadsScene::getDepthHighBits(const Common::Point &pt) { + if (_sceneResources._depthStyle == 2) + return 0; + + const byte *p = _depthSurface->getBasePtr(pt.x, pt.y); + return (*p & 0x70) >> 4; +} + /*--------------------------------------------------------------------------*/ MadsAction::MadsAction() { @@ -733,9 +764,9 @@ void MadsSceneResources::load(int sceneNumber, const char *resName, int v0, M4Su // Load in any scene objects for (int i = 0; i < objectCount; ++i) { - MadsObject rec; + SceneNode rec; rec.load(stream); - _objects.push_back(rec); + _nodes.push_back(rec); } for (int i = 0; i < 20 - objectCount; ++i) stream->skip(48); @@ -810,6 +841,9 @@ void MadsSceneResources::load(int sceneNumber, const char *resName, int v0, M4Su delete depthSurface; } +void MadsSceneResources::setRouteNode(int nodeIndex, const Common::Point &pt, M4Surface *depthSurface) { + // TODO +} /*--------------------------------------------------------------------------*/ diff --git a/engines/m4/mads_scene.h b/engines/m4/mads_scene.h index e671dfb194..5a8897802a 100644 --- a/engines/m4/mads_scene.h +++ b/engines/m4/mads_scene.h @@ -37,6 +37,13 @@ class MadsInterfaceView; #define DEPTH_BANDS_SIZE 15 +class SceneNode { +public: + Common::Point pt; + + void load(Common::SeekableReadStream *stream); +}; + class MadsSceneResources: public SceneResources { public: int _sceneId; @@ -44,7 +51,7 @@ public: int _depthStyle; int _width; int _height; - Common::Array _objects; + Common::Array _nodes; Common::Array _setNames; int _yBandsStart, _yBandsEnd; int _maxScale, _minScale; @@ -55,6 +62,7 @@ public: void load(int sceneId, const char *resName, int v0, M4Surface *depthSurface, M4Surface *surface); int bandsRange() const { return _yBandsEnd - _yBandsStart; } int scaleRange() const { return _maxScale - _minScale; } + void setRouteNode(int nodeIndex, const Common::Point &pt, M4Surface *depthSurface); }; enum MadsActionMode {ACTMODE_NONE = 0, ACTMODE_VERB = 1, ACTMODE_OBJECT = 3, ACTMODE_TALK = 6}; @@ -138,6 +146,8 @@ public: MadsSceneResources &getSceneResources() { return _sceneResources; } MadsAction &getAction() { return _action; } void setStatusText(const char *text) {}//***DEPRECATED*** + bool getDepthHighBit(const Common::Point &pt); + bool getDepthHighBits(const Common::Point &pt); }; #define CHEAT_SEQUENCE_MAX 8 diff --git a/engines/m4/rails.h b/engines/m4/rails.h index a7add5a8eb..e3183c243f 100644 --- a/engines/m4/rails.h +++ b/engines/m4/rails.h @@ -93,6 +93,8 @@ private: bool isLineWalkable(int x0, int y0, int x1, int y1); }; +long SqrtF16(long n); + } // End of namespace M4 #endif -- cgit v1.2.3