diff options
author | uruk | 2014-05-30 11:14:47 +0200 |
---|---|---|
committer | uruk | 2014-05-30 11:14:47 +0200 |
commit | bb2f8dd68e1d6b2b30b07f60c0cd4e125b47ea4d (patch) | |
tree | 9a1e28cfb1eb1a322225c05adc0962a2f96ea521 /engines/mads/rails.cpp | |
parent | 5ad4e157e5398347651a0da0db07f9daf01bf373 (diff) | |
parent | 0a46d67baea121bed0511ce45bfdd8438a43d35d (diff) | |
download | scummvm-rg350-bb2f8dd68e1d6b2b30b07f60c0cd4e125b47ea4d.tar.gz scummvm-rg350-bb2f8dd68e1d6b2b30b07f60c0cd4e125b47ea4d.tar.bz2 scummvm-rg350-bb2f8dd68e1d6b2b30b07f60c0cd4e125b47ea4d.zip |
Merge branch 'master' of https://github.com/scummvm/scummvm into cge2
Diffstat (limited to 'engines/mads/rails.cpp')
-rw-r--r-- | engines/mads/rails.cpp | 277 |
1 files changed, 277 insertions, 0 deletions
diff --git a/engines/mads/rails.cpp b/engines/mads/rails.cpp new file mode 100644 index 0000000000..7f8a56d21b --- /dev/null +++ b/engines/mads/rails.cpp @@ -0,0 +1,277 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" +#include "mads/mads.h" +#include "mads/rails.h" + +namespace MADS { + +WalkNode::WalkNode() { + _active = false; + Common::fill(&_distances[0], &_distances[MAX_ROUTE_NODES], 0); +} + +void WalkNode::load(Common::SeekableReadStream *f) { + _walkPos.x = f->readSint16LE(); + _walkPos.y = f->readSint16LE(); + for (int i = 0; i < MAX_ROUTE_NODES; ++i) + _distances[i] = f->readUint16LE(); +} + +/*------------------------------------------------------------------------*/ + +Rails::Rails() { + _depthSurface = nullptr; + _routeLength = 0; + _depthStyle = 0; + _next = 0; +} + +void Rails::load(const WalkNodeList &nodes, DepthSurface *depthSurface, int depthStyle) { + // Store the depth surface and depth style to use + _depthSurface = depthSurface; + _depthStyle = depthStyle; + + // Load the passed node list + _nodes.clear(); + + for (uint i = 0; i < nodes.size(); ++i) + _nodes.push_back(nodes[i]); + + // Add two more empty nodes for the start and end points of any walk sequence + _nodes.push_back(WalkNode()); + _nodes.push_back(WalkNode()); +} + + +void Rails::setupRoute(bool bitFlag, const Common::Point &srcPos, const Common::Point &destPos) { + // Reset the nodes in as being inactive + for (uint i = 0; i < _nodes.size(); ++i) + _nodes[i]._active = false; + + // Set the two extra walk nodes to the start and destination positions + setNodePosition(_nodes.size() - 2, srcPos); + setNodePosition(_nodes.size() - 1, destPos); + + // Start constructing route node list + _routeLength = 0x3FFF; + _routeIndexes.clear(); + + // Recursively form a route from the destination walk node back to the player's position + setupRouteNode(&_tempRoute[0], _nodes.size() - 1, bitFlag ? 0xC000 : 0x8000, 0); + + _next = 0; + if (_routeIndexes.size() > 0) { + Common::Point currPos = srcPos; + for (int routeCtr = size() - 1; (routeCtr >= 0) && !_next; --routeCtr) { + int idx = _routeIndexes[routeCtr]; + const Common::Point &pt = _nodes[idx]._walkPos; + + _next = scanPath(currPos, pt); + currPos = pt; + } + } +} + +void Rails::setupRouteNode(int *routeIndexP, int nodeIndex, int flags, int routeLength) { + WalkNode ¤tNode = _nodes[nodeIndex]; + currentNode._active = true; + + *routeIndexP++ = nodeIndex; + + // Get the index of the ultimate source position (the player) + int subIndex = _nodes.size() - 2; + + int distanceVal = _nodes[nodeIndex]._distances[subIndex]; + if (distanceVal & flags) { + routeLength += distanceVal & 0x3FFF; + if (routeLength < _routeLength) { + // Found a new shorter route to destination, so set up the route with the found one + _routeIndexes.clear(); + for (int i = 0; routeIndexP != &_tempRoute[i]; ++i) + _routeIndexes.push(_tempRoute[i]); + _routeLength = routeLength; + } + } else { + for (int idx = _nodes.size() - 2; idx > 0; --idx) { + int nodePos = idx - 1; + if (!_nodes[nodePos]._active && ((currentNode._distances[nodePos] & flags) != 0)) + setupRouteNode(routeIndexP, nodePos, 0x8000, routeLength + (distanceVal & 0x3fff)); + } + } + + currentNode._active = false; +} + + +int Rails::scanPath(const Common::Point &srcPos, const Common::Point &destPos) { + // For compressed depth surfaces, always return 0 + if (_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.x; + 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 loop + for (int xCtr = 0; xCtr < xDiff; ++xCtr, srcP += xDirection) { + 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; + } + } + + return 0; +} + +void Rails::resetRoute() { + _routeIndexes.clear(); + _next = 0; +} + +const WalkNode &Rails::popNode() { + assert(!_routeIndexes.empty()); + + return _nodes[_routeIndexes.pop()]; +} + +void Rails::setNodePosition(int nodeIndex, const Common::Point &pt) { + 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); + + 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]._distances[nodeIndex] = entry; + _nodes[nodeIndex]._distances[idx] = entry; + } +} + +int Rails::getRouteFlags(const Common::Point &src, const Common::Point &dest) { + 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 minorDiff = 0; + if (dest.x < src.x) + minorDiff = MIN(xDiff, yDiff); + ++xDiff; + ++yDiff; + + byte *srcP = _depthSurface->getBasePtr(src.x, src.y); + + int totalCtr = minorDiff; + 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; +} + +void Rails::synchronize(Common::Serializer &s) { + s.syncAsSint16LE(_routeLength); + s.syncAsSint16LE(_next); + + if (s.isLoading()) { + _routeIndexes.clear(); + } +} + +} // End of namespace MADS |