diff options
Diffstat (limited to 'engines/hopkins/lines.cpp')
-rw-r--r-- | engines/hopkins/lines.cpp | 2914 |
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 |