aboutsummaryrefslogtreecommitdiff
path: root/engines/hopkins/lines.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/hopkins/lines.cpp')
-rw-r--r--engines/hopkins/lines.cpp2914
1 files changed, 2914 insertions, 0 deletions
diff --git a/engines/hopkins/lines.cpp b/engines/hopkins/lines.cpp
new file mode 100644
index 0000000000..6603708449
--- /dev/null
+++ b/engines/hopkins/lines.cpp
@@ -0,0 +1,2914 @@
+/* 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 "hopkins/lines.h"
+
+#include "hopkins/graphics.h"
+#include "hopkins/hopkins.h"
+
+#include "common/system.h"
+#include "common/textconsole.h"
+
+namespace Hopkins {
+
+LinesManager::LinesManager(HopkinsEngine *vm) {
+ _vm = vm;
+
+ for (int i = 0; i < MAX_LINES; ++i) {
+ Common::fill((byte *)&_zoneLine[i], (byte *)&_zoneLine[i] + sizeof(LigneZoneItem), 0);
+ Common::fill((byte *)&_lineItem[i], (byte *)&_lineItem[i] + sizeof(LigneItem), 0);
+ }
+
+ for (int i = 0; i < 4000; ++i)
+ Common::fill((byte *)&_smoothRoute[i], (byte *)&_smoothRoute[i] + sizeof(SmoothItem), 0);
+
+ for (int i = 0; i < 8001; ++i)
+ _bestRoute[i].set(0, 0, DIR_NONE);
+
+ for (int i = 0; i < 101; ++i) {
+ Common::fill((byte *)&_segment[i], (byte *)&_segment[i] + sizeof(SegmentItem), 0);
+ Common::fill((byte *)&_squareZone[i], (byte *)&_squareZone[i] + sizeof(SquareZoneItem), 0);
+ }
+
+ for (int i = 0; i < 105; ++i) {
+ _bobZone[i] = 0;
+ _bobZoneFl[i] = false;
+ }
+
+ for (int i = 0; i < 106; ++i)
+ Common::fill((byte *)&_zone[i], (byte *)&_zone[i] + sizeof(ZoneItem), 0);
+
+ _linesNumb = 0;
+ _newLineIdx = 0;
+ _newLineDataIdx = 0;
+ _newRouteIdx = 0;
+ _newPosX = 0;
+ _newPosY = 0;
+ _smoothMoveDirection = DIR_NONE;
+ _lastLine = 0;
+ _maxLineIdx = 0;
+ _pathFindingMaxDepth = 0;
+ _testRoute0 = NULL;
+ _testRoute1 = NULL;
+ _testRoute2 = NULL;
+ _lineBuf = NULL;
+ _route = NULL;
+ _currentSegmentId = 0;
+ _largeBuf = NULL;
+ _zoneSkipCount = 0;
+ _hotspotTextColor = 0;
+ _forceHideText = false;
+ _oldMouseZoneId = 0;
+ _oldMouseX = 0;
+ _oldMouseY = 0;
+ _oldRouteFromX = 0;
+ _oldRouteFromY = 0;
+ _oldRouteDestX = 0;
+ _oldRouteDestY = 0;
+ _oldZoneNum = 0;
+}
+
+LinesManager::~LinesManager() {
+ _vm->_globals->freeMemory(_largeBuf);
+ if (_testRoute0)
+ delete[] _testRoute0;
+ if (_testRoute1)
+ delete[] _testRoute1;
+ if (_testRoute2)
+ delete[] _testRoute2;
+}
+
+int LigneItem::appendToRouteInc(int from, int to, RouteItem *route, int index) {
+ if (to == -1)
+ to = _lineDataEndIdx;
+
+ for (int i = from; i < to; ++i)
+ route[index++].set(_lineData[2*i], _lineData[2*i+1], _directionRouteInc);
+ return index;
+}
+int LigneItem::appendToRouteDec(int from, int to, RouteItem *route, int index) {
+ if (from == -1)
+ from = _lineDataEndIdx - 1;
+
+ for (int i = from; i > to; --i)
+ route[index++].set(_lineData[2*i], _lineData[2*i+1], _directionRouteDec);
+ return index;
+}
+
+/**
+ * Load lines
+ */
+void LinesManager::loadLines(const Common::String &file) {
+ resetLines();
+ _linesNumb = 0;
+ _lastLine = 0;
+ byte *ptr = _vm->_fileIO->loadFile(file);
+ for (int idx = 0; READ_LE_INT16((uint16 *)ptr + (idx * 5)) != -1; idx++) {
+ addLine(idx,
+ (Directions)READ_LE_INT16((uint16 *)ptr + (idx * 5)),
+ READ_LE_INT16((uint16 *)ptr + (idx * 5) + 1),
+ READ_LE_INT16((uint16 *)ptr + (idx * 5) + 2),
+ READ_LE_INT16((uint16 *)ptr + (idx * 5) + 3),
+ READ_LE_INT16((uint16 *)ptr + (idx * 5) + 4));
+ }
+ initRoute();
+ _vm->_globals->freeMemory(ptr);
+}
+
+/**
+ * Check Hotspots in Inventory screen
+ * Returns the ID of the hotspot under mouse
+ */
+int LinesManager::checkInventoryHotspots(int posX, int posY) {
+ int hotspotId = 0;
+ if (posY >= 120 && posY <= 153)
+ hotspotId = checkInventoryHotspotsRow(posX, 1, false);
+ if (posY >= 154 && posY <= 191)
+ hotspotId = checkInventoryHotspotsRow(posX, 7, false);
+ if (posY >= 192 && posY <= 229)
+ hotspotId = checkInventoryHotspotsRow(posX, 13, false);
+ if (posY >= 230 && posY <= 267)
+ hotspotId = checkInventoryHotspotsRow(posX, 19, false);
+ if (posY >= 268 && posY <= 306)
+ hotspotId = checkInventoryHotspotsRow(posX, 25, true);
+ if (posY >= 268 && posY <= 288 && posX >= _vm->_graphicsMan->_scrollOffset + 424 && posX <= _vm->_graphicsMan->_scrollOffset + 478)
+ hotspotId = 30;
+ if (posY >= 290 && posY <= 306 && posX >= _vm->_graphicsMan->_scrollOffset + 424 && posX <= _vm->_graphicsMan->_scrollOffset + 478)
+ hotspotId = 31;
+ if (posY < 114 || posY > 306 || posX < _vm->_graphicsMan->_scrollOffset + 152 || posX > _vm->_graphicsMan->_scrollOffset + 484)
+ hotspotId = 32;
+
+ return hotspotId;
+}
+
+/**
+ * Check the hotspots in an inventory line
+ * Returns the hotspot Id under the mouse, if any.
+ */
+int LinesManager::checkInventoryHotspotsRow(int posX, int minZoneNum, bool lastRow) {
+ int result = minZoneNum;
+
+ if (posX >= _vm->_graphicsMan->_scrollOffset + 158 && posX < _vm->_graphicsMan->_scrollOffset + 208)
+ return result;
+
+ if (posX >= _vm->_graphicsMan->_scrollOffset + 208 && posX < _vm->_graphicsMan->_scrollOffset + 266) {
+ result += 1;
+ return result;
+ }
+
+ if (posX >= _vm->_graphicsMan->_scrollOffset + 266 && posX < _vm->_graphicsMan->_scrollOffset + 320) {
+ result += 2;
+ return result;
+ }
+
+ if (posX >= _vm->_graphicsMan->_scrollOffset + 320 && posX < _vm->_graphicsMan->_scrollOffset + 370) {
+ result += 3;
+ return result;
+ }
+
+ if (posX >= _vm->_graphicsMan->_scrollOffset + 370 && posX < _vm->_graphicsMan->_scrollOffset + 424) {
+ result += 4;
+ return result;
+ }
+
+ if (!lastRow && posX >= _vm->_graphicsMan->_scrollOffset + 424 && posX <= _vm->_graphicsMan->_scrollOffset + 478) {
+ result += 5;
+ return result;
+ }
+
+ return 0;
+}
+
+/**
+ * Add Zone Line
+ */
+void LinesManager::addZoneLine(int idx, int fromX, int fromY, int destX, int destY, int bobZoneIdx) {
+ int16 *zoneData;
+
+ if (fromX == fromY && fromY == destX && fromY == destY) {
+ _bobZoneFl[bobZoneIdx] = true;
+ _bobZone[bobZoneIdx] = fromY;
+ } else {
+ assert (idx <= MAX_LINES);
+ _zoneLine[idx]._zoneData = (int16 *)_vm->_globals->freeMemory((byte *)_zoneLine[idx]._zoneData);
+
+ int distX = abs(fromX - destX);
+ int distY = abs(fromY - destY);
+ int maxDist = 1;
+ if (distX <= distY)
+ maxDist += distY;
+ else
+ maxDist += distX;
+
+ zoneData = (int16 *)_vm->_globals->allocMemory(2 * sizeof(int16) * maxDist + (4 * sizeof(int16)));
+ assert(zoneData);
+
+ _zoneLine[idx]._zoneData = zoneData;
+
+ int16 *dataP = zoneData;
+ int stepX = 1000 * distX / maxDist;
+ int stepY = 1000 * distY / maxDist;
+ if (destX < fromX)
+ stepX = -stepX;
+ if (destY < fromY)
+ stepY = -stepY;
+ int smoothPosX = 1000 * fromX;
+ int smoothPosY = 1000 * fromY;
+ for (int i = 0; i < maxDist; i++) {
+ *dataP++ = smoothPosX / 1000;
+ *dataP++ = smoothPosY / 1000;
+
+ smoothPosX += stepX;
+ smoothPosY += stepY;
+ }
+ *dataP++ = -1;
+ *dataP++ = -1;
+
+ _zoneLine[idx]._count = maxDist;
+ _zoneLine[idx]._bobZoneIdx = bobZoneIdx;
+ }
+}
+
+/**
+ * Add Line
+ */
+void LinesManager::addLine(int lineIdx, Directions direction, int fromX, int fromY, int destX, int destY) {
+ assert (lineIdx <= MAX_LINES);
+
+ if (_linesNumb < lineIdx)
+ _linesNumb = lineIdx;
+
+ _lineItem[lineIdx]._lineData = (int16 *)_vm->_globals->freeMemory((byte *)_lineItem[lineIdx]._lineData);
+ int distX = abs(fromX - destX) + 1;
+ int distY = abs(fromY - destY) + 1;
+ int maxDist = distY;
+ if (distX > maxDist)
+ maxDist = distX;
+
+ byte *zoneData = _vm->_globals->allocMemory(4 * maxDist + 8);
+ assert (zoneData);
+
+ Common::fill(zoneData, zoneData + 4 * maxDist + 8, 0);
+ _lineItem[lineIdx]._lineData = (int16 *)zoneData;
+
+ int16 *curLineData = _lineItem[lineIdx]._lineData;
+ int stepX = 1000 * distX / (maxDist - 1);
+ int stepY = 1000 * distY / (maxDist - 1);
+ if (destX < fromX)
+ stepX = -stepX;
+ if (destY < fromY)
+ stepY = -stepY;
+ int dirX = (int)stepX / 1000; // -1: Left, 0: None, 1: Right
+ int dirY = (int)stepY / 1000; // -1: Up, 0: None, 1: Right
+ if (!dirX) {
+ if (dirY == -1) {
+ _lineItem[lineIdx]._directionRouteInc = DIR_UP;
+ _lineItem[lineIdx]._directionRouteDec = DIR_DOWN;
+ } else if (dirY == 1) {
+ _lineItem[lineIdx]._directionRouteInc = DIR_DOWN;
+ _lineItem[lineIdx]._directionRouteDec = DIR_UP;
+ }
+ // If dirY == 0, no move
+ } else if (dirX == 1) {
+ if (dirY == -1) {
+ _lineItem[lineIdx]._directionRouteInc = DIR_UP_RIGHT;
+ _lineItem[lineIdx]._directionRouteDec = DIR_DOWN_LEFT;
+ } else if (!dirY) {
+ _lineItem[lineIdx]._directionRouteInc = DIR_RIGHT;
+ _lineItem[lineIdx]._directionRouteDec = DIR_LEFT;
+ } else if (dirY == 1) {
+ _lineItem[lineIdx]._directionRouteInc = DIR_DOWN_RIGHT;
+ _lineItem[lineIdx]._directionRouteDec = DIR_UP_LEFT;
+ }
+ } else if (dirX == -1) {
+ if (dirY == 1) {
+ _lineItem[lineIdx]._directionRouteInc = DIR_DOWN_LEFT;
+ _lineItem[lineIdx]._directionRouteDec = DIR_UP_RIGHT;
+ } else if (!dirY) {
+ _lineItem[lineIdx]._directionRouteInc = DIR_LEFT;
+ _lineItem[lineIdx]._directionRouteDec = DIR_RIGHT;
+ } else if (dirY == -1) {
+ _lineItem[lineIdx]._directionRouteInc = DIR_UP_LEFT;
+ _lineItem[lineIdx]._directionRouteDec = DIR_DOWN_RIGHT;
+ }
+ }
+
+ // Second pass to soften cases where dirY == 0
+ if (dirX == 1) {
+ if (stepY > 250 && stepY <= 999) {
+ _lineItem[lineIdx]._directionRouteInc = DIR_DOWN_RIGHT;
+ _lineItem[lineIdx]._directionRouteDec = DIR_UP_LEFT;
+ } else if (stepY < -250 && stepY > -1000) {
+ _lineItem[lineIdx]._directionRouteInc = DIR_UP_RIGHT;
+ _lineItem[lineIdx]._directionRouteDec = DIR_DOWN_LEFT;
+ }
+ } else if (dirX == -1) {
+ if (stepY > 250 && stepY <= 999) {
+ _lineItem[lineIdx]._directionRouteInc = DIR_DOWN_LEFT;
+ _lineItem[lineIdx]._directionRouteDec = DIR_UP_RIGHT;
+ } else if (stepY < -250 && stepY > -1000) {
+ // In the original code, the test was on positive values and
+ // was impossible to meet.
+ _lineItem[lineIdx]._directionRouteInc = DIR_UP_LEFT;
+ _lineItem[lineIdx]._directionRouteDec = DIR_DOWN_RIGHT;
+ }
+ }
+
+ stepX = 1000 * distX / maxDist;
+ stepY = 1000 * distY / maxDist;
+ if (destX < fromX)
+ stepX = -stepX;
+ if (destY < fromY)
+ stepY = -stepY;
+ int smoothPosX = 1000 * fromX;
+ int smoothPosY = 1000 * fromY;
+ for (int i = 0; i < maxDist - 1; i++) {
+ curLineData[0] = smoothPosX / 1000;
+ curLineData[1] = smoothPosY / 1000;
+ curLineData += 2;
+
+ smoothPosX += stepX;
+ smoothPosY += stepY;
+ }
+ curLineData[0] = destX;
+ curLineData[1] = destY;
+
+ curLineData += 2;
+ curLineData[0] = -1;
+ curLineData[1] = -1;
+
+ _lineItem[lineIdx]._lineDataEndIdx = maxDist;
+ _lineItem[lineIdx]._direction = direction;
+
+ ++_linesNumb;
+}
+
+/**
+ * Check collision line
+ */
+bool LinesManager::checkCollisionLine(int xp, int yp, int *foundDataIdx, int *foundLineIdx, int startLineIdx, int endLineIdx) {
+ int16 *lineData;
+
+ int left = xp + 4;
+ int right = xp - 4;
+ int top = yp + 4;
+ int bottom = yp - 4;
+
+ *foundDataIdx = -1;
+ *foundLineIdx = -1;
+
+ for (int curLineIdx = startLineIdx; curLineIdx <= endLineIdx; curLineIdx++) {
+ lineData = _lineItem[curLineIdx]._lineData;
+
+ if (lineData == NULL)
+ continue;
+
+ bool collisionFl = true;
+ int lineStartX = lineData[0];
+ int lineStartY = lineData[1];
+ int lineDataIdx = 2 * _lineItem[curLineIdx]._lineDataEndIdx;
+ int lineEndX = lineData[lineDataIdx - 2];
+ int lineEndY = lineData[lineDataIdx - 1];
+ if (lineStartX >= lineEndX) {
+ if (right > lineStartX || left < lineEndX)
+ collisionFl = false;
+ } else { // lineStartX < lineEndX
+ if (left < lineStartX || right > lineEndX)
+ collisionFl = false;
+ }
+ if (lineStartY >= lineEndY) {
+ if (bottom > lineStartY || top < lineEndY)
+ collisionFl = false;
+ } else { // lineStartY < lineEndY
+ if (top < lineStartY || bottom > lineEndY)
+ collisionFl = false;
+ }
+
+ if (!collisionFl)
+ continue;
+
+ for (int idx = 0; idx < _lineItem[curLineIdx]._lineDataEndIdx; idx++) {
+ int lineX = lineData[0];
+ int lineY = lineData[1];
+ lineData += 2;
+
+ if ((xp == lineX || xp + 1 == lineX) && (yp == lineY || yp + 1 == lineY)) {
+ *foundDataIdx = idx;
+ *foundLineIdx = curLineIdx;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/**
+ * Init route
+ */
+void LinesManager::initRoute() {
+ int lineX = _lineItem[0]._lineData[0];
+ int lineY = _lineItem[0]._lineData[1];
+
+ int lineIdx = 1;
+ for (;;) {
+ int curDataIdx = _lineItem[lineIdx]._lineDataEndIdx;
+ int16 *curLineData = _lineItem[lineIdx]._lineData;
+
+ int curLineX = curLineData[2 * curDataIdx - 2];
+ int curLineY = curLineData[2 * curDataIdx - 1];
+ if (_vm->_graphicsMan->_maxX == curLineX || _vm->_graphicsMan->_maxY == curLineY ||
+ _vm->_graphicsMan->_minX == curLineX || _vm->_graphicsMan->_minY == curLineY ||
+ (lineX == curLineX && lineY == curLineY))
+ break;
+ if (lineIdx == MAX_LINES)
+ error("ERROR - LAST LINE NOT FOUND");
+
+ int16 *nextLineData = _lineItem[lineIdx + 1]._lineData;
+ if (!nextLineData)
+ break;
+ if (nextLineData[0] != curLineX && nextLineData[1] != curLineY)
+ break;
+ ++lineIdx;
+ }
+
+ _lastLine = lineIdx;
+ for (int idx = 1; idx < MAX_LINES; idx++) {
+ if ((_lineItem[idx]._lineDataEndIdx < _maxLineIdx) && (idx != _lastLine + 1)) {
+ _lineItem[idx]._directionRouteInc = _lineItem[idx - 1]._directionRouteInc;
+ _lineItem[idx]._directionRouteDec = _lineItem[idx - 1]._directionRouteDec;
+ }
+ }
+}
+
+// Avoid obstacle
+int LinesManager::avoidObstacle(int lineIdx, int lineDataIdx, int routeIdx, int destLineIdx, int destLineDataIdx, RouteItem *route) {
+ int curLineIdx = lineIdx;
+ int curLineDataIdx = lineDataIdx;
+ int curRouteIdx = routeIdx;
+ if (lineIdx < destLineIdx) {
+ curRouteIdx = _lineItem[lineIdx].appendToRouteInc(lineDataIdx, -1, route, curRouteIdx);
+
+ for (int i = lineIdx + 1; i < destLineIdx; i++)
+ curRouteIdx = _lineItem[i].appendToRouteInc(0, -1, route, curRouteIdx);
+
+ curLineDataIdx = 0;
+ curLineIdx = destLineIdx;
+ }
+ if (curLineIdx > destLineIdx) {
+ curRouteIdx = _lineItem[curLineIdx].appendToRouteDec(curLineDataIdx, 0, route, curRouteIdx);
+ for (int i = curLineIdx - 1; i > destLineIdx; i--)
+ curRouteIdx = _lineItem[i].appendToRouteDec(-1, 0, route, curRouteIdx);
+ curLineDataIdx = _lineItem[destLineIdx]._lineDataEndIdx - 1;
+ curLineIdx = destLineIdx;
+ }
+ if (curLineIdx == destLineIdx) {
+ if (destLineDataIdx >= curLineDataIdx) {
+ curRouteIdx = _lineItem[destLineIdx].appendToRouteInc(curLineDataIdx, destLineDataIdx, route, curRouteIdx);
+ } else {
+ curRouteIdx = _lineItem[destLineIdx].appendToRouteDec(curLineDataIdx, destLineDataIdx, route, curRouteIdx);
+ }
+ }
+ return curRouteIdx;
+}
+
+// Avoid Obstacle, taking into account start/End lind Idx
+int LinesManager::avoidObstacleOnSegment(int lineIdx, int lineDataIdx, int routeIdx, int destLineIdx, int destLineDataIdx, RouteItem *route, int startLineIdx, int endLineIdx) {
+ int curLineIdx = lineIdx;
+ int curLineDataIdx = lineDataIdx;
+ int curRouteIdx = routeIdx;
+ if (destLineIdx < lineIdx) {
+ curRouteIdx = _lineItem[lineIdx].appendToRouteInc(lineDataIdx, -1, route, curRouteIdx);
+ int wrkLineIdx = lineIdx + 1;
+ if (wrkLineIdx == endLineIdx + 1)
+ wrkLineIdx = startLineIdx;
+ while (destLineIdx != wrkLineIdx) {
+ curRouteIdx = _lineItem[wrkLineIdx].appendToRouteInc(0, -1, route, curRouteIdx);
+ ++wrkLineIdx;
+ if (endLineIdx + 1 == wrkLineIdx)
+ wrkLineIdx = startLineIdx;
+ }
+ curLineDataIdx = 0;
+ curLineIdx = destLineIdx;
+ }
+ if (destLineIdx > curLineIdx) {
+ curRouteIdx = _lineItem[curLineIdx].appendToRouteDec(curLineDataIdx, 0, route, curRouteIdx);
+ int wrkLineIdx = curLineIdx - 1;
+ if (wrkLineIdx == startLineIdx - 1)
+ wrkLineIdx = endLineIdx;
+ while (destLineIdx != wrkLineIdx) {
+ curRouteIdx = _lineItem[wrkLineIdx].appendToRouteDec(-1, 0, route, curRouteIdx);
+ --wrkLineIdx;
+ if (startLineIdx - 1 == wrkLineIdx)
+ wrkLineIdx = endLineIdx;
+ }
+ curLineDataIdx = _lineItem[destLineIdx]._lineDataEndIdx - 1;
+ curLineIdx = destLineIdx;
+ }
+ if (destLineIdx == curLineIdx) {
+ if (destLineDataIdx >= curLineDataIdx) {
+ curRouteIdx = _lineItem[destLineIdx].appendToRouteInc(curLineDataIdx, destLineDataIdx, route, curRouteIdx);
+ } else {
+ curRouteIdx = _lineItem[destLineIdx].appendToRouteDec(curLineDataIdx, destLineDataIdx, route, curRouteIdx);
+ }
+ }
+ return curRouteIdx;
+}
+
+bool LinesManager::MIRACLE(int fromX, int fromY, int lineIdx, int destLineIdx, int routeIdx) {
+ int newLinesDataIdx = 0;
+ int newLinesIdx = 0;
+ int lineIdxLeft = 0;
+ int lineDataIdxLeft = 0;
+ int lineIdxRight = 0;
+ int lineDataIdxRight = 0;
+ int linesIdxUp = 0;
+ int linesDataIdxUp = 0;
+ int lineIdxDown = 0;
+ int lineDataIdxDown = 0;
+
+ int curX = fromX;
+ int curY = fromY;
+ int curLineIdx = lineIdx;
+ int tmpRouteIdx = routeIdx;
+ int dummyDataIdx;
+ if (checkCollisionLine(fromX, fromY, &dummyDataIdx, &curLineIdx, 0, _linesNumb)) {
+ switch (_lineItem[curLineIdx]._direction) {
+ case DIR_UP:
+ curY -= 2;
+ break;
+ case DIR_UP_RIGHT:
+ curY -= 2;
+ curX += 2;
+ break;
+ case DIR_RIGHT:
+ curX += 2;
+ break;
+ case DIR_DOWN_RIGHT:
+ curY += 2;
+ curX += 2;
+ break;
+ case DIR_DOWN:
+ curY += 2;
+ break;
+ case DIR_DOWN_LEFT:
+ curY += 2;
+ curX -= 2;
+ break;
+ case DIR_LEFT:
+ curX -= 2;
+ break;
+ case DIR_UP_LEFT:
+ curY -= 2;
+ curX -= 2;
+ break;
+ default:
+ break;
+ }
+ }
+
+ int stepVertIncCount = 0;
+ for (int i = curY; curY + 200 > i; i++) {
+ if (checkCollisionLine(curX, i, &lineDataIdxDown, &lineIdxDown, 0, _lastLine) == 1 && lineIdxDown <= _lastLine)
+ break;
+ lineDataIdxDown = 0;
+ lineIdxDown = -1;
+ ++stepVertIncCount;
+ }
+
+ int stepVertDecCount = 0;
+ for (int i = curY; curY - 200 < i; i--) {
+ if (checkCollisionLine(curX, i, &linesDataIdxUp, &linesIdxUp, 0, _lastLine) == 1 && linesIdxUp <= _lastLine)
+ break;
+ linesDataIdxUp = 0;
+ linesIdxUp = -1;
+ ++stepVertDecCount;
+ }
+
+ int stepHoriIncCount = 0;
+ for (int i = curX; curX + 200 > i; i++) {
+ if (checkCollisionLine(i, curY, &lineDataIdxRight, &lineIdxRight, 0, _lastLine) == 1 && lineIdxRight <= _lastLine)
+ break;
+ lineDataIdxRight = 0;
+ lineIdxRight = -1;
+ ++stepHoriIncCount;
+ }
+
+ int stepHoriDecCount = 0;
+ for (int i = curX; curX - 200 < i; i--) {
+ if (checkCollisionLine(i, curY, &lineDataIdxLeft, &lineIdxLeft, 0, _lastLine) == 1 && lineIdxLeft <= _lastLine)
+ break;
+ lineDataIdxLeft = 0;
+ lineIdxLeft = -1;
+ ++stepHoriDecCount;
+ }
+
+ if (destLineIdx > curLineIdx) {
+ if (linesIdxUp != -1 && linesIdxUp <= curLineIdx)
+ linesIdxUp = -1;
+ if (lineIdxRight != -1 && curLineIdx >= lineIdxRight)
+ lineIdxRight = -1;
+ if (lineIdxDown != -1 && curLineIdx >= lineIdxDown)
+ lineIdxDown = -1;
+ if (lineIdxLeft != -1 && curLineIdx >= lineIdxLeft)
+ lineIdxLeft = -1;
+ if (linesIdxUp != -1 && destLineIdx < linesIdxUp)
+ linesIdxUp = -1;
+ if (lineIdxRight != -1 && destLineIdx < lineIdxRight)
+ lineIdxRight = -1;
+ if (lineIdxDown != -1 && destLineIdx < lineIdxDown)
+ lineIdxDown = -1;
+ if (lineIdxLeft != -1 && destLineIdx < lineIdxLeft)
+ lineIdxLeft = -1;
+ } else if (destLineIdx < curLineIdx) {
+ if (linesIdxUp != -1 && linesIdxUp >= curLineIdx)
+ linesIdxUp = -1;
+ if (lineIdxRight != -1 && curLineIdx <= lineIdxRight)
+ lineIdxRight = -1;
+ if (lineIdxDown != -1 && curLineIdx <= lineIdxDown)
+ lineIdxDown = -1;
+ if (lineIdxLeft != -1 && curLineIdx <= lineIdxLeft)
+ lineIdxLeft = -1;
+ if (linesIdxUp != -1 && destLineIdx > linesIdxUp)
+ linesIdxUp = -1;
+ if (lineIdxRight != -1 && destLineIdx > lineIdxRight)
+ lineIdxRight = -1;
+ if (lineIdxDown != -1 && destLineIdx > lineIdxDown)
+ lineIdxDown = -1;
+ if (lineIdxLeft != -1 && destLineIdx > lineIdxLeft)
+ lineIdxLeft = -1;
+ }
+ if (linesIdxUp != -1 || lineIdxRight != -1 || lineIdxDown != -1 || lineIdxLeft != -1) {
+ Directions newDir = DIR_NONE;
+ if (destLineIdx > curLineIdx) {
+ if (lineIdxDown <= linesIdxUp && lineIdxRight <= linesIdxUp && lineIdxLeft <= linesIdxUp && linesIdxUp > curLineIdx)
+ newDir = DIR_UP;
+ if (lineIdxDown <= lineIdxRight && linesIdxUp <= lineIdxRight && lineIdxLeft <= lineIdxRight && curLineIdx < lineIdxRight)
+ newDir = DIR_RIGHT;
+ if (linesIdxUp <= lineIdxDown && lineIdxRight <= lineIdxDown && lineIdxLeft <= lineIdxDown && curLineIdx < lineIdxDown)
+ newDir = DIR_DOWN;
+ if (lineIdxDown <= lineIdxLeft && lineIdxRight <= lineIdxLeft && linesIdxUp <= lineIdxLeft && curLineIdx < lineIdxLeft)
+ newDir = DIR_LEFT;
+ } else if (destLineIdx < curLineIdx) {
+ if (linesIdxUp == -1)
+ linesIdxUp = INVALID_LINE_VALUE;
+ if (lineIdxRight == -1)
+ lineIdxRight = INVALID_LINE_VALUE;
+ if (lineIdxDown == -1)
+ lineIdxDown = INVALID_LINE_VALUE;
+ if (lineIdxLeft == -1)
+ lineIdxLeft = INVALID_LINE_VALUE;
+ if (linesIdxUp != INVALID_LINE_VALUE && lineIdxDown >= linesIdxUp && lineIdxRight >= linesIdxUp && lineIdxLeft >= linesIdxUp && linesIdxUp < curLineIdx)
+ newDir = DIR_UP;
+ if (lineIdxRight != INVALID_LINE_VALUE && lineIdxDown >= lineIdxRight && linesIdxUp >= lineIdxRight && lineIdxLeft >= lineIdxRight && curLineIdx > lineIdxRight)
+ newDir = DIR_RIGHT;
+ if (lineIdxDown != INVALID_LINE_VALUE && linesIdxUp >= lineIdxDown && lineIdxRight >= lineIdxDown && lineIdxLeft >= lineIdxDown && curLineIdx > lineIdxDown)
+ newDir = DIR_DOWN;
+ if (lineIdxLeft != INVALID_LINE_VALUE && lineIdxDown >= lineIdxLeft && lineIdxRight >= lineIdxLeft && linesIdxUp >= lineIdxLeft && curLineIdx > lineIdxLeft)
+ newDir = DIR_LEFT;
+ }
+
+ switch(newDir) {
+ case DIR_UP:
+ newLinesIdx = linesIdxUp;
+ newLinesDataIdx = linesDataIdxUp;
+ for (int i = 0; i < stepVertDecCount; i++) {
+ if (checkCollisionLine(curX, curY - i, &linesDataIdxUp, &linesIdxUp, _lastLine + 1, _linesNumb) && _lastLine < linesIdxUp) {
+ int tmpRouteIdxUp = computeRouteIdx(linesIdxUp, linesDataIdxUp, curX, curY - i, curX, curY - stepVertDecCount, tmpRouteIdx, &_bestRoute[0]);
+ if (tmpRouteIdxUp == -1)
+ return false;
+ tmpRouteIdx = tmpRouteIdxUp;
+ if (_newPosY != -1)
+ i = _newPosY - curY;
+ }
+ _bestRoute[tmpRouteIdx].set(curX, curY - i, DIR_UP);
+ tmpRouteIdx++;
+ }
+ _newLineIdx = newLinesIdx;
+ _newLineDataIdx = newLinesDataIdx;
+ _newRouteIdx = tmpRouteIdx;
+ return true;
+ break;
+ case DIR_RIGHT:
+ newLinesIdx = lineIdxRight;
+ newLinesDataIdx = lineDataIdxRight;
+ for (int i = 0; i < stepHoriIncCount; i++) {
+ if (checkCollisionLine(i + curX, curY, &linesDataIdxUp, &linesIdxUp, _lastLine + 1, _linesNumb) && _lastLine < linesIdxUp) {
+ int tmpRouteIdxRight = computeRouteIdx(linesIdxUp, linesDataIdxUp, i + curX, curY, stepHoriIncCount + curX, curY, tmpRouteIdx, &_bestRoute[0]);
+ if (tmpRouteIdxRight == -1)
+ return false;
+ tmpRouteIdx = tmpRouteIdxRight;
+ if (_newPosX != -1)
+ i = _newPosX - curX;
+ }
+ _bestRoute[tmpRouteIdx].set(i + curX, curY, DIR_RIGHT);
+ tmpRouteIdx++;
+ }
+ _newLineIdx = newLinesIdx;
+ _newLineDataIdx = newLinesDataIdx;
+ _newRouteIdx = tmpRouteIdx;
+ return true;
+ break;
+ case DIR_DOWN:
+ newLinesIdx = lineIdxDown;
+ newLinesDataIdx = lineDataIdxDown;
+ for (int i = 0; i < stepVertIncCount; i++) {
+ if (checkCollisionLine(curX, i + curY, &linesDataIdxUp, &linesIdxUp, _lastLine + 1, _linesNumb) && _lastLine < linesIdxUp) {
+ int tmpRouteIdxDown = computeRouteIdx(linesIdxUp, linesDataIdxUp, curX, i + curY, curX, stepVertIncCount + curY, tmpRouteIdx, &_bestRoute[0]);
+ if (tmpRouteIdxDown == -1)
+ return false;
+ tmpRouteIdx = tmpRouteIdxDown;
+ if (_newPosY != -1)
+ i = curY - _newPosY;
+ }
+ _bestRoute[tmpRouteIdx].set(curX, i + curY, DIR_DOWN);
+ tmpRouteIdx++;
+ }
+ _newLineIdx = newLinesIdx;
+ _newLineDataIdx = newLinesDataIdx;
+ _newRouteIdx = tmpRouteIdx;
+ return true;
+ break;
+ case DIR_LEFT:
+ newLinesIdx = lineIdxLeft;
+ newLinesDataIdx = lineDataIdxLeft;
+ for (int i = 0; i < stepHoriDecCount; i++) {
+ if (checkCollisionLine(curX - i, curY, &linesDataIdxUp, &linesIdxUp, _lastLine + 1, _linesNumb) && _lastLine < linesIdxUp) {
+ int tmpRouteIdxLeft = computeRouteIdx(linesIdxUp, linesDataIdxUp, curX - i, curY, curX - stepHoriDecCount, curY, tmpRouteIdx, &_bestRoute[0]);
+ if (tmpRouteIdxLeft == -1)
+ return false;
+ tmpRouteIdx = tmpRouteIdxLeft;
+ if (_newPosX != -1)
+ i = curX - _newPosX;
+ }
+ _bestRoute[tmpRouteIdx].set(curX - i, curY, DIR_LEFT);
+ tmpRouteIdx++;
+ }
+ _newLineIdx = newLinesIdx;
+ _newLineDataIdx = newLinesDataIdx;
+ _newRouteIdx = tmpRouteIdx;
+ return true;
+ break;
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+int LinesManager::computeRouteIdx(int lineIdx, int dataIdx, int fromX, int fromY, int destX, int destY, int routerIdx, RouteItem *route) {
+ int result = routerIdx;
+ ++_pathFindingMaxDepth;
+ if (_pathFindingMaxDepth > 10) {
+ warning("PathFinding - Max depth reached");
+ route[routerIdx].invalidate();
+ return -1;
+ }
+ int lineX = _lineItem[lineIdx]._lineData[0];
+ int lineY = _lineItem[lineIdx]._lineData[1];
+ int startLineIdx = lineIdx;
+
+ int curLineDataEndIdx;
+ bool loopCond = false;
+ for (;;) {
+ int curLineIdx = startLineIdx - 1;
+ int endLineIdx = 2 * _lineItem[startLineIdx - 1]._lineDataEndIdx;
+
+ int16 *lineData = _lineItem[startLineIdx - 1]._lineData;
+ if (lineData == NULL)
+ break;
+ while (lineData[endLineIdx - 2] != lineX || lineY != lineData[endLineIdx - 1]) {
+ --curLineIdx;
+ if (_lastLine - 1 != curLineIdx) {
+ endLineIdx = 2 * _lineItem[curLineIdx]._lineDataEndIdx;
+ lineData = _lineItem[curLineIdx]._lineData;
+ if (lineData)
+ continue;
+ }
+ loopCond = true;
+ break;
+ }
+ if (loopCond)
+ break;
+
+ startLineIdx = curLineIdx;
+ lineX = lineData[0];
+ lineY = lineData[1];
+ }
+
+ int lastIdx = _lineItem[lineIdx]._lineDataEndIdx - 1;
+ int lastPosX = _lineItem[lineIdx]._lineData[(2 * lastIdx)];
+ int lastPosY = _lineItem[lineIdx]._lineData[(2 * lastIdx) + 1];
+ int endLineIdx = lineIdx;
+ int foundLineIdx, foundDataIdx;
+ loopCond = false;
+ for (;;) {
+ int curLineIdx = endLineIdx + 1;
+ int nextLineDataEndIdx = 2 * _lineItem[curLineIdx]._lineDataEndIdx;
+ int16 *lineData = _lineItem[curLineIdx]._lineData;
+ if (lineData == NULL)
+ break;
+ for (;;) {
+ curLineDataEndIdx = nextLineDataEndIdx;
+ if (lineData[0] == lastPosX && lastPosY == lineData[1])
+ break;
+
+ ++curLineIdx;
+ if (curLineIdx != _linesNumb + 1) {
+ nextLineDataEndIdx = 2 * _lineItem[curLineIdx]._lineDataEndIdx;
+ lineData = _lineItem[curLineIdx]._lineData;
+ if (lineData)
+ continue;
+ }
+ loopCond = true;
+ break;
+ }
+ if (loopCond)
+ break;
+
+ endLineIdx = curLineIdx;
+ lastPosX = lineData[curLineDataEndIdx - 2];
+ lastPosY = lineData[curLineDataEndIdx - 1];
+ }
+
+ int distX = abs(fromX - destX) + 1;
+ int distY = abs(fromY - destY) + 1;
+ int maxDist = distY;
+ if (distX > distY)
+ maxDist = distX;
+ int stepX = 1000 * distX / maxDist;
+ int stepY = 1000 * distY / maxDist;
+ int smoothPosX = 1000 * fromX;
+ int smoothPosY = 1000 * fromY;
+ if (destX < fromX)
+ stepX = -stepX;
+ if (destY < fromY)
+ stepY = -stepY;
+ if (maxDist > 800)
+ maxDist = 800;
+
+ Common::fill(&_lineBuf[0], &_lineBuf[1000], 0);
+ int bugLigIdx = 0;
+ for (int i = 0; i < maxDist + 1; i++) {
+ _lineBuf[bugLigIdx] = smoothPosX / 1000;
+ _lineBuf[bugLigIdx + 1] = smoothPosY / 1000;
+ smoothPosX += stepX;
+ smoothPosY += stepY;
+ bugLigIdx += 2;
+ }
+ bugLigIdx -= 2;
+ int destDataIdx = 0;
+ int destLineIdx = -1;
+ int bufX = 0;
+ int bufY = 0;
+ for (int i = maxDist + 1; i > 0; i--) {
+ if (checkCollisionLine(_lineBuf[bugLigIdx], _lineBuf[bugLigIdx + 1], &foundDataIdx, &foundLineIdx, startLineIdx, endLineIdx) && _lastLine < foundLineIdx) {
+ destLineIdx = foundLineIdx;
+ destDataIdx = foundDataIdx;
+ bufX = _lineBuf[bugLigIdx];
+ bufY = _lineBuf[bugLigIdx + 1];
+ break;
+ }
+ bugLigIdx -= 2;
+ }
+ int maxLineX = 0;
+ int minLineX = 0;
+ int maxLineY = 0;
+ int minLineY = 0;
+ for (int i = startLineIdx; i <= endLineIdx; ++i) {
+ int16 *lineData = _lineItem[i]._lineData;
+ if (lineData == NULL)
+ error("error in genial routine");
+ if (i == startLineIdx) {
+ minLineY = MIN(lineData[1], lineData[2 * _lineItem[i]._lineDataEndIdx - 1]);
+ maxLineY = MAX(lineData[1], lineData[2 * _lineItem[i]._lineDataEndIdx - 1]);
+
+ minLineX = MIN(lineData[0], lineData[2 * _lineItem[i]._lineDataEndIdx - 2]);
+ maxLineX = MAX(lineData[0], lineData[2 * _lineItem[i]._lineDataEndIdx - 2]);
+ } else {
+ if (lineData[1] < lineData[2 * _lineItem[i]._lineDataEndIdx - 1] && lineData[1] < minLineY)
+ minLineY = lineData[1];
+ if (lineData[2 * _lineItem[i]._lineDataEndIdx - 1] < lineData[1] && lineData[2 * _lineItem[i]._lineDataEndIdx - 1] < minLineY)
+ minLineY = lineData[2 * _lineItem[i]._lineDataEndIdx - 1];
+ if (lineData[1] > lineData[2 * _lineItem[i]._lineDataEndIdx - 1] && lineData[1] > maxLineY)
+ maxLineY = lineData[1];
+ if (lineData[2 * _lineItem[i]._lineDataEndIdx - 1] > lineData[1] && lineData[2 * _lineItem[i]._lineDataEndIdx - 1] > maxLineY)
+ maxLineY = lineData[2 * _lineItem[i]._lineDataEndIdx - 1];
+ if (lineData[0] < lineData[2 * _lineItem[i]._lineDataEndIdx - 2] && minLineX > lineData[0])
+ minLineX = lineData[0];
+ if (lineData[2 * _lineItem[i]._lineDataEndIdx - 2] < lineData[0] && minLineX > lineData[2 * _lineItem[i]._lineDataEndIdx - 2])
+ minLineX = lineData[2 * _lineItem[i]._lineDataEndIdx - 2];
+ if (lineData[0] > lineData[2 * _lineItem[i]._lineDataEndIdx - 2] && maxLineX < lineData[0])
+ maxLineX = lineData[0];
+ if (lineData[2 * _lineItem[i]._lineDataEndIdx - 2] > lineData[0] && maxLineX < lineData[2 * _lineItem[i]._lineDataEndIdx - 2])
+ maxLineX = lineData[2 * _lineItem[i]._lineDataEndIdx - 2];
+ }
+ }
+
+ minLineX -= 2;
+ minLineY -= 2;
+ maxLineX += 2;
+ maxLineY += 2;
+ if (destX >= minLineX && destX <= maxLineX && destY >= minLineY && destY <= maxLineY) {
+ int curY = destY;
+ int linesIdxUp = -1;
+ for (;;) {
+ --curY;
+ if (!checkCollisionLine(destX, curY, &foundDataIdx, &foundLineIdx, startLineIdx, endLineIdx))
+ break;
+
+ linesIdxUp = foundLineIdx;
+ if (!curY || minLineY > curY)
+ break;
+ }
+ curY = destY;
+ int lineIdxDown = -1;
+ for (;;) {
+ ++curY;
+ if (!checkCollisionLine(destX, curY, &foundDataIdx, &foundLineIdx, startLineIdx, endLineIdx))
+ break;
+
+ lineIdxDown = foundLineIdx;
+ if (_vm->_globals->_characterMaxPosY <= curY || maxLineY <= curY)
+ break;
+ }
+ int curX = destX;
+ int lineIdxRight = -1;
+ for (;;) {
+ ++curX;
+ if (!checkCollisionLine(curX, destY, &foundDataIdx, &foundLineIdx, startLineIdx, endLineIdx))
+ break;
+
+ lineIdxRight = foundLineIdx;
+
+ if (_vm->_graphicsMan->_maxX <= curX || maxLineX <= curX)
+ break;
+ }
+ curX = destX;
+ int lineIdxLeft = -1;
+ for(;;) {
+ --curX;
+ if (!checkCollisionLine(curX, destY, &foundDataIdx, &foundLineIdx, startLineIdx, endLineIdx))
+ break;
+ lineIdxLeft = foundLineIdx;
+ if (curX <= 0 || minLineX >= curX)
+ break;
+ }
+ if (lineIdxRight != -1 && lineIdxLeft != -1 && linesIdxUp != -1 && lineIdxDown != -1) {
+ route[routerIdx].invalidate();
+ return -1;
+ }
+ }
+ if (bufX < fromX - 1 || bufX > fromX + 1 || bufY < fromY - 1 || bufY > fromY + 1) {
+ _newPosX = bufX;
+ _newPosY = bufY;
+ if (lineIdx < destLineIdx) {
+ int stepCount = 0;
+ int curLineIdx = lineIdx;
+ do {
+ if (curLineIdx == startLineIdx - 1)
+ curLineIdx = endLineIdx;
+ ++stepCount;
+ --curLineIdx;
+ if (curLineIdx == startLineIdx - 1)
+ curLineIdx = endLineIdx;
+ } while (destLineIdx != curLineIdx);
+ if (abs(destLineIdx - lineIdx) == stepCount) {
+ if (dataIdx > abs(_lineItem[lineIdx]._lineDataEndIdx / 2)) {
+ result = avoidObstacle(lineIdx, dataIdx, routerIdx, destLineIdx, destDataIdx, route);
+ } else {
+ result = avoidObstacleOnSegment(lineIdx, dataIdx, routerIdx, destLineIdx, destDataIdx, route, startLineIdx, endLineIdx);
+ }
+ }
+ if (abs(destLineIdx - lineIdx) < stepCount)
+ result = avoidObstacle(lineIdx, dataIdx, result, destLineIdx, destDataIdx, route);
+ if (stepCount < abs(destLineIdx - lineIdx))
+ result = avoidObstacleOnSegment(lineIdx, dataIdx, result, destLineIdx, destDataIdx, route, startLineIdx, endLineIdx);
+ }
+ if (lineIdx > destLineIdx) {
+ int destStepCount = abs(lineIdx - destLineIdx);
+ int curLineIdx = lineIdx;
+ int curStepCount = 0;
+ do {
+ if (curLineIdx == endLineIdx + 1)
+ curLineIdx = startLineIdx;
+ ++curStepCount;
+ ++curLineIdx;
+ if (curLineIdx == endLineIdx + 1)
+ curLineIdx = startLineIdx;
+ } while (destLineIdx != curLineIdx);
+ if (destStepCount == curStepCount) {
+ if (dataIdx > abs(_lineItem[lineIdx]._lineDataEndIdx / 2)) {
+ result = avoidObstacleOnSegment(lineIdx, dataIdx, result, destLineIdx, destDataIdx, route, startLineIdx, endLineIdx);
+ } else {
+ result = avoidObstacle(lineIdx, dataIdx, result, destLineIdx, destDataIdx, route);
+ }
+ }
+ if (destStepCount < curStepCount)
+ result = avoidObstacle(lineIdx, dataIdx, result, destLineIdx, destDataIdx, route);
+ if (curStepCount < destStepCount)
+ result = avoidObstacleOnSegment(lineIdx, dataIdx, result, destLineIdx, destDataIdx, route, startLineIdx, endLineIdx);
+ }
+ if (lineIdx == destLineIdx)
+ result = avoidObstacle(lineIdx, dataIdx, result, lineIdx, destDataIdx, route);
+ for(;;) {
+ if (!checkCollisionLine(_newPosX, _newPosY, &foundDataIdx, &foundLineIdx, _lastLine + 1, _linesNumb))
+ break;
+
+ switch (_lineItem[foundLineIdx]._direction) {
+ case DIR_UP:
+ --_newPosY;
+ break;
+ case DIR_UP_RIGHT:
+ --_newPosY;
+ ++_newPosX;
+ break;
+ case DIR_RIGHT:
+ ++_newPosX;
+ break;
+ case DIR_DOWN_RIGHT:
+ ++_newPosY;
+ ++_newPosX;
+ break;
+ case DIR_DOWN:
+ ++_newPosY;
+ break;
+ case DIR_DOWN_LEFT:
+ ++_newPosY;
+ --_newPosX;
+ break;
+ case DIR_LEFT:
+ --_newPosX;
+ break;
+ case DIR_UP_LEFT:
+ --_newPosY;
+ --_newPosX;
+ break;
+ default:
+ break;
+ }
+ }
+ } else {
+ _newPosX = -1;
+ _newPosY = -1;
+ }
+ return result;
+}
+
+// Find Route from a point to the other
+RouteItem *LinesManager::findRoute(int fromX, int fromY, int destX, int destY) {
+ int foundLineIdx;
+ int foundDataIdx;
+ int curLineY = 0;
+ int curLineX = 0;
+ int stepArr[9];
+ int deltaArr[9];
+ int collLineDataIdxArr[9];
+ int collLineIdxArr[9];
+
+ int clipDestX = destX;
+ int clipDestY = destY;
+ int curLineIdx = 0;
+ int curLineDataIdx = 0;
+ int lineIdx = 0;
+ int lineDataIdx = 0;
+ Directions newDir = DIR_NONE;
+ if (destY <= 24)
+ clipDestY = 25;
+ if (!_vm->_globals->_checkDistanceFl) {
+ if (abs(fromX - _oldRouteFromX) <= 4 && abs(fromY - _oldRouteFromY) <= 4 &&
+ abs(_oldRouteDestX - destX) <= 4 && abs(_oldRouteDestY - clipDestY) <= 4)
+ return NULL;
+
+ if (abs(fromX - destX) <= 4 && abs(fromY - clipDestY) <= 4)
+ return NULL;
+
+ if (_oldZoneNum > 0 && _vm->_objectsMan->_zoneNum > 0 && _oldZoneNum == _vm->_objectsMan->_zoneNum)
+ return NULL;
+ }
+ _vm->_globals->_checkDistanceFl = false;
+ _oldZoneNum = _vm->_objectsMan->_zoneNum;
+ _oldRouteFromX = fromX;
+ _oldRouteDestX = destX;
+ _oldRouteFromY = fromY;
+ _oldRouteDestY = clipDestY;
+ _pathFindingMaxDepth = 0;
+ int routeIdx = 0;
+ if (destX <= 19)
+ clipDestX = 20;
+ if (clipDestY <= 19)
+ clipDestY = 20;
+ if (clipDestX > _vm->_graphicsMan->_maxX - 10)
+ clipDestX = _vm->_graphicsMan->_maxX - 10;
+ if (clipDestY > _vm->_globals->_characterMaxPosY)
+ clipDestY = _vm->_globals->_characterMaxPosY;
+
+ if (abs(fromX - clipDestX) <= 3 && abs(fromY - clipDestY) <= 3)
+ return NULL;
+
+ for (int i = 0; i <= 8; ++i) {
+ collLineIdxArr[i] = -1;
+ collLineDataIdxArr[i] = 0;
+ deltaArr[i] = INVALID_LINE_VALUE;
+ stepArr[i] = INVALID_LINE_VALUE;
+ }
+
+ if (characterRoute(fromX, fromY, clipDestX, clipDestY, -1, -1, 0) == 1)
+ return _bestRoute;
+
+ int tmpDelta = 0;
+ for (int tmpY = clipDestY; tmpY < _vm->_graphicsMan->_maxY; tmpY++, tmpDelta++) {
+ if (checkCollisionLine(clipDestX, tmpY, &collLineDataIdxArr[DIR_DOWN], &collLineIdxArr[DIR_DOWN], 0, _lastLine) && collLineIdxArr[DIR_DOWN] <= _lastLine)
+ break;
+ collLineDataIdxArr[DIR_DOWN] = 0;
+ collLineIdxArr[DIR_DOWN] = -1;
+ }
+ deltaArr[DIR_DOWN] = tmpDelta;
+
+ tmpDelta = 0;
+ for (int tmpY = clipDestY; tmpY > _vm->_graphicsMan->_minY; tmpY--, tmpDelta++) {
+ if (checkCollisionLine(clipDestX, tmpY, &collLineDataIdxArr[DIR_UP], &collLineIdxArr[DIR_UP], 0, _lastLine) && collLineIdxArr[DIR_UP] <= _lastLine)
+ break;
+ collLineDataIdxArr[DIR_UP] = 0;
+ collLineIdxArr[DIR_UP] = -1;
+ if (deltaArr[DIR_DOWN] < tmpDelta && collLineIdxArr[DIR_DOWN] != -1)
+ break;
+ }
+ deltaArr[DIR_UP] = tmpDelta;
+
+ tmpDelta = 0;
+ for (int tmpX = clipDestX; tmpX < _vm->_graphicsMan->_maxX; tmpX++) {
+ if (checkCollisionLine(tmpX, clipDestY, &collLineDataIdxArr[DIR_RIGHT], &collLineIdxArr[DIR_RIGHT], 0, _lastLine) && collLineIdxArr[DIR_RIGHT] <= _lastLine)
+ break;
+ collLineDataIdxArr[DIR_RIGHT] = 0;
+ collLineIdxArr[DIR_RIGHT] = -1;
+ ++tmpDelta;
+ if (deltaArr[DIR_UP] < tmpDelta && collLineIdxArr[DIR_UP] != -1)
+ break;
+ if (deltaArr[DIR_DOWN] < tmpDelta && collLineIdxArr[DIR_DOWN] != -1)
+ break;
+ }
+ deltaArr[DIR_RIGHT] = tmpDelta;
+
+ tmpDelta = 0;
+ for (int tmpX = clipDestX; tmpX > _vm->_graphicsMan->_minX; tmpX--) {
+ if (checkCollisionLine(tmpX, clipDestY, &collLineDataIdxArr[DIR_LEFT], &collLineIdxArr[DIR_LEFT], 0, _lastLine) && collLineIdxArr[DIR_LEFT] <= _lastLine)
+ break;
+ collLineDataIdxArr[DIR_LEFT] = 0;
+ collLineIdxArr[DIR_LEFT] = -1;
+ ++tmpDelta;
+ if (deltaArr[DIR_UP] < tmpDelta && collLineIdxArr[DIR_UP] != -1)
+ break;
+ if (deltaArr[DIR_DOWN] < tmpDelta && collLineIdxArr[DIR_DOWN] != -1)
+ break;
+ if (deltaArr[DIR_RIGHT] < tmpDelta && collLineIdxArr[DIR_RIGHT] != -1)
+ break;
+ }
+ deltaArr[DIR_LEFT] = tmpDelta;
+
+ if (collLineIdxArr[DIR_UP] < 0 || _lastLine < collLineIdxArr[DIR_UP])
+ collLineIdxArr[DIR_UP] = -1;
+ if (collLineIdxArr[DIR_RIGHT] < 0 || _lastLine < collLineIdxArr[DIR_RIGHT])
+ collLineIdxArr[DIR_RIGHT] = -1;
+ if (collLineIdxArr[DIR_DOWN] < 0 || _lastLine < collLineIdxArr[DIR_DOWN])
+ collLineIdxArr[DIR_DOWN] = -1;
+ if (collLineIdxArr[DIR_LEFT] < 0 || _lastLine < collLineIdxArr[DIR_LEFT])
+ collLineIdxArr[DIR_LEFT] = -1;
+ if (collLineIdxArr[DIR_UP] < 0)
+ deltaArr[DIR_UP] = INVALID_LINE_VALUE;
+ if (collLineIdxArr[DIR_RIGHT] < 0)
+ deltaArr[DIR_RIGHT] = INVALID_LINE_VALUE;
+ if (collLineIdxArr[DIR_DOWN] < 0)
+ deltaArr[DIR_DOWN] = INVALID_LINE_VALUE;
+ if (collLineIdxArr[DIR_LEFT] < 0)
+ deltaArr[DIR_LEFT] = INVALID_LINE_VALUE;
+ if (collLineIdxArr[DIR_UP] == -1 && collLineIdxArr[DIR_RIGHT] == -1 && collLineIdxArr[DIR_DOWN] == -1 && collLineIdxArr[DIR_LEFT] == -1)
+ return NULL;
+
+ if (collLineIdxArr[DIR_DOWN] != -1 && deltaArr[DIR_UP] >= deltaArr[DIR_DOWN] && deltaArr[DIR_RIGHT] >= deltaArr[DIR_DOWN] && deltaArr[DIR_LEFT] >= deltaArr[DIR_DOWN]) {
+ curLineIdx = collLineIdxArr[DIR_DOWN];
+ curLineDataIdx = collLineDataIdxArr[DIR_DOWN];
+ } else if (collLineIdxArr[DIR_UP] != -1 && deltaArr[DIR_DOWN] >= deltaArr[DIR_UP] && deltaArr[DIR_RIGHT] >= deltaArr[DIR_UP] && deltaArr[DIR_LEFT] >= deltaArr[DIR_UP]) {
+ curLineIdx = collLineIdxArr[DIR_UP];
+ curLineDataIdx = collLineDataIdxArr[DIR_UP];
+ } else if (collLineIdxArr[DIR_RIGHT] != -1 && deltaArr[DIR_UP] >= deltaArr[DIR_RIGHT] && deltaArr[DIR_DOWN] >= deltaArr[DIR_RIGHT] && deltaArr[DIR_LEFT] >= deltaArr[DIR_RIGHT]) {
+ curLineIdx = collLineIdxArr[DIR_RIGHT];
+ curLineDataIdx = collLineDataIdxArr[DIR_RIGHT];
+ } else if (collLineIdxArr[DIR_LEFT] != -1 && deltaArr[DIR_DOWN] >= deltaArr[DIR_LEFT] && deltaArr[DIR_RIGHT] >= deltaArr[DIR_LEFT] && deltaArr[DIR_UP] >= deltaArr[DIR_LEFT]) {
+ curLineIdx = collLineIdxArr[DIR_LEFT];
+ curLineDataIdx = collLineDataIdxArr[DIR_LEFT];
+ }
+
+ for (int i = 0; i <= 8; ++i) {
+ collLineIdxArr[i] = -1;
+ collLineDataIdxArr[i] = 0;
+ deltaArr[i] = INVALID_LINE_VALUE;
+ stepArr[i] = INVALID_LINE_VALUE;
+ }
+
+ tmpDelta = 0;
+ for (int tmpY = fromY; tmpY < _vm->_graphicsMan->_maxY; tmpY++, tmpDelta++) {
+ if (checkCollisionLine(fromX, tmpY, &collLineDataIdxArr[DIR_DOWN], &collLineIdxArr[DIR_DOWN], 0, _lastLine) && collLineIdxArr[DIR_DOWN] <= _lastLine)
+ break;
+ collLineDataIdxArr[DIR_DOWN] = 0;
+ collLineIdxArr[DIR_DOWN] = -1;
+ }
+ deltaArr[DIR_DOWN] = tmpDelta + 1;
+
+ tmpDelta = 0;
+ for (int tmpY = fromY; tmpY > _vm->_graphicsMan->_minY; tmpY--) {
+ if (checkCollisionLine(fromX, tmpY, &collLineDataIdxArr[DIR_UP], &collLineIdxArr[DIR_UP], 0, _lastLine) && collLineIdxArr[DIR_UP] <= _lastLine)
+ break;
+ collLineDataIdxArr[DIR_UP] = 0;
+ collLineIdxArr[DIR_UP] = -1;
+ ++tmpDelta;
+ if (collLineIdxArr[DIR_DOWN] != -1 && tmpDelta > 80)
+ break;
+ }
+ deltaArr[DIR_UP] = tmpDelta + 1;
+
+ tmpDelta = 0;
+ for (int tmpX = fromX; tmpX < _vm->_graphicsMan->_maxX; tmpX++) {
+ if (checkCollisionLine(tmpX, fromY, &collLineDataIdxArr[DIR_RIGHT], &collLineIdxArr[DIR_RIGHT], 0, _lastLine) && collLineIdxArr[DIR_RIGHT] <= _lastLine)
+ break;
+ collLineDataIdxArr[DIR_RIGHT] = 0;
+ collLineIdxArr[DIR_RIGHT] = -1;
+ ++tmpDelta;
+ if ((collLineIdxArr[DIR_DOWN] != -1 || collLineIdxArr[DIR_UP] != -1) && (tmpDelta > 100))
+ break;
+ }
+ deltaArr[DIR_RIGHT] = tmpDelta + 1;
+
+ tmpDelta = 0;
+ for (int tmpX = fromX; tmpX > _vm->_graphicsMan->_minX; tmpX--) {
+ if (checkCollisionLine(tmpX, fromY, &collLineDataIdxArr[DIR_LEFT], &collLineIdxArr[DIR_LEFT], 0, _lastLine) && collLineIdxArr[DIR_LEFT] <= _lastLine)
+ break;
+ collLineDataIdxArr[DIR_LEFT] = 0;
+ collLineIdxArr[DIR_LEFT] = -1;
+ ++tmpDelta;
+ if ((collLineIdxArr[DIR_DOWN] != -1 || collLineIdxArr[DIR_UP] != -1 || collLineIdxArr[DIR_RIGHT] != -1) && (tmpDelta > 100))
+ break;
+ }
+ deltaArr[DIR_LEFT] = tmpDelta + 1;
+
+ if (collLineIdxArr[DIR_UP] != -1)
+ stepArr[DIR_UP] = abs(collLineIdxArr[DIR_UP] - curLineIdx);
+
+ if (collLineIdxArr[DIR_RIGHT] != -1)
+ stepArr[DIR_RIGHT] = abs(collLineIdxArr[DIR_RIGHT] - curLineIdx);
+
+ if (collLineIdxArr[DIR_DOWN] != -1)
+ stepArr[DIR_DOWN] = abs(collLineIdxArr[DIR_DOWN] - curLineIdx);
+
+ if (collLineIdxArr[DIR_LEFT] != -1)
+ stepArr[DIR_LEFT] = abs(collLineIdxArr[DIR_LEFT] - curLineIdx);
+
+ if (collLineIdxArr[DIR_UP] == -1 && collLineIdxArr[DIR_RIGHT] == -1 && collLineIdxArr[DIR_DOWN] == -1 && collLineIdxArr[DIR_LEFT] == -1)
+ error("Nearest point not found");
+
+ int delta = 0;
+ if (collLineIdxArr[DIR_UP] != -1 && stepArr[DIR_RIGHT] >= stepArr[DIR_UP] && stepArr[DIR_DOWN] >= stepArr[DIR_UP] && stepArr[DIR_LEFT] >= stepArr[DIR_UP]) {
+ lineIdx = collLineIdxArr[DIR_UP];
+ delta = deltaArr[DIR_UP];
+ newDir = DIR_UP;
+ lineDataIdx = collLineDataIdxArr[DIR_UP];
+ } else if (collLineIdxArr[DIR_DOWN] != -1 && stepArr[DIR_RIGHT] >= stepArr[DIR_DOWN] && stepArr[DIR_UP] >= stepArr[DIR_DOWN] && stepArr[DIR_LEFT] >= stepArr[DIR_DOWN]) {
+ lineIdx = collLineIdxArr[DIR_DOWN];
+ delta = deltaArr[DIR_DOWN];
+ newDir = DIR_DOWN;
+ lineDataIdx = collLineDataIdxArr[DIR_DOWN];
+ } else if (collLineIdxArr[DIR_RIGHT] != -1 && stepArr[DIR_UP] >= stepArr[DIR_RIGHT] && stepArr[DIR_DOWN] >= stepArr[DIR_RIGHT] && stepArr[DIR_LEFT] >= stepArr[DIR_RIGHT]) {
+ lineIdx = collLineIdxArr[DIR_RIGHT];
+ delta = deltaArr[DIR_RIGHT];
+ newDir = DIR_RIGHT;
+ lineDataIdx = collLineDataIdxArr[DIR_RIGHT];
+ } else if (collLineIdxArr[DIR_LEFT] != -1 && stepArr[DIR_UP] >= stepArr[DIR_LEFT] && stepArr[DIR_DOWN] >= stepArr[DIR_LEFT] && stepArr[DIR_RIGHT] >= stepArr[DIR_LEFT]) {
+ lineIdx = collLineIdxArr[DIR_LEFT];
+ delta = deltaArr[DIR_LEFT];
+ newDir = DIR_LEFT;
+ lineDataIdx = collLineDataIdxArr[DIR_LEFT];
+ }
+
+ int bestRouteNum = characterRoute(fromX, fromY, clipDestX, clipDestY, lineIdx, curLineIdx, 0);
+
+ if (bestRouteNum == 1)
+ return _bestRoute;
+
+ if (bestRouteNum == 2) {
+ lineIdx = _newLineIdx;
+ lineDataIdx = _newLineDataIdx;
+ routeIdx = _newRouteIdx;
+ } else {
+ switch (newDir) {
+ case DIR_UP:
+ for (int deltaY = 0; deltaY < delta; deltaY++) {
+ if (checkCollisionLine(fromX, fromY - deltaY, &foundDataIdx, &foundLineIdx, _lastLine + 1, _linesNumb) && _lastLine < foundLineIdx) {
+ int tmpRouteIdx = computeRouteIdx(foundLineIdx, foundDataIdx, fromX, fromY - deltaY, fromX, fromY - delta, routeIdx, _bestRoute);
+ if (tmpRouteIdx == -1) {
+ _bestRoute[routeIdx].invalidate();
+ return &_bestRoute[0];
+ }
+ routeIdx = tmpRouteIdx;
+ if (_newPosY != -1)
+ deltaY = fromY - _newPosY;
+ }
+ _bestRoute[routeIdx].set(fromX, fromY - deltaY, DIR_UP);
+ routeIdx++;
+ }
+ break;
+ case DIR_DOWN:
+ for (int deltaY = 0; deltaY < delta; deltaY++) {
+ if (checkCollisionLine(fromX, deltaY + fromY, &foundDataIdx, &foundLineIdx, _lastLine + 1, _linesNumb)
+ && _lastLine < foundLineIdx) {
+ int tmpRouteIdx = computeRouteIdx(foundLineIdx, foundDataIdx, fromX, deltaY + fromY, fromX, delta + fromY, routeIdx, &_bestRoute[0]);
+ if (tmpRouteIdx == -1) {
+ _bestRoute[routeIdx].invalidate();
+ return &_bestRoute[0];
+ }
+ routeIdx = tmpRouteIdx;
+ if (_newPosY != -1)
+ deltaY = _newPosY - fromY;
+ }
+ _bestRoute[routeIdx].set(fromX, fromY + deltaY, DIR_DOWN);
+ routeIdx++;
+ }
+ break;
+ case DIR_LEFT:
+ for (int deltaX = 0; deltaX < delta; deltaX++) {
+ if (checkCollisionLine(fromX - deltaX, fromY, &foundDataIdx, &foundLineIdx, _lastLine + 1, _linesNumb) && _lastLine < foundLineIdx) {
+ int tmpRouteIdx = computeRouteIdx(foundLineIdx, foundDataIdx, fromX - deltaX, fromY, fromX - delta, fromY, routeIdx, &_bestRoute[0]);
+ if (tmpRouteIdx == -1) {
+ _bestRoute[routeIdx].invalidate();
+ return &_bestRoute[0];
+ }
+ routeIdx = tmpRouteIdx;
+ if (_newPosX != -1)
+ deltaX = fromX - _newPosX;
+ }
+ _bestRoute[routeIdx].set(fromX - deltaX, fromY, DIR_LEFT);
+ routeIdx++;
+ }
+ break;
+ case DIR_RIGHT:
+ for (int deltaX = 0; deltaX < delta; deltaX++) {
+ if (checkCollisionLine(deltaX + fromX, fromY, &foundDataIdx, &foundLineIdx, _lastLine + 1, _linesNumb) && _lastLine < foundLineIdx) {
+ int tmpRouteIdx = computeRouteIdx(foundLineIdx, foundDataIdx, deltaX + fromX, fromY, delta + fromX, fromY, routeIdx, &_bestRoute[0]);
+ if (tmpRouteIdx == -1) {
+ _bestRoute[routeIdx].invalidate();
+ return &_bestRoute[0];
+ }
+ routeIdx = tmpRouteIdx;
+ if (_newPosX != -1)
+ deltaX = _newPosX - fromX;
+ }
+ _bestRoute[routeIdx].set(fromX + deltaX, fromY, DIR_RIGHT);
+ routeIdx++;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ bool loopCond;
+ do {
+ loopCond = false;
+ if (lineIdx < curLineIdx) {
+ for (int i = lineDataIdx; _lineItem[lineIdx]._lineDataEndIdx > i; ++i) {
+ curLineX = _lineItem[lineIdx]._lineData[2 * i];
+ curLineY = _lineItem[lineIdx]._lineData[2 * i + 1];
+ _bestRoute[routeIdx].set(_lineItem[lineIdx]._lineData[2 * i], _lineItem[lineIdx]._lineData[2 * i + 1], _lineItem[lineIdx]._directionRouteInc);
+ routeIdx++;
+ }
+ for (int idx = lineIdx + 1; idx < curLineIdx; idx++) {
+ for (int dataIdx = 0; _lineItem[idx]._lineDataEndIdx > dataIdx; dataIdx++) {
+ curLineX = _lineItem[idx]._lineData[2 * dataIdx];
+ curLineY = _lineItem[idx]._lineData[2 * dataIdx + 1];
+ _bestRoute[routeIdx].set(_lineItem[idx]._lineData[2 * dataIdx], _lineItem[idx]._lineData[2 * dataIdx + 1], _lineItem[idx]._directionRouteInc);
+ routeIdx++;
+ if (_lineItem[idx]._lineDataEndIdx > 30 && dataIdx == _lineItem[idx]._lineDataEndIdx / 2) {
+ bestRouteNum = characterRoute(_lineItem[idx]._lineData[2 * dataIdx], _lineItem[idx]._lineData[2 * dataIdx + 1], clipDestX, clipDestY, idx, curLineIdx, routeIdx);
+ if (bestRouteNum == 1)
+ return &_bestRoute[0];
+ if (bestRouteNum == 2 || MIRACLE(curLineX, curLineY, idx, curLineIdx, routeIdx)) {
+ lineIdx = _newLineIdx;
+ lineDataIdx = _newLineDataIdx;
+ routeIdx = _newRouteIdx;
+ loopCond = true;
+ break;
+ }
+ }
+ }
+
+ if (loopCond)
+ break;
+
+ bestRouteNum = characterRoute(curLineX, curLineY, clipDestX, clipDestY, idx, curLineIdx, routeIdx);
+ if (bestRouteNum == 1)
+ return &_bestRoute[0];
+ if (bestRouteNum == 2 || MIRACLE(curLineX, curLineY, idx, curLineIdx, routeIdx)) {
+ lineIdx = _newLineIdx;
+ lineDataIdx = _newLineDataIdx;
+ routeIdx = _newRouteIdx;
+ loopCond = true;
+ break;
+ }
+ }
+ if (loopCond)
+ continue;
+
+ lineDataIdx = 0;
+ lineIdx = curLineIdx;
+ }
+ if (lineIdx > curLineIdx) {
+ for (int dataIdx = lineDataIdx; dataIdx > 0; dataIdx--) {
+ curLineX = _lineItem[lineIdx]._lineData[2 * dataIdx];
+ curLineY = _lineItem[lineIdx]._lineData[2 * dataIdx + 1];
+
+ _bestRoute[routeIdx].set(_lineItem[lineIdx]._lineData[2 * dataIdx], _lineItem[lineIdx]._lineData[2 * dataIdx + 1], _lineItem[lineIdx]._directionRouteDec);
+ routeIdx++;
+ }
+ for (int i = lineIdx - 1; i > curLineIdx; i--) {
+ for (int dataIdx = _lineItem[i]._lineDataEndIdx - 1; dataIdx > -1; dataIdx--) {
+ curLineX = _lineItem[i]._lineData[2 * dataIdx];
+ curLineY = _lineItem[i]._lineData[2 * dataIdx + 1];
+ _bestRoute[routeIdx].set(_lineItem[i]._lineData[2 * dataIdx], _lineItem[i]._lineData[2 * dataIdx + 1], _lineItem[i]._directionRouteDec);
+ routeIdx++;
+ if (_lineItem[i]._lineDataEndIdx > 30 && dataIdx == _lineItem[i]._lineDataEndIdx / 2) {
+ bestRouteNum = characterRoute(curLineX, curLineY, clipDestX, clipDestY, i, curLineIdx, routeIdx);
+ if (bestRouteNum == 1)
+ return &_bestRoute[0];
+ if (bestRouteNum == 2 || MIRACLE(curLineX, curLineY, i, curLineIdx, routeIdx)) {
+ lineIdx = _newLineIdx;
+ lineDataIdx = _newLineDataIdx;
+ routeIdx = _newRouteIdx;
+ loopCond = true;
+ break;
+ }
+ }
+ }
+
+ if (loopCond)
+ break;
+
+ bestRouteNum = characterRoute(curLineX, curLineY, clipDestX, clipDestY, i, curLineIdx, routeIdx);
+ if (bestRouteNum == 1)
+ return &_bestRoute[0];
+ if (bestRouteNum == 2 || MIRACLE(curLineX, curLineY, i, curLineIdx, routeIdx)) {
+ lineIdx = _newLineIdx;
+ lineDataIdx = _newLineDataIdx;
+ routeIdx = _newRouteIdx;
+ loopCond = true;
+ break;
+ }
+ }
+
+ if (!loopCond) {
+ lineDataIdx = _lineItem[curLineIdx]._lineDataEndIdx - 1;
+ lineIdx = curLineIdx;
+ }
+ }
+ } while (loopCond);
+
+ if (lineIdx == curLineIdx) {
+ if (lineDataIdx <= curLineDataIdx)
+ routeIdx = _lineItem[curLineIdx].appendToRouteInc(lineDataIdx, curLineDataIdx, _bestRoute, routeIdx);
+ else
+ routeIdx = _lineItem[curLineIdx].appendToRouteDec(lineDataIdx, curLineDataIdx, _bestRoute, routeIdx);
+ }
+ if (characterRoute(_bestRoute[routeIdx - 1]._x, _bestRoute[routeIdx - 1]._y, clipDestX, clipDestY, -1, -1, routeIdx) != 1) {
+ _bestRoute[routeIdx].invalidate();
+ }
+
+ return &_bestRoute[0];
+}
+
+void LinesManager::useRoute0(int idx, int curRouteIdx) {
+ if (idx) {
+ int i = 0;
+ do {
+ assert(curRouteIdx <= 8000);
+ _bestRoute[curRouteIdx++] = _testRoute0[i++];
+ } while (_testRoute0[i].isValid());
+ }
+ _bestRoute[curRouteIdx].invalidate();
+}
+
+void LinesManager::useRoute1(int idx, int curRouteIdx) {
+ if (idx) {
+ int i = 0;
+ do {
+ assert(curRouteIdx <= 8000);
+ _bestRoute[curRouteIdx++] = _testRoute1[i++];
+ } while (_testRoute1[i].isValid());
+ }
+ _bestRoute[curRouteIdx].invalidate();
+}
+
+void LinesManager::useRoute2(int idx, int curRouteIdx) {
+ if (idx) {
+ int i = 0;
+ do {
+ assert(curRouteIdx <= 8000);
+ _bestRoute[curRouteIdx++] = _testRoute2[i++];
+ } while (_testRoute2[i].isValid());
+ }
+ _bestRoute[curRouteIdx].invalidate();
+}
+
+int LinesManager::characterRoute(int fromX, int fromY, int destX, int destY, int startLineIdx, int endLineIdx, int routeIdx) {
+ int collDataIdxRoute2 = 0;
+ bool colResult = false;
+
+ int curX = fromX;
+ int curY = fromY;
+ int curRouteIdx = routeIdx;
+ bool dummyLineFl = false;
+ if (startLineIdx == -1 && endLineIdx == -1)
+ dummyLineFl = true;
+ int foundDataIdx;
+ int foundLineIdx = startLineIdx;
+ if (checkCollisionLine(fromX, fromY, &foundDataIdx, &foundLineIdx, 0, _linesNumb)) {
+ switch (_lineItem[foundLineIdx]._direction) {
+ case DIR_UP:
+ curY -= 2;
+ break;
+ case DIR_UP_RIGHT:
+ curY -= 2;
+ curX += 2;
+ break;
+ case DIR_RIGHT:
+ curX += 2;
+ break;
+ case DIR_DOWN_RIGHT:
+ curY += 2;
+ curX += 2;
+ case DIR_DOWN:
+ curY += 2;
+ break;
+ case DIR_DOWN_LEFT:
+ curY += 2;
+ curX -= 2;
+ break;
+ case DIR_LEFT:
+ curX -= 2;
+ break;
+ case DIR_UP_LEFT:
+ curY -= 2;
+ curX -= 2;
+ break;
+ default:
+ break;
+ }
+ }
+ int oldX = curX;
+ int oldY = curY;
+ int idxRoute0 = 0;
+ int collLineIdxRoute0 = -1;
+ int collLineIdxRoute1 = -1;
+ int collLineIdxRoute2 = -1;
+
+ int distX, distY;
+ int repeatFlag = 0;
+ int collDataIdxRoute0 = 0;
+ int collDataIdxRoute1 = 0;
+ for (;;) {
+ int newX = curX;
+ int newY = curY;
+ if (destX >= curX - 2 && destX <= curX + 2 && destY >= curY - 2 && destY <= curY + 2) {
+ _testRoute0[idxRoute0].invalidate();
+ useRoute0(idxRoute0, curRouteIdx);
+ return 1;
+ }
+ distX = abs(curX - destX) + 1;
+ distY = abs(curY - destY) + 1;
+ int maxDist;
+ if (distX > distY)
+ maxDist = distX;
+ else
+ maxDist = distY;
+ maxDist--;
+ assert(maxDist != 0);
+ int stepX = 1000 * distX / maxDist;
+ int stepY = 1000 * distY / maxDist;
+ if (destX < curX)
+ stepX = -stepX;
+ if (destY < curY)
+ stepY = -stepY;
+ int vertDirection = (int16)stepX / 1000;
+ int horzDirection = (int16)stepY / 1000;
+ Directions newDirection = DIR_NONE;
+ if (horzDirection == -1 && (stepX >= 0 && stepX <= 150))
+ newDirection = DIR_UP;
+ if (vertDirection == 1 && (stepY >= -1 && stepY <= 150))
+ newDirection = DIR_RIGHT;
+ if (horzDirection == 1 && (stepX >= -150 && stepX <= 150))
+ newDirection = DIR_DOWN;
+ if (vertDirection == -1 && (stepY >= -150 && stepY <= 150))
+ newDirection = DIR_LEFT;
+ if (horzDirection == -1 && (stepX >= -150 && stepX <= 0))
+ newDirection = DIR_UP;
+
+ if (newDirection == DIR_NONE && !checkSmoothMove(curX, newY, destX, destY) && !makeSmoothMove(curX, newY, destX, destY)) {
+ newDirection = _smoothMoveDirection;
+ int smoothRouteIdx = 0;
+ for (smoothRouteIdx = 0; _smoothRoute[smoothRouteIdx]._posX != -1 && _smoothRoute[smoothRouteIdx]._posY != -1; ++smoothRouteIdx) {
+ if (checkCollisionLine(_smoothRoute[smoothRouteIdx]._posX, _smoothRoute[smoothRouteIdx]._posY, &collDataIdxRoute0, &collLineIdxRoute0, 0, _linesNumb)) {
+ if (collLineIdxRoute0 > _lastLine)
+ collLineIdxRoute0 = -1;
+ break;
+ }
+
+ _testRoute0[idxRoute0].set(_smoothRoute[smoothRouteIdx]._posX, _smoothRoute[smoothRouteIdx]._posY, newDirection);
+ idxRoute0++;
+
+ if (repeatFlag == 1) {
+ repeatFlag = 2;
+ break;
+ }
+ }
+
+ if (repeatFlag != 2 && _smoothRoute[smoothRouteIdx]._posX != -1 && _smoothRoute[smoothRouteIdx]._posY != -1)
+ break;
+
+ repeatFlag = 1;
+ newX = _smoothRoute[smoothRouteIdx - 1]._posX;
+ newY = _smoothRoute[smoothRouteIdx - 1]._posY;
+ }
+ int newDistX = abs(newX - destX) + 1;
+ int newDistY = abs(newY - destY) + 1;
+ int newMaxDist = newDistY;
+ if (newDistX > newDistY)
+ newMaxDist = newDistX;
+ if (newMaxDist <= 10) {
+ _testRoute0[idxRoute0].invalidate();
+ useRoute0(idxRoute0, curRouteIdx);
+ return 1;
+ }
+ int newStepX = 1000 * newDistX / (newMaxDist - 1);
+ int newStepY = 1000 * newDistY / (newMaxDist - 1);
+ if (destX < newX)
+ newStepX = -newStepX;
+ if (destY < newY)
+ newStepY = -newStepY;
+ int newVertDirection = newStepX / 1000;
+ int newHorzDirection = newStepY / 1000;
+ int newSmoothX = 1000 * newX;
+ int newSmoothY = 1000 * newY;
+ int curPosX = newSmoothX / 1000;
+ int curPosY = newSmoothY / 1000;
+ if (!(newStepX / 1000) && newHorzDirection == -1)
+ newDirection = DIR_UP;
+ if (newVertDirection == 1) {
+ if (newHorzDirection == -1)
+ newDirection = DIR_UP_RIGHT;
+ if (!newHorzDirection)
+ newDirection = DIR_RIGHT;
+ if (newHorzDirection == 1)
+ newDirection = DIR_DOWN_RIGHT;
+ }
+ if (!newVertDirection && newHorzDirection == 1)
+ newDirection = DIR_DOWN;
+ if ((newVertDirection != -1) && (newHorzDirection == -1)) {
+ if (newStepX >= 0 && newStepX < 510)
+ newDirection = DIR_UP;
+ else if (newStepX >= 510 && newStepX <= 1000)
+ newDirection = DIR_UP_RIGHT;
+ } else {
+ if (newHorzDirection == 1)
+ newDirection = DIR_DOWN_LEFT;
+ else if (!newHorzDirection)
+ newDirection = DIR_LEFT;
+ else if (newHorzDirection == -1) {
+ if (newStepX >= 0 && newStepX < 510)
+ newDirection = DIR_UP;
+ else if (newStepX >= 510 && newStepX <= 1000)
+ newDirection = DIR_UP_RIGHT;
+ else
+ newDirection = DIR_UP_LEFT;
+ }
+ }
+ if (newVertDirection == 1) {
+ if (newStepY >= -1000 && newStepY <= -510)
+ newDirection = DIR_UP_RIGHT;
+ if (newStepY >= -510 && newStepY <= 510)
+ newDirection = DIR_RIGHT;
+ if (newStepY >= 510 && newStepY <= 1000)
+ newDirection = DIR_DOWN_RIGHT;
+ }
+ if (newHorzDirection == 1) {
+ if (newStepX >= 510 && newStepX <= 1000)
+ newDirection = DIR_DOWN_RIGHT;
+ if (newStepX >= -510 && newStepX <= 510)
+ newDirection = DIR_DOWN;
+ if (newStepX >= -1000 && newStepX <= -510)
+ newDirection = DIR_DOWN_LEFT;
+ }
+ if (newVertDirection == -1) {
+ if (newStepY >= 510 && newStepY <= 1000)
+ newDirection = DIR_DOWN_LEFT;
+ if (newStepY >= -510 && newStepY <= 510)
+ newDirection = DIR_LEFT;
+ if (newStepY >= -1000 && newStepY <= -510)
+ newDirection = DIR_UP_LEFT;
+ }
+ if (newHorzDirection == -1) {
+ if (newStepX >= -1000 && newStepX <= -510)
+ newDirection = DIR_UP_LEFT;
+ if (newStepX >= -510 && newStepX <= 0)
+ newDirection = DIR_UP;
+ }
+ if (newMaxDist + 1 <= 0) {
+ _testRoute0[idxRoute0].invalidate();
+ useRoute0(idxRoute0, curRouteIdx);
+ return 1;
+ }
+ int curDist = 0;
+ while (!checkCollisionLine(curPosX, curPosY, &collDataIdxRoute0, &collLineIdxRoute0, 0, _linesNumb)) {
+ _testRoute0[idxRoute0].set(curPosX, curPosY, newDirection);
+ newSmoothX += newStepX;
+ newSmoothY += newStepY;
+ curPosX = newSmoothX / 1000;
+ curPosY = newSmoothY / 1000;
+ idxRoute0++;
+ ++curDist;
+ if (curDist >= newMaxDist + 1) {
+ _testRoute0[idxRoute0].invalidate();
+ useRoute0(idxRoute0, curRouteIdx);
+ return 1;
+ }
+ }
+ if (_lastLine >= collLineIdxRoute0)
+ break;
+ int tmpRouteIdx = computeRouteIdx(collLineIdxRoute0, collDataIdxRoute0, curPosX, curPosY, destX, destY, idxRoute0, _testRoute0);
+ if (tmpRouteIdx == -1) {
+ useRoute0(idxRoute0, curRouteIdx);
+ return 1;
+ }
+ idxRoute0 = tmpRouteIdx;
+ if (_newPosX != -1 || _newPosY != -1) {
+ collLineIdxRoute0 = -1;
+ break;
+ }
+ curX = -1;
+ curY = -1;
+ }
+
+ _testRoute0[idxRoute0].invalidate();
+
+ int idxRoute1 = 0;
+ int posXRoute1 = oldX;
+ int posYRoute1 = oldY;
+
+ while (true) {
+
+ if (destX >= posXRoute1 - 2 && destX <= posXRoute1 + 2 && destY >= posYRoute1 - 2 && destY <= posYRoute1 + 2) {
+ _testRoute1[idxRoute1].invalidate();
+ useRoute1(idxRoute1, curRouteIdx);
+ return 1;
+ }
+ while (posXRoute1 != destX) {
+ if (checkCollisionLine(posXRoute1, posYRoute1, &collDataIdxRoute1, &collLineIdxRoute1, 0, _linesNumb)) {
+ if (collLineIdxRoute1 > _lastLine)
+ collLineIdxRoute1 = -1;
+ break;
+ }
+
+ if (posXRoute1 < destX)
+ _testRoute1[idxRoute1++].set(posXRoute1++, posYRoute1, DIR_RIGHT);
+ else
+ _testRoute1[idxRoute1++].set(posXRoute1--, posYRoute1, DIR_LEFT);
+ }
+ if (posXRoute1 != destX)
+ break;
+
+ int curPosY = posYRoute1;
+ while (curPosY != destY) {
+ if (checkCollisionLine(destX, curPosY, &collDataIdxRoute1, &collLineIdxRoute1, 0, _linesNumb)) {
+ if (collLineIdxRoute1 <= _lastLine)
+ break;
+
+ int tmpRouteIdx = computeRouteIdx(collLineIdxRoute1, collDataIdxRoute1, destX, curPosY, destX, destY, idxRoute1, _testRoute1);
+ if (tmpRouteIdx == -1) {
+ useRoute1(idxRoute1, curRouteIdx);
+ return 1;
+ }
+ idxRoute1 = tmpRouteIdx;
+ if (_newPosX != -1 && _newPosY != -1)
+ break;
+ }
+
+ if (curPosY < destY)
+ _testRoute1[idxRoute1++].set(destX, curPosY++, DIR_DOWN);
+ else
+ _testRoute1[idxRoute1++].set(destX, curPosY--, DIR_UP);
+ }
+ if (curPosY == destY) {
+ _testRoute1[idxRoute1].invalidate();
+ useRoute1(idxRoute1, curRouteIdx);
+ return 1;
+ }
+ if (collLineIdxRoute1 <= _lastLine)
+ break;
+ posXRoute1 = _newPosX;
+ posYRoute1 = _newPosY;
+ bool colRes = checkCollisionLine(_newPosX, _newPosY, &collDataIdxRoute1, &collLineIdxRoute1, 0, _lastLine);
+ if (colRes && collLineIdxRoute1 <= _lastLine)
+ break;
+ }
+
+ _testRoute1[idxRoute1].invalidate();
+ idxRoute1 = 0;
+ int posXRoute2 = oldX;
+ int posYRoute2 = oldY;
+ while (true) {
+ int curPosX;
+ if (destX >= posXRoute2 - 2 && destX <= posXRoute2 + 2 && destY >= posYRoute2 - 2 && destY <= posYRoute2 + 2) {
+ _testRoute2[idxRoute1].invalidate();
+ useRoute2(idxRoute1, curRouteIdx);
+ return 1;
+ }
+
+ int curPosYRoute2 = posYRoute2;
+ while (curPosYRoute2 != destY) {
+ if (checkCollisionLine(posXRoute2, curPosYRoute2, &collDataIdxRoute2, &collLineIdxRoute2, 0, _linesNumb)) {
+ if (collLineIdxRoute2 > _lastLine)
+ collLineIdxRoute2 = -1;
+ break;
+ }
+
+ if (curPosYRoute2 < destY)
+ _testRoute2[idxRoute1++].set(posXRoute2, curPosYRoute2++, DIR_DOWN);
+ else
+ _testRoute2[idxRoute1++].set(posXRoute2, curPosYRoute2--, DIR_UP);
+ }
+ if (curPosYRoute2 != destY)
+ break;
+
+ curPosX = posXRoute2;
+ while (curPosX != destX) {
+ if (checkCollisionLine(curPosX, destY, &collDataIdxRoute2, &collLineIdxRoute2, 0, _linesNumb)) {
+ if (collLineIdxRoute2 <= _lastLine)
+ break;
+
+ int tmpRouteIdx = computeRouteIdx(collLineIdxRoute2, collDataIdxRoute2, curPosX, destY, destX, destY, idxRoute1, _testRoute2);
+ if (tmpRouteIdx == -1) {
+ useRoute2(idxRoute1, curRouteIdx);
+ return 1;
+ }
+ idxRoute1 = tmpRouteIdx;
+ if (_newPosX != -1 && _newPosY != -1)
+ break;
+ }
+
+ if (curPosX < destX)
+ _testRoute2[idxRoute1++].set(curPosX++, destY, DIR_RIGHT);
+ else
+ _testRoute2[idxRoute1++].set(curPosX--, destY, DIR_LEFT);
+ }
+ if (curPosX == destX) {
+ collLineIdxRoute2 = -1;
+ _testRoute2[idxRoute1].invalidate();
+ useRoute2(idxRoute1, curRouteIdx);
+ return 1;
+ }
+ if (collLineIdxRoute2 <= _lastLine)
+ break;
+
+ posXRoute2 = _newPosX;
+ posYRoute2 = _newPosY;
+ colResult = checkCollisionLine(_newPosX, _newPosY, &collDataIdxRoute2, &collLineIdxRoute2, 0, _lastLine);
+ if (colResult && collLineIdxRoute2 <= _lastLine)
+ break;
+ }
+
+ _testRoute2[idxRoute1].invalidate();
+
+ if (!dummyLineFl) {
+ if (endLineIdx > foundLineIdx) {
+ if (_testRoute0[0]._x != -1 && collLineIdxRoute0 > foundLineIdx && collLineIdxRoute1 <= collLineIdxRoute0 && collLineIdxRoute2 <= collLineIdxRoute0 && endLineIdx >= collLineIdxRoute0) {
+ _newLineIdx = collLineIdxRoute0;
+ _newLineDataIdx = collDataIdxRoute0;
+ int i = 0;
+ do {
+ assert(curRouteIdx <= 8000);
+ _bestRoute[curRouteIdx++] = _testRoute0[i++];
+ } while (_testRoute0[i].isValid());
+ _newRouteIdx = curRouteIdx;
+ return 2;
+ }
+ if (_testRoute1[0]._x != -1 && foundLineIdx < collLineIdxRoute1 && collLineIdxRoute2 <= collLineIdxRoute1 && collLineIdxRoute0 <= collLineIdxRoute1 && endLineIdx >= collLineIdxRoute1) {
+ _newLineIdx = collLineIdxRoute1;
+ _newLineDataIdx = collDataIdxRoute1;
+ int i = 0;
+ do {
+ assert(curRouteIdx <= 8000);
+ _bestRoute[curRouteIdx++] = _testRoute1[i++];
+ } while (_testRoute1[i].isValid());
+ _newRouteIdx = curRouteIdx;
+ return 2;
+ }
+ if (_testRoute2[0]._x != -1 && foundLineIdx < collLineIdxRoute2 && collLineIdxRoute1 < collLineIdxRoute2 && collLineIdxRoute0 < collLineIdxRoute2 && endLineIdx >= collLineIdxRoute2) {
+ _newLineIdx = collLineIdxRoute2;
+ _newLineDataIdx = collDataIdxRoute2;
+ int i = 0;
+ do {
+ assert(curRouteIdx <= 8000);
+ _bestRoute[curRouteIdx++] = _testRoute2[i++];
+ } while (_testRoute2[i].isValid());
+ _newRouteIdx = curRouteIdx;
+ return 2;
+ }
+ }
+ if (endLineIdx < foundLineIdx) {
+ if (collLineIdxRoute0 == -1)
+ collLineIdxRoute0 = INVALID_LINE_VALUE;
+ if (collLineIdxRoute1 == -1)
+ collLineIdxRoute0 = INVALID_LINE_VALUE;
+ if (collLineIdxRoute2 == -1)
+ collLineIdxRoute0 = INVALID_LINE_VALUE;
+ if (_testRoute1[0]._x != -1 && collLineIdxRoute1 < foundLineIdx && collLineIdxRoute2 >= collLineIdxRoute1 && collLineIdxRoute0 >= collLineIdxRoute1 && endLineIdx <= collLineIdxRoute1) {
+ _newLineIdx = collLineIdxRoute1;
+ _newLineDataIdx = collDataIdxRoute1;
+ int i = 0;
+ do {
+ assert(curRouteIdx <= 8000);
+ _bestRoute[curRouteIdx++] = _testRoute1[i++];
+ } while (_testRoute1[i].isValid());
+ _newRouteIdx = curRouteIdx;
+ return 2;
+ }
+ if (_testRoute2[0]._x != -1 && foundLineIdx > collLineIdxRoute2 && collLineIdxRoute1 >= collLineIdxRoute2 && collLineIdxRoute0 >= collLineIdxRoute2 && endLineIdx <= collLineIdxRoute2) {
+ _newLineIdx = collLineIdxRoute2;
+ _newLineDataIdx = collDataIdxRoute2;
+ int i = 0;
+ do {
+ assert(curRouteIdx <= 8000);
+ _bestRoute[curRouteIdx++] = _testRoute2[i++];
+ } while (_testRoute2[i].isValid());
+ _newRouteIdx = curRouteIdx;
+ return 2;
+ }
+ // CHECKME: Checking essai0[0]._x might make more sense here?
+ if (_testRoute1[0]._x != -1 && foundLineIdx > collLineIdxRoute0 && collLineIdxRoute1 >= collLineIdxRoute0 && collLineIdxRoute2 >= collLineIdxRoute0 && endLineIdx <= collLineIdxRoute0) {
+ _newLineIdx = collLineIdxRoute0;
+ _newLineDataIdx = collDataIdxRoute0;
+ int i = 0;
+ do {
+ assert(curRouteIdx <= 8000);
+ _bestRoute[curRouteIdx++] = _testRoute0[i++];
+ } while (_testRoute0[i].isValid());
+ _newRouteIdx = curRouteIdx;
+ return 2;
+ }
+ }
+ }
+ return 0;
+}
+
+RouteItem *LinesManager::cityMapCarRoute(int x1, int y1, int x2, int y2) {
+ RouteItem *result;
+ int arrDelta[10];
+ int arrDataIdx[10];
+ int arrLineIdx[10];
+
+ int clipX2 = x2;
+ int clipY2 = y2;
+ if (x2 <= 14)
+ clipX2 = 15;
+ if (y2 <= 14)
+ clipY2 = 15;
+ if (clipX2 > _vm->_graphicsMan->_maxX - 10)
+ clipX2 = _vm->_graphicsMan->_maxX - 10;
+ if (clipY2 > 445)
+ clipY2 = 440;
+
+ int delta = 0;
+ for (delta = 0; clipY2 + delta < _vm->_graphicsMan->_maxY; delta++) {
+ if (checkCollisionLine(clipX2, clipY2 + delta, &arrDataIdx[DIR_DOWN], &arrLineIdx[DIR_DOWN], 0, _lastLine) && arrLineIdx[DIR_DOWN] <= _lastLine)
+ break;
+ arrDataIdx[DIR_DOWN] = 0;
+ arrLineIdx[DIR_DOWN] = -1;
+ }
+ arrDelta[DIR_DOWN] = delta;
+
+ for (delta = 0; clipY2 - delta > _vm->_graphicsMan->_minY; delta++) {
+ if (checkCollisionLine(clipX2, clipY2 - delta , &arrDataIdx[DIR_UP], &arrLineIdx[DIR_UP], 0, _lastLine) && arrLineIdx[DIR_UP] <= _lastLine)
+ break;
+ arrDataIdx[DIR_UP] = 0;
+ arrLineIdx[DIR_UP] = -1;
+ if (arrDelta[DIR_DOWN] < delta && arrLineIdx[DIR_DOWN] != -1)
+ break;
+ }
+ arrDelta[DIR_UP] = delta;
+
+ for (delta = 0; clipX2 + delta < _vm->_graphicsMan->_maxX; delta++) {
+ if (checkCollisionLine(clipX2 + delta, clipY2, &arrDataIdx[DIR_RIGHT], &arrLineIdx[DIR_RIGHT], 0, _lastLine) && arrLineIdx[DIR_RIGHT] <= _lastLine)
+ break;
+ arrDataIdx[DIR_RIGHT] = 0;
+ arrLineIdx[DIR_RIGHT] = -1;
+ if ((arrDelta[DIR_UP] <= delta && arrLineIdx[DIR_UP] != -1) || (arrDelta[DIR_DOWN] <= delta && arrLineIdx[DIR_DOWN] != -1))
+ break;
+ }
+ arrDelta[DIR_RIGHT] = delta;
+
+ for (delta = 0; clipX2 - delta > _vm->_graphicsMan->_minX; delta++) {
+ if (checkCollisionLine(clipX2 - delta, clipY2, &arrDataIdx[DIR_LEFT], &arrLineIdx[DIR_LEFT], 0, _lastLine) && arrLineIdx[DIR_LEFT] <= _lastLine)
+ break;
+ arrDataIdx[DIR_LEFT] = 0;
+ arrLineIdx[DIR_LEFT] = -1;
+ if ((arrDelta[DIR_UP] <= delta && arrLineIdx[DIR_UP] != -1) || (arrDelta[DIR_RIGHT] <= delta && arrLineIdx[DIR_RIGHT] != -1) || (arrDelta[DIR_DOWN] <= delta && arrLineIdx[DIR_DOWN] != -1))
+ break;
+ }
+ arrDelta[DIR_LEFT] = delta;
+
+ if (arrLineIdx[DIR_UP] == -1)
+ arrDelta[DIR_UP] = INVALID_LINE_VALUE;
+ if (arrLineIdx[DIR_RIGHT] == -1)
+ arrDelta[DIR_RIGHT] = INVALID_LINE_VALUE;
+ if (arrLineIdx[DIR_DOWN] == -1)
+ arrDelta[DIR_DOWN] = INVALID_LINE_VALUE;
+ if (arrLineIdx[DIR_LEFT] == -1)
+ arrDelta[DIR_LEFT] = INVALID_LINE_VALUE;
+ if (arrLineIdx[DIR_UP] != -1 || arrLineIdx[DIR_RIGHT] != -1 || arrLineIdx[DIR_DOWN] != -1 || arrLineIdx[DIR_LEFT] != -1) {
+ int curLineDataIdx = 0;
+ int curLineIdx = 0;
+ if (arrLineIdx[DIR_DOWN] != -1 && arrDelta[DIR_UP] >= arrDelta[DIR_DOWN] && arrDelta[DIR_RIGHT] >= arrDelta[DIR_DOWN] && arrDelta[DIR_LEFT] >= arrDelta[DIR_DOWN]) {
+ curLineIdx = arrLineIdx[DIR_DOWN];
+ curLineDataIdx = arrDataIdx[DIR_DOWN];
+ } else if (arrLineIdx[DIR_UP] != -1 && arrDelta[DIR_DOWN] >= arrDelta[DIR_UP] && arrDelta[DIR_RIGHT] >= arrDelta[DIR_UP] && arrDelta[DIR_LEFT] >= arrDelta[DIR_UP]) {
+ curLineIdx = arrLineIdx[DIR_UP];
+ curLineDataIdx = arrDataIdx[DIR_UP];
+ } else if (arrLineIdx[DIR_RIGHT] != -1 && arrDelta[DIR_UP] >= arrDelta[DIR_RIGHT] && arrDelta[DIR_DOWN] >= arrDelta[DIR_RIGHT] && arrDelta[DIR_LEFT] >= arrDelta[DIR_RIGHT]) {
+ curLineIdx = arrLineIdx[DIR_RIGHT];
+ curLineDataIdx = arrDataIdx[DIR_RIGHT];
+ } else if (arrLineIdx[DIR_LEFT] != -1 && arrDelta[DIR_DOWN] >= arrDelta[DIR_LEFT] && arrDelta[DIR_RIGHT] >= arrDelta[DIR_LEFT] && arrDelta[DIR_UP] >= arrDelta[DIR_LEFT]) {
+ curLineIdx = arrLineIdx[DIR_LEFT];
+ curLineDataIdx = arrDataIdx[DIR_LEFT];
+ }
+
+ for (int i = 0; i <= 8; i++) {
+ arrLineIdx[i] = -1;
+ arrDataIdx[i] = 0;
+ arrDelta[i] = INVALID_LINE_VALUE;
+ }
+
+ int superRouteIdx = 0;
+ int curRouteDataIdx = 0;
+ int curRouteLineIdx = 0;
+ if (checkCollisionLine(x1, y1, &arrDataIdx[DIR_UP], &arrLineIdx[DIR_UP], 0, _lastLine)) {
+ curRouteLineIdx = arrLineIdx[DIR_UP];
+ curRouteDataIdx = arrDataIdx[DIR_UP];
+ } else if (checkCollisionLine(x1, y1, &arrDataIdx[DIR_UP], &arrLineIdx[DIR_UP], 0, _linesNumb)) {
+ int curRouteIdx = 0;
+ int curRouteX;
+ for (;;) {
+ curRouteX = _testRoute2[curRouteIdx]._x;
+ int curRouteY = _testRoute2[curRouteIdx]._y;
+ Directions curRouteDir = _testRoute2[curRouteIdx]._dir;
+ curRouteIdx++;
+
+ if (checkCollisionLine(curRouteX, curRouteY, &arrDataIdx[DIR_UP], &arrLineIdx[DIR_UP], 0, _lastLine))
+ break;
+
+ _bestRoute[superRouteIdx].set(curRouteX, curRouteY, curRouteDir);
+
+ _testRoute0[superRouteIdx].set(curRouteX, curRouteY, curRouteDir);
+ superRouteIdx++;
+ if (curRouteX == -1)
+ break;;
+ }
+ if (curRouteX != -1) {
+ curRouteLineIdx = arrLineIdx[DIR_UP];
+ curRouteDataIdx = arrDataIdx[DIR_UP];
+ }
+ } else {
+ curRouteLineIdx = 1;
+ curRouteDataIdx = 1;
+ superRouteIdx = 0;
+ }
+ bool loopFl = true;
+ while (loopFl) {
+ loopFl = false;
+ if (curRouteLineIdx < curLineIdx) {
+ superRouteIdx = _lineItem[curRouteLineIdx].appendToRouteInc(curRouteDataIdx, _lineItem[curRouteLineIdx]._lineDataEndIdx - 2, _bestRoute, superRouteIdx);
+ for (int j = curRouteLineIdx + 1; j < curLineIdx; ++j) {
+ if (PLAN_TEST(_lineItem[j]._lineData[0], _lineItem[j]._lineData[1], superRouteIdx, j, curLineIdx)) {
+ curRouteLineIdx = _newLineIdx;
+ curRouteDataIdx = _newLineDataIdx;
+ superRouteIdx = _newRouteIdx;
+ loopFl = true;
+ break;
+ }
+ if (_lineItem[j]._lineDataEndIdx - 2 > 0) {
+ superRouteIdx = _lineItem[j].appendToRouteInc(0, _lineItem[j]._lineDataEndIdx - 2, _bestRoute, superRouteIdx);
+ }
+ }
+ if (loopFl)
+ continue;
+ curRouteDataIdx = 0;
+ curRouteLineIdx = curLineIdx;
+ }
+ if (curRouteLineIdx > curLineIdx) {
+ superRouteIdx = _lineItem[curRouteLineIdx].appendToRouteDec(curRouteDataIdx, 0, _bestRoute, superRouteIdx);
+ for (int l = curRouteLineIdx - 1; l > curLineIdx; --l) {
+ if (PLAN_TEST(_lineItem[l]._lineData[2 * _lineItem[l]._lineDataEndIdx - 2], _lineItem[l]._lineData[2 * _lineItem[l]._lineDataEndIdx - 1], superRouteIdx, l, curLineIdx)) {
+ curRouteLineIdx = _newLineIdx;
+ curRouteDataIdx = _newLineDataIdx;
+ superRouteIdx = _newRouteIdx;
+ loopFl = true;
+ break;
+ }
+
+ superRouteIdx = _lineItem[l].appendToRouteDec(_lineItem[l]._lineDataEndIdx - 2, 0, _bestRoute, superRouteIdx);
+ }
+ if (loopFl)
+ continue;
+
+ curRouteDataIdx = _lineItem[curLineIdx]._lineDataEndIdx - 1;
+ curRouteLineIdx = curLineIdx;
+ }
+ if (curRouteLineIdx == curLineIdx) {
+ if (curRouteDataIdx <= curLineDataIdx) {
+ superRouteIdx = _lineItem[curLineIdx].appendToRouteInc(curRouteDataIdx, curLineDataIdx, _bestRoute, superRouteIdx);
+ } else {
+ superRouteIdx = _lineItem[curLineIdx].appendToRouteDec(curRouteDataIdx, curLineDataIdx, _bestRoute, superRouteIdx);
+ }
+ }
+ }
+ _bestRoute[superRouteIdx].invalidate();
+ result = &_bestRoute[0];
+ } else {
+ result = NULL;
+ }
+ return result;
+}
+
+bool LinesManager::checkSmoothMove(int fromX, int fromY, int destX, int destY) {
+ int distX = abs(fromX - destX) + 1;
+ int distY = abs(fromY - destY) + 1;
+ if (distX > distY)
+ distY = distX;
+ if (distY <= 10)
+ return true;
+
+ int stepX = 1000 * distX / (distY - 1);
+ int stepY = 1000 * distY / (distY - 1);
+ if (destX < fromX)
+ stepX = -stepX;
+ if (destY < fromY)
+ stepY = -stepY;
+
+ int smoothPosX = 1000 * fromX;
+ int smoothPosY = 1000 * fromY;
+ int newPosX = fromX;
+ int newPosY = fromY;
+
+ if (distY + 1 > 0) {
+ int stepCount = 0;
+ int foundLineIdx;
+ int foundDataIdx;
+ while (!checkCollisionLine(newPosX, newPosY, &foundDataIdx, &foundLineIdx, 0, _linesNumb) || foundLineIdx > _lastLine) {
+ smoothPosX += stepX;
+ smoothPosY += stepY;
+ newPosX = smoothPosX / 1000;
+ newPosY = smoothPosY / 1000;
+ ++stepCount;
+ if (stepCount >= distY + 1)
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool LinesManager::makeSmoothMove(int fromX, int fromY, int destX, int destY) {
+ int curX = fromX;
+ int curY = fromY;
+ if (fromX > destX && destY > fromY) {
+ int hopkinsIdx = 36;
+ int smoothIdx = 0;
+ int stepCount = 0;
+ while (curX > destX && destY > curY) {
+ int realSpeedX = _vm->_globals->_hopkinsItem[hopkinsIdx]._speedX;
+ int realSpeedY = _vm->_globals->_hopkinsItem[hopkinsIdx]._speedY;
+ int spriteSize = _vm->_globals->_spriteSize[curY];
+ if (spriteSize < 0) {
+ realSpeedX = _vm->_graphicsMan->zoomOut(realSpeedX, -spriteSize);
+ realSpeedY = _vm->_graphicsMan->zoomOut(realSpeedY, -spriteSize);
+ } else if (spriteSize > 0) {
+ realSpeedX = _vm->_graphicsMan->zoomIn(realSpeedX, spriteSize);
+ realSpeedY = _vm->_graphicsMan->zoomIn(realSpeedY, spriteSize);
+ }
+ for (int i = 0; i < realSpeedX; i++) {
+ --curX;
+ _smoothRoute[smoothIdx]._posX = curX;
+ if (curY != curY + realSpeedY)
+ curY++;
+ _smoothRoute[smoothIdx]._posY = curY;
+ smoothIdx++;
+ }
+ ++hopkinsIdx;
+ if (hopkinsIdx == 48)
+ hopkinsIdx = 36;
+ ++stepCount;
+ }
+ if (stepCount > 5) {
+ _smoothRoute[smoothIdx]._posX = -1;
+ _smoothRoute[smoothIdx]._posY = -1;
+ _smoothMoveDirection = DIR_DOWN_LEFT;
+ return false;
+ }
+ } else if (fromX < destX && destY > fromY) {
+ int hopkinsIdx = 36;
+ int smoothIdx = 0;
+ int stepCount = 0;
+ while (curX < destX && destY > curY) {
+ int realSpeedX = _vm->_globals->_hopkinsItem[hopkinsIdx]._speedX;
+ int realSpeedY = _vm->_globals->_hopkinsItem[hopkinsIdx]._speedY;
+ int spriteSize = _vm->_globals->_spriteSize[curY];
+ if (spriteSize < 0) {
+ realSpeedX = _vm->_graphicsMan->zoomOut(realSpeedX, -spriteSize);
+ realSpeedY = _vm->_graphicsMan->zoomOut(realSpeedY, -spriteSize);
+ } else if (spriteSize > 0) {
+ realSpeedX = _vm->_graphicsMan->zoomIn(realSpeedX, spriteSize);
+ realSpeedY = _vm->_graphicsMan->zoomIn(realSpeedY, spriteSize);
+ }
+ for (int i = 0; i < realSpeedX; i++) {
+ ++curX;
+ _smoothRoute[smoothIdx]._posX = curX;
+ if (curY != curY + realSpeedY)
+ curY++;
+ _smoothRoute[smoothIdx]._posY = curY;
+ smoothIdx++;
+ }
+ ++hopkinsIdx;
+ if (hopkinsIdx == 48)
+ hopkinsIdx = 36;
+ ++stepCount;
+ }
+ if (stepCount > 5) {
+ _smoothRoute[smoothIdx]._posX = -1;
+ _smoothRoute[smoothIdx]._posY = -1;
+ _smoothMoveDirection = DIR_DOWN_RIGHT;
+ return false;
+ }
+ } else if (fromX > destX && destY < fromY) {
+ int hopkinsIdx = 12;
+ int smoothIdx = 0;
+ int stepCount = 0;
+ while (curX > destX && destY < curY) {
+ int realSpeedX = _vm->_graphicsMan->zoomOut(_vm->_globals->_hopkinsItem[hopkinsIdx]._speedX, 25);
+ int realSpeedY = _vm->_graphicsMan->zoomOut(_vm->_globals->_hopkinsItem[hopkinsIdx]._speedY, 25);
+ int oldY = curY;
+ for (int i = 0; i < realSpeedX; i++) {
+ --curX;
+ _smoothRoute[smoothIdx]._posX = curX;
+ if ((uint16)curY != (uint16)oldY + realSpeedY)
+ curY--;
+ _smoothRoute[smoothIdx]._posY = curY;
+ smoothIdx++;
+ }
+ ++hopkinsIdx;
+ if (hopkinsIdx == 24)
+ hopkinsIdx = 12;
+ ++stepCount;
+ }
+ if (stepCount > 5) {
+ _smoothRoute[smoothIdx]._posX = -1;
+ _smoothRoute[smoothIdx]._posY = -1;
+ _smoothMoveDirection = DIR_UP_LEFT;
+ return false;
+ }
+ } else if (fromX < destX && destY < fromY) {
+ int hopkinsIdx = 12;
+ int smoothIdx = 0;
+ int stepCount = 0;
+ while (curX < destX && destY < curY) {
+ int oldY = curY;
+ int realSpeedX = _vm->_graphicsMan->zoomOut(_vm->_globals->_hopkinsItem[hopkinsIdx]._speedX, 25);
+ int realSpeedY = _vm->_graphicsMan->zoomOut(_vm->_globals->_hopkinsItem[hopkinsIdx]._speedY, 25);
+ for (int i = 0; i < realSpeedX; i++) {
+ ++curX;
+ _smoothRoute[smoothIdx]._posX = curX;
+ if ((uint16)curY != (uint16)oldY + realSpeedY)
+ curY--;
+ _smoothRoute[smoothIdx]._posY = curY;
+ smoothIdx++;
+ }
+ ++hopkinsIdx;
+ if (hopkinsIdx == 24)
+ hopkinsIdx = 12;
+ ++stepCount;
+ }
+
+ if (stepCount > 5) {
+ _smoothRoute[smoothIdx]._posX = -1;
+ _smoothRoute[smoothIdx]._posY = -1;
+ _smoothMoveDirection = DIR_UP_RIGHT;
+ return false;
+ }
+ }
+ return true;
+}
+
+bool LinesManager::PLAN_TEST(int paramX, int paramY, int superRouteIdx, int paramStartLineIdx, int paramEndLineIdx) {
+ int sideTestUp;
+ int sideTestDown;
+ int sideTestLeft;
+ int sideTestRight;
+ int lineIdxTestUp;
+ int lineIdxTestDown;
+ int lineIdxTestLeft;
+ int lineIdxTestRight;
+ int dataIdxTestUp;
+ int dataIdxTestDown;
+ int dataIdxTestLeft;
+ int dataIdxTestRight;
+
+ int idxTestUp = testLine(paramX, paramY - 2, &sideTestUp, &lineIdxTestUp, &dataIdxTestUp);
+ int idxTestDown = testLine(paramX, paramY + 2, &sideTestDown, &lineIdxTestDown, &dataIdxTestDown);
+ int idxTestLeft = testLine(paramX - 2, paramY, &sideTestLeft, &lineIdxTestLeft, &dataIdxTestLeft);
+ int idxTestRight = testLine(paramX + 2, paramY, &sideTestRight, &lineIdxTestRight, &dataIdxTestRight);
+ if (idxTestUp == -1 && idxTestDown == -1 && idxTestLeft == -1 && idxTestRight == -1)
+ return false;
+
+ // Direction: 1 = Up, 2 = Down, 3 = Left, 4 = Right
+ int direction;
+ if (paramStartLineIdx == -1 || paramEndLineIdx == -1) {
+ if (idxTestUp != -1)
+ direction = 1;
+ else if (idxTestDown != -1)
+ direction = 2;
+ else if (idxTestLeft != -1)
+ direction = 3;
+ else if (idxTestRight != -1)
+ direction = 4;
+ else
+ return false;
+ } else {
+ int stepCountUp = 100;
+ int stepCountDown = 100;
+ int stepCountLeft = 100;
+ int stepCountRight = 100;
+ int paramStepCount = abs(paramStartLineIdx - paramEndLineIdx);
+ if (idxTestUp != -1) {
+ stepCountUp = abs(lineIdxTestUp - paramEndLineIdx);
+ }
+ if (idxTestDown != -1) {
+ stepCountDown = abs(lineIdxTestDown - paramEndLineIdx);
+ }
+ if (idxTestLeft != -1) {
+ stepCountLeft = abs(lineIdxTestLeft - paramEndLineIdx);
+ }
+ if (idxTestRight != -1) {
+ stepCountRight = abs(lineIdxTestRight - paramEndLineIdx);
+ }
+
+ if (stepCountUp < paramStepCount && stepCountUp <= stepCountDown && stepCountUp <= stepCountLeft && stepCountUp <= stepCountRight)
+ direction = 1;
+ else if (paramStepCount > stepCountDown && stepCountUp >= stepCountDown && stepCountLeft >= stepCountDown && stepCountRight >= stepCountDown)
+ direction = 2;
+ else if (stepCountLeft < paramStepCount && stepCountLeft <= stepCountUp && stepCountLeft <= stepCountDown && stepCountLeft <= stepCountRight)
+ direction = 3;
+ else if (stepCountRight < paramStepCount && stepCountRight <= stepCountUp && stepCountRight <= stepCountDown && stepCountRight <= stepCountLeft)
+ direction = 4;
+ else
+ return false;
+ }
+
+ int sideTest = 0;
+ int idxTest = 0;
+ if (direction == 1) {
+ idxTest = idxTestUp;
+ sideTest = sideTestUp;
+ _newLineIdx = lineIdxTestUp;
+ _newLineDataIdx = dataIdxTestUp;
+ } else if (direction == 2) {
+ idxTest = idxTestDown;
+ sideTest = sideTestDown;
+ _newLineIdx = lineIdxTestDown;
+ _newLineDataIdx = dataIdxTestDown;
+ } else if (direction == 3) {
+ idxTest = idxTestLeft;
+ sideTest = sideTestLeft;
+ _newLineIdx = lineIdxTestLeft;
+ _newLineDataIdx = dataIdxTestLeft;
+ } else if (direction == 4) {
+ idxTest = idxTestRight;
+ sideTest = sideTestRight;
+ _newLineIdx = lineIdxTestRight;
+ _newLineDataIdx = dataIdxTestRight;
+ }
+
+ int routeIdx = superRouteIdx;
+ if (sideTest == 1) {
+ routeIdx = _lineItem[idxTest].appendToRouteInc(0, -1, _bestRoute, routeIdx);
+ } else if (sideTest == 2) {
+ routeIdx = _lineItem[idxTest].appendToRouteDec(-1, -1, _bestRoute, routeIdx);
+ }
+ _newRouteIdx = routeIdx;
+ return true;
+}
+
+// Test line
+int LinesManager::testLine(int paramX, int paramY, int *testValue, int *foundLineIdx, int *foundDataIdx) {
+ int16 *lineData;
+ int lineDataEndIdx;
+ int collLineIdx;
+ int collDataIdx;
+
+ for (int idx = _lastLine + 1; idx < _linesNumb + 1; idx++) {
+ lineData = _lineItem[idx]._lineData;
+ lineDataEndIdx = _lineItem[idx]._lineDataEndIdx;
+ if (lineData) {
+ if (lineData[0] == paramX && lineData[1] == paramY) {
+ *testValue = 1;
+ int posX = lineData[2 * (lineDataEndIdx - 1)];
+ int posY = lineData[2 * (lineDataEndIdx - 1) + 1];
+ if (_lineItem[idx]._directionRouteInc == DIR_DOWN || _lineItem[idx]._directionRouteInc == DIR_UP)
+ posY += 2;
+ if (_lineItem[idx]._directionRouteInc == DIR_RIGHT || _lineItem[idx]._directionRouteDec == DIR_LEFT)
+ posX += 2;
+ if (!checkCollisionLine(posX, posY, &collDataIdx, &collLineIdx, 0, _lastLine))
+ error("Error in test line");
+ *foundLineIdx = collLineIdx;
+ *foundDataIdx = collDataIdx;
+ return idx;
+ }
+ }
+
+ if (lineDataEndIdx > 0) {
+ if (lineData[2 * (lineDataEndIdx - 1)] == paramX && lineData[2 * (lineDataEndIdx - 1) + 1] == paramY) {
+ *testValue = 2;
+ int posX = lineData[0];
+ int posY = lineData[1];
+ if (_lineItem[idx]._directionRouteInc == DIR_DOWN || _lineItem[idx]._directionRouteInc == DIR_UP)
+ posY -= 2;
+ if (_lineItem[idx]._directionRouteInc == DIR_RIGHT || _lineItem[idx]._directionRouteDec == DIR_LEFT)
+ posX -= 2;
+ if (!checkCollisionLine(posX, posY, &collDataIdx, &collLineIdx, 0, _lastLine))
+ error("Error in test line");
+ *foundLineIdx = collLineIdx;
+ *foundDataIdx = collDataIdx;
+ return idx;
+ }
+ }
+ }
+ return -1;
+}
+
+int LinesManager::computeYSteps(int idx) {
+ int zoomPct = _vm->_globals->_spriteSize[idx];
+ if (_vm->_globals->_characterType == 1) {
+ if (zoomPct < 0)
+ zoomPct = -zoomPct;
+ zoomPct = 20 * (5 * zoomPct - 100) / -80;
+ } else if (_vm->_globals->_characterType == 2) {
+ if (zoomPct < 0)
+ zoomPct = -zoomPct;
+ zoomPct = 20 * (5 * zoomPct - 165) / -67;
+ }
+
+ int retVal = 25;
+ if (zoomPct < 0)
+ retVal = _vm->_graphicsMan->zoomOut(25, -zoomPct);
+ else if (zoomPct > 0)
+ retVal = _vm->_graphicsMan->zoomIn(25, zoomPct);
+
+ return retVal;
+}
+
+void LinesManager::optimizeRoute(RouteItem *route) {
+ if (route[0]._x == -1 && route[0]._y == -1)
+ return;
+
+ int routeIdx = 0;
+ Directions oldDir = DIR_NONE;
+ int route0Y = route[0]._y;
+ Directions curDir = route[0]._dir;
+
+ for (;;) {
+ if (oldDir != DIR_NONE && curDir != oldDir) {
+ int oldRouteIdx = routeIdx;
+ int routeCount = 0;
+ int yStep = computeYSteps(route0Y);
+ int curRouteX = route[routeIdx]._x;
+ int curRouteY = route[routeIdx]._y;
+ while (curRouteX != -1 || curRouteY != -1) {
+ int idx = routeIdx;
+ ++routeIdx;
+ ++routeCount;
+ if (route[idx]._dir != curDir)
+ break;
+ curRouteX = route[routeIdx]._x;
+ curRouteY = route[routeIdx]._y;
+ }
+ if (routeCount < yStep) {
+ int idx = oldRouteIdx;
+ for (int i = 0; i < routeCount; i++) {
+ route[idx]._dir = oldDir;
+ idx++;
+ }
+ curDir = oldDir;
+ }
+ routeIdx = oldRouteIdx;
+ if (curRouteX == -1 && curRouteY == -1)
+ break;
+ }
+ routeIdx++;
+ oldDir = curDir;
+ route0Y = route[routeIdx]._y;
+ curDir = route[routeIdx]._dir;
+ if (route[routeIdx]._x == -1 && route0Y == -1)
+ break;
+ }
+}
+
+int LinesManager::getMouseZone() {
+ int result;
+
+ int xp = _vm->_events->_mousePos.x + _vm->_events->_mouseOffset.x;
+ int yp = _vm->_events->_mousePos.y + _vm->_events->_mouseOffset.y;
+ if ((_vm->_events->_mousePos.y + _vm->_events->_mouseOffset.y) > 19) {
+ for (int bobZoneId = 0; bobZoneId <= 48; bobZoneId++) {
+ int bobId = _bobZone[bobZoneId];
+ if (bobId && _bobZoneFl[bobZoneId] && _vm->_objectsMan->_bob[bobId]._bobMode && _vm->_objectsMan->_bob[bobId]._frameIndex != 250 &&
+ !_vm->_objectsMan->_bob[bobId]._disabledAnimationFl && xp > _vm->_objectsMan->_bob[bobId]._oldX &&
+ xp < _vm->_objectsMan->_bob[bobId]._oldWidth + _vm->_objectsMan->_bob[bobId]._oldX && yp > _vm->_objectsMan->_bob[bobId]._oldY) {
+ if (yp < _vm->_objectsMan->_bob[bobId]._oldHeight + _vm->_objectsMan->_bob[bobId]._oldY) {
+ if (_zone[bobZoneId]._spriteIndex == -1) {
+ _zone[bobZoneId]._destX = 0;
+ _zone[bobZoneId]._destY = 0;
+ }
+ if (!_zone[bobZoneId]._destX && !_zone[bobZoneId]._destY) {
+ _zone[bobZoneId]._destX = _vm->_objectsMan->_bob[bobId]._oldWidth + _vm->_objectsMan->_bob[bobId]._oldX;
+ _zone[bobZoneId]._destY = _vm->_objectsMan->_bob[bobId]._oldHeight + _vm->_objectsMan->_bob[bobId]._oldY + 6;
+ _zone[bobZoneId]._spriteIndex = -1;
+ }
+ return bobZoneId;
+ }
+ }
+ }
+ _currentSegmentId = 0;
+ for (int squareZoneId = 0; squareZoneId <= 99; squareZoneId++) {
+ if (_zone[squareZoneId]._enabledFl && _squareZone[squareZoneId]._enabledFl
+ && _squareZone[squareZoneId]._left <= xp && _squareZone[squareZoneId]._right >= xp
+ && _squareZone[squareZoneId]._top <= yp && _squareZone[squareZoneId]._bottom >= yp) {
+ if (_squareZone[squareZoneId]._squareZoneFl)
+ return _zoneLine[_squareZone[squareZoneId]._minZoneLineIdx]._bobZoneIdx;
+
+ _segment[_currentSegmentId]._minZoneLineIdx = _squareZone[squareZoneId]._minZoneLineIdx;
+ _segment[_currentSegmentId]._maxZoneLineIdx = _squareZone[squareZoneId]._maxZoneLineIdx;
+ ++_currentSegmentId;
+ }
+ }
+ if (!_currentSegmentId)
+ return -1;
+
+
+ int colRes1 = 0;
+ for (int yCurrent = yp; yCurrent >= 0; --yCurrent) {
+ colRes1 = checkCollision(xp, yCurrent);
+ if (colRes1 != -1 && _zone[colRes1]._enabledFl)
+ break;
+ }
+
+ if (colRes1 == -1)
+ return -1;
+
+ int colRes2 = 0;
+ for (int j = yp; j < _vm->_graphicsMan->_maxY; ++j) {
+ colRes2 = checkCollision(xp, j);
+ if (colRes2 != -1 && _zone[colRes1]._enabledFl)
+ break;
+ }
+
+ if (colRes2 == -1)
+ return -1;
+
+ int colRes3 = 0;
+ for (int k = xp; k >= 0; --k) {
+ colRes3 = checkCollision(k, yp);
+ if (colRes3 != -1 && _zone[colRes1]._enabledFl)
+ break;
+ }
+ if (colRes3 == -1)
+ return -1;
+
+ int colRes4 = 0;
+ for (int xCurrent = xp; _vm->_graphicsMan->_maxX > xCurrent; ++xCurrent) {
+ colRes4 = checkCollision(xCurrent, yp);
+ if (colRes4 != -1 && _zone[colRes1]._enabledFl)
+ break;
+ }
+ if (colRes1 == colRes2 && colRes1 == colRes3 && colRes1 == colRes4)
+ result = colRes1;
+ else
+ result = -1;
+
+ } else {
+ result = 0;
+ }
+ return result;
+}
+
+int LinesManager::checkCollision(int xp, int yp) {
+ if (_currentSegmentId <= 0)
+ return -1;
+
+ int xMax = xp + 4;
+ int xMin = xp - 4;
+
+ for (int idx = 0; idx <= _currentSegmentId; ++idx) {
+ int curZoneLineIdx = _segment[idx]._minZoneLineIdx;
+ if (_segment[idx]._maxZoneLineIdx < curZoneLineIdx)
+ continue;
+
+ int yMax = yp + 4;
+ int yMin = yp - 4;
+
+ do {
+ LigneZoneItem *curZoneLine = &_zoneLine[curZoneLineIdx];
+ int16 *dataP = curZoneLine->_zoneData;
+ if (dataP) {
+ int count = curZoneLine->_count;
+ int startX = dataP[0];
+ int startY = dataP[1];
+ int destX = dataP[count * 2 - 2];
+ int destY = dataP[count * 2 - 1];
+
+ bool flag = true;
+ if ((startX < destX && (xMax < startX || xMin > destX)) ||
+ (startX >= destX && (xMin > startX || xMax < destX)) ||
+ (startY < destY && (yMax < startY || yMin > destY)) ||
+ (startY >= destY && (yMin > startY || yMax < destY)))
+ flag = false;
+
+ if (flag && curZoneLine->_count > 0) {
+ for (int i = 0; i < count; ++i) {
+ int xCheck = *dataP++;
+ int yCheck = *dataP++;
+
+ if ((xp == xCheck || (xp + 1) == xCheck) && (yp == yCheck))
+ return curZoneLine->_bobZoneIdx;
+ }
+ }
+ }
+ } while (++curZoneLineIdx <= _segment[idx]._maxZoneLineIdx);
+ }
+
+ return -1;
+}
+
+// Square Zone
+void LinesManager::initSquareZones() {
+ for (int idx = 0; idx < 100; ++idx) {
+ SquareZoneItem *curZone = &_squareZone[idx];
+ curZone->_enabledFl = false;
+ curZone->_squareZoneFl = false;
+ curZone->_left = 1280;
+ curZone->_right = 0;
+ curZone->_top = 460;
+ curZone->_bottom = 0;
+ curZone->_minZoneLineIdx = 401;
+ curZone->_maxZoneLineIdx = 0;
+ }
+
+ for (int idx = 0; idx < MAX_LINES; ++idx) {
+ int16 *dataP = _zoneLine[idx]._zoneData;
+ if (dataP == NULL)
+ continue;
+
+ SquareZoneItem *curZone = &_squareZone[_zoneLine[idx]._bobZoneIdx];
+ curZone->_enabledFl = true;
+ curZone->_maxZoneLineIdx = MAX(curZone->_maxZoneLineIdx, idx);
+ curZone->_minZoneLineIdx = MIN(curZone->_minZoneLineIdx, idx);
+
+ for (int i = 0; i < _zoneLine[idx]._count; i++) {
+ int zoneX = *dataP++;
+ int zoneY = *dataP++;
+
+ curZone->_left = MIN(curZone->_left, zoneX);
+ curZone->_right = MAX(curZone->_right, zoneX);
+ curZone->_top = MIN(curZone->_top, zoneY);
+ curZone->_bottom = MAX(curZone->_bottom, zoneY);
+ }
+ }
+
+ for (int idx = 0; idx < 100; idx++) {
+ int zoneWidth = abs(_squareZone[idx]._left - _squareZone[idx]._right);
+ int zoneHeight = abs(_squareZone[idx]._top - _squareZone[idx]._bottom);
+ if (zoneWidth == zoneHeight)
+ _squareZone[idx]._squareZoneFl = true;
+ }
+}
+
+void LinesManager::clearAll() {
+ for (int idx = 0; idx < 105; ++idx) {
+ _zone[idx]._destX = 0;
+ _zone[idx]._destY = 0;
+ _zone[idx]._spriteIndex = 0;
+ }
+
+ _testRoute0 = NULL;
+ _testRoute1 = NULL;
+ _testRoute2 = NULL;
+ _lineBuf = NULL;
+ _route = NULL;
+
+ for (int idx = 0; idx < MAX_LINES; ++idx) {
+ _lineItem[idx]._lineDataEndIdx = 0;
+ _lineItem[idx]._direction = DIR_NONE;
+ _lineItem[idx]._directionRouteInc = DIR_NONE;
+ _lineItem[idx]._directionRouteDec = DIR_NONE;
+ _lineItem[idx]._lineData = NULL;
+
+ _zoneLine[idx]._count = 0;
+ _zoneLine[idx]._bobZoneIdx = 0;
+ _zoneLine[idx]._zoneData = NULL;
+ }
+
+ for (int idx = 0; idx < 100; ++idx)
+ _squareZone[idx]._enabledFl = false;
+
+ _testRoute0 = new RouteItem[8334];
+ _testRoute1 = new RouteItem[8334];
+ _testRoute2 = new RouteItem[8334];
+ if (!_testRoute0)
+ _testRoute0 = NULL;
+ if (!_testRoute1)
+ _testRoute1 = NULL;
+ if (!_testRoute2)
+ _testRoute2 = NULL;
+
+ _largeBuf = _vm->_globals->allocMemory(10000);
+ _lineBuf = (int16 *)(_largeBuf);
+}
+
+/**
+ * Clear all zones and reset nextLine
+ */
+void LinesManager::clearAllZones() {
+ for (int idx = 0; idx < MAX_LINES; ++idx)
+ removeZoneLine(idx);
+}
+
+/**
+ * Remove Zone Line
+ */
+void LinesManager::removeZoneLine(int idx) {
+ assert (idx <= MAX_LINES);
+ _zoneLine[idx]._zoneData = (int16 *)_vm->_globals->freeMemory((byte *)_zoneLine[idx]._zoneData);
+}
+
+void LinesManager::resetLines() {
+ for (int idx = 0; idx < MAX_LINES; ++idx) {
+ removeLine(idx);
+ _lineItem[idx]._lineDataEndIdx = 0;
+ _lineItem[idx]._lineData = NULL;
+ }
+}
+
+// Remove Line
+void LinesManager::removeLine(int idx) {
+ if (idx > MAX_LINES)
+ error("Attempting to add a line obstacle > MAX_LIGNE.");
+ _lineItem[idx]._lineData = (int16 *)_vm->_globals->freeMemory((byte *)_lineItem[idx]._lineData);
+}
+
+void LinesManager::setMaxLineIdx(int idx) {
+ _maxLineIdx = idx;
+}
+
+void LinesManager::resetLastLine() {
+ _lastLine = 0;
+}
+
+void LinesManager::resetLinesNumb() {
+ _linesNumb = 0;
+}
+
+void LinesManager::enableZone(int idx) {
+ if (_bobZone[idx]) {
+ _bobZoneFl[idx] = true;
+ } else {
+ _zone[idx]._enabledFl = true;
+ }
+}
+
+void LinesManager::disableZone(int idx) {
+ if (_bobZone[idx]) {
+ _bobZoneFl[idx] = false;
+ } else {
+ _zone[idx]._enabledFl = false;
+ }
+}
+
+void LinesManager::checkZone() {
+ int mouseX = _vm->_events->getMouseX();
+ int mouseY = _vm->_events->getMouseY();
+ int oldMouseY = mouseY;
+ if (_vm->_globals->_cityMapEnabledFl
+ || _vm->_events->_startPos.x >= mouseX
+ || (mouseY = _vm->_graphicsMan->_scrollOffset + 54, mouseX >= mouseY)
+ || (mouseY = oldMouseY - 1, mouseY < 0 || mouseY > 59)) {
+ if (_vm->_objectsMan->_visibleFl)
+ _vm->_objectsMan->_eraseVisibleCounter = 4;
+ _vm->_objectsMan->_visibleFl = false;
+ } else {
+ _vm->_objectsMan->_visibleFl = true;
+ }
+ if (_vm->_objectsMan->_forceZoneFl) {
+ _zoneSkipCount = 100;
+ _oldMouseZoneId = -1;
+ _oldMouseX = -200;
+ _oldMouseY = -220;
+ _vm->_objectsMan->_forceZoneFl = false;
+ }
+
+ _zoneSkipCount++;
+ if (_zoneSkipCount <= 1)
+ return;
+
+ if (_vm->_globals->_freezeCharacterFl || (_route == NULL) || _zoneSkipCount > 4) {
+ _zoneSkipCount = 0;
+ int zoneId;
+ if (_oldMouseX != mouseX || _oldMouseY != oldMouseY) {
+ zoneId = getMouseZone();
+ } else {
+ zoneId = _oldMouseZoneId;
+ }
+ if (_oldMouseZoneId != zoneId) {
+ _vm->_graphicsMan->setColorPercentage2(251, 100, 100, 100);
+ _vm->_events->_mouseCursorId = 4;
+ _vm->_events->changeMouseCursor(4);
+ if (_forceHideText) {
+ _vm->_fontMan->hideText(5);
+ _forceHideText = false;
+ return;
+ }
+ }
+ if (zoneId != -1) {
+ if (_zone[zoneId]._verbFl1 || _zone[zoneId]._verbFl2 ||
+ _zone[zoneId]._verbFl3 || _zone[zoneId]._verbFl4 ||
+ _zone[zoneId]._verbFl5 || _zone[zoneId]._verbFl6 ||
+ _zone[zoneId]._verbFl7 || _zone[zoneId]._verbFl8 ||
+ _zone[zoneId]._verbFl9 || _zone[zoneId]._verbFl10) {
+ if (_oldMouseZoneId != zoneId) {
+ _vm->_fontMan->initTextBuffers(5, _zone[zoneId]._messageId, _vm->_globals->_zoneFilename, 0, 430, 0, 0, 252);
+ _vm->_fontMan->showText(5);
+ _forceHideText = true;
+ }
+ _hotspotTextColor += 25;
+ if (_hotspotTextColor > 100)
+ _hotspotTextColor = 0;
+ _vm->_graphicsMan->setColorPercentage2(251, _hotspotTextColor, _hotspotTextColor, _hotspotTextColor);
+ if (_vm->_events->_mouseCursorId == 4) {
+ if (_zone[zoneId]._verbFl1 == 2) {
+ _vm->_events->changeMouseCursor(16);
+ _vm->_events->_mouseCursorId = 16;
+ _vm->_objectsMan->setVerb(16);
+ }
+ }
+ } else {
+ _vm->_graphicsMan->setColorPercentage2(251, 100, 100, 100);
+ _vm->_events->_mouseCursorId = 4;
+ _vm->_events->changeMouseCursor(4);
+ }
+ }
+ _vm->_objectsMan->_zoneNum = zoneId;
+ _oldMouseX = mouseX;
+ _oldMouseY = oldMouseY;
+ _oldMouseZoneId = zoneId;
+ if (_vm->_globals->_freezeCharacterFl && (_vm->_events->_mouseCursorId == 4)) {
+ if (zoneId != -1 && zoneId != 0)
+ _vm->_objectsMan->handleRightButton();
+ }
+ if ((_vm->_globals->_cityMapEnabledFl && zoneId == -1) || !zoneId) {
+ _vm->_objectsMan->setVerb(0);
+ _vm->_events->_mouseCursorId = 0;
+ _vm->_events->changeMouseCursor(0);
+ }
+ }
+}
+
+} // End of namespace Hopkins