1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "hopkins/lines.h"
24
25 #include "hopkins/graphics.h"
26 #include "hopkins/hopkins.h"
27
28 #include "common/system.h"
29 #include "common/textconsole.h"
30
31 namespace Hopkins {
32
LinesManager(HopkinsEngine * vm)33 LinesManager::LinesManager(HopkinsEngine *vm) {
34 _vm = vm;
35
36 for (int i = 0; i < MAX_LINES + 1; ++i)
37 Common::fill((byte *)&_zoneLine[i], (byte *)&_zoneLine[i] + sizeof(LigneZoneItem), 0);
38
39 for (int i = 0; i < MAX_LINES; ++i)
40 Common::fill((byte *)&_lineItem[i], (byte *)&_lineItem[i] + sizeof(LigneItem), 0);
41
42 for (int i = 0; i < 4000; ++i)
43 Common::fill((byte *)&_smoothRoute[i], (byte *)&_smoothRoute[i] + sizeof(SmoothItem), 0);
44
45 for (int i = 0; i < 8001; ++i)
46 _bestRoute[i].set(0, 0, DIR_NONE);
47
48 for (int i = 0; i < 101; ++i) {
49 Common::fill((byte *)&_segment[i], (byte *)&_segment[i] + sizeof(SegmentItem), 0);
50 Common::fill((byte *)&_squareZone[i], (byte *)&_squareZone[i] + sizeof(SquareZoneItem), 0);
51 }
52
53 for (int i = 0; i < 105; ++i) {
54 _bobZone[i] = 0;
55 _bobZoneFl[i] = false;
56 }
57
58 for (int i = 0; i < 106; ++i)
59 Common::fill((byte *)&_zone[i], (byte *)&_zone[i] + sizeof(ZoneItem), 0);
60
61 _linesNumb = 0;
62 _newLineIdx = 0;
63 _newLineDataIdx = 0;
64 _newRouteIdx = 0;
65 _newPosX = 0;
66 _newPosY = 0;
67 _smoothMoveDirection = DIR_NONE;
68 _lastLine = 0;
69 _maxLineIdx = 0;
70 _pathFindingMaxDepth = 0;
71 _testRoute0 = NULL;
72 _testRoute1 = NULL;
73 _testRoute2 = NULL;
74 _lineBuf = NULL;
75 _route = NULL;
76 _currentSegmentId = 0;
77 _largeBuf = NULL;
78 _zoneSkipCount = 0;
79 _hotspotTextColor = 0;
80 _forceHideText = false;
81 _oldMouseZoneId = 0;
82 _oldMouseX = 0;
83 _oldMouseY = 0;
84 _oldRouteFromX = 0;
85 _oldRouteFromY = 0;
86 _oldRouteDestX = 0;
87 _oldRouteDestY = 0;
88 _oldZoneNum = 0;
89 }
90
~LinesManager()91 LinesManager::~LinesManager() {
92 _vm->_globals->freeMemory(_largeBuf);
93 if (_testRoute0)
94 delete[] _testRoute0;
95 if (_testRoute1)
96 delete[] _testRoute1;
97 if (_testRoute2)
98 delete[] _testRoute2;
99 }
100
appendToRouteInc(int from,int to,RouteItem * route,int index)101 int LigneItem::appendToRouteInc(int from, int to, RouteItem *route, int index) {
102 debugC(5, kDebugPath, "appendToRouteInc(%d, %d, route, %d)", from, to, index);
103 if (to == -1)
104 to = _lineDataEndIdx;
105
106 for (int i = from; i < to; ++i)
107 route[index++].set(_lineData[2*i], _lineData[2*i+1], _directionRouteInc);
108 return index;
109 }
110
appendToRouteDec(int from,int to,RouteItem * route,int index)111 int LigneItem::appendToRouteDec(int from, int to, RouteItem *route, int index) {
112 debugC(5, kDebugPath, "appendToRouteDecc(%d, %d, route, %d)", from, to, index);
113 if (from == -1)
114 from = _lineDataEndIdx - 1;
115
116 for (int i = from; i > to; --i)
117 route[index++].set(_lineData[2*i], _lineData[2*i+1], _directionRouteDec);
118 return index;
119 }
120
121 /**
122 * Load lines
123 */
loadLines(const Common::String & file)124 void LinesManager::loadLines(const Common::String &file) {
125 debugC(5, kDebugPath, "loadLines(%s)", file.c_str());
126 resetLines();
127 _linesNumb = 0;
128 _lastLine = 0;
129 byte *ptr = _vm->_fileIO->loadFile(file);
130 for (int idx = 0; READ_LE_INT16((uint16 *)ptr + (idx * 5)) != -1; idx++) {
131 addLine(idx,
132 (Directions)READ_LE_INT16((uint16 *)ptr + (idx * 5)),
133 READ_LE_INT16((uint16 *)ptr + (idx * 5) + 1),
134 READ_LE_INT16((uint16 *)ptr + (idx * 5) + 2),
135 READ_LE_INT16((uint16 *)ptr + (idx * 5) + 3),
136 READ_LE_INT16((uint16 *)ptr + (idx * 5) + 4));
137 }
138 initRoute();
139 _vm->_globals->freeMemory(ptr);
140 }
141
142 /**
143 * Check Hotspots in Inventory screen
144 * Returns the ID of the hotspot under mouse
145 */
checkInventoryHotspots(int posX,int posY)146 int LinesManager::checkInventoryHotspots(int posX, int posY) {
147 debugC(5, kDebugPath, "checkInventoryHotspots(%d, %d)", posX, posY);
148 int hotspotId = 0;
149 if (posY >= 120 && posY <= 153)
150 hotspotId = checkInventoryHotspotsRow(posX, 1, false);
151 if (posY >= 154 && posY <= 191)
152 hotspotId = checkInventoryHotspotsRow(posX, 7, false);
153 if (posY >= 192 && posY <= 229)
154 hotspotId = checkInventoryHotspotsRow(posX, 13, false);
155 if (posY >= 230 && posY <= 267)
156 hotspotId = checkInventoryHotspotsRow(posX, 19, false);
157 if (posY >= 268 && posY <= 306)
158 hotspotId = checkInventoryHotspotsRow(posX, 25, true);
159 if (posY >= 268 && posY <= 288 && posX >= _vm->_graphicsMan->_scrollOffset + 424 && posX <= _vm->_graphicsMan->_scrollOffset + 478)
160 hotspotId = 30;
161 if (posY >= 290 && posY <= 306 && posX >= _vm->_graphicsMan->_scrollOffset + 424 && posX <= _vm->_graphicsMan->_scrollOffset + 478)
162 hotspotId = 31;
163 if (posY < 114 || posY > 306 || posX < _vm->_graphicsMan->_scrollOffset + 152 || posX > _vm->_graphicsMan->_scrollOffset + 484)
164 hotspotId = 32;
165
166 return hotspotId;
167 }
168
169 /**
170 * Check the hotspots in an inventory line
171 * Returns the hotspot Id under the mouse, if any.
172 */
checkInventoryHotspotsRow(int posX,int minZoneNum,bool lastRow)173 int LinesManager::checkInventoryHotspotsRow(int posX, int minZoneNum, bool lastRow) {
174 debugC(5, kDebugPath, "checkInventoryHotspotsRow(%d, %d, %d)", posX, minZoneNum, lastRow ? 1 : 0);
175 int result = minZoneNum;
176
177 if (posX >= _vm->_graphicsMan->_scrollOffset + 158 && posX < _vm->_graphicsMan->_scrollOffset + 208)
178 return result;
179
180 if (posX >= _vm->_graphicsMan->_scrollOffset + 208 && posX < _vm->_graphicsMan->_scrollOffset + 266) {
181 result += 1;
182 return result;
183 }
184
185 if (posX >= _vm->_graphicsMan->_scrollOffset + 266 && posX < _vm->_graphicsMan->_scrollOffset + 320) {
186 result += 2;
187 return result;
188 }
189
190 if (posX >= _vm->_graphicsMan->_scrollOffset + 320 && posX < _vm->_graphicsMan->_scrollOffset + 370) {
191 result += 3;
192 return result;
193 }
194
195 if (posX >= _vm->_graphicsMan->_scrollOffset + 370 && posX < _vm->_graphicsMan->_scrollOffset + 424) {
196 result += 4;
197 return result;
198 }
199
200 if (!lastRow && posX >= _vm->_graphicsMan->_scrollOffset + 424 && posX <= _vm->_graphicsMan->_scrollOffset + 478) {
201 result += 5;
202 return result;
203 }
204
205 return 0;
206 }
207
208 /**
209 * Add Zone Line
210 */
addZoneLine(int idx,int fromX,int fromY,int destX,int destY,int bobZoneIdx)211 void LinesManager::addZoneLine(int idx, int fromX, int fromY, int destX, int destY, int bobZoneIdx) {
212 debugC(5, kDebugPath, "addZoneLine(%d, %d, %d, %d, %d, %d)", idx, fromX, fromY, destX, destY, bobZoneIdx);
213 int16 *zoneData;
214
215 if (fromX == fromY && fromY == destX && fromY == destY) {
216 _bobZoneFl[bobZoneIdx] = true;
217 _bobZone[bobZoneIdx] = fromY;
218 } else {
219 assert(idx < MAX_LINES + 1);
220 _zoneLine[idx]._zoneData = (int16 *)_vm->_globals->freeMemory((byte *)_zoneLine[idx]._zoneData);
221
222 int distX = abs(fromX - destX);
223 int distY = abs(fromY - destY);
224 int maxDist = 1;
225 if (distX <= distY)
226 maxDist += distY;
227 else
228 maxDist += distX;
229
230 zoneData = (int16 *)_vm->_globals->allocMemory(2 * sizeof(int16) * maxDist + (4 * sizeof(int16)));
231 assert(zoneData);
232
233 _zoneLine[idx]._zoneData = zoneData;
234
235 int16 *dataP = zoneData;
236 int stepX = 1000 * distX / maxDist;
237 int stepY = 1000 * distY / maxDist;
238 if (destX < fromX)
239 stepX = -stepX;
240 if (destY < fromY)
241 stepY = -stepY;
242 int smoothPosX = 1000 * fromX;
243 int smoothPosY = 1000 * fromY;
244 for (int i = 0; i < maxDist; i++) {
245 *dataP++ = smoothPosX / 1000;
246 *dataP++ = smoothPosY / 1000;
247
248 smoothPosX += stepX;
249 smoothPosY += stepY;
250 }
251 *dataP++ = -1;
252 *dataP++ = -1;
253
254 _zoneLine[idx]._count = maxDist;
255 _zoneLine[idx]._bobZoneIdx = bobZoneIdx;
256 }
257 }
258
259 /**
260 * Add Line
261 */
addLine(int lineIdx,Directions direction,int fromX,int fromY,int destX,int destY)262 void LinesManager::addLine(int lineIdx, Directions direction, int fromX, int fromY, int destX, int destY) {
263 debugC(5, kDebugPath, "addLine(%d, %d, %d, %d, %d, %d)", lineIdx, direction, fromX, fromY, destX, destY);
264 assert(lineIdx < MAX_LINES);
265
266 if (_linesNumb < lineIdx)
267 _linesNumb = lineIdx;
268
269 _lineItem[lineIdx]._lineData = (int16 *)_vm->_globals->freeMemory((byte *)_lineItem[lineIdx]._lineData);
270 int distX = abs(fromX - destX) + 1;
271 int distY = abs(fromY - destY) + 1;
272 int maxDist = distY;
273 if (distX > maxDist)
274 maxDist = distX;
275
276 byte *zoneData = _vm->_globals->allocMemory(4 * maxDist + 8);
277 assert(zoneData);
278
279 Common::fill(zoneData, zoneData + 4 * maxDist + 8, 0);
280 _lineItem[lineIdx]._lineData = (int16 *)zoneData;
281
282 int16 *curLineData = _lineItem[lineIdx]._lineData;
283 int stepX = 1000 * distX / (maxDist - 1);
284 int stepY = 1000 * distY / (maxDist - 1);
285 if (destX < fromX)
286 stepX = -stepX;
287 if (destY < fromY)
288 stepY = -stepY;
289 int dirX = (int)stepX / 1000; // -1: Left, 0: None, 1: Right
290 int dirY = (int)stepY / 1000; // -1: Up, 0: None, 1: Right
291 if (!dirX) {
292 if (dirY == -1) {
293 _lineItem[lineIdx]._directionRouteInc = DIR_UP;
294 _lineItem[lineIdx]._directionRouteDec = DIR_DOWN;
295 } else if (dirY == 1) {
296 _lineItem[lineIdx]._directionRouteInc = DIR_DOWN;
297 _lineItem[lineIdx]._directionRouteDec = DIR_UP;
298 }
299 // If dirY == 0, no move
300 } else if (dirX == 1) {
301 if (dirY == -1) {
302 _lineItem[lineIdx]._directionRouteInc = DIR_UP_RIGHT;
303 _lineItem[lineIdx]._directionRouteDec = DIR_DOWN_LEFT;
304 } else if (!dirY) {
305 _lineItem[lineIdx]._directionRouteInc = DIR_RIGHT;
306 _lineItem[lineIdx]._directionRouteDec = DIR_LEFT;
307 } else if (dirY == 1) {
308 _lineItem[lineIdx]._directionRouteInc = DIR_DOWN_RIGHT;
309 _lineItem[lineIdx]._directionRouteDec = DIR_UP_LEFT;
310 }
311 } else if (dirX == -1) {
312 if (dirY == 1) {
313 _lineItem[lineIdx]._directionRouteInc = DIR_DOWN_LEFT;
314 _lineItem[lineIdx]._directionRouteDec = DIR_UP_RIGHT;
315 } else if (!dirY) {
316 _lineItem[lineIdx]._directionRouteInc = DIR_LEFT;
317 _lineItem[lineIdx]._directionRouteDec = DIR_RIGHT;
318 } else if (dirY == -1) {
319 _lineItem[lineIdx]._directionRouteInc = DIR_UP_LEFT;
320 _lineItem[lineIdx]._directionRouteDec = DIR_DOWN_RIGHT;
321 }
322 }
323
324 // Second pass to soften cases where dirY == 0
325 if (dirX == 1) {
326 if (stepY > 250 && stepY <= 999) {
327 _lineItem[lineIdx]._directionRouteInc = DIR_DOWN_RIGHT;
328 _lineItem[lineIdx]._directionRouteDec = DIR_UP_LEFT;
329 } else if (stepY < -250 && stepY > -1000) {
330 _lineItem[lineIdx]._directionRouteInc = DIR_UP_RIGHT;
331 _lineItem[lineIdx]._directionRouteDec = DIR_DOWN_LEFT;
332 }
333 } else if (dirX == -1) {
334 if (stepY > 250 && stepY <= 999) {
335 _lineItem[lineIdx]._directionRouteInc = DIR_DOWN_LEFT;
336 _lineItem[lineIdx]._directionRouteDec = DIR_UP_RIGHT;
337 } else if (stepY < -250 && stepY > -1000) {
338 // In the original code, the test was on positive values and
339 // was impossible to meet.
340 _lineItem[lineIdx]._directionRouteInc = DIR_UP_LEFT;
341 _lineItem[lineIdx]._directionRouteDec = DIR_DOWN_RIGHT;
342 }
343 }
344
345 stepX = 1000 * distX / maxDist;
346 stepY = 1000 * distY / maxDist;
347 if (destX < fromX)
348 stepX = -stepX;
349 if (destY < fromY)
350 stepY = -stepY;
351 int smoothPosX = 1000 * fromX;
352 int smoothPosY = 1000 * fromY;
353 for (int i = 0; i < maxDist - 1; i++) {
354 curLineData[0] = smoothPosX / 1000;
355 curLineData[1] = smoothPosY / 1000;
356 curLineData += 2;
357
358 smoothPosX += stepX;
359 smoothPosY += stepY;
360 }
361 curLineData[0] = destX;
362 curLineData[1] = destY;
363
364 curLineData += 2;
365 curLineData[0] = -1;
366 curLineData[1] = -1;
367
368 _lineItem[lineIdx]._lineDataEndIdx = maxDist;
369 _lineItem[lineIdx]._direction = direction;
370
371 ++_linesNumb;
372 }
373
374 /**
375 * Check collision line
376 */
checkCollisionLine(int xp,int yp,int * foundDataIdx,int * foundLineIdx,int startLineIdx,int endLineIdx)377 bool LinesManager::checkCollisionLine(int xp, int yp, int *foundDataIdx, int *foundLineIdx, int startLineIdx, int endLineIdx) {
378 debugC(5, kDebugPath, "checkCollisionLine(%d, %d, foundDataIdx, foundLineIdx, %d, %d)", xp, yp, startLineIdx ,endLineIdx);
379 int16 *lineData;
380
381 int left = xp + 4;
382 int right = xp - 4;
383 int top = yp + 4;
384 int bottom = yp - 4;
385
386 *foundDataIdx = -1;
387 *foundLineIdx = -1;
388
389 for (int curLineIdx = startLineIdx; curLineIdx <= endLineIdx; curLineIdx++) {
390 lineData = _lineItem[curLineIdx]._lineData;
391
392 if (lineData == NULL)
393 continue;
394
395 bool collisionFl = true;
396 int lineStartX = lineData[0];
397 int lineStartY = lineData[1];
398 int lineDataIdx = 2 * _lineItem[curLineIdx]._lineDataEndIdx;
399 int lineEndX = lineData[lineDataIdx - 2];
400 int lineEndY = lineData[lineDataIdx - 1];
401 if (lineStartX >= lineEndX) {
402 if (right > lineStartX || left < lineEndX)
403 collisionFl = false;
404 } else { // lineStartX < lineEndX
405 if (left < lineStartX || right > lineEndX)
406 collisionFl = false;
407 }
408 if (lineStartY >= lineEndY) {
409 if (bottom > lineStartY || top < lineEndY)
410 collisionFl = false;
411 } else { // lineStartY < lineEndY
412 if (top < lineStartY || bottom > lineEndY)
413 collisionFl = false;
414 }
415
416 if (!collisionFl)
417 continue;
418
419 for (int idx = 0; idx < _lineItem[curLineIdx]._lineDataEndIdx; idx++) {
420 int lineX = lineData[0];
421 int lineY = lineData[1];
422 lineData += 2;
423
424 if ((xp == lineX || xp + 1 == lineX) && (yp == lineY || yp + 1 == lineY)) {
425 *foundDataIdx = idx;
426 *foundLineIdx = curLineIdx;
427 return true;
428 }
429 }
430 }
431 return false;
432 }
433
434 /**
435 * Init route
436 */
initRoute()437 void LinesManager::initRoute() {
438 debugC(5, kDebugPath, "initRoute()");
439 int lineX = _lineItem[0]._lineData[0];
440 int lineY = _lineItem[0]._lineData[1];
441
442 int lineIdx = 1;
443 for (;;) {
444 int curDataIdx = _lineItem[lineIdx]._lineDataEndIdx;
445 int16 *curLineData = _lineItem[lineIdx]._lineData;
446
447 int curLineX = curLineData[2 * curDataIdx - 2];
448 int curLineY = curLineData[2 * curDataIdx - 1];
449 if (_vm->_graphicsMan->_maxX == curLineX || _vm->_graphicsMan->_maxY == curLineY ||
450 _vm->_graphicsMan->_minX == curLineX || _vm->_graphicsMan->_minY == curLineY ||
451 (lineX == curLineX && lineY == curLineY))
452 break;
453 if (lineIdx == MAX_LINES)
454 error("ERROR - LAST LINE NOT FOUND");
455
456 int16 *nextLineData = _lineItem[lineIdx + 1]._lineData;
457 if (!nextLineData)
458 break;
459 if (nextLineData[0] != curLineX && nextLineData[1] != curLineY)
460 break;
461 ++lineIdx;
462 }
463
464 _lastLine = lineIdx;
465 for (int idx = 1; idx < MAX_LINES; idx++) {
466 if ((_lineItem[idx]._lineDataEndIdx < _maxLineIdx) && (idx != _lastLine + 1)) {
467 _lineItem[idx]._directionRouteInc = _lineItem[idx - 1]._directionRouteInc;
468 _lineItem[idx]._directionRouteDec = _lineItem[idx - 1]._directionRouteDec;
469 }
470 }
471 }
472
473 // Avoid obstacle
avoidObstacle(int lineIdx,int lineDataIdx,int routeIdx,int destLineIdx,int destLineDataIdx,RouteItem * route)474 int LinesManager::avoidObstacle(int lineIdx, int lineDataIdx, int routeIdx, int destLineIdx, int destLineDataIdx, RouteItem *route) {
475 debugC(5, kDebugPath, "avoidObstacle(%d, %d, %d, %d, %d, route)", lineIdx, lineDataIdx, routeIdx, destLineIdx, destLineDataIdx);
476 int curLineIdx = lineIdx;
477 int curLineDataIdx = lineDataIdx;
478 int curRouteIdx = routeIdx;
479 if (lineIdx < destLineIdx) {
480 curRouteIdx = _lineItem[lineIdx].appendToRouteInc(lineDataIdx, -1, route, curRouteIdx);
481
482 for (int i = lineIdx + 1; i < destLineIdx; i++)
483 curRouteIdx = _lineItem[i].appendToRouteInc(0, -1, route, curRouteIdx);
484
485 curLineDataIdx = 0;
486 curLineIdx = destLineIdx;
487 }
488 if (curLineIdx > destLineIdx) {
489 curRouteIdx = _lineItem[curLineIdx].appendToRouteDec(curLineDataIdx, 0, route, curRouteIdx);
490 for (int i = curLineIdx - 1; i > destLineIdx; i--)
491 curRouteIdx = _lineItem[i].appendToRouteDec(-1, 0, route, curRouteIdx);
492 curLineDataIdx = _lineItem[destLineIdx]._lineDataEndIdx - 1;
493 curLineIdx = destLineIdx;
494 }
495 if (curLineIdx == destLineIdx) {
496 if (destLineDataIdx >= curLineDataIdx) {
497 curRouteIdx = _lineItem[destLineIdx].appendToRouteInc(curLineDataIdx, destLineDataIdx, route, curRouteIdx);
498 } else {
499 curRouteIdx = _lineItem[destLineIdx].appendToRouteDec(curLineDataIdx, destLineDataIdx, route, curRouteIdx);
500 }
501 }
502 return curRouteIdx;
503 }
504
505 // Avoid Obstacle, taking into account start/End lind Idx
avoidObstacleOnSegment(int lineIdx,int lineDataIdx,int routeIdx,int destLineIdx,int destLineDataIdx,RouteItem * route,int startLineIdx,int endLineIdx)506 int LinesManager::avoidObstacleOnSegment(int lineIdx, int lineDataIdx, int routeIdx, int destLineIdx, int destLineDataIdx, RouteItem *route, int startLineIdx, int endLineIdx) {
507 debugC(5, kDebugPath, "avoidObstacleOnSegment(%d, %d, %d, %d, %d, route, %d, %d)", lineIdx, lineDataIdx, routeIdx, destLineIdx, destLineDataIdx, startLineIdx, endLineIdx);
508 int curLineIdx = lineIdx;
509 int curLineDataIdx = lineDataIdx;
510 int curRouteIdx = routeIdx;
511 if (destLineIdx < lineIdx) {
512 curRouteIdx = _lineItem[lineIdx].appendToRouteInc(lineDataIdx, -1, route, curRouteIdx);
513 int wrkLineIdx = lineIdx + 1;
514 if (wrkLineIdx == endLineIdx + 1)
515 wrkLineIdx = startLineIdx;
516 while (destLineIdx != wrkLineIdx) {
517 curRouteIdx = _lineItem[wrkLineIdx].appendToRouteInc(0, -1, route, curRouteIdx);
518 ++wrkLineIdx;
519 if (endLineIdx + 1 == wrkLineIdx)
520 wrkLineIdx = startLineIdx;
521 }
522 curLineDataIdx = 0;
523 curLineIdx = destLineIdx;
524 }
525 if (destLineIdx > curLineIdx) {
526 curRouteIdx = _lineItem[curLineIdx].appendToRouteDec(curLineDataIdx, 0, route, curRouteIdx);
527 int wrkLineIdx = curLineIdx - 1;
528 if (wrkLineIdx == startLineIdx - 1)
529 wrkLineIdx = endLineIdx;
530 while (destLineIdx != wrkLineIdx) {
531 curRouteIdx = _lineItem[wrkLineIdx].appendToRouteDec(-1, 0, route, curRouteIdx);
532 --wrkLineIdx;
533 if (startLineIdx - 1 == wrkLineIdx)
534 wrkLineIdx = endLineIdx;
535 }
536 curLineDataIdx = _lineItem[destLineIdx]._lineDataEndIdx - 1;
537 curLineIdx = destLineIdx;
538 }
539 if (destLineIdx == curLineIdx) {
540 if (destLineDataIdx >= curLineDataIdx) {
541 curRouteIdx = _lineItem[destLineIdx].appendToRouteInc(curLineDataIdx, destLineDataIdx, route, curRouteIdx);
542 } else {
543 curRouteIdx = _lineItem[destLineIdx].appendToRouteDec(curLineDataIdx, destLineDataIdx, route, curRouteIdx);
544 }
545 }
546 return curRouteIdx;
547 }
548
MIRACLE(int fromX,int fromY,int lineIdx,int destLineIdx,int routeIdx)549 bool LinesManager::MIRACLE(int fromX, int fromY, int lineIdx, int destLineIdx, int routeIdx) {
550 debugC(5, kDebugPath, "MIRACLE(%d, %d, %d, %d, %d)", fromX, fromY, lineIdx, destLineIdx, routeIdx);
551 int lineIdxLeft = 0;
552 int lineDataIdxLeft = 0;
553 int lineIdxRight = 0;
554 int lineDataIdxRight = 0;
555 int linesIdxUp = 0;
556 int linesDataIdxUp = 0;
557 int lineIdxDown = 0;
558 int lineDataIdxDown = 0;
559
560 int curX = fromX;
561 int curY = fromY;
562 int curLineIdx = lineIdx;
563 int tmpRouteIdx = routeIdx;
564 int dummyDataIdx;
565 if (checkCollisionLine(fromX, fromY, &dummyDataIdx, &curLineIdx, 0, _linesNumb)) {
566 switch (_lineItem[curLineIdx]._direction) {
567 case DIR_UP:
568 curY -= 2;
569 break;
570 case DIR_UP_RIGHT:
571 curY -= 2;
572 curX += 2;
573 break;
574 case DIR_RIGHT:
575 curX += 2;
576 break;
577 case DIR_DOWN_RIGHT:
578 curY += 2;
579 curX += 2;
580 break;
581 case DIR_DOWN:
582 curY += 2;
583 break;
584 case DIR_DOWN_LEFT:
585 curY += 2;
586 curX -= 2;
587 break;
588 case DIR_LEFT:
589 curX -= 2;
590 break;
591 case DIR_UP_LEFT:
592 curY -= 2;
593 curX -= 2;
594 break;
595 default:
596 break;
597 }
598 }
599
600 int stepVertIncCount = 0;
601 for (int i = curY; curY + 200 > i; i++) {
602 if (checkCollisionLine(curX, i, &lineDataIdxDown, &lineIdxDown, 0, _lastLine) == 1 && lineIdxDown <= _lastLine)
603 break;
604 lineDataIdxDown = 0;
605 lineIdxDown = -1;
606 ++stepVertIncCount;
607 }
608
609 int stepVertDecCount = 0;
610 for (int i = curY; curY - 200 < i; i--) {
611 if (checkCollisionLine(curX, i, &linesDataIdxUp, &linesIdxUp, 0, _lastLine) == 1 && linesIdxUp <= _lastLine)
612 break;
613 linesDataIdxUp = 0;
614 linesIdxUp = -1;
615 ++stepVertDecCount;
616 }
617
618 int stepHoriIncCount = 0;
619 for (int i = curX; curX + 200 > i; i++) {
620 if (checkCollisionLine(i, curY, &lineDataIdxRight, &lineIdxRight, 0, _lastLine) == 1 && lineIdxRight <= _lastLine)
621 break;
622 lineDataIdxRight = 0;
623 lineIdxRight = -1;
624 ++stepHoriIncCount;
625 }
626
627 int stepHoriDecCount = 0;
628 for (int i = curX; curX - 200 < i; i--) {
629 if (checkCollisionLine(i, curY, &lineDataIdxLeft, &lineIdxLeft, 0, _lastLine) == 1 && lineIdxLeft <= _lastLine)
630 break;
631 lineDataIdxLeft = 0;
632 lineIdxLeft = -1;
633 ++stepHoriDecCount;
634 }
635
636 if (destLineIdx > curLineIdx) {
637 if (linesIdxUp != -1 && linesIdxUp <= curLineIdx)
638 linesIdxUp = -1;
639 if (lineIdxRight != -1 && curLineIdx >= lineIdxRight)
640 lineIdxRight = -1;
641 if (lineIdxDown != -1 && curLineIdx >= lineIdxDown)
642 lineIdxDown = -1;
643 if (lineIdxLeft != -1 && curLineIdx >= lineIdxLeft)
644 lineIdxLeft = -1;
645 if (linesIdxUp != -1 && destLineIdx < linesIdxUp)
646 linesIdxUp = -1;
647 if (lineIdxRight != -1 && destLineIdx < lineIdxRight)
648 lineIdxRight = -1;
649 if (lineIdxDown != -1 && destLineIdx < lineIdxDown)
650 lineIdxDown = -1;
651 if (lineIdxLeft != -1 && destLineIdx < lineIdxLeft)
652 lineIdxLeft = -1;
653 } else if (destLineIdx < curLineIdx) {
654 if (linesIdxUp != -1 && linesIdxUp >= curLineIdx)
655 linesIdxUp = -1;
656 if (lineIdxRight != -1 && curLineIdx <= lineIdxRight)
657 lineIdxRight = -1;
658 if (lineIdxDown != -1 && curLineIdx <= lineIdxDown)
659 lineIdxDown = -1;
660 if (lineIdxLeft != -1 && curLineIdx <= lineIdxLeft)
661 lineIdxLeft = -1;
662 if (linesIdxUp != -1 && destLineIdx > linesIdxUp)
663 linesIdxUp = -1;
664 if (lineIdxRight != -1 && destLineIdx > lineIdxRight)
665 lineIdxRight = -1;
666 if (lineIdxDown != -1 && destLineIdx > lineIdxDown)
667 lineIdxDown = -1;
668 if (lineIdxLeft != -1 && destLineIdx > lineIdxLeft)
669 lineIdxLeft = -1;
670 }
671 if (linesIdxUp != -1 || lineIdxRight != -1 || lineIdxDown != -1 || lineIdxLeft != -1) {
672 Directions newDir = DIR_NONE;
673 if (destLineIdx > curLineIdx) {
674 if (lineIdxDown <= linesIdxUp && lineIdxRight <= linesIdxUp && lineIdxLeft <= linesIdxUp && linesIdxUp > curLineIdx)
675 newDir = DIR_UP;
676 if (lineIdxDown <= lineIdxRight && linesIdxUp <= lineIdxRight && lineIdxLeft <= lineIdxRight && curLineIdx < lineIdxRight)
677 newDir = DIR_RIGHT;
678 if (linesIdxUp <= lineIdxDown && lineIdxRight <= lineIdxDown && lineIdxLeft <= lineIdxDown && curLineIdx < lineIdxDown)
679 newDir = DIR_DOWN;
680 if (lineIdxDown <= lineIdxLeft && lineIdxRight <= lineIdxLeft && linesIdxUp <= lineIdxLeft && curLineIdx < lineIdxLeft)
681 newDir = DIR_LEFT;
682 } else if (destLineIdx < curLineIdx) {
683 if (linesIdxUp == -1)
684 linesIdxUp = INVALID_LINE_VALUE;
685 if (lineIdxRight == -1)
686 lineIdxRight = INVALID_LINE_VALUE;
687 if (lineIdxDown == -1)
688 lineIdxDown = INVALID_LINE_VALUE;
689 if (lineIdxLeft == -1)
690 lineIdxLeft = INVALID_LINE_VALUE;
691 if (linesIdxUp != INVALID_LINE_VALUE && lineIdxDown >= linesIdxUp && lineIdxRight >= linesIdxUp && lineIdxLeft >= linesIdxUp && linesIdxUp < curLineIdx)
692 newDir = DIR_UP;
693 if (lineIdxRight != INVALID_LINE_VALUE && lineIdxDown >= lineIdxRight && linesIdxUp >= lineIdxRight && lineIdxLeft >= lineIdxRight && curLineIdx > lineIdxRight)
694 newDir = DIR_RIGHT;
695 if (lineIdxDown != INVALID_LINE_VALUE && linesIdxUp >= lineIdxDown && lineIdxRight >= lineIdxDown && lineIdxLeft >= lineIdxDown && curLineIdx > lineIdxDown)
696 newDir = DIR_DOWN;
697 if (lineIdxLeft != INVALID_LINE_VALUE && lineIdxDown >= lineIdxLeft && lineIdxRight >= lineIdxLeft && linesIdxUp >= lineIdxLeft && curLineIdx > lineIdxLeft)
698 newDir = DIR_LEFT;
699 }
700
701 int newLinesDataIdx = 0;
702 int newLinesIdx = 0;
703 switch(newDir) {
704 case DIR_UP:
705 newLinesIdx = linesIdxUp;
706 newLinesDataIdx = linesDataIdxUp;
707 for (int i = 0; i < stepVertDecCount; i++) {
708 if (checkCollisionLine(curX, curY - i, &linesDataIdxUp, &linesIdxUp, _lastLine + 1, _linesNumb) && _lastLine < linesIdxUp) {
709 int tmpRouteIdxUp = computeRouteIdx(linesIdxUp, linesDataIdxUp, curX, curY - i, curX, curY - stepVertDecCount, tmpRouteIdx, &_bestRoute[0]);
710 if (tmpRouteIdxUp == -1)
711 return false;
712 tmpRouteIdx = tmpRouteIdxUp;
713 if (_newPosY != -1)
714 i = _newPosY - curY;
715 }
716 _bestRoute[tmpRouteIdx].set(curX, curY - i, DIR_UP);
717 tmpRouteIdx++;
718 }
719 _newLineIdx = newLinesIdx;
720 _newLineDataIdx = newLinesDataIdx;
721 _newRouteIdx = tmpRouteIdx;
722 return true;
723 break;
724 case DIR_RIGHT:
725 newLinesIdx = lineIdxRight;
726 newLinesDataIdx = lineDataIdxRight;
727 for (int i = 0; i < stepHoriIncCount; i++) {
728 if (checkCollisionLine(i + curX, curY, &linesDataIdxUp, &linesIdxUp, _lastLine + 1, _linesNumb) && _lastLine < linesIdxUp) {
729 int tmpRouteIdxRight = computeRouteIdx(linesIdxUp, linesDataIdxUp, i + curX, curY, stepHoriIncCount + curX, curY, tmpRouteIdx, &_bestRoute[0]);
730 if (tmpRouteIdxRight == -1)
731 return false;
732 tmpRouteIdx = tmpRouteIdxRight;
733 if (_newPosX != -1)
734 i = _newPosX - curX;
735 }
736 _bestRoute[tmpRouteIdx].set(i + curX, curY, DIR_RIGHT);
737 tmpRouteIdx++;
738 }
739 _newLineIdx = newLinesIdx;
740 _newLineDataIdx = newLinesDataIdx;
741 _newRouteIdx = tmpRouteIdx;
742 return true;
743 break;
744 case DIR_DOWN:
745 newLinesIdx = lineIdxDown;
746 newLinesDataIdx = lineDataIdxDown;
747 for (int i = 0; i < stepVertIncCount; i++) {
748 if (checkCollisionLine(curX, i + curY, &linesDataIdxUp, &linesIdxUp, _lastLine + 1, _linesNumb) && _lastLine < linesIdxUp) {
749 int tmpRouteIdxDown = computeRouteIdx(linesIdxUp, linesDataIdxUp, curX, i + curY, curX, stepVertIncCount + curY, tmpRouteIdx, &_bestRoute[0]);
750 if (tmpRouteIdxDown == -1)
751 return false;
752 tmpRouteIdx = tmpRouteIdxDown;
753 if (_newPosY != -1)
754 i = curY - _newPosY;
755 }
756 _bestRoute[tmpRouteIdx].set(curX, i + curY, DIR_DOWN);
757 tmpRouteIdx++;
758 }
759 _newLineIdx = newLinesIdx;
760 _newLineDataIdx = newLinesDataIdx;
761 _newRouteIdx = tmpRouteIdx;
762 return true;
763 break;
764 case DIR_LEFT:
765 newLinesIdx = lineIdxLeft;
766 newLinesDataIdx = lineDataIdxLeft;
767 for (int i = 0; i < stepHoriDecCount; i++) {
768 if (checkCollisionLine(curX - i, curY, &linesDataIdxUp, &linesIdxUp, _lastLine + 1, _linesNumb) && _lastLine < linesIdxUp) {
769 int tmpRouteIdxLeft = computeRouteIdx(linesIdxUp, linesDataIdxUp, curX - i, curY, curX - stepHoriDecCount, curY, tmpRouteIdx, &_bestRoute[0]);
770 if (tmpRouteIdxLeft == -1)
771 return false;
772 tmpRouteIdx = tmpRouteIdxLeft;
773 if (_newPosX != -1)
774 i = curX - _newPosX;
775 }
776 _bestRoute[tmpRouteIdx].set(curX - i, curY, DIR_LEFT);
777 tmpRouteIdx++;
778 }
779 _newLineIdx = newLinesIdx;
780 _newLineDataIdx = newLinesDataIdx;
781 _newRouteIdx = tmpRouteIdx;
782 return true;
783 break;
784 default:
785 break;
786 }
787 }
788 return false;
789 }
790
computeRouteIdx(int lineIdx,int dataIdx,int fromX,int fromY,int destX,int destY,int routerIdx,RouteItem * route)791 int LinesManager::computeRouteIdx(int lineIdx, int dataIdx, int fromX, int fromY, int destX, int destY, int routerIdx, RouteItem *route) {
792 debugC(5, kDebugPath, "computeRouteIdx(%d, %d, %d, %d, %d, %d, %d)", lineIdx, dataIdx, fromX, fromY, destX, destY, routerIdx);
793 int result = routerIdx;
794 ++_pathFindingMaxDepth;
795 if (_pathFindingMaxDepth > 10) {
796 warning("PathFinding - Max depth reached");
797 route[routerIdx].invalidate();
798 return -1;
799 }
800 int lineX = _lineItem[lineIdx]._lineData[0];
801 int lineY = _lineItem[lineIdx]._lineData[1];
802 int startLineIdx = lineIdx;
803
804 int curLineDataEndIdx;
805 bool loopCond = false;
806 for (;;) {
807 int curLineIdx = startLineIdx - 1;
808 int endLineIdx = 2 * _lineItem[startLineIdx - 1]._lineDataEndIdx;
809
810 int16 *lineData = _lineItem[startLineIdx - 1]._lineData;
811 if (lineData == NULL)
812 break;
813 while (lineData[endLineIdx - 2] != lineX || lineY != lineData[endLineIdx - 1]) {
814 --curLineIdx;
815 if (_lastLine - 1 != curLineIdx) {
816 endLineIdx = 2 * _lineItem[curLineIdx]._lineDataEndIdx;
817 lineData = _lineItem[curLineIdx]._lineData;
818 if (lineData)
819 continue;
820 }
821 loopCond = true;
822 break;
823 }
824 if (loopCond)
825 break;
826
827 startLineIdx = curLineIdx;
828 lineX = lineData[0];
829 lineY = lineData[1];
830 }
831
832 int lastIdx = _lineItem[lineIdx]._lineDataEndIdx - 1;
833 int lastPosX = _lineItem[lineIdx]._lineData[(2 * lastIdx)];
834 int lastPosY = _lineItem[lineIdx]._lineData[(2 * lastIdx) + 1];
835 int endLineIdx = lineIdx;
836 int foundLineIdx, foundDataIdx;
837 loopCond = false;
838 for (;;) {
839 int curLineIdx = endLineIdx + 1;
840 int nextLineDataEndIdx = 2 * _lineItem[curLineIdx]._lineDataEndIdx;
841 int16 *lineData = _lineItem[curLineIdx]._lineData;
842 if (lineData == NULL)
843 break;
844 for (;;) {
845 curLineDataEndIdx = nextLineDataEndIdx;
846 if (lineData[0] == lastPosX && lastPosY == lineData[1])
847 break;
848
849 ++curLineIdx;
850 if (curLineIdx != _linesNumb + 1) {
851 nextLineDataEndIdx = 2 * _lineItem[curLineIdx]._lineDataEndIdx;
852 lineData = _lineItem[curLineIdx]._lineData;
853 if (lineData)
854 continue;
855 }
856 loopCond = true;
857 break;
858 }
859 if (loopCond)
860 break;
861
862 endLineIdx = curLineIdx;
863 lastPosX = lineData[curLineDataEndIdx - 2];
864 lastPosY = lineData[curLineDataEndIdx - 1];
865 }
866
867 int distX = abs(fromX - destX) + 1;
868 int distY = abs(fromY - destY) + 1;
869 int maxDist = distY;
870 if (distX > distY)
871 maxDist = distX;
872 int stepX = 1000 * distX / maxDist;
873 int stepY = 1000 * distY / maxDist;
874 int smoothPosX = 1000 * fromX;
875 int smoothPosY = 1000 * fromY;
876 if (destX < fromX)
877 stepX = -stepX;
878 if (destY < fromY)
879 stepY = -stepY;
880 if (maxDist > 800)
881 maxDist = 800;
882
883 Common::fill(&_lineBuf[0], &_lineBuf[1000], 0);
884 int bugLigIdx = 0;
885 for (int i = 0; i < maxDist + 1; i++) {
886 _lineBuf[bugLigIdx] = smoothPosX / 1000;
887 _lineBuf[bugLigIdx + 1] = smoothPosY / 1000;
888 smoothPosX += stepX;
889 smoothPosY += stepY;
890 bugLigIdx += 2;
891 }
892 bugLigIdx -= 2;
893 int destDataIdx = 0;
894 int destLineIdx = -1;
895 int bufX = 0;
896 int bufY = 0;
897 for (int i = maxDist + 1; i > 0; i--) {
898 if (checkCollisionLine(_lineBuf[bugLigIdx], _lineBuf[bugLigIdx + 1], &foundDataIdx, &foundLineIdx, startLineIdx, endLineIdx) && _lastLine < foundLineIdx) {
899 destLineIdx = foundLineIdx;
900 destDataIdx = foundDataIdx;
901 bufX = _lineBuf[bugLigIdx];
902 bufY = _lineBuf[bugLigIdx + 1];
903 break;
904 }
905 bugLigIdx -= 2;
906 }
907 int maxLineX = 0;
908 int minLineX = 0;
909 int maxLineY = 0;
910 int minLineY = 0;
911 for (int i = startLineIdx; i <= endLineIdx; ++i) {
912 int16 *lineData = _lineItem[i]._lineData;
913 if (lineData == NULL)
914 error("error in genial routine");
915 if (i == startLineIdx) {
916 minLineY = MIN(lineData[1], lineData[2 * _lineItem[i]._lineDataEndIdx - 1]);
917 maxLineY = MAX(lineData[1], lineData[2 * _lineItem[i]._lineDataEndIdx - 1]);
918
919 minLineX = MIN(lineData[0], lineData[2 * _lineItem[i]._lineDataEndIdx - 2]);
920 maxLineX = MAX(lineData[0], lineData[2 * _lineItem[i]._lineDataEndIdx - 2]);
921 } else {
922 if (lineData[1] < lineData[2 * _lineItem[i]._lineDataEndIdx - 1] && lineData[1] < minLineY)
923 minLineY = lineData[1];
924 if (lineData[2 * _lineItem[i]._lineDataEndIdx - 1] < lineData[1] && lineData[2 * _lineItem[i]._lineDataEndIdx - 1] < minLineY)
925 minLineY = lineData[2 * _lineItem[i]._lineDataEndIdx - 1];
926 if (lineData[1] > lineData[2 * _lineItem[i]._lineDataEndIdx - 1] && lineData[1] > maxLineY)
927 maxLineY = lineData[1];
928 if (lineData[2 * _lineItem[i]._lineDataEndIdx - 1] > lineData[1] && lineData[2 * _lineItem[i]._lineDataEndIdx - 1] > maxLineY)
929 maxLineY = lineData[2 * _lineItem[i]._lineDataEndIdx - 1];
930 if (lineData[0] < lineData[2 * _lineItem[i]._lineDataEndIdx - 2] && minLineX > lineData[0])
931 minLineX = lineData[0];
932 if (lineData[2 * _lineItem[i]._lineDataEndIdx - 2] < lineData[0] && minLineX > lineData[2 * _lineItem[i]._lineDataEndIdx - 2])
933 minLineX = lineData[2 * _lineItem[i]._lineDataEndIdx - 2];
934 if (lineData[0] > lineData[2 * _lineItem[i]._lineDataEndIdx - 2] && maxLineX < lineData[0])
935 maxLineX = lineData[0];
936 if (lineData[2 * _lineItem[i]._lineDataEndIdx - 2] > lineData[0] && maxLineX < lineData[2 * _lineItem[i]._lineDataEndIdx - 2])
937 maxLineX = lineData[2 * _lineItem[i]._lineDataEndIdx - 2];
938 }
939 }
940
941 minLineX -= 2;
942 minLineY -= 2;
943 maxLineX += 2;
944 maxLineY += 2;
945 if (destX >= minLineX && destX <= maxLineX && destY >= minLineY && destY <= maxLineY) {
946 int curY = destY;
947 int linesIdxUp = -1;
948 do {
949 --curY;
950 if (checkCollisionLine(destX, curY, &foundDataIdx, &foundLineIdx, startLineIdx, endLineIdx)) {
951 linesIdxUp = foundLineIdx;
952 break;
953 }
954 } while (curY && curY >= minLineY);
955
956 curY = destY;
957 int lineIdxDown = -1;
958 do {
959 ++curY;
960 if (checkCollisionLine(destX, curY, &foundDataIdx, &foundLineIdx, startLineIdx, endLineIdx)) {
961 lineIdxDown = foundLineIdx;
962 break;
963 }
964 } while (curY < _vm->_globals->_characterMaxPosY && curY < maxLineY);
965
966 int curX = destX;
967 int lineIdxRight = -1;
968 do {
969 ++curX;
970 if (checkCollisionLine(curX, destY, &foundDataIdx, &foundLineIdx, startLineIdx, endLineIdx)) {
971 lineIdxRight = foundLineIdx;
972 break;
973 }
974 } while (curX < _vm->_graphicsMan->_maxX && curX < maxLineX);
975
976 curX = destX;
977 int lineIdxLeft = -1;
978 do {
979 --curX;
980 if (checkCollisionLine(curX, destY, &foundDataIdx, &foundLineIdx, startLineIdx, endLineIdx)) {
981 lineIdxLeft = foundLineIdx;
982 break;
983 }
984 } while (curX > 0 && curX > minLineX);
985
986 if (lineIdxRight != -1 && lineIdxLeft != -1 && linesIdxUp != -1 && lineIdxDown != -1) {
987 route[routerIdx].invalidate();
988 return -1;
989 }
990 }
991 if (bufX < fromX - 1 || bufX > fromX + 1 || bufY < fromY - 1 || bufY > fromY + 1) {
992 _newPosX = bufX;
993 _newPosY = bufY;
994 if (lineIdx < destLineIdx) {
995 int stepCount = 0;
996 int curLineIdx = lineIdx;
997 do {
998 if (curLineIdx == startLineIdx - 1)
999 curLineIdx = endLineIdx;
1000 ++stepCount;
1001 --curLineIdx;
1002 if (curLineIdx == startLineIdx - 1)
1003 curLineIdx = endLineIdx;
1004 } while (destLineIdx != curLineIdx);
1005 if (abs(destLineIdx - lineIdx) == stepCount) {
1006 if (dataIdx > abs(_lineItem[lineIdx]._lineDataEndIdx / 2)) {
1007 result = avoidObstacle(lineIdx, dataIdx, routerIdx, destLineIdx, destDataIdx, route);
1008 } else {
1009 result = avoidObstacleOnSegment(lineIdx, dataIdx, routerIdx, destLineIdx, destDataIdx, route, startLineIdx, endLineIdx);
1010 }
1011 }
1012 if (abs(destLineIdx - lineIdx) < stepCount)
1013 result = avoidObstacle(lineIdx, dataIdx, result, destLineIdx, destDataIdx, route);
1014 if (stepCount < abs(destLineIdx - lineIdx))
1015 result = avoidObstacleOnSegment(lineIdx, dataIdx, result, destLineIdx, destDataIdx, route, startLineIdx, endLineIdx);
1016 }
1017 if (lineIdx > destLineIdx) {
1018 int destStepCount = abs(lineIdx - destLineIdx);
1019 int curLineIdx = lineIdx;
1020 int curStepCount = 0;
1021 do {
1022 if (curLineIdx == endLineIdx + 1)
1023 curLineIdx = startLineIdx;
1024 ++curStepCount;
1025 ++curLineIdx;
1026 if (curLineIdx == endLineIdx + 1)
1027 curLineIdx = startLineIdx;
1028 } while (destLineIdx != curLineIdx);
1029 if (destStepCount == curStepCount) {
1030 if (dataIdx > abs(_lineItem[lineIdx]._lineDataEndIdx / 2)) {
1031 result = avoidObstacleOnSegment(lineIdx, dataIdx, result, destLineIdx, destDataIdx, route, startLineIdx, endLineIdx);
1032 } else {
1033 result = avoidObstacle(lineIdx, dataIdx, result, destLineIdx, destDataIdx, route);
1034 }
1035 }
1036 if (destStepCount < curStepCount)
1037 result = avoidObstacle(lineIdx, dataIdx, result, destLineIdx, destDataIdx, route);
1038 if (curStepCount < destStepCount)
1039 result = avoidObstacleOnSegment(lineIdx, dataIdx, result, destLineIdx, destDataIdx, route, startLineIdx, endLineIdx);
1040 }
1041 if (lineIdx == destLineIdx)
1042 result = avoidObstacle(lineIdx, dataIdx, result, lineIdx, destDataIdx, route);
1043 for(;;) {
1044 if (!checkCollisionLine(_newPosX, _newPosY, &foundDataIdx, &foundLineIdx, _lastLine + 1, _linesNumb))
1045 break;
1046
1047 switch (_lineItem[foundLineIdx]._direction) {
1048 case DIR_UP:
1049 --_newPosY;
1050 break;
1051 case DIR_UP_RIGHT:
1052 --_newPosY;
1053 ++_newPosX;
1054 break;
1055 case DIR_RIGHT:
1056 ++_newPosX;
1057 break;
1058 case DIR_DOWN_RIGHT:
1059 ++_newPosY;
1060 ++_newPosX;
1061 break;
1062 case DIR_DOWN:
1063 ++_newPosY;
1064 break;
1065 case DIR_DOWN_LEFT:
1066 ++_newPosY;
1067 --_newPosX;
1068 break;
1069 case DIR_LEFT:
1070 --_newPosX;
1071 break;
1072 case DIR_UP_LEFT:
1073 --_newPosY;
1074 --_newPosX;
1075 break;
1076 default:
1077 break;
1078 }
1079 }
1080 } else {
1081 _newPosX = -1;
1082 _newPosY = -1;
1083 }
1084 return result;
1085 }
1086
1087 // Find Route from a point to the other
findRoute(int fromX,int fromY,int destX,int destY)1088 RouteItem *LinesManager::findRoute(int fromX, int fromY, int destX, int destY) {
1089 debugC(5, kDebugPath, "findRoute(%d, %d, %d, %d)", fromX, fromY, destX, destY);
1090 int foundLineIdx;
1091 int foundDataIdx;
1092 int curLineY = 0;
1093 int curLineX = 0;
1094 int stepArr[9];
1095 int deltaArr[9];
1096 int collLineDataIdxArr[9];
1097 int collLineIdxArr[9];
1098
1099 int clipDestX = destX;
1100 int clipDestY = destY;
1101 int curLineIdx = 0;
1102 int curLineDataIdx = 0;
1103 int lineIdx = 0;
1104 int lineDataIdx = 0;
1105 Directions newDir = DIR_NONE;
1106 if (destY <= 24)
1107 clipDestY = 25;
1108 if (!_vm->_globals->_checkDistanceFl) {
1109 if (abs(fromX - _oldRouteFromX) <= 4 && abs(fromY - _oldRouteFromY) <= 4 &&
1110 abs(_oldRouteDestX - destX) <= 4 && abs(_oldRouteDestY - clipDestY) <= 4)
1111 return NULL;
1112
1113 if (abs(fromX - destX) <= 4 && abs(fromY - clipDestY) <= 4)
1114 return NULL;
1115
1116 if (_oldZoneNum > 0 && _vm->_objectsMan->_zoneNum > 0 && _oldZoneNum == _vm->_objectsMan->_zoneNum)
1117 return NULL;
1118 }
1119 _vm->_globals->_checkDistanceFl = false;
1120 _oldZoneNum = _vm->_objectsMan->_zoneNum;
1121 _oldRouteFromX = fromX;
1122 _oldRouteDestX = destX;
1123 _oldRouteFromY = fromY;
1124 _oldRouteDestY = clipDestY;
1125 _pathFindingMaxDepth = 0;
1126 int routeIdx = 0;
1127 if (destX <= 19)
1128 clipDestX = 20;
1129 if (clipDestY <= 19)
1130 clipDestY = 20;
1131 if (clipDestX > _vm->_graphicsMan->_maxX - 10)
1132 clipDestX = _vm->_graphicsMan->_maxX - 10;
1133 if (clipDestY > _vm->_globals->_characterMaxPosY)
1134 clipDestY = _vm->_globals->_characterMaxPosY;
1135
1136 if (abs(fromX - clipDestX) <= 3 && abs(fromY - clipDestY) <= 3)
1137 return NULL;
1138
1139 for (int i = 0; i <= 8; ++i) {
1140 collLineIdxArr[i] = -1;
1141 collLineDataIdxArr[i] = 0;
1142 deltaArr[i] = INVALID_LINE_VALUE;
1143 stepArr[i] = INVALID_LINE_VALUE;
1144 }
1145
1146 if (characterRoute(fromX, fromY, clipDestX, clipDestY, -1, -1, 0) == 1)
1147 return _bestRoute;
1148
1149 int tmpDelta = 0;
1150 for (int tmpY = clipDestY; tmpY < _vm->_graphicsMan->_maxY; tmpY++, tmpDelta++) {
1151 if (checkCollisionLine(clipDestX, tmpY, &collLineDataIdxArr[DIR_DOWN], &collLineIdxArr[DIR_DOWN], 0, _lastLine) && collLineIdxArr[DIR_DOWN] <= _lastLine)
1152 break;
1153 collLineDataIdxArr[DIR_DOWN] = 0;
1154 collLineIdxArr[DIR_DOWN] = -1;
1155 }
1156 deltaArr[DIR_DOWN] = tmpDelta;
1157
1158 tmpDelta = 0;
1159 for (int tmpY = clipDestY; tmpY > _vm->_graphicsMan->_minY; tmpY--, tmpDelta++) {
1160 if (checkCollisionLine(clipDestX, tmpY, &collLineDataIdxArr[DIR_UP], &collLineIdxArr[DIR_UP], 0, _lastLine) && collLineIdxArr[DIR_UP] <= _lastLine)
1161 break;
1162 collLineDataIdxArr[DIR_UP] = 0;
1163 collLineIdxArr[DIR_UP] = -1;
1164 if (deltaArr[DIR_DOWN] < tmpDelta && collLineIdxArr[DIR_DOWN] != -1)
1165 break;
1166 }
1167 deltaArr[DIR_UP] = tmpDelta;
1168
1169 tmpDelta = 0;
1170 for (int tmpX = clipDestX; tmpX < _vm->_graphicsMan->_maxX; tmpX++) {
1171 if (checkCollisionLine(tmpX, clipDestY, &collLineDataIdxArr[DIR_RIGHT], &collLineIdxArr[DIR_RIGHT], 0, _lastLine) && collLineIdxArr[DIR_RIGHT] <= _lastLine)
1172 break;
1173 collLineDataIdxArr[DIR_RIGHT] = 0;
1174 collLineIdxArr[DIR_RIGHT] = -1;
1175 ++tmpDelta;
1176 if (deltaArr[DIR_UP] < tmpDelta && collLineIdxArr[DIR_UP] != -1)
1177 break;
1178 if (deltaArr[DIR_DOWN] < tmpDelta && collLineIdxArr[DIR_DOWN] != -1)
1179 break;
1180 }
1181 deltaArr[DIR_RIGHT] = tmpDelta;
1182
1183 tmpDelta = 0;
1184 for (int tmpX = clipDestX; tmpX > _vm->_graphicsMan->_minX; tmpX--) {
1185 if (checkCollisionLine(tmpX, clipDestY, &collLineDataIdxArr[DIR_LEFT], &collLineIdxArr[DIR_LEFT], 0, _lastLine) && collLineIdxArr[DIR_LEFT] <= _lastLine)
1186 break;
1187 collLineDataIdxArr[DIR_LEFT] = 0;
1188 collLineIdxArr[DIR_LEFT] = -1;
1189 ++tmpDelta;
1190 if (deltaArr[DIR_UP] < tmpDelta && collLineIdxArr[DIR_UP] != -1)
1191 break;
1192 if (deltaArr[DIR_DOWN] < tmpDelta && collLineIdxArr[DIR_DOWN] != -1)
1193 break;
1194 if (deltaArr[DIR_RIGHT] < tmpDelta && collLineIdxArr[DIR_RIGHT] != -1)
1195 break;
1196 }
1197 deltaArr[DIR_LEFT] = tmpDelta;
1198
1199 if (collLineIdxArr[DIR_UP] < 0 || _lastLine < collLineIdxArr[DIR_UP])
1200 collLineIdxArr[DIR_UP] = -1;
1201 if (collLineIdxArr[DIR_RIGHT] < 0 || _lastLine < collLineIdxArr[DIR_RIGHT])
1202 collLineIdxArr[DIR_RIGHT] = -1;
1203 if (collLineIdxArr[DIR_DOWN] < 0 || _lastLine < collLineIdxArr[DIR_DOWN])
1204 collLineIdxArr[DIR_DOWN] = -1;
1205 if (collLineIdxArr[DIR_LEFT] < 0 || _lastLine < collLineIdxArr[DIR_LEFT])
1206 collLineIdxArr[DIR_LEFT] = -1;
1207 if (collLineIdxArr[DIR_UP] < 0)
1208 deltaArr[DIR_UP] = INVALID_LINE_VALUE;
1209 if (collLineIdxArr[DIR_RIGHT] < 0)
1210 deltaArr[DIR_RIGHT] = INVALID_LINE_VALUE;
1211 if (collLineIdxArr[DIR_DOWN] < 0)
1212 deltaArr[DIR_DOWN] = INVALID_LINE_VALUE;
1213 if (collLineIdxArr[DIR_LEFT] < 0)
1214 deltaArr[DIR_LEFT] = INVALID_LINE_VALUE;
1215 if (collLineIdxArr[DIR_UP] == -1 && collLineIdxArr[DIR_RIGHT] == -1 && collLineIdxArr[DIR_DOWN] == -1 && collLineIdxArr[DIR_LEFT] == -1)
1216 return NULL;
1217
1218 if (collLineIdxArr[DIR_DOWN] != -1 && deltaArr[DIR_UP] >= deltaArr[DIR_DOWN] && deltaArr[DIR_RIGHT] >= deltaArr[DIR_DOWN] && deltaArr[DIR_LEFT] >= deltaArr[DIR_DOWN]) {
1219 curLineIdx = collLineIdxArr[DIR_DOWN];
1220 curLineDataIdx = collLineDataIdxArr[DIR_DOWN];
1221 } else if (collLineIdxArr[DIR_UP] != -1 && deltaArr[DIR_DOWN] >= deltaArr[DIR_UP] && deltaArr[DIR_RIGHT] >= deltaArr[DIR_UP] && deltaArr[DIR_LEFT] >= deltaArr[DIR_UP]) {
1222 curLineIdx = collLineIdxArr[DIR_UP];
1223 curLineDataIdx = collLineDataIdxArr[DIR_UP];
1224 } else if (collLineIdxArr[DIR_RIGHT] != -1 && deltaArr[DIR_UP] >= deltaArr[DIR_RIGHT] && deltaArr[DIR_DOWN] >= deltaArr[DIR_RIGHT] && deltaArr[DIR_LEFT] >= deltaArr[DIR_RIGHT]) {
1225 curLineIdx = collLineIdxArr[DIR_RIGHT];
1226 curLineDataIdx = collLineDataIdxArr[DIR_RIGHT];
1227 } else if (collLineIdxArr[DIR_LEFT] != -1 && deltaArr[DIR_DOWN] >= deltaArr[DIR_LEFT] && deltaArr[DIR_RIGHT] >= deltaArr[DIR_LEFT] && deltaArr[DIR_UP] >= deltaArr[DIR_LEFT]) {
1228 curLineIdx = collLineIdxArr[DIR_LEFT];
1229 curLineDataIdx = collLineDataIdxArr[DIR_LEFT];
1230 }
1231
1232 for (int i = 0; i <= 8; ++i) {
1233 collLineIdxArr[i] = -1;
1234 collLineDataIdxArr[i] = 0;
1235 deltaArr[i] = INVALID_LINE_VALUE;
1236 stepArr[i] = INVALID_LINE_VALUE;
1237 }
1238
1239 tmpDelta = 0;
1240 for (int tmpY = fromY; tmpY < _vm->_graphicsMan->_maxY; tmpY++, tmpDelta++) {
1241 if (checkCollisionLine(fromX, tmpY, &collLineDataIdxArr[DIR_DOWN], &collLineIdxArr[DIR_DOWN], 0, _lastLine) && collLineIdxArr[DIR_DOWN] <= _lastLine)
1242 break;
1243 collLineDataIdxArr[DIR_DOWN] = 0;
1244 collLineIdxArr[DIR_DOWN] = -1;
1245 }
1246 deltaArr[DIR_DOWN] = tmpDelta + 1;
1247
1248 tmpDelta = 0;
1249 for (int tmpY = fromY; tmpY > _vm->_graphicsMan->_minY; tmpY--) {
1250 if (checkCollisionLine(fromX, tmpY, &collLineDataIdxArr[DIR_UP], &collLineIdxArr[DIR_UP], 0, _lastLine) && collLineIdxArr[DIR_UP] <= _lastLine)
1251 break;
1252 collLineDataIdxArr[DIR_UP] = 0;
1253 collLineIdxArr[DIR_UP] = -1;
1254 ++tmpDelta;
1255 if (collLineIdxArr[DIR_DOWN] != -1 && tmpDelta > 80)
1256 break;
1257 }
1258 deltaArr[DIR_UP] = tmpDelta + 1;
1259
1260 tmpDelta = 0;
1261 for (int tmpX = fromX; tmpX < _vm->_graphicsMan->_maxX; tmpX++) {
1262 if (checkCollisionLine(tmpX, fromY, &collLineDataIdxArr[DIR_RIGHT], &collLineIdxArr[DIR_RIGHT], 0, _lastLine) && collLineIdxArr[DIR_RIGHT] <= _lastLine)
1263 break;
1264 collLineDataIdxArr[DIR_RIGHT] = 0;
1265 collLineIdxArr[DIR_RIGHT] = -1;
1266 ++tmpDelta;
1267 if ((collLineIdxArr[DIR_DOWN] != -1 || collLineIdxArr[DIR_UP] != -1) && (tmpDelta > 100))
1268 break;
1269 }
1270 deltaArr[DIR_RIGHT] = tmpDelta + 1;
1271
1272 tmpDelta = 0;
1273 for (int tmpX = fromX; tmpX > _vm->_graphicsMan->_minX; tmpX--) {
1274 if (checkCollisionLine(tmpX, fromY, &collLineDataIdxArr[DIR_LEFT], &collLineIdxArr[DIR_LEFT], 0, _lastLine) && collLineIdxArr[DIR_LEFT] <= _lastLine)
1275 break;
1276 collLineDataIdxArr[DIR_LEFT] = 0;
1277 collLineIdxArr[DIR_LEFT] = -1;
1278 ++tmpDelta;
1279 if ((collLineIdxArr[DIR_DOWN] != -1 || collLineIdxArr[DIR_UP] != -1 || collLineIdxArr[DIR_RIGHT] != -1) && (tmpDelta > 100))
1280 break;
1281 }
1282 deltaArr[DIR_LEFT] = tmpDelta + 1;
1283
1284 if (collLineIdxArr[DIR_UP] != -1)
1285 stepArr[DIR_UP] = abs(collLineIdxArr[DIR_UP] - curLineIdx);
1286
1287 if (collLineIdxArr[DIR_RIGHT] != -1)
1288 stepArr[DIR_RIGHT] = abs(collLineIdxArr[DIR_RIGHT] - curLineIdx);
1289
1290 if (collLineIdxArr[DIR_DOWN] != -1)
1291 stepArr[DIR_DOWN] = abs(collLineIdxArr[DIR_DOWN] - curLineIdx);
1292
1293 if (collLineIdxArr[DIR_LEFT] != -1)
1294 stepArr[DIR_LEFT] = abs(collLineIdxArr[DIR_LEFT] - curLineIdx);
1295
1296 if (collLineIdxArr[DIR_UP] == -1 && collLineIdxArr[DIR_RIGHT] == -1 && collLineIdxArr[DIR_DOWN] == -1 && collLineIdxArr[DIR_LEFT] == -1)
1297 error("Nearest point not found");
1298
1299 int delta = 0;
1300 if (collLineIdxArr[DIR_UP] != -1 && stepArr[DIR_RIGHT] >= stepArr[DIR_UP] && stepArr[DIR_DOWN] >= stepArr[DIR_UP] && stepArr[DIR_LEFT] >= stepArr[DIR_UP]) {
1301 lineIdx = collLineIdxArr[DIR_UP];
1302 delta = deltaArr[DIR_UP];
1303 newDir = DIR_UP;
1304 lineDataIdx = collLineDataIdxArr[DIR_UP];
1305 } else if (collLineIdxArr[DIR_DOWN] != -1 && stepArr[DIR_RIGHT] >= stepArr[DIR_DOWN] && stepArr[DIR_UP] >= stepArr[DIR_DOWN] && stepArr[DIR_LEFT] >= stepArr[DIR_DOWN]) {
1306 lineIdx = collLineIdxArr[DIR_DOWN];
1307 delta = deltaArr[DIR_DOWN];
1308 newDir = DIR_DOWN;
1309 lineDataIdx = collLineDataIdxArr[DIR_DOWN];
1310 } else if (collLineIdxArr[DIR_RIGHT] != -1 && stepArr[DIR_UP] >= stepArr[DIR_RIGHT] && stepArr[DIR_DOWN] >= stepArr[DIR_RIGHT] && stepArr[DIR_LEFT] >= stepArr[DIR_RIGHT]) {
1311 lineIdx = collLineIdxArr[DIR_RIGHT];
1312 delta = deltaArr[DIR_RIGHT];
1313 newDir = DIR_RIGHT;
1314 lineDataIdx = collLineDataIdxArr[DIR_RIGHT];
1315 } else if (collLineIdxArr[DIR_LEFT] != -1 && stepArr[DIR_UP] >= stepArr[DIR_LEFT] && stepArr[DIR_DOWN] >= stepArr[DIR_LEFT] && stepArr[DIR_RIGHT] >= stepArr[DIR_LEFT]) {
1316 lineIdx = collLineIdxArr[DIR_LEFT];
1317 delta = deltaArr[DIR_LEFT];
1318 newDir = DIR_LEFT;
1319 lineDataIdx = collLineDataIdxArr[DIR_LEFT];
1320 }
1321
1322 int bestRouteNum = characterRoute(fromX, fromY, clipDestX, clipDestY, lineIdx, curLineIdx, 0);
1323
1324 if (bestRouteNum == 1)
1325 return _bestRoute;
1326
1327 if (bestRouteNum == 2) {
1328 lineIdx = _newLineIdx;
1329 lineDataIdx = _newLineDataIdx;
1330 routeIdx = _newRouteIdx;
1331 } else {
1332 switch (newDir) {
1333 case DIR_UP:
1334 for (int deltaY = 0; deltaY < delta; deltaY++) {
1335 if (checkCollisionLine(fromX, fromY - deltaY, &foundDataIdx, &foundLineIdx, _lastLine + 1, _linesNumb) && _lastLine < foundLineIdx) {
1336 int tmpRouteIdx = computeRouteIdx(foundLineIdx, foundDataIdx, fromX, fromY - deltaY, fromX, fromY - delta, routeIdx, _bestRoute);
1337 if (tmpRouteIdx == -1) {
1338 _bestRoute[routeIdx].invalidate();
1339 return &_bestRoute[0];
1340 }
1341 routeIdx = tmpRouteIdx;
1342 if (_newPosY != -1)
1343 deltaY = fromY - _newPosY;
1344 }
1345 _bestRoute[routeIdx].set(fromX, fromY - deltaY, DIR_UP);
1346 routeIdx++;
1347 }
1348 break;
1349 case DIR_DOWN:
1350 for (int deltaY = 0; deltaY < delta; deltaY++) {
1351 if (checkCollisionLine(fromX, deltaY + fromY, &foundDataIdx, &foundLineIdx, _lastLine + 1, _linesNumb)
1352 && _lastLine < foundLineIdx) {
1353 int tmpRouteIdx = computeRouteIdx(foundLineIdx, foundDataIdx, fromX, deltaY + fromY, fromX, delta + fromY, routeIdx, &_bestRoute[0]);
1354 if (tmpRouteIdx == -1) {
1355 _bestRoute[routeIdx].invalidate();
1356 return &_bestRoute[0];
1357 }
1358 routeIdx = tmpRouteIdx;
1359 if (_newPosY != -1)
1360 deltaY = _newPosY - fromY;
1361 }
1362 _bestRoute[routeIdx].set(fromX, fromY + deltaY, DIR_DOWN);
1363 routeIdx++;
1364 }
1365 break;
1366 case DIR_LEFT:
1367 for (int deltaX = 0; deltaX < delta; deltaX++) {
1368 if (checkCollisionLine(fromX - deltaX, fromY, &foundDataIdx, &foundLineIdx, _lastLine + 1, _linesNumb) && _lastLine < foundLineIdx) {
1369 int tmpRouteIdx = computeRouteIdx(foundLineIdx, foundDataIdx, fromX - deltaX, fromY, fromX - delta, fromY, routeIdx, &_bestRoute[0]);
1370 if (tmpRouteIdx == -1) {
1371 _bestRoute[routeIdx].invalidate();
1372 return &_bestRoute[0];
1373 }
1374 routeIdx = tmpRouteIdx;
1375 if (_newPosX != -1)
1376 deltaX = fromX - _newPosX;
1377 }
1378 _bestRoute[routeIdx].set(fromX - deltaX, fromY, DIR_LEFT);
1379 routeIdx++;
1380 }
1381 break;
1382 case DIR_RIGHT:
1383 for (int deltaX = 0; deltaX < delta; deltaX++) {
1384 if (checkCollisionLine(deltaX + fromX, fromY, &foundDataIdx, &foundLineIdx, _lastLine + 1, _linesNumb) && _lastLine < foundLineIdx) {
1385 int tmpRouteIdx = computeRouteIdx(foundLineIdx, foundDataIdx, deltaX + fromX, fromY, delta + fromX, fromY, routeIdx, &_bestRoute[0]);
1386 if (tmpRouteIdx == -1) {
1387 _bestRoute[routeIdx].invalidate();
1388 return &_bestRoute[0];
1389 }
1390 routeIdx = tmpRouteIdx;
1391 if (_newPosX != -1)
1392 deltaX = _newPosX - fromX;
1393 }
1394 _bestRoute[routeIdx].set(fromX + deltaX, fromY, DIR_RIGHT);
1395 routeIdx++;
1396 }
1397 break;
1398 default:
1399 break;
1400 }
1401 }
1402
1403 bool loopCond;
1404 do {
1405 loopCond = false;
1406 if (lineIdx < curLineIdx) {
1407 for (int i = lineDataIdx; _lineItem[lineIdx]._lineDataEndIdx > i; ++i) {
1408 curLineX = _lineItem[lineIdx]._lineData[2 * i];
1409 curLineY = _lineItem[lineIdx]._lineData[2 * i + 1];
1410 _bestRoute[routeIdx].set(_lineItem[lineIdx]._lineData[2 * i], _lineItem[lineIdx]._lineData[2 * i + 1], _lineItem[lineIdx]._directionRouteInc);
1411 routeIdx++;
1412 }
1413 for (int idx = lineIdx + 1; idx < curLineIdx; idx++) {
1414 for (int dataIdx = 0; _lineItem[idx]._lineDataEndIdx > dataIdx; dataIdx++) {
1415 curLineX = _lineItem[idx]._lineData[2 * dataIdx];
1416 curLineY = _lineItem[idx]._lineData[2 * dataIdx + 1];
1417 _bestRoute[routeIdx].set(_lineItem[idx]._lineData[2 * dataIdx], _lineItem[idx]._lineData[2 * dataIdx + 1], _lineItem[idx]._directionRouteInc);
1418 routeIdx++;
1419 if (_lineItem[idx]._lineDataEndIdx > 30 && dataIdx == _lineItem[idx]._lineDataEndIdx / 2) {
1420 bestRouteNum = characterRoute(_lineItem[idx]._lineData[2 * dataIdx], _lineItem[idx]._lineData[2 * dataIdx + 1], clipDestX, clipDestY, idx, curLineIdx, routeIdx);
1421 if (bestRouteNum == 1)
1422 return &_bestRoute[0];
1423 if (bestRouteNum == 2 || MIRACLE(curLineX, curLineY, idx, curLineIdx, routeIdx)) {
1424 lineIdx = _newLineIdx;
1425 lineDataIdx = _newLineDataIdx;
1426 routeIdx = _newRouteIdx;
1427 loopCond = true;
1428 break;
1429 }
1430 }
1431 }
1432
1433 if (loopCond)
1434 break;
1435
1436 bestRouteNum = characterRoute(curLineX, curLineY, clipDestX, clipDestY, idx, curLineIdx, routeIdx);
1437 if (bestRouteNum == 1)
1438 return &_bestRoute[0];
1439 if (bestRouteNum == 2 || MIRACLE(curLineX, curLineY, idx, curLineIdx, routeIdx)) {
1440 lineIdx = _newLineIdx;
1441 lineDataIdx = _newLineDataIdx;
1442 routeIdx = _newRouteIdx;
1443 loopCond = true;
1444 break;
1445 }
1446 }
1447 if (loopCond)
1448 continue;
1449
1450 lineDataIdx = 0;
1451 lineIdx = curLineIdx;
1452 }
1453 if (lineIdx > curLineIdx) {
1454 for (int dataIdx = lineDataIdx; dataIdx > 0; dataIdx--) {
1455 curLineX = _lineItem[lineIdx]._lineData[2 * dataIdx];
1456 curLineY = _lineItem[lineIdx]._lineData[2 * dataIdx + 1];
1457
1458 _bestRoute[routeIdx].set(_lineItem[lineIdx]._lineData[2 * dataIdx], _lineItem[lineIdx]._lineData[2 * dataIdx + 1], _lineItem[lineIdx]._directionRouteDec);
1459 routeIdx++;
1460 }
1461 for (int i = lineIdx - 1; i > curLineIdx; i--) {
1462 for (int dataIdx = _lineItem[i]._lineDataEndIdx - 1; dataIdx > -1; dataIdx--) {
1463 curLineX = _lineItem[i]._lineData[2 * dataIdx];
1464 curLineY = _lineItem[i]._lineData[2 * dataIdx + 1];
1465 _bestRoute[routeIdx].set(_lineItem[i]._lineData[2 * dataIdx], _lineItem[i]._lineData[2 * dataIdx + 1], _lineItem[i]._directionRouteDec);
1466 routeIdx++;
1467 if (_lineItem[i]._lineDataEndIdx > 30 && dataIdx == _lineItem[i]._lineDataEndIdx / 2) {
1468 bestRouteNum = characterRoute(curLineX, curLineY, clipDestX, clipDestY, i, curLineIdx, routeIdx);
1469 if (bestRouteNum == 1)
1470 return &_bestRoute[0];
1471 if (bestRouteNum == 2 || MIRACLE(curLineX, curLineY, i, curLineIdx, routeIdx)) {
1472 lineIdx = _newLineIdx;
1473 lineDataIdx = _newLineDataIdx;
1474 routeIdx = _newRouteIdx;
1475 loopCond = true;
1476 break;
1477 }
1478 }
1479 }
1480
1481 if (loopCond)
1482 break;
1483
1484 bestRouteNum = characterRoute(curLineX, curLineY, clipDestX, clipDestY, i, curLineIdx, routeIdx);
1485 if (bestRouteNum == 1)
1486 return &_bestRoute[0];
1487 if (bestRouteNum == 2 || MIRACLE(curLineX, curLineY, i, curLineIdx, routeIdx)) {
1488 lineIdx = _newLineIdx;
1489 lineDataIdx = _newLineDataIdx;
1490 routeIdx = _newRouteIdx;
1491 loopCond = true;
1492 break;
1493 }
1494 }
1495
1496 if (!loopCond) {
1497 lineDataIdx = _lineItem[curLineIdx]._lineDataEndIdx - 1;
1498 lineIdx = curLineIdx;
1499 }
1500 }
1501 } while (loopCond);
1502
1503 if (lineIdx == curLineIdx) {
1504 if (lineDataIdx <= curLineDataIdx)
1505 routeIdx = _lineItem[curLineIdx].appendToRouteInc(lineDataIdx, curLineDataIdx, _bestRoute, routeIdx);
1506 else
1507 routeIdx = _lineItem[curLineIdx].appendToRouteDec(lineDataIdx, curLineDataIdx, _bestRoute, routeIdx);
1508 }
1509 if (characterRoute(_bestRoute[routeIdx - 1]._x, _bestRoute[routeIdx - 1]._y, clipDestX, clipDestY, -1, -1, routeIdx) != 1) {
1510 _bestRoute[routeIdx].invalidate();
1511 }
1512
1513 return &_bestRoute[0];
1514 }
1515
useRoute0(int idx,int curRouteIdx)1516 void LinesManager::useRoute0(int idx, int curRouteIdx) {
1517 debugC(5, kDebugPath, "useRoute0(%d, %d)", idx, curRouteIdx);
1518 if (idx) {
1519 int i = 0;
1520 do {
1521 assert(curRouteIdx <= 8000);
1522 _bestRoute[curRouteIdx++] = _testRoute0[i++];
1523 } while (_testRoute0[i].isValid());
1524 }
1525 _bestRoute[curRouteIdx].invalidate();
1526 }
1527
useRoute1(int idx,int curRouteIdx)1528 void LinesManager::useRoute1(int idx, int curRouteIdx) {
1529 debugC(5, kDebugPath, "useRoute1(%d, %d)", idx, curRouteIdx);
1530 if (idx) {
1531 int i = 0;
1532 do {
1533 assert(curRouteIdx <= 8000);
1534 _bestRoute[curRouteIdx++] = _testRoute1[i++];
1535 } while (_testRoute1[i].isValid());
1536 }
1537 _bestRoute[curRouteIdx].invalidate();
1538 }
1539
useRoute2(int idx,int curRouteIdx)1540 void LinesManager::useRoute2(int idx, int curRouteIdx) {
1541 debugC(5, kDebugPath, "useRoute2(%d, %d)", idx, curRouteIdx);
1542 if (idx) {
1543 int i = 0;
1544 do {
1545 assert(curRouteIdx <= 8000);
1546 _bestRoute[curRouteIdx++] = _testRoute2[i++];
1547 } while (_testRoute2[i].isValid());
1548 }
1549 _bestRoute[curRouteIdx].invalidate();
1550 }
1551
characterRoute(int fromX,int fromY,int destX,int destY,int startLineIdx,int endLineIdx,int routeIdx)1552 int LinesManager::characterRoute(int fromX, int fromY, int destX, int destY, int startLineIdx, int endLineIdx, int routeIdx) {
1553 debugC(5, kDebugPath, "characterRoute(%d, %d, %d, %d, %d, %d, %d)", fromX, fromY, destX, destY, startLineIdx, endLineIdx, routeIdx);
1554 int collDataIdxRoute2 = 0;
1555
1556 int curX = fromX;
1557 int curY = fromY;
1558 int curRouteIdx = routeIdx;
1559 bool dummyLineFl = false;
1560 if (startLineIdx == -1 && endLineIdx == -1)
1561 dummyLineFl = true;
1562 int foundDataIdx;
1563 int foundLineIdx = startLineIdx;
1564 if (checkCollisionLine(fromX, fromY, &foundDataIdx, &foundLineIdx, 0, _linesNumb)) {
1565 switch (_lineItem[foundLineIdx]._direction) {
1566 case DIR_UP:
1567 curY -= 2;
1568 break;
1569 case DIR_UP_RIGHT:
1570 curY -= 2;
1571 curX += 2;
1572 break;
1573 case DIR_RIGHT:
1574 curX += 2;
1575 break;
1576 case DIR_DOWN_RIGHT:
1577 curY += 2;
1578 curX += 2;
1579 break;
1580 case DIR_DOWN:
1581 curY += 2;
1582 break;
1583 case DIR_DOWN_LEFT:
1584 curY += 2;
1585 curX -= 2;
1586 break;
1587 case DIR_LEFT:
1588 curX -= 2;
1589 break;
1590 case DIR_UP_LEFT:
1591 curY -= 2;
1592 curX -= 2;
1593 break;
1594 default:
1595 break;
1596 }
1597 }
1598 int oldX = curX;
1599 int oldY = curY;
1600 int idxRoute0 = 0;
1601 int collLineIdxRoute0 = -1;
1602 int collLineIdxRoute1 = -1;
1603 int collLineIdxRoute2 = -1;
1604
1605 int repeatFlag = 0;
1606 int collDataIdxRoute0 = 0;
1607 int collDataIdxRoute1 = 0;
1608 for (;;) {
1609 int newX = curX;
1610 int newY = curY;
1611 if (destX >= curX - 2 && destX <= curX + 2 && destY >= curY - 2 && destY <= curY + 2) {
1612 _testRoute0[idxRoute0].invalidate();
1613 useRoute0(idxRoute0, curRouteIdx);
1614 return 1;
1615 }
1616 int distX = abs(curX - destX) + 1;
1617 int distY = abs(curY - destY) + 1;
1618 int maxDist;
1619 if (distX > distY)
1620 maxDist = distX;
1621 else
1622 maxDist = distY;
1623 maxDist--;
1624 assert(maxDist != 0);
1625 int stepX = 1000 * distX / maxDist;
1626 int stepY = 1000 * distY / maxDist;
1627 if (destX < curX)
1628 stepX = -stepX;
1629 if (destY < curY)
1630 stepY = -stepY;
1631 int vertDirection = (int16)stepX / 1000;
1632 int horzDirection = (int16)stepY / 1000;
1633 Directions newDirection = DIR_NONE;
1634 if (horzDirection == -1 && (stepX >= 0 && stepX <= 150))
1635 newDirection = DIR_UP;
1636 if (vertDirection == 1 && (stepY >= -1 && stepY <= 150))
1637 newDirection = DIR_RIGHT;
1638 if (horzDirection == 1 && (stepX >= -150 && stepX <= 150))
1639 newDirection = DIR_DOWN;
1640 if (vertDirection == -1 && (stepY >= -150 && stepY <= 150))
1641 newDirection = DIR_LEFT;
1642 if (horzDirection == -1 && (stepX >= -150 && stepX <= 0))
1643 newDirection = DIR_UP;
1644
1645 if (newDirection == DIR_NONE && !checkSmoothMove(curX, newY, destX, destY) && !makeSmoothMove(curX, newY, destX, destY)) {
1646 newDirection = _smoothMoveDirection;
1647 int smoothRouteIdx = 0;
1648 for (smoothRouteIdx = 0; _smoothRoute[smoothRouteIdx]._posX != -1 && _smoothRoute[smoothRouteIdx]._posY != -1; ++smoothRouteIdx) {
1649 if (checkCollisionLine(_smoothRoute[smoothRouteIdx]._posX, _smoothRoute[smoothRouteIdx]._posY, &collDataIdxRoute0, &collLineIdxRoute0, 0, _linesNumb)) {
1650 if (collLineIdxRoute0 > _lastLine)
1651 collLineIdxRoute0 = -1;
1652 break;
1653 }
1654
1655 _testRoute0[idxRoute0].set(_smoothRoute[smoothRouteIdx]._posX, _smoothRoute[smoothRouteIdx]._posY, newDirection);
1656 idxRoute0++;
1657
1658 if (repeatFlag == 1) {
1659 repeatFlag = 2;
1660 break;
1661 }
1662 }
1663
1664 if (repeatFlag != 2 && _smoothRoute[smoothRouteIdx]._posX != -1 && _smoothRoute[smoothRouteIdx]._posY != -1)
1665 break;
1666
1667 repeatFlag = 1;
1668 newX = _smoothRoute[smoothRouteIdx - 1]._posX;
1669 newY = _smoothRoute[smoothRouteIdx - 1]._posY;
1670 }
1671 int newDistX = abs(newX - destX) + 1;
1672 int newDistY = abs(newY - destY) + 1;
1673 int newMaxDist = newDistY;
1674 if (newDistX > newDistY)
1675 newMaxDist = newDistX;
1676 if (newMaxDist <= 10) {
1677 _testRoute0[idxRoute0].invalidate();
1678 useRoute0(idxRoute0, curRouteIdx);
1679 return 1;
1680 }
1681 int newStepX = 1000 * newDistX / (newMaxDist - 1);
1682 int newStepY = 1000 * newDistY / (newMaxDist - 1);
1683 if (destX < newX)
1684 newStepX = -newStepX;
1685 if (destY < newY)
1686 newStepY = -newStepY;
1687 int newVertDirection = newStepX / 1000;
1688 int newHorzDirection = newStepY / 1000;
1689 int newSmoothX = 1000 * newX;
1690 int newSmoothY = 1000 * newY;
1691 int curPosX = newSmoothX / 1000;
1692 int curPosY = newSmoothY / 1000;
1693 if (!(newStepX / 1000) && newHorzDirection == -1)
1694 newDirection = DIR_UP;
1695 if (newVertDirection == 1) {
1696 if (newHorzDirection == -1)
1697 newDirection = DIR_UP_RIGHT;
1698 if (!newHorzDirection)
1699 newDirection = DIR_RIGHT;
1700 if (newHorzDirection == 1)
1701 newDirection = DIR_DOWN_RIGHT;
1702 }
1703 if (!newVertDirection && newHorzDirection == 1)
1704 newDirection = DIR_DOWN;
1705 if ((newVertDirection != -1) && (newHorzDirection == -1)) {
1706 if (newStepX >= 0 && newStepX < 510)
1707 newDirection = DIR_UP;
1708 else if (newStepX >= 510 && newStepX <= 1000)
1709 newDirection = DIR_UP_RIGHT;
1710 } else {
1711 if (newHorzDirection == 1)
1712 newDirection = DIR_DOWN_LEFT;
1713 else if (!newHorzDirection)
1714 newDirection = DIR_LEFT;
1715 else if (newHorzDirection == -1) {
1716 if (newStepX >= 0 && newStepX < 510)
1717 newDirection = DIR_UP;
1718 else if (newStepX >= 510 && newStepX <= 1000)
1719 newDirection = DIR_UP_RIGHT;
1720 else
1721 newDirection = DIR_UP_LEFT;
1722 }
1723 }
1724 if (newVertDirection == 1) {
1725 if (newStepY >= -1000 && newStepY <= -510)
1726 newDirection = DIR_UP_RIGHT;
1727 if (newStepY >= -510 && newStepY <= 510)
1728 newDirection = DIR_RIGHT;
1729 if (newStepY >= 510 && newStepY <= 1000)
1730 newDirection = DIR_DOWN_RIGHT;
1731 }
1732 if (newHorzDirection == 1) {
1733 if (newStepX >= 510 && newStepX <= 1000)
1734 newDirection = DIR_DOWN_RIGHT;
1735 if (newStepX >= -510 && newStepX <= 510)
1736 newDirection = DIR_DOWN;
1737 if (newStepX >= -1000 && newStepX <= -510)
1738 newDirection = DIR_DOWN_LEFT;
1739 }
1740 if (newVertDirection == -1) {
1741 if (newStepY >= 510 && newStepY <= 1000)
1742 newDirection = DIR_DOWN_LEFT;
1743 if (newStepY >= -510 && newStepY <= 510)
1744 newDirection = DIR_LEFT;
1745 if (newStepY >= -1000 && newStepY <= -510)
1746 newDirection = DIR_UP_LEFT;
1747 }
1748 if (newHorzDirection == -1) {
1749 if (newStepX >= -1000 && newStepX <= -510)
1750 newDirection = DIR_UP_LEFT;
1751 if (newStepX >= -510 && newStepX <= 0)
1752 newDirection = DIR_UP;
1753 }
1754 if (newMaxDist + 1 <= 0) {
1755 _testRoute0[idxRoute0].invalidate();
1756 useRoute0(idxRoute0, curRouteIdx);
1757 return 1;
1758 }
1759 int curDist = 0;
1760 while (!checkCollisionLine(curPosX, curPosY, &collDataIdxRoute0, &collLineIdxRoute0, 0, _linesNumb)) {
1761 _testRoute0[idxRoute0].set(curPosX, curPosY, newDirection);
1762 newSmoothX += newStepX;
1763 newSmoothY += newStepY;
1764 curPosX = newSmoothX / 1000;
1765 curPosY = newSmoothY / 1000;
1766 idxRoute0++;
1767 ++curDist;
1768 if (curDist >= newMaxDist + 1) {
1769 _testRoute0[idxRoute0].invalidate();
1770 useRoute0(idxRoute0, curRouteIdx);
1771 return 1;
1772 }
1773 }
1774 if (_lastLine >= collLineIdxRoute0)
1775 break;
1776 int tmpRouteIdx = computeRouteIdx(collLineIdxRoute0, collDataIdxRoute0, curPosX, curPosY, destX, destY, idxRoute0, _testRoute0);
1777 if (tmpRouteIdx == -1) {
1778 useRoute0(idxRoute0, curRouteIdx);
1779 return 1;
1780 }
1781 idxRoute0 = tmpRouteIdx;
1782 if (_newPosX != -1 || _newPosY != -1) {
1783 collLineIdxRoute0 = -1;
1784 break;
1785 }
1786 curX = -1;
1787 curY = -1;
1788 }
1789
1790 _testRoute0[idxRoute0].invalidate();
1791
1792 int idxRoute1 = 0;
1793 int posXRoute1 = oldX;
1794 int posYRoute1 = oldY;
1795
1796 while (true) {
1797
1798 if (destX >= posXRoute1 - 2 && destX <= posXRoute1 + 2 && destY >= posYRoute1 - 2 && destY <= posYRoute1 + 2) {
1799 _testRoute1[idxRoute1].invalidate();
1800 useRoute1(idxRoute1, curRouteIdx);
1801 return 1;
1802 }
1803 while (posXRoute1 != destX) {
1804 if (checkCollisionLine(posXRoute1, posYRoute1, &collDataIdxRoute1, &collLineIdxRoute1, 0, _linesNumb)) {
1805 if (collLineIdxRoute1 > _lastLine)
1806 collLineIdxRoute1 = -1;
1807 break;
1808 }
1809
1810 if (posXRoute1 < destX)
1811 _testRoute1[idxRoute1++].set(posXRoute1++, posYRoute1, DIR_RIGHT);
1812 else
1813 _testRoute1[idxRoute1++].set(posXRoute1--, posYRoute1, DIR_LEFT);
1814 }
1815 if (posXRoute1 != destX)
1816 break;
1817
1818 int curPosY = posYRoute1;
1819 while (curPosY != destY) {
1820 if (checkCollisionLine(destX, curPosY, &collDataIdxRoute1, &collLineIdxRoute1, 0, _linesNumb)) {
1821 if (collLineIdxRoute1 <= _lastLine)
1822 break;
1823
1824 int tmpRouteIdx = computeRouteIdx(collLineIdxRoute1, collDataIdxRoute1, destX, curPosY, destX, destY, idxRoute1, _testRoute1);
1825 if (tmpRouteIdx == -1) {
1826 useRoute1(idxRoute1, curRouteIdx);
1827 return 1;
1828 }
1829 idxRoute1 = tmpRouteIdx;
1830 if (_newPosX != -1 && _newPosY != -1)
1831 break;
1832 }
1833
1834 if (curPosY < destY)
1835 _testRoute1[idxRoute1++].set(destX, curPosY++, DIR_DOWN);
1836 else
1837 _testRoute1[idxRoute1++].set(destX, curPosY--, DIR_UP);
1838 }
1839 if (curPosY == destY) {
1840 _testRoute1[idxRoute1].invalidate();
1841 useRoute1(idxRoute1, curRouteIdx);
1842 return 1;
1843 }
1844 if (collLineIdxRoute1 <= _lastLine)
1845 break;
1846 posXRoute1 = _newPosX;
1847 posYRoute1 = _newPosY;
1848 bool colRes = checkCollisionLine(_newPosX, _newPosY, &collDataIdxRoute1, &collLineIdxRoute1, 0, _lastLine);
1849 if (colRes && collLineIdxRoute1 <= _lastLine)
1850 break;
1851 }
1852
1853 _testRoute1[idxRoute1].invalidate();
1854 idxRoute1 = 0;
1855 int posXRoute2 = oldX;
1856 int posYRoute2 = oldY;
1857 while (true) {
1858 int curPosX;
1859 if (destX >= posXRoute2 - 2 && destX <= posXRoute2 + 2 && destY >= posYRoute2 - 2 && destY <= posYRoute2 + 2) {
1860 _testRoute2[idxRoute1].invalidate();
1861 useRoute2(idxRoute1, curRouteIdx);
1862 return 1;
1863 }
1864
1865 int curPosYRoute2 = posYRoute2;
1866 while (curPosYRoute2 != destY) {
1867 if (checkCollisionLine(posXRoute2, curPosYRoute2, &collDataIdxRoute2, &collLineIdxRoute2, 0, _linesNumb)) {
1868 if (collLineIdxRoute2 > _lastLine)
1869 collLineIdxRoute2 = -1;
1870 break;
1871 }
1872
1873 if (curPosYRoute2 < destY)
1874 _testRoute2[idxRoute1++].set(posXRoute2, curPosYRoute2++, DIR_DOWN);
1875 else
1876 _testRoute2[idxRoute1++].set(posXRoute2, curPosYRoute2--, DIR_UP);
1877 }
1878 if (curPosYRoute2 != destY)
1879 break;
1880
1881 curPosX = posXRoute2;
1882 while (curPosX != destX) {
1883 if (checkCollisionLine(curPosX, destY, &collDataIdxRoute2, &collLineIdxRoute2, 0, _linesNumb)) {
1884 if (collLineIdxRoute2 <= _lastLine)
1885 break;
1886
1887 int tmpRouteIdx = computeRouteIdx(collLineIdxRoute2, collDataIdxRoute2, curPosX, destY, destX, destY, idxRoute1, _testRoute2);
1888 if (tmpRouteIdx == -1) {
1889 useRoute2(idxRoute1, curRouteIdx);
1890 return 1;
1891 }
1892 idxRoute1 = tmpRouteIdx;
1893 if (_newPosX != -1 && _newPosY != -1)
1894 break;
1895 }
1896
1897 if (curPosX < destX)
1898 _testRoute2[idxRoute1++].set(curPosX++, destY, DIR_RIGHT);
1899 else
1900 _testRoute2[idxRoute1++].set(curPosX--, destY, DIR_LEFT);
1901 }
1902 if (curPosX == destX) {
1903 collLineIdxRoute2 = -1;
1904 _testRoute2[idxRoute1].invalidate();
1905 useRoute2(idxRoute1, curRouteIdx);
1906 return 1;
1907 }
1908 if (collLineIdxRoute2 <= _lastLine)
1909 break;
1910
1911 posXRoute2 = _newPosX;
1912 posYRoute2 = _newPosY;
1913 bool colResult = checkCollisionLine(_newPosX, _newPosY, &collDataIdxRoute2, &collLineIdxRoute2, 0, _lastLine);
1914 if (colResult && collLineIdxRoute2 <= _lastLine)
1915 break;
1916 }
1917
1918 _testRoute2[idxRoute1].invalidate();
1919
1920 if (!dummyLineFl) {
1921 if (endLineIdx > foundLineIdx) {
1922 if (_testRoute0[0]._x != -1 && collLineIdxRoute0 > foundLineIdx && collLineIdxRoute1 <= collLineIdxRoute0 && collLineIdxRoute2 <= collLineIdxRoute0 && endLineIdx >= collLineIdxRoute0) {
1923 _newLineIdx = collLineIdxRoute0;
1924 _newLineDataIdx = collDataIdxRoute0;
1925 int i = 0;
1926 do {
1927 assert(curRouteIdx <= 8000);
1928 _bestRoute[curRouteIdx++] = _testRoute0[i++];
1929 } while (_testRoute0[i].isValid());
1930 _newRouteIdx = curRouteIdx;
1931 return 2;
1932 }
1933 if (_testRoute1[0]._x != -1 && foundLineIdx < collLineIdxRoute1 && collLineIdxRoute2 <= collLineIdxRoute1 && collLineIdxRoute0 <= collLineIdxRoute1 && endLineIdx >= collLineIdxRoute1) {
1934 _newLineIdx = collLineIdxRoute1;
1935 _newLineDataIdx = collDataIdxRoute1;
1936 int i = 0;
1937 do {
1938 assert(curRouteIdx <= 8000);
1939 _bestRoute[curRouteIdx++] = _testRoute1[i++];
1940 } while (_testRoute1[i].isValid());
1941 _newRouteIdx = curRouteIdx;
1942 return 2;
1943 }
1944 if (_testRoute2[0]._x != -1 && foundLineIdx < collLineIdxRoute2 && collLineIdxRoute1 < collLineIdxRoute2 && collLineIdxRoute0 < collLineIdxRoute2 && endLineIdx >= collLineIdxRoute2) {
1945 _newLineIdx = collLineIdxRoute2;
1946 _newLineDataIdx = collDataIdxRoute2;
1947 int i = 0;
1948 do {
1949 assert(curRouteIdx <= 8000);
1950 _bestRoute[curRouteIdx++] = _testRoute2[i++];
1951 } while (_testRoute2[i].isValid());
1952 _newRouteIdx = curRouteIdx;
1953 return 2;
1954 }
1955 }
1956 if (endLineIdx < foundLineIdx) {
1957 if (collLineIdxRoute0 == -1)
1958 collLineIdxRoute0 = INVALID_LINE_VALUE;
1959 if (collLineIdxRoute1 == -1)
1960 collLineIdxRoute0 = INVALID_LINE_VALUE;
1961 if (collLineIdxRoute2 == -1)
1962 collLineIdxRoute0 = INVALID_LINE_VALUE;
1963 if (_testRoute1[0]._x != -1 && collLineIdxRoute1 < foundLineIdx && collLineIdxRoute2 >= collLineIdxRoute1 && collLineIdxRoute0 >= collLineIdxRoute1 && endLineIdx <= collLineIdxRoute1) {
1964 _newLineIdx = collLineIdxRoute1;
1965 _newLineDataIdx = collDataIdxRoute1;
1966 int i = 0;
1967 do {
1968 assert(curRouteIdx <= 8000);
1969 _bestRoute[curRouteIdx++] = _testRoute1[i++];
1970 } while (_testRoute1[i].isValid());
1971 _newRouteIdx = curRouteIdx;
1972 return 2;
1973 }
1974 if (_testRoute2[0]._x != -1 && foundLineIdx > collLineIdxRoute2 && collLineIdxRoute1 >= collLineIdxRoute2 && collLineIdxRoute0 >= collLineIdxRoute2 && endLineIdx <= collLineIdxRoute2) {
1975 _newLineIdx = collLineIdxRoute2;
1976 _newLineDataIdx = collDataIdxRoute2;
1977 int i = 0;
1978 do {
1979 assert(curRouteIdx <= 8000);
1980 _bestRoute[curRouteIdx++] = _testRoute2[i++];
1981 } while (_testRoute2[i].isValid());
1982 _newRouteIdx = curRouteIdx;
1983 return 2;
1984 }
1985
1986 if (_testRoute0[0]._x != -1 && foundLineIdx > collLineIdxRoute0 && collLineIdxRoute1 >= collLineIdxRoute0 && collLineIdxRoute2 >= collLineIdxRoute0 && endLineIdx <= collLineIdxRoute0) {
1987 _newLineIdx = collLineIdxRoute0;
1988 _newLineDataIdx = collDataIdxRoute0;
1989 int i = 0;
1990 do {
1991 assert(curRouteIdx <= 8000);
1992 _bestRoute[curRouteIdx++] = _testRoute0[i++];
1993 } while (_testRoute0[i].isValid());
1994 _newRouteIdx = curRouteIdx;
1995 return 2;
1996 }
1997 }
1998 }
1999 return 0;
2000 }
2001
cityMapCarRoute(int x1,int y1,int x2,int y2)2002 RouteItem *LinesManager::cityMapCarRoute(int x1, int y1, int x2, int y2) {
2003 debugC(5, kDebugPath, "cityMapCarRoute(%d, %d, %d, %d)", x1, y1, x2, y2);
2004 RouteItem *result;
2005 int arrDelta[10];
2006 int arrDataIdx[10];
2007 int arrLineIdx[10];
2008
2009 int clipX2 = x2;
2010 int clipY2 = y2;
2011 if (x2 <= 14)
2012 clipX2 = 15;
2013 if (y2 <= 14)
2014 clipY2 = 15;
2015 if (clipX2 > _vm->_graphicsMan->_maxX - 10)
2016 clipX2 = _vm->_graphicsMan->_maxX - 10;
2017 if (clipY2 > 445)
2018 clipY2 = 440;
2019
2020 int delta = 0;
2021 for (delta = 0; clipY2 + delta < _vm->_graphicsMan->_maxY; delta++) {
2022 if (checkCollisionLine(clipX2, clipY2 + delta, &arrDataIdx[DIR_DOWN], &arrLineIdx[DIR_DOWN], 0, _lastLine) && arrLineIdx[DIR_DOWN] <= _lastLine)
2023 break;
2024 arrDataIdx[DIR_DOWN] = 0;
2025 arrLineIdx[DIR_DOWN] = -1;
2026 }
2027 arrDelta[DIR_DOWN] = delta;
2028
2029 for (delta = 0; clipY2 - delta > _vm->_graphicsMan->_minY; delta++) {
2030 if (checkCollisionLine(clipX2, clipY2 - delta , &arrDataIdx[DIR_UP], &arrLineIdx[DIR_UP], 0, _lastLine) && arrLineIdx[DIR_UP] <= _lastLine)
2031 break;
2032 arrDataIdx[DIR_UP] = 0;
2033 arrLineIdx[DIR_UP] = -1;
2034 if (arrDelta[DIR_DOWN] < delta && arrLineIdx[DIR_DOWN] != -1)
2035 break;
2036 }
2037 arrDelta[DIR_UP] = delta;
2038
2039 for (delta = 0; clipX2 + delta < _vm->_graphicsMan->_maxX; delta++) {
2040 if (checkCollisionLine(clipX2 + delta, clipY2, &arrDataIdx[DIR_RIGHT], &arrLineIdx[DIR_RIGHT], 0, _lastLine) && arrLineIdx[DIR_RIGHT] <= _lastLine)
2041 break;
2042 arrDataIdx[DIR_RIGHT] = 0;
2043 arrLineIdx[DIR_RIGHT] = -1;
2044 if ((arrDelta[DIR_UP] <= delta && arrLineIdx[DIR_UP] != -1) || (arrDelta[DIR_DOWN] <= delta && arrLineIdx[DIR_DOWN] != -1))
2045 break;
2046 }
2047 arrDelta[DIR_RIGHT] = delta;
2048
2049 for (delta = 0; clipX2 - delta > _vm->_graphicsMan->_minX; delta++) {
2050 if (checkCollisionLine(clipX2 - delta, clipY2, &arrDataIdx[DIR_LEFT], &arrLineIdx[DIR_LEFT], 0, _lastLine) && arrLineIdx[DIR_LEFT] <= _lastLine)
2051 break;
2052 arrDataIdx[DIR_LEFT] = 0;
2053 arrLineIdx[DIR_LEFT] = -1;
2054 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))
2055 break;
2056 }
2057 arrDelta[DIR_LEFT] = delta;
2058
2059 if (arrLineIdx[DIR_UP] == -1)
2060 arrDelta[DIR_UP] = INVALID_LINE_VALUE;
2061 if (arrLineIdx[DIR_RIGHT] == -1)
2062 arrDelta[DIR_RIGHT] = INVALID_LINE_VALUE;
2063 if (arrLineIdx[DIR_DOWN] == -1)
2064 arrDelta[DIR_DOWN] = INVALID_LINE_VALUE;
2065 if (arrLineIdx[DIR_LEFT] == -1)
2066 arrDelta[DIR_LEFT] = INVALID_LINE_VALUE;
2067 if (arrLineIdx[DIR_UP] != -1 || arrLineIdx[DIR_RIGHT] != -1 || arrLineIdx[DIR_DOWN] != -1 || arrLineIdx[DIR_LEFT] != -1) {
2068 int curLineDataIdx = 0;
2069 int curLineIdx = 0;
2070 if (arrLineIdx[DIR_DOWN] != -1 && arrDelta[DIR_UP] >= arrDelta[DIR_DOWN] && arrDelta[DIR_RIGHT] >= arrDelta[DIR_DOWN] && arrDelta[DIR_LEFT] >= arrDelta[DIR_DOWN]) {
2071 curLineIdx = arrLineIdx[DIR_DOWN];
2072 curLineDataIdx = arrDataIdx[DIR_DOWN];
2073 } else if (arrLineIdx[DIR_UP] != -1 && arrDelta[DIR_DOWN] >= arrDelta[DIR_UP] && arrDelta[DIR_RIGHT] >= arrDelta[DIR_UP] && arrDelta[DIR_LEFT] >= arrDelta[DIR_UP]) {
2074 curLineIdx = arrLineIdx[DIR_UP];
2075 curLineDataIdx = arrDataIdx[DIR_UP];
2076 } else if (arrLineIdx[DIR_RIGHT] != -1 && arrDelta[DIR_UP] >= arrDelta[DIR_RIGHT] && arrDelta[DIR_DOWN] >= arrDelta[DIR_RIGHT] && arrDelta[DIR_LEFT] >= arrDelta[DIR_RIGHT]) {
2077 curLineIdx = arrLineIdx[DIR_RIGHT];
2078 curLineDataIdx = arrDataIdx[DIR_RIGHT];
2079 } else if (arrLineIdx[DIR_LEFT] != -1 && arrDelta[DIR_DOWN] >= arrDelta[DIR_LEFT] && arrDelta[DIR_RIGHT] >= arrDelta[DIR_LEFT] && arrDelta[DIR_UP] >= arrDelta[DIR_LEFT]) {
2080 curLineIdx = arrLineIdx[DIR_LEFT];
2081 curLineDataIdx = arrDataIdx[DIR_LEFT];
2082 }
2083
2084 for (int i = 0; i <= 8; i++) {
2085 arrLineIdx[i] = -1;
2086 arrDataIdx[i] = 0;
2087 arrDelta[i] = INVALID_LINE_VALUE;
2088 }
2089
2090 int superRouteIdx = 0;
2091 int curRouteDataIdx = 0;
2092 int curRouteLineIdx = 0;
2093 if (checkCollisionLine(x1, y1, &arrDataIdx[DIR_UP], &arrLineIdx[DIR_UP], 0, _lastLine)) {
2094 curRouteLineIdx = arrLineIdx[DIR_UP];
2095 curRouteDataIdx = arrDataIdx[DIR_UP];
2096 } else if (checkCollisionLine(x1, y1, &arrDataIdx[DIR_UP], &arrLineIdx[DIR_UP], 0, _linesNumb)) {
2097 int curRouteIdx = 0;
2098 int curRouteX;
2099 for (;;) {
2100 curRouteX = _testRoute2[curRouteIdx]._x;
2101 int curRouteY = _testRoute2[curRouteIdx]._y;
2102 Directions curRouteDir = _testRoute2[curRouteIdx]._dir;
2103 curRouteIdx++;
2104
2105 if (checkCollisionLine(curRouteX, curRouteY, &arrDataIdx[DIR_UP], &arrLineIdx[DIR_UP], 0, _lastLine))
2106 break;
2107
2108 _bestRoute[superRouteIdx].set(curRouteX, curRouteY, curRouteDir);
2109
2110 _testRoute0[superRouteIdx].set(curRouteX, curRouteY, curRouteDir);
2111 superRouteIdx++;
2112 if (curRouteX == -1)
2113 break;
2114 }
2115 if (curRouteX != -1) {
2116 curRouteLineIdx = arrLineIdx[DIR_UP];
2117 curRouteDataIdx = arrDataIdx[DIR_UP];
2118 }
2119 } else {
2120 curRouteLineIdx = 1;
2121 curRouteDataIdx = 1;
2122 superRouteIdx = 0;
2123 }
2124 bool loopFl = true;
2125 while (loopFl) {
2126 loopFl = false;
2127 if (curRouteLineIdx < curLineIdx) {
2128 superRouteIdx = _lineItem[curRouteLineIdx].appendToRouteInc(curRouteDataIdx, _lineItem[curRouteLineIdx]._lineDataEndIdx - 2, _bestRoute, superRouteIdx);
2129 for (int j = curRouteLineIdx + 1; j < curLineIdx; ++j) {
2130 if (PLAN_TEST(_lineItem[j]._lineData[0], _lineItem[j]._lineData[1], superRouteIdx, j, curLineIdx)) {
2131 curRouteLineIdx = _newLineIdx;
2132 curRouteDataIdx = _newLineDataIdx;
2133 superRouteIdx = _newRouteIdx;
2134 loopFl = true;
2135 break;
2136 }
2137 if (_lineItem[j]._lineDataEndIdx - 2 > 0) {
2138 superRouteIdx = _lineItem[j].appendToRouteInc(0, _lineItem[j]._lineDataEndIdx - 2, _bestRoute, superRouteIdx);
2139 }
2140 }
2141 if (loopFl)
2142 continue;
2143 curRouteDataIdx = 0;
2144 curRouteLineIdx = curLineIdx;
2145 }
2146 if (curRouteLineIdx > curLineIdx) {
2147 superRouteIdx = _lineItem[curRouteLineIdx].appendToRouteDec(curRouteDataIdx, 0, _bestRoute, superRouteIdx);
2148 for (int l = curRouteLineIdx - 1; l > curLineIdx; --l) {
2149 if (PLAN_TEST(_lineItem[l]._lineData[2 * _lineItem[l]._lineDataEndIdx - 2], _lineItem[l]._lineData[2 * _lineItem[l]._lineDataEndIdx - 1], superRouteIdx, l, curLineIdx)) {
2150 curRouteLineIdx = _newLineIdx;
2151 curRouteDataIdx = _newLineDataIdx;
2152 superRouteIdx = _newRouteIdx;
2153 loopFl = true;
2154 break;
2155 }
2156
2157 superRouteIdx = _lineItem[l].appendToRouteDec(_lineItem[l]._lineDataEndIdx - 2, 0, _bestRoute, superRouteIdx);
2158 }
2159 if (loopFl)
2160 continue;
2161
2162 curRouteDataIdx = _lineItem[curLineIdx]._lineDataEndIdx - 1;
2163 curRouteLineIdx = curLineIdx;
2164 }
2165 if (curRouteLineIdx == curLineIdx) {
2166 if (curRouteDataIdx <= curLineDataIdx) {
2167 superRouteIdx = _lineItem[curLineIdx].appendToRouteInc(curRouteDataIdx, curLineDataIdx, _bestRoute, superRouteIdx);
2168 } else {
2169 superRouteIdx = _lineItem[curLineIdx].appendToRouteDec(curRouteDataIdx, curLineDataIdx, _bestRoute, superRouteIdx);
2170 }
2171 }
2172 }
2173 _bestRoute[superRouteIdx].invalidate();
2174 result = &_bestRoute[0];
2175 } else {
2176 result = NULL;
2177 }
2178 return result;
2179 }
2180
checkSmoothMove(int fromX,int fromY,int destX,int destY)2181 bool LinesManager::checkSmoothMove(int fromX, int fromY, int destX, int destY) {
2182 debugC(5, kDebugPath, "checkSmoothMove(%d, %d, %d, %d)", fromX, fromY, destX, destY);
2183 int distX = abs(fromX - destX) + 1;
2184 int distY = abs(fromY - destY) + 1;
2185 if (distX > distY)
2186 distY = distX;
2187 if (distY <= 10)
2188 return true;
2189
2190 int stepX = 1000 * distX / (distY - 1);
2191 int stepY = 1000 * distY / (distY - 1);
2192 if (destX < fromX)
2193 stepX = -stepX;
2194 if (destY < fromY)
2195 stepY = -stepY;
2196
2197 int smoothPosX = 1000 * fromX;
2198 int smoothPosY = 1000 * fromY;
2199 int newPosX = fromX;
2200 int newPosY = fromY;
2201
2202 if (distY + 1 > 0) {
2203 int stepCount = 0;
2204 int foundLineIdx;
2205 int foundDataIdx;
2206 while (!checkCollisionLine(newPosX, newPosY, &foundDataIdx, &foundLineIdx, 0, _linesNumb) || foundLineIdx > _lastLine) {
2207 smoothPosX += stepX;
2208 smoothPosY += stepY;
2209 newPosX = smoothPosX / 1000;
2210 newPosY = smoothPosY / 1000;
2211 ++stepCount;
2212 if (stepCount >= distY + 1)
2213 return false;
2214 }
2215 return true;
2216 }
2217 return false;
2218 }
2219
makeSmoothMove(int fromX,int fromY,int destX,int destY)2220 bool LinesManager::makeSmoothMove(int fromX, int fromY, int destX, int destY) {
2221 debugC(5, kDebugPath, "makeSmoothMove(%d, %d, %d, %d)", fromX, fromY, destX, destY);
2222 int curX = fromX;
2223 int curY = fromY;
2224 if (fromX > destX && destY > fromY) {
2225 int hopkinsIdx = 36;
2226 int smoothIdx = 0;
2227 int stepCount = 0;
2228 while (curX > destX && destY > curY) {
2229 int realSpeedX = _vm->_globals->_hopkinsItem[hopkinsIdx]._speedX;
2230 int realSpeedY = _vm->_globals->_hopkinsItem[hopkinsIdx]._speedY;
2231 int spriteSize = _vm->_globals->_spriteSize[curY];
2232 if (spriteSize < 0) {
2233 realSpeedX = _vm->_graphicsMan->zoomOut(realSpeedX, -spriteSize);
2234 realSpeedY = _vm->_graphicsMan->zoomOut(realSpeedY, -spriteSize);
2235 } else if (spriteSize > 0) {
2236 realSpeedX = _vm->_graphicsMan->zoomIn(realSpeedX, spriteSize);
2237 realSpeedY = _vm->_graphicsMan->zoomIn(realSpeedY, spriteSize);
2238 }
2239 int oldY = curY;
2240 for (int i = 0; i < realSpeedX; i++) {
2241 --curX;
2242 _smoothRoute[smoothIdx]._posX = curX;
2243 if (curY != oldY + realSpeedY)
2244 curY++;
2245 _smoothRoute[smoothIdx]._posY = curY;
2246 smoothIdx++;
2247 }
2248 ++hopkinsIdx;
2249 if (hopkinsIdx == 48)
2250 hopkinsIdx = 36;
2251 ++stepCount;
2252 }
2253 if (stepCount > 5) {
2254 _smoothRoute[smoothIdx]._posX = -1;
2255 _smoothRoute[smoothIdx]._posY = -1;
2256 _smoothMoveDirection = DIR_DOWN_LEFT;
2257 return false;
2258 }
2259 } else if (fromX < destX && destY > fromY) {
2260 int hopkinsIdx = 36;
2261 int smoothIdx = 0;
2262 int stepCount = 0;
2263 while (curX < destX && destY > curY) {
2264 int realSpeedX = _vm->_globals->_hopkinsItem[hopkinsIdx]._speedX;
2265 int realSpeedY = _vm->_globals->_hopkinsItem[hopkinsIdx]._speedY;
2266 int spriteSize = _vm->_globals->_spriteSize[curY];
2267 if (spriteSize < 0) {
2268 realSpeedX = _vm->_graphicsMan->zoomOut(realSpeedX, -spriteSize);
2269 realSpeedY = _vm->_graphicsMan->zoomOut(realSpeedY, -spriteSize);
2270 } else if (spriteSize > 0) {
2271 realSpeedX = _vm->_graphicsMan->zoomIn(realSpeedX, spriteSize);
2272 realSpeedY = _vm->_graphicsMan->zoomIn(realSpeedY, spriteSize);
2273 }
2274 int oldY = curY;
2275 for (int i = 0; i < realSpeedX; i++) {
2276 ++curX;
2277 _smoothRoute[smoothIdx]._posX = curX;
2278 if (curY != oldY + realSpeedY)
2279 curY++;
2280 _smoothRoute[smoothIdx]._posY = curY;
2281 smoothIdx++;
2282 }
2283 ++hopkinsIdx;
2284 if (hopkinsIdx == 48)
2285 hopkinsIdx = 36;
2286 ++stepCount;
2287 }
2288 if (stepCount > 5) {
2289 _smoothRoute[smoothIdx]._posX = -1;
2290 _smoothRoute[smoothIdx]._posY = -1;
2291 _smoothMoveDirection = DIR_DOWN_RIGHT;
2292 return false;
2293 }
2294 } else if (fromX > destX && destY < fromY) {
2295 int hopkinsIdx = 12;
2296 int smoothIdx = 0;
2297 int stepCount = 0;
2298 while (curX > destX && destY < curY) {
2299 int realSpeedX = _vm->_graphicsMan->zoomOut(_vm->_globals->_hopkinsItem[hopkinsIdx]._speedX, 25);
2300 int realSpeedY = _vm->_graphicsMan->zoomOut(_vm->_globals->_hopkinsItem[hopkinsIdx]._speedY, 25);
2301 int oldY = curY;
2302 for (int i = 0; i < realSpeedX; i++) {
2303 --curX;
2304 _smoothRoute[smoothIdx]._posX = curX;
2305 if ((uint16)curY != (uint16)oldY + realSpeedY)
2306 curY--;
2307 _smoothRoute[smoothIdx]._posY = curY;
2308 smoothIdx++;
2309 }
2310 ++hopkinsIdx;
2311 if (hopkinsIdx == 24)
2312 hopkinsIdx = 12;
2313 ++stepCount;
2314 }
2315 if (stepCount > 5) {
2316 _smoothRoute[smoothIdx]._posX = -1;
2317 _smoothRoute[smoothIdx]._posY = -1;
2318 _smoothMoveDirection = DIR_UP_LEFT;
2319 return false;
2320 }
2321 } else if (fromX < destX && destY < fromY) {
2322 int hopkinsIdx = 12;
2323 int smoothIdx = 0;
2324 int stepCount = 0;
2325 while (curX < destX && destY < curY) {
2326 int oldY = curY;
2327 int realSpeedX = _vm->_graphicsMan->zoomOut(_vm->_globals->_hopkinsItem[hopkinsIdx]._speedX, 25);
2328 int realSpeedY = _vm->_graphicsMan->zoomOut(_vm->_globals->_hopkinsItem[hopkinsIdx]._speedY, 25);
2329 for (int i = 0; i < realSpeedX; i++) {
2330 ++curX;
2331 _smoothRoute[smoothIdx]._posX = curX;
2332 if ((uint16)curY != (uint16)oldY + realSpeedY)
2333 curY--;
2334 _smoothRoute[smoothIdx]._posY = curY;
2335 smoothIdx++;
2336 }
2337 ++hopkinsIdx;
2338 if (hopkinsIdx == 24)
2339 hopkinsIdx = 12;
2340 ++stepCount;
2341 }
2342
2343 if (stepCount > 5) {
2344 _smoothRoute[smoothIdx]._posX = -1;
2345 _smoothRoute[smoothIdx]._posY = -1;
2346 _smoothMoveDirection = DIR_UP_RIGHT;
2347 return false;
2348 }
2349 }
2350 return true;
2351 }
2352
PLAN_TEST(int paramX,int paramY,int superRouteIdx,int paramStartLineIdx,int paramEndLineIdx)2353 bool LinesManager::PLAN_TEST(int paramX, int paramY, int superRouteIdx, int paramStartLineIdx, int paramEndLineIdx) {
2354 debugC(5, kDebugPath, "PLAN_TEST(%d, %d, %d, %d, %d)", paramX, paramY, superRouteIdx, paramStartLineIdx, paramEndLineIdx);
2355 int sideTestUp;
2356 int sideTestDown;
2357 int sideTestLeft;
2358 int sideTestRight;
2359 int lineIdxTestUp;
2360 int lineIdxTestDown;
2361 int lineIdxTestLeft;
2362 int lineIdxTestRight;
2363 int dataIdxTestUp;
2364 int dataIdxTestDown;
2365 int dataIdxTestLeft;
2366 int dataIdxTestRight;
2367
2368 int idxTestUp = testLine(paramX, paramY - 2, &sideTestUp, &lineIdxTestUp, &dataIdxTestUp);
2369 int idxTestDown = testLine(paramX, paramY + 2, &sideTestDown, &lineIdxTestDown, &dataIdxTestDown);
2370 int idxTestLeft = testLine(paramX - 2, paramY, &sideTestLeft, &lineIdxTestLeft, &dataIdxTestLeft);
2371 int idxTestRight = testLine(paramX + 2, paramY, &sideTestRight, &lineIdxTestRight, &dataIdxTestRight);
2372 if (idxTestUp == -1 && idxTestDown == -1 && idxTestLeft == -1 && idxTestRight == -1)
2373 return false;
2374
2375 // Direction: 1 = Up, 2 = Down, 3 = Left, 4 = Right
2376 int direction;
2377 if (paramStartLineIdx == -1 || paramEndLineIdx == -1) {
2378 if (idxTestUp != -1)
2379 direction = 1;
2380 else if (idxTestDown != -1)
2381 direction = 2;
2382 else if (idxTestLeft != -1)
2383 direction = 3;
2384 else if (idxTestRight != -1)
2385 direction = 4;
2386 else
2387 return false;
2388 } else {
2389 int stepCountUp = 100;
2390 int stepCountDown = 100;
2391 int stepCountLeft = 100;
2392 int stepCountRight = 100;
2393 int paramStepCount = abs(paramStartLineIdx - paramEndLineIdx);
2394 if (idxTestUp != -1) {
2395 stepCountUp = abs(lineIdxTestUp - paramEndLineIdx);
2396 }
2397 if (idxTestDown != -1) {
2398 stepCountDown = abs(lineIdxTestDown - paramEndLineIdx);
2399 }
2400 if (idxTestLeft != -1) {
2401 stepCountLeft = abs(lineIdxTestLeft - paramEndLineIdx);
2402 }
2403 if (idxTestRight != -1) {
2404 stepCountRight = abs(lineIdxTestRight - paramEndLineIdx);
2405 }
2406
2407 if (stepCountUp < paramStepCount && stepCountUp <= stepCountDown && stepCountUp <= stepCountLeft && stepCountUp <= stepCountRight)
2408 direction = 1;
2409 else if (paramStepCount > stepCountDown && stepCountUp >= stepCountDown && stepCountLeft >= stepCountDown && stepCountRight >= stepCountDown)
2410 direction = 2;
2411 else if (stepCountLeft < paramStepCount && stepCountLeft <= stepCountUp && stepCountLeft <= stepCountDown && stepCountLeft <= stepCountRight)
2412 direction = 3;
2413 else if (stepCountRight < paramStepCount && stepCountRight <= stepCountUp && stepCountRight <= stepCountDown && stepCountRight <= stepCountLeft)
2414 direction = 4;
2415 else
2416 return false;
2417 }
2418
2419 int sideTest = 0;
2420 int idxTest = 0;
2421 if (direction == 1) {
2422 idxTest = idxTestUp;
2423 sideTest = sideTestUp;
2424 _newLineIdx = lineIdxTestUp;
2425 _newLineDataIdx = dataIdxTestUp;
2426 } else if (direction == 2) {
2427 idxTest = idxTestDown;
2428 sideTest = sideTestDown;
2429 _newLineIdx = lineIdxTestDown;
2430 _newLineDataIdx = dataIdxTestDown;
2431 } else if (direction == 3) {
2432 idxTest = idxTestLeft;
2433 sideTest = sideTestLeft;
2434 _newLineIdx = lineIdxTestLeft;
2435 _newLineDataIdx = dataIdxTestLeft;
2436 } else if (direction == 4) {
2437 idxTest = idxTestRight;
2438 sideTest = sideTestRight;
2439 _newLineIdx = lineIdxTestRight;
2440 _newLineDataIdx = dataIdxTestRight;
2441 }
2442
2443 int routeIdx = superRouteIdx;
2444 if (sideTest == 1) {
2445 routeIdx = _lineItem[idxTest].appendToRouteInc(0, -1, _bestRoute, routeIdx);
2446 } else if (sideTest == 2) {
2447 routeIdx = _lineItem[idxTest].appendToRouteDec(-1, -1, _bestRoute, routeIdx);
2448 }
2449 _newRouteIdx = routeIdx;
2450 return true;
2451 }
2452
2453 // Test line
testLine(int paramX,int paramY,int * testValue,int * foundLineIdx,int * foundDataIdx)2454 int LinesManager::testLine(int paramX, int paramY, int *testValue, int *foundLineIdx, int *foundDataIdx) {
2455 debugC(5, kDebugPath, "testLine(%d, %d, testValue, foundLineIdx, foundDataIdx)", paramX, paramY);
2456 int16 *lineData;
2457 int collLineIdx;
2458 int collDataIdx;
2459
2460 for (int idx = _lastLine + 1; idx < _linesNumb + 1; idx++) {
2461 lineData = _lineItem[idx]._lineData;
2462 int lineDataEndIdx = _lineItem[idx]._lineDataEndIdx;
2463 if (!lineData)
2464 continue;
2465
2466 if (lineData[0] == paramX && lineData[1] == paramY) {
2467 *testValue = 1;
2468 int posX = lineData[2 * (lineDataEndIdx - 1)];
2469 int posY = lineData[2 * (lineDataEndIdx - 1) + 1];
2470 if (_lineItem[idx]._directionRouteInc == DIR_DOWN || _lineItem[idx]._directionRouteInc == DIR_UP)
2471 posY += 2;
2472 if (_lineItem[idx]._directionRouteInc == DIR_RIGHT || _lineItem[idx]._directionRouteDec == DIR_LEFT)
2473 posX += 2;
2474 if (!checkCollisionLine(posX, posY, &collDataIdx, &collLineIdx, 0, _lastLine))
2475 error("Error in test line");
2476 *foundLineIdx = collLineIdx;
2477 *foundDataIdx = collDataIdx;
2478 return idx;
2479 }
2480
2481 if (lineDataEndIdx > 0) {
2482 if (lineData[2 * (lineDataEndIdx - 1)] == paramX && lineData[2 * (lineDataEndIdx - 1) + 1] == paramY) {
2483 *testValue = 2;
2484 int posX = lineData[0];
2485 int posY = lineData[1];
2486 if (_lineItem[idx]._directionRouteInc == DIR_DOWN || _lineItem[idx]._directionRouteInc == DIR_UP)
2487 posY -= 2;
2488 if (_lineItem[idx]._directionRouteInc == DIR_RIGHT || _lineItem[idx]._directionRouteDec == DIR_LEFT)
2489 posX -= 2;
2490 if (!checkCollisionLine(posX, posY, &collDataIdx, &collLineIdx, 0, _lastLine))
2491 error("Error in test line");
2492 *foundLineIdx = collLineIdx;
2493 *foundDataIdx = collDataIdx;
2494 return idx;
2495 }
2496 }
2497 }
2498 return -1;
2499 }
2500
computeYSteps(int idx)2501 int LinesManager::computeYSteps(int idx) {
2502 debugC(5, kDebugPath, "computeYSteps(%d)", idx);
2503 int zoomPct = _vm->_globals->_spriteSize[idx];
2504 if (_vm->_globals->_characterType == CHARACTER_HOPKINS_CLONE) {
2505 if (zoomPct < 0)
2506 zoomPct = -zoomPct;
2507 zoomPct = 20 * (5 * zoomPct - 100) / -80;
2508 } else if (_vm->_globals->_characterType == CHARACTER_SAMANTHA) {
2509 if (zoomPct < 0)
2510 zoomPct = -zoomPct;
2511 zoomPct = 20 * (5 * zoomPct - 165) / -67;
2512 }
2513
2514 int retVal = 25;
2515 if (zoomPct < 0)
2516 retVal = _vm->_graphicsMan->zoomOut(25, -zoomPct);
2517 else if (zoomPct > 0)
2518 retVal = _vm->_graphicsMan->zoomIn(25, zoomPct);
2519
2520 return retVal;
2521 }
2522
optimizeRoute(RouteItem * route)2523 void LinesManager::optimizeRoute(RouteItem *route) {
2524 debugC(5, kDebugPath, "optimizeRoute(route)");
2525 if (route[0]._x == -1 && route[0]._y == -1)
2526 return;
2527
2528 int routeIdx = 0;
2529 Directions oldDir = DIR_NONE;
2530 int route0Y = route[0]._y;
2531 Directions curDir = route[0]._dir;
2532
2533 for (;;) {
2534 if (oldDir != DIR_NONE && curDir != oldDir) {
2535 int oldRouteIdx = routeIdx;
2536 int routeCount = 0;
2537 int yStep = computeYSteps(route0Y);
2538 int curRouteX = route[routeIdx]._x;
2539 int curRouteY = route[routeIdx]._y;
2540 while (curRouteX != -1 || curRouteY != -1) {
2541 int idx = routeIdx;
2542 ++routeIdx;
2543 ++routeCount;
2544 if (route[idx]._dir != curDir)
2545 break;
2546 curRouteX = route[routeIdx]._x;
2547 curRouteY = route[routeIdx]._y;
2548 }
2549 if (routeCount < yStep) {
2550 int idx = oldRouteIdx;
2551 for (int i = 0; i < routeCount; i++) {
2552 route[idx]._dir = oldDir;
2553 idx++;
2554 }
2555 curDir = oldDir;
2556 }
2557 routeIdx = oldRouteIdx;
2558 if (curRouteX == -1 && curRouteY == -1)
2559 break;
2560 }
2561 routeIdx++;
2562 oldDir = curDir;
2563 route0Y = route[routeIdx]._y;
2564 curDir = route[routeIdx]._dir;
2565 if (route[routeIdx]._x == -1 && route0Y == -1)
2566 break;
2567 }
2568 }
2569
getMouseZone()2570 int LinesManager::getMouseZone() {
2571 debugC(9, kDebugPath, "getMouseZone()");
2572 int result;
2573
2574 int xp = _vm->_events->_mousePos.x + _vm->_events->_mouseOffset.x;
2575 int yp = _vm->_events->_mousePos.y + _vm->_events->_mouseOffset.y;
2576 if ((_vm->_events->_mousePos.y + _vm->_events->_mouseOffset.y) > 19) {
2577 for (int bobZoneId = 0; bobZoneId <= 48; bobZoneId++) {
2578 int bobId = _bobZone[bobZoneId];
2579 if (bobId && _bobZoneFl[bobZoneId] && _vm->_objectsMan->_bob[bobId]._bobMode && _vm->_objectsMan->_bob[bobId]._frameIndex != 250 &&
2580 !_vm->_objectsMan->_bob[bobId]._disabledAnimationFl && xp > _vm->_objectsMan->_bob[bobId]._oldX &&
2581 xp < _vm->_objectsMan->_bob[bobId]._oldWidth + _vm->_objectsMan->_bob[bobId]._oldX && yp > _vm->_objectsMan->_bob[bobId]._oldY) {
2582 if (yp < _vm->_objectsMan->_bob[bobId]._oldHeight + _vm->_objectsMan->_bob[bobId]._oldY) {
2583 if (_zone[bobZoneId]._spriteIndex == -1) {
2584 _zone[bobZoneId]._destX = 0;
2585 _zone[bobZoneId]._destY = 0;
2586 }
2587 if (!_zone[bobZoneId]._destX && !_zone[bobZoneId]._destY) {
2588 _zone[bobZoneId]._destX = _vm->_objectsMan->_bob[bobId]._oldWidth + _vm->_objectsMan->_bob[bobId]._oldX;
2589 _zone[bobZoneId]._destY = _vm->_objectsMan->_bob[bobId]._oldHeight + _vm->_objectsMan->_bob[bobId]._oldY + 6;
2590 _zone[bobZoneId]._spriteIndex = -1;
2591 }
2592
2593 // WORKAROUND: Avoid allowing hotspots that should remain non-interactive
2594 if (bobZoneId == 24 && _vm->_globals->_curRoomNum == 14)
2595 continue;
2596
2597 return bobZoneId;
2598 }
2599 }
2600 }
2601 _currentSegmentId = 0;
2602 for (int squareZoneId = 0; squareZoneId <= 99; squareZoneId++) {
2603 if (_zone[squareZoneId]._enabledFl && _squareZone[squareZoneId]._enabledFl
2604 && _squareZone[squareZoneId]._left <= xp && _squareZone[squareZoneId]._right >= xp
2605 && _squareZone[squareZoneId]._top <= yp && _squareZone[squareZoneId]._bottom >= yp) {
2606 if (_squareZone[squareZoneId]._squareZoneFl)
2607 return _zoneLine[_squareZone[squareZoneId]._minZoneLineIdx]._bobZoneIdx;
2608
2609 _segment[_currentSegmentId]._minZoneLineIdx = _squareZone[squareZoneId]._minZoneLineIdx;
2610 _segment[_currentSegmentId]._maxZoneLineIdx = _squareZone[squareZoneId]._maxZoneLineIdx;
2611 ++_currentSegmentId;
2612 }
2613 }
2614 if (!_currentSegmentId)
2615 return -1;
2616
2617
2618 int colRes1 = 0;
2619 for (int yCurrent = yp; yCurrent >= 0; --yCurrent) {
2620 colRes1 = checkCollision(xp, yCurrent);
2621 if (colRes1 != -1 && _zone[colRes1]._enabledFl)
2622 break;
2623 }
2624
2625 if (colRes1 == -1)
2626 return -1;
2627
2628 int colRes2 = 0;
2629 for (int j = yp; j < _vm->_graphicsMan->_maxY; ++j) {
2630 colRes2 = checkCollision(xp, j);
2631 if (colRes2 != -1 && _zone[colRes1]._enabledFl)
2632 break;
2633 }
2634
2635 if (colRes2 == -1)
2636 return -1;
2637
2638 int colRes3 = 0;
2639 for (int k = xp; k >= 0; --k) {
2640 colRes3 = checkCollision(k, yp);
2641 if (colRes3 != -1 && _zone[colRes1]._enabledFl)
2642 break;
2643 }
2644 if (colRes3 == -1)
2645 return -1;
2646
2647 int colRes4 = 0;
2648 for (int xCurrent = xp; _vm->_graphicsMan->_maxX > xCurrent; ++xCurrent) {
2649 colRes4 = checkCollision(xCurrent, yp);
2650 if (colRes4 != -1 && _zone[colRes1]._enabledFl)
2651 break;
2652 }
2653 if (colRes1 == colRes2 && colRes1 == colRes3 && colRes1 == colRes4)
2654 result = colRes1;
2655 else
2656 result = -1;
2657
2658 } else {
2659 result = 0;
2660 }
2661 return result;
2662 }
2663
checkCollision(int xp,int yp)2664 int LinesManager::checkCollision(int xp, int yp) {
2665 debugC(7, kDebugPath, "checkCollision(%d, %d)", xp, yp);
2666 if (_currentSegmentId <= 0)
2667 return -1;
2668
2669 int xMax = xp + 4;
2670 int xMin = xp - 4;
2671
2672 for (int idx = 0; idx <= _currentSegmentId; ++idx) {
2673 int curZoneLineIdx = _segment[idx]._minZoneLineIdx;
2674 if (_segment[idx]._maxZoneLineIdx < curZoneLineIdx)
2675 continue;
2676
2677 int yMax = yp + 4;
2678 int yMin = yp - 4;
2679
2680 do {
2681 LigneZoneItem *curZoneLine = &_zoneLine[curZoneLineIdx];
2682 int16 *dataP = curZoneLine->_zoneData;
2683 if (dataP) {
2684 int count = curZoneLine->_count;
2685 int startX = dataP[0];
2686 int startY = dataP[1];
2687 int destX = dataP[count * 2 - 2];
2688 int destY = dataP[count * 2 - 1];
2689
2690 bool flag = true;
2691 if ((startX < destX && (xMax < startX || xMin > destX)) ||
2692 (startX >= destX && (xMin > startX || xMax < destX)) ||
2693 (startY < destY && (yMax < startY || yMin > destY)) ||
2694 (startY >= destY && (yMin > startY || yMax < destY)))
2695 flag = false;
2696
2697 if (flag && curZoneLine->_count > 0) {
2698 for (int i = 0; i < count; ++i) {
2699 int xCheck = *dataP++;
2700 int yCheck = *dataP++;
2701
2702 if ((xp == xCheck || (xp + 1) == xCheck) && (yp == yCheck))
2703 return curZoneLine->_bobZoneIdx;
2704 }
2705 }
2706 }
2707 } while (++curZoneLineIdx <= _segment[idx]._maxZoneLineIdx);
2708 }
2709
2710 return -1;
2711 }
2712
2713 // Square Zone
initSquareZones()2714 void LinesManager::initSquareZones() {
2715 debugC(5, kDebugPath, "initSquareZones()");
2716 for (int idx = 0; idx < 100; ++idx) {
2717 SquareZoneItem *curZone = &_squareZone[idx];
2718 curZone->_enabledFl = false;
2719 curZone->_squareZoneFl = false;
2720 curZone->_left = 1280;
2721 curZone->_right = 0;
2722 curZone->_top = 460;
2723 curZone->_bottom = 0;
2724 curZone->_minZoneLineIdx = 401;
2725 curZone->_maxZoneLineIdx = 0;
2726 }
2727
2728 for (int idx = 0; idx < MAX_LINES + 1; ++idx) {
2729 int16 *dataP = _zoneLine[idx]._zoneData;
2730 if (dataP == NULL)
2731 continue;
2732
2733 SquareZoneItem *curZone = &_squareZone[_zoneLine[idx]._bobZoneIdx];
2734 curZone->_enabledFl = true;
2735 curZone->_maxZoneLineIdx = MAX(curZone->_maxZoneLineIdx, idx);
2736 curZone->_minZoneLineIdx = MIN(curZone->_minZoneLineIdx, idx);
2737
2738 for (int i = 0; i < _zoneLine[idx]._count; i++) {
2739 int zoneX = *dataP++;
2740 int zoneY = *dataP++;
2741
2742 curZone->_left = MIN(curZone->_left, zoneX);
2743 curZone->_right = MAX(curZone->_right, zoneX);
2744 curZone->_top = MIN(curZone->_top, zoneY);
2745 curZone->_bottom = MAX(curZone->_bottom, zoneY);
2746 }
2747 }
2748
2749 for (int idx = 0; idx < 100; idx++) {
2750 int zoneWidth = abs(_squareZone[idx]._left - _squareZone[idx]._right);
2751 int zoneHeight = abs(_squareZone[idx]._top - _squareZone[idx]._bottom);
2752 if (zoneWidth == zoneHeight)
2753 _squareZone[idx]._squareZoneFl = true;
2754 }
2755 }
2756
clearAll()2757 void LinesManager::clearAll() {
2758 debugC(5, kDebugPath, "clearAll()");
2759 for (int idx = 0; idx < 105; ++idx) {
2760 _zone[idx]._destX = 0;
2761 _zone[idx]._destY = 0;
2762 _zone[idx]._spriteIndex = 0;
2763 }
2764
2765 _testRoute0 = NULL;
2766 _testRoute1 = NULL;
2767 _testRoute2 = NULL;
2768 _lineBuf = NULL;
2769 _route = NULL;
2770
2771 for (int idx = 0; idx < MAX_LINES; ++idx) {
2772 _lineItem[idx]._lineDataEndIdx = 0;
2773 _lineItem[idx]._direction = DIR_NONE;
2774 _lineItem[idx]._directionRouteInc = DIR_NONE;
2775 _lineItem[idx]._directionRouteDec = DIR_NONE;
2776 _lineItem[idx]._lineData = NULL;
2777
2778 _zoneLine[idx]._count = 0;
2779 _zoneLine[idx]._bobZoneIdx = 0;
2780 _zoneLine[idx]._zoneData = NULL;
2781 }
2782
2783 for (int idx = 0; idx < 100; ++idx)
2784 _squareZone[idx]._enabledFl = false;
2785
2786 _testRoute0 = new RouteItem[8334];
2787 _testRoute1 = new RouteItem[8334];
2788 _testRoute2 = new RouteItem[8334];
2789 if (!_testRoute0)
2790 _testRoute0 = NULL;
2791 if (!_testRoute1)
2792 _testRoute1 = NULL;
2793 if (!_testRoute2)
2794 _testRoute2 = NULL;
2795
2796 _largeBuf = _vm->_globals->allocMemory(10000);
2797 _lineBuf = (int16 *)(_largeBuf);
2798 }
2799
2800 /**
2801 * Clear all zones and reset nextLine
2802 */
clearAllZones()2803 void LinesManager::clearAllZones() {
2804 debugC(5, kDebugPath, "clearAllZones()");
2805 for (int idx = 0; idx < MAX_LINES; ++idx)
2806 removeZoneLine(idx);
2807 }
2808
2809 /**
2810 * Remove Zone Line
2811 */
removeZoneLine(int idx)2812 void LinesManager::removeZoneLine(int idx) {
2813 debugC(5, kDebugPath, "removeZoneLine(%d)", idx);
2814 assert(idx < MAX_LINES + 1);
2815 _zoneLine[idx]._zoneData = (int16 *)_vm->_globals->freeMemory((byte *)_zoneLine[idx]._zoneData);
2816 }
2817
resetLines()2818 void LinesManager::resetLines() {
2819 debugC(5, kDebugPath, "resetLines()");
2820 for (int idx = 0; idx < MAX_LINES; ++idx) {
2821 _lineItem[idx]._lineData = (int16 *)_vm->_globals->freeMemory((byte *)_lineItem[idx]._lineData);
2822 _lineItem[idx]._lineDataEndIdx = 0;
2823 _lineItem[idx]._lineData = NULL;
2824 }
2825 }
2826
setMaxLineIdx(int idx)2827 void LinesManager::setMaxLineIdx(int idx) {
2828 debugC(5, kDebugPath, "setMaxLineIdx(%d)", idx);
2829 _maxLineIdx = idx;
2830 }
2831
resetLastLine()2832 void LinesManager::resetLastLine() {
2833 debugC(5, kDebugPath, "resetLastLine()");
2834 _lastLine = 0;
2835 }
2836
resetLinesNumb()2837 void LinesManager::resetLinesNumb() {
2838 debugC(5, kDebugPath, "resetLinesNumb()");
2839 _linesNumb = 0;
2840 }
2841
enableZone(int idx)2842 void LinesManager::enableZone(int idx) {
2843 debugC(5, kDebugPath, "enableZone(%d)", idx);
2844 if (_bobZone[idx]) {
2845 _bobZoneFl[idx] = true;
2846 } else {
2847 _zone[idx]._enabledFl = true;
2848 }
2849 }
2850
disableZone(int idx)2851 void LinesManager::disableZone(int idx) {
2852 debugC(5, kDebugPath, "disableZone(%d)", idx);
2853 if (_bobZone[idx]) {
2854 _bobZoneFl[idx] = false;
2855 } else {
2856 _zone[idx]._enabledFl = false;
2857 }
2858 }
2859
checkZone()2860 void LinesManager::checkZone() {
2861 debugC(9, kDebugPath, "checkZone()");
2862 int mouseX = _vm->_events->getMouseX();
2863 int mouseY = _vm->_events->getMouseY();
2864 int oldMouseY = mouseY;
2865 if (_vm->_globals->_cityMapEnabledFl
2866 || _vm->_events->_startPos.x >= mouseX
2867 || (mouseY = _vm->_graphicsMan->_scrollOffset + 54, mouseX >= mouseY)
2868 || (mouseY = oldMouseY - 1, mouseY < 0 || mouseY > 59)) {
2869 if (_vm->_objectsMan->_visibleFl)
2870 _vm->_objectsMan->_eraseVisibleCounter = 4;
2871 _vm->_objectsMan->_visibleFl = false;
2872 } else {
2873 _vm->_objectsMan->_visibleFl = true;
2874 }
2875 if (_vm->_objectsMan->_forceZoneFl) {
2876 _zoneSkipCount = 100;
2877 _oldMouseZoneId = -1;
2878 _oldMouseX = -200;
2879 _oldMouseY = -220;
2880 _vm->_objectsMan->_forceZoneFl = false;
2881 }
2882
2883 _zoneSkipCount++;
2884 if (_zoneSkipCount <= 1)
2885 return;
2886
2887 if (_vm->_globals->_freezeCharacterFl || (_route == NULL) || _zoneSkipCount > 4) {
2888 _zoneSkipCount = 0;
2889 int zoneId;
2890 if (_oldMouseX != mouseX || _oldMouseY != oldMouseY) {
2891 zoneId = getMouseZone();
2892
2893 // WORKAROUND: Incorrect hotspot zones in the guard's control room
2894 if (_vm->_globals->_curRoomNum == 71 && (zoneId == 14 || zoneId == 12 || zoneId == 17))
2895 zoneId = _oldMouseZoneId;
2896 } else {
2897 zoneId = _oldMouseZoneId;
2898 }
2899 if (_oldMouseZoneId != zoneId) {
2900 _vm->_graphicsMan->setColorPercentage2(251, 100, 100, 100);
2901 _vm->_events->_mouseCursorId = 4;
2902 _vm->_events->changeMouseCursor(4);
2903 if (_forceHideText) {
2904 _vm->_fontMan->hideText(5);
2905 _forceHideText = false;
2906 return;
2907 }
2908 }
2909 if (zoneId != -1) {
2910 if (_zone[zoneId]._verbFl1 || _zone[zoneId]._verbFl2 ||
2911 _zone[zoneId]._verbFl3 || _zone[zoneId]._verbFl4 ||
2912 _zone[zoneId]._verbFl5 || _zone[zoneId]._verbFl6 ||
2913 _zone[zoneId]._verbFl7 || _zone[zoneId]._verbFl8 ||
2914 _zone[zoneId]._verbFl9 || _zone[zoneId]._verbFl10) {
2915 if (_oldMouseZoneId != zoneId) {
2916 _vm->_fontMan->initTextBuffers(5, _zone[zoneId]._messageId, _vm->_globals->_zoneFilename, 0, 430, 0, 0, 252);
2917 _vm->_fontMan->showText(5);
2918 _forceHideText = true;
2919 }
2920 _hotspotTextColor += 25;
2921 if (_hotspotTextColor > 100)
2922 _hotspotTextColor = 0;
2923 _vm->_graphicsMan->setColorPercentage2(251, _hotspotTextColor, _hotspotTextColor, _hotspotTextColor);
2924 if (_vm->_events->_mouseCursorId == 4) {
2925 if (_zone[zoneId]._verbFl1 == 2) {
2926 _vm->_events->changeMouseCursor(16);
2927 _vm->_events->_mouseCursorId = 16;
2928 _vm->_objectsMan->setVerb(16);
2929 }
2930 }
2931 } else {
2932 _vm->_graphicsMan->setColorPercentage2(251, 100, 100, 100);
2933 _vm->_events->_mouseCursorId = 4;
2934 _vm->_events->changeMouseCursor(4);
2935 }
2936 }
2937 _vm->_objectsMan->_zoneNum = zoneId;
2938 _oldMouseX = mouseX;
2939 _oldMouseY = oldMouseY;
2940 _oldMouseZoneId = zoneId;
2941 if (_vm->_globals->_freezeCharacterFl && (_vm->_events->_mouseCursorId == 4)) {
2942 if (zoneId != -1 && zoneId != 0)
2943 _vm->_objectsMan->handleRightButton();
2944 }
2945 if ((_vm->_globals->_cityMapEnabledFl && zoneId == -1) || !zoneId) {
2946 _vm->_objectsMan->setVerb(0);
2947 _vm->_events->_mouseCursorId = 0;
2948 _vm->_events->changeMouseCursor(0);
2949 }
2950 }
2951 }
2952
2953 } // End of namespace Hopkins
2954