aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/m4/mads_player.cpp317
-rw-r--r--engines/m4/mads_player.h26
-rw-r--r--engines/m4/mads_scene.cpp38
-rw-r--r--engines/m4/mads_scene.h12
-rw-r--r--engines/m4/rails.h2
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<MadsObject> _objects;
+ Common::Array<SceneNode> _nodes;
Common::Array<Common::String> _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