1
/* ScummVM - Graphic Adventure Engine
3
* ScummVM is the legal property of its developers, whose names
4
* are too numerous to list here. Please refer to the COPYRIGHT
5
* file distributed with this source distribution.
7
* This program is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU General Public License
9
* as published by the Free Software Foundation; either version 2
10
* of the License, or (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23
#include "common/scummsys.h"
24
#include "mads/mads.h"
25
#include "mads/rails.h"
29
WalkNode::WalkNode() {
31
Common::fill(&_distances[0], &_distances[MAX_ROUTE_NODES], 0);
34
void WalkNode::load(Common::SeekableReadStream *f) {
35
_walkPos.x = f->readSint16LE();
36
_walkPos.y = f->readSint16LE();
37
for (int i = 0; i < MAX_ROUTE_NODES; ++i)
38
_distances[i] = f->readUint16LE();
41
/*------------------------------------------------------------------------*/
44
_depthSurface = nullptr;
50
void Rails::load(const WalkNodeList &nodes, DepthSurface *depthSurface, int depthStyle) {
51
// Store the depth surface and depth style to use
52
_depthSurface = depthSurface;
53
_depthStyle = depthStyle;
55
// Load the passed node list
58
for (uint i = 0; i < nodes.size(); ++i)
59
_nodes.push_back(nodes[i]);
61
// Add two more empty nodes for the start and end points of any walk sequence
62
_nodes.push_back(WalkNode());
63
_nodes.push_back(WalkNode());
67
void Rails::setupRoute(bool bitFlag, const Common::Point &srcPos, const Common::Point &destPos) {
68
// Reset the nodes in as being inactive
69
for (uint i = 0; i < _nodes.size(); ++i)
70
_nodes[i]._active = false;
72
// Set the two extra walk nodes to the start and destination positions
73
setNodePosition(_nodes.size() - 2, srcPos);
74
setNodePosition(_nodes.size() - 1, destPos);
76
// Start constructing route node list
77
_routeLength = 0x3FFF;
78
_routeIndexes.clear();
80
// Recursively form a route from the destination walk node back to the player's position
81
setupRouteNode(&_tempRoute[0], _nodes.size() - 1, bitFlag ? 0xC000 : 0x8000, 0);
84
if (_routeIndexes.size() > 0) {
85
Common::Point currPos = srcPos;
86
for (int routeCtr = size() - 1; (routeCtr >= 0) && !_next; --routeCtr) {
87
int idx = _routeIndexes[routeCtr];
88
const Common::Point &pt = _nodes[idx]._walkPos;
90
_next = scanPath(currPos, pt);
96
void Rails::setupRouteNode(int *routeIndexP, int nodeIndex, int flags, int routeLength) {
97
WalkNode ¤tNode = _nodes[nodeIndex];
98
currentNode._active = true;
100
*routeIndexP++ = nodeIndex;
102
// Get the index of the ultimate source position (the player)
103
int subIndex = _nodes.size() - 2;
105
int distanceVal = _nodes[nodeIndex]._distances[subIndex];
106
if (distanceVal & flags) {
107
routeLength += distanceVal & 0x3FFF;
108
if (routeLength < _routeLength) {
109
// Found a new shorter route to destination, so set up the route with the found one
110
_routeIndexes.clear();
111
for (int i = 0; routeIndexP != &_tempRoute[i]; ++i)
112
_routeIndexes.push(_tempRoute[i]);
113
_routeLength = routeLength;
116
for (int idx = _nodes.size() - 2; idx > 0; --idx) {
117
int nodePos = idx - 1;
118
if (!_nodes[nodePos]._active && ((currentNode._distances[nodePos] & flags) != 0))
119
setupRouteNode(routeIndexP, nodePos, 0x8000, routeLength + (distanceVal & 0x3fff));
123
currentNode._active = false;
127
int Rails::scanPath(const Common::Point &srcPos, const Common::Point &destPos) {
128
// For compressed depth surfaces, always return 0
129
if (_depthStyle == 2)
132
int yDiff = destPos.y - srcPos.y;
133
int yAmount = MADS_SCREEN_WIDTH;
140
int xDiff = destPos.x - srcPos.x;
145
xDirection = -xDirection;
146
xAmount = MIN(yDiff, xDiff);
152
const byte *srcP = _depthSurface->getBasePtr(srcPos.x, srcPos.y);
156
for (int xCtr = 0; xCtr < xDiff; ++xCtr, srcP += xDirection) {
158
int v = (*srcP & 0x7F) >> 4;
162
// Inner loop for handling vertical movement
163
while (index >= xDiff) {
166
v = (*srcP & 0x7F) >> 4;
177
void Rails::resetRoute() {
178
_routeIndexes.clear();
182
const WalkNode &Rails::popNode() {
183
assert(!_routeIndexes.empty());
185
return _nodes[_routeIndexes.pop()];
188
void Rails::setNodePosition(int nodeIndex, const Common::Point &pt) {
189
int flags, hypotenuse;
191
_nodes[nodeIndex]._walkPos = pt;
193
// Recalculate inter-node lengths
194
for (uint idx = 0; idx < _nodes.size(); ++idx) {
196
if (idx == (uint)nodeIndex) {
200
flags = getRouteFlags(pt, _nodes[idx]._walkPos);
202
int xDiff = ABS(_nodes[idx]._walkPos.x - pt.x);
203
int yDiff = ABS(_nodes[idx]._walkPos.y - pt.y);
204
hypotenuse = (int)sqrt((double)(xDiff * xDiff + yDiff * yDiff));
206
if (hypotenuse >= 0x3FFF)
207
// Shouldn't ever be this large
210
entry = hypotenuse | flags;
213
_nodes[idx]._distances[nodeIndex] = entry;
214
_nodes[nodeIndex]._distances[idx] = entry;
218
int Rails::getRouteFlags(const Common::Point &src, const Common::Point &dest) {
222
int xDiff = ABS(dest.x - src.x);
223
int yDiff = ABS(dest.y - src.y);
224
int xDirection = dest.x >= src.x ? 1 : -1;
225
int yDirection = dest.y >= src.y ? _depthSurface->w : -_depthSurface->w;
228
minorDiff = MIN(xDiff, yDiff);
232
byte *srcP = _depthSurface->getBasePtr(src.x, src.y);
234
int totalCtr = minorDiff;
235
for (int xCtr = 0; xCtr < xDiff; ++xCtr, srcP += xDirection) {
238
if ((*srcP & 0x80) == 0)
247
while (totalCtr >= xDiff) {
250
if ((*srcP & 0x80) == 0)
268
void Rails::synchronize(Common::Serializer &s) {
269
s.syncAsSint16LE(_routeLength);
270
s.syncAsSint16LE(_next);
273
_routeIndexes.clear();
277
} // End of namespace MADS