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