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 "prince/prince.h"
24 #include "prince/hero.h"
25 #include "prince/script.h"
26 
27 namespace Prince {
28 
walkTo()29 void PrinceEngine::walkTo() {
30 	if (_mainHero->_visible) {
31 		_mainHero->freeHeroAnim();
32 		_mainHero->freeOldMove();
33 		_interpreter->storeNewPC(_script->_scriptInfo.usdCode);
34 		int destX, destY;
35 		if (_optionsMob != -1) {
36 			destX = _mobList[_optionsMob]._examPosition.x;
37 			destY = _mobList[_optionsMob]._examPosition.y;
38 			_mainHero->_destDirection = _mobList[_optionsMob]._examDirection;
39 		} else {
40 			Common::Point mousePos = _system->getEventManager()->getMousePos();
41 			destX = mousePos.x + _picWindowX;
42 			destY = mousePos.y + _picWindowY;
43 			_mainHero->_destDirection = 0;
44 		}
45 		_mainHero->_coords = makePath(kMainHero, _mainHero->_middleX, _mainHero->_middleY, destX, destY);
46 		if (_mainHero->_coords != nullptr) {
47 			_mainHero->_currCoords = _mainHero->_coords;
48 			_mainHero->_dirTab = _directionTable;
49 			_mainHero->_currDirTab = _directionTable;
50 			_directionTable = nullptr;
51 			_mainHero->_state = Hero::kHeroStateMove;
52 			moveShandria();
53 		}
54 	}
55 }
56 
moveRunHero(int heroId,int x,int y,int dir,bool runHeroFlag)57 void PrinceEngine::moveRunHero(int heroId, int x, int y, int dir, bool runHeroFlag) {
58 	Hero *hero = nullptr;
59 	if (!heroId) {
60 		hero = _mainHero;
61 	} else if (heroId == 1) {
62 		hero = _secondHero;
63 	}
64 
65 	if (hero != nullptr) {
66 		if (dir) {
67 			hero->_destDirection = dir;
68 		}
69 		if (x || y) {
70 			hero->freeOldMove();
71 			hero->_coords = makePath(heroId, hero->_middleX, hero->_middleY, x, y);
72 			if (hero->_coords != nullptr) {
73 				hero->_currCoords = hero->_coords;
74 				hero->_dirTab = _directionTable;
75 				hero->_currDirTab = _directionTable;
76 				_directionTable = nullptr;
77 				if (runHeroFlag) {
78 					hero->_state = Hero::kHeroStateRun;
79 				} else {
80 					hero->_state = Hero::kHeroStateMove;
81 				}
82 				if (heroId == kMainHero && _mouseFlag) {
83 					moveShandria();
84 				}
85 			}
86 		} else {
87 			hero->freeOldMove();
88 			hero->_state = Hero::kHeroStateTurn;
89 		}
90 		hero->freeHeroAnim();
91 		hero->_visible = 1;
92 	}
93 }
94 
95 // Modified version of Graphics::drawLine() to allow breaking the loop and return value
drawLine(int x0,int y0,int x1,int y1,int (* plotProc)(int,int,void *),void * data)96 int PrinceEngine::drawLine(int x0, int y0, int x1, int y1, int (*plotProc)(int, int, void *), void *data) {
97 	// Bresenham's line algorithm, as described by Wikipedia
98 	const bool steep = ABS(y1 - y0) > ABS(x1 - x0);
99 
100 	if (steep) {
101 		SWAP(x0, y0);
102 		SWAP(x1, y1);
103 	}
104 
105 	const int delta_x = ABS(x1 - x0);
106 	const int delta_y = ABS(y1 - y0);
107 	const int delta_err = delta_y;
108 	int x = x0;
109 	int y = y0;
110 	int err = 0;
111 
112 	const int x_step = (x0 < x1) ? 1 : -1;
113 	const int y_step = (y0 < y1) ? 1 : -1;
114 
115 	int stopFlag = 0;
116 	if (steep)
117 		stopFlag = (*plotProc)(y, x, data);
118 	else
119 		stopFlag = (*plotProc)(x, y, data);
120 
121 	while (x != x1 && !stopFlag) {
122 		x += x_step;
123 		err += delta_err;
124 		if (2 * err > delta_x) {
125 			y += y_step;
126 			err -= delta_x;
127 		}
128 		if (steep)
129 			stopFlag = (*plotProc)(y, x, data);
130 		else
131 			stopFlag = (*plotProc)(x, y, data);
132 	}
133 	return stopFlag;
134 }
135 
getPixelAddr(byte * pathBitmap,int x,int y)136 int PrinceEngine::getPixelAddr(byte *pathBitmap, int x, int y) {
137 	int mask = 128 >> (x & 7);
138 	byte value = pathBitmap[x / 8 + y * 80];
139 	return (mask & value);
140 }
141 
findPoint(int x,int y)142 void PrinceEngine::findPoint(int x, int y) {
143 	_fpX = x;
144 	_fpY = y;
145 
146 	if (getPixelAddr(_roomPathBitmap, x, y)) {
147 		return;
148 	}
149 
150 	int fpL = x;
151 	int fpU = y;
152 	int fpR = x;
153 	int fpD = y;
154 
155 	while (1) {
156 		if (fpD != kMaxPicHeight) {
157 			if (getPixelAddr(_roomPathBitmap, x, fpD)) {
158 				_fpX = x;
159 				_fpY = fpD;
160 				break;
161 			}
162 			fpD++;
163 		}
164 		if (fpU) {
165 			if (getPixelAddr(_roomPathBitmap, x, fpU)) {
166 				_fpX = x;
167 				_fpY = fpU;
168 				break;
169 			}
170 			fpU--;
171 		}
172 		if (fpL) {
173 			if (getPixelAddr(_roomPathBitmap, fpL, y)) {
174 				_fpX = fpL;
175 				_fpY = y;
176 				break;
177 			}
178 			fpL--;
179 		}
180 		if (fpR != _sceneWidth) {
181 			if (getPixelAddr(_roomPathBitmap, fpR, y)) {
182 				_fpX = fpR;
183 				_fpY = y;
184 				break;
185 			}
186 			fpR++;
187 		}
188 		if (!fpU && (fpD == kMaxPicHeight)) {
189 			if (!fpL && (fpR == _sceneWidth)) {
190 				break;
191 			}
192 		}
193 	}
194 }
195 
makeDirection(int x1,int y1,int x2,int y2)196 Direction PrinceEngine::makeDirection(int x1, int y1, int x2, int y2) {
197 	if (x1 != x2) {
198 		if (y1 != y2) {
199 			if (x1 > x2) {
200 				if (y1 > y2) {
201 					if (x1 - x2 >= y1 - y2) {
202 						return kDirLU;
203 					} else {
204 						return kDirUL;
205 					}
206 				} else {
207 					if (x1 - x2 >= y2 - y1) {
208 						return kDirLD;
209 					} else {
210 						return kDirDL;
211 					}
212 				}
213 			} else {
214 				if (y1 > y2) {
215 					if (x2 - x1 >= y1 - y2) {
216 						return kDirRU;
217 					} else {
218 						return kDirUR;
219 					}
220 				} else {
221 					if (x2 - x1 >= y2 - y1) {
222 						return kDirRD;
223 					} else {
224 						return kDirDR;
225 					}
226 				}
227 			}
228 		} else {
229 			if (x1 >= x2) {
230 				return kDirL;
231 			} else {
232 				return kDirR;
233 			}
234 		}
235 	} else {
236 		if (y1 >= y2) {
237 			return kDirU;
238 		} else {
239 			return kDirD;
240 		}
241 	}
242 }
243 
specialPlot(int x,int y)244 void PrinceEngine::specialPlot(int x, int y) {
245 	if (_coords < _coordsBufEnd) {
246 		WRITE_LE_UINT16(_coords, x);
247 		_coords += 2;
248 		WRITE_LE_UINT16(_coords, y);
249 		_coords += 2;
250 		specialPlot2(x, y);
251 	}
252 }
253 
specialPlot2(int x,int y)254 void PrinceEngine::specialPlot2(int x, int y) {
255 	int mask = 128 >> (x & 7);
256 	_roomPathBitmapTemp[x / 8 + y * 80] |= mask;
257 }
258 
specialPlotInside(int x,int y)259 void PrinceEngine::specialPlotInside(int x, int y) {
260 	if (_coords < _coordsBufEnd) {
261 		WRITE_LE_UINT16(_coords, x);
262 		_coords += 2;
263 		WRITE_LE_UINT16(_coords, y);
264 		_coords += 2;
265 	}
266 }
267 
plotTraceLine(int x,int y,void * data)268 int PrinceEngine::plotTraceLine(int x, int y, void *data) {
269 	PrinceEngine *traceLine = (PrinceEngine *)data;
270 	if (!traceLine->_traceLineFirstPointFlag) {
271 		if (!traceLine->getPixelAddr(traceLine->_roomPathBitmapTemp, x, y)) {
272 			if (traceLine->getPixelAddr(traceLine->_roomPathBitmap, x, y)) {
273 				traceLine->specialPlotInside(x, y);
274 				traceLine->_traceLineLen++;
275 				return 0;
276 			} else {
277 				return -1;
278 			}
279 		} else {
280 			return 1;
281 		}
282 	} else {
283 		traceLine->_traceLineFirstPointFlag = false;
284 		return 0;
285 	}
286 }
287 
leftDownDir()288 int PrinceEngine::leftDownDir() {
289 	if (!checkLeftDownDir()) {
290 		specialPlot(_checkX, _checkY);
291 		return 0;
292 	}
293 	if (!checkLeftDir()) {
294 		specialPlot(_checkX, _checkY);
295 		return 0;
296 	}
297 	if (!checkDownDir()) {
298 		specialPlot(_checkX, _checkY);
299 		return 0;
300 	}
301 	if (!checkLeftUpDir()) {
302 		specialPlot(_checkX, _checkY);
303 		return 0;
304 	}
305 	if (!checkRightDownDir()) {
306 		specialPlot(_checkX, _checkY);
307 		return 0;
308 	}
309 	if (!checkUpDir()) {
310 		specialPlot(_checkX, _checkY);
311 		return 0;
312 	}
313 	if (!checkRightDir()) {
314 		specialPlot(_checkX, _checkY);
315 		return 0;
316 	}
317 	if (!checkRightUpDir()) {
318 		specialPlot(_checkX, _checkY);
319 		return 0;
320 	}
321 	return -1;
322 }
323 
leftDir()324 int PrinceEngine::leftDir() {
325 	if (!checkLeftDir()) {
326 		specialPlot(_checkX, _checkY);
327 		return 0;
328 	}
329 	if (!checkLeftUpDir()) {
330 		specialPlot(_checkX, _checkY);
331 		return 0;
332 	}
333 	if (!checkLeftDownDir()) {
334 		specialPlot(_checkX, _checkY);
335 		return 0;
336 	}
337 	if (!checkUpDir()) {
338 		specialPlot(_checkX, _checkY);
339 		return 0;
340 	}
341 	if (!checkDownDir()) {
342 		specialPlot(_checkX, _checkY);
343 		return 0;
344 	}
345 	if (!checkRightUpDir()) {
346 		specialPlot(_checkX, _checkY);
347 		return 0;
348 	}
349 	if (!checkRightDownDir()) {
350 		specialPlot(_checkX, _checkY);
351 		return 0;
352 	}
353 	if (!checkRightDir()) {
354 		specialPlot(_checkX, _checkY);
355 		return 0;
356 	}
357 	return -1;
358 }
359 
leftUpDir()360 int PrinceEngine::leftUpDir() {
361 	if (!checkLeftUpDir()) {
362 		specialPlot(_checkX, _checkY);
363 		return 0;
364 	}
365 	if (!checkLeftDir()) {
366 		specialPlot(_checkX, _checkY);
367 		return 0;
368 	}
369 	if (!checkUpDir()) {
370 		specialPlot(_checkX, _checkY);
371 		return 0;
372 	}
373 	if (!checkLeftDownDir()) {
374 		specialPlot(_checkX, _checkY);
375 		return 0;
376 	}
377 	if (!checkRightUpDir()) {
378 		specialPlot(_checkX, _checkY);
379 		return 0;
380 	}
381 	if (!checkDownDir()) {
382 		specialPlot(_checkX, _checkY);
383 		return 0;
384 	}
385 	if (!checkRightDir()) {
386 		specialPlot(_checkX, _checkY);
387 		return 0;
388 	}
389 	if (!checkRightDownDir()) {
390 		specialPlot(_checkX, _checkY);
391 		return 0;
392 	}
393 	return -1;
394 }
395 
rightDownDir()396 int PrinceEngine::rightDownDir() {
397 	if (!checkRightDownDir()) {
398 		specialPlot(_checkX, _checkY);
399 		return 0;
400 	}
401 	if (!checkRightDir()) {
402 		specialPlot(_checkX, _checkY);
403 		return 0;
404 	}
405 	if (!checkDownDir()) {
406 		specialPlot(_checkX, _checkY);
407 		return 0;
408 	}
409 	if (!checkRightUpDir()) {
410 		specialPlot(_checkX, _checkY);
411 		return 0;
412 	}
413 	if (!checkLeftDownDir()) {
414 		specialPlot(_checkX, _checkY);
415 		return 0;
416 	}
417 	if (!checkUpDir()) {
418 		specialPlot(_checkX, _checkY);
419 		return 0;
420 	}
421 	if (!checkLeftDir()) {
422 		specialPlot(_checkX, _checkY);
423 		return 0;
424 	}
425 	if (!checkLeftUpDir()) {
426 		specialPlot(_checkX, _checkY);
427 		return 0;
428 	}
429 	return -1;
430 }
431 
rightDir()432 int PrinceEngine::rightDir() {
433 	if (!checkRightDir()) {
434 		specialPlot(_checkX, _checkY);
435 		return 0;
436 	}
437 	if (!checkRightUpDir()) {
438 		specialPlot(_checkX, _checkY);
439 		return 0;
440 	}
441 	if (!checkRightDownDir()) {
442 		specialPlot(_checkX, _checkY);
443 		return 0;
444 	}
445 	if (!checkUpDir()) {
446 		specialPlot(_checkX, _checkY);
447 		return 0;
448 	}
449 	if (!checkDownDir()) {
450 		specialPlot(_checkX, _checkY);
451 		return 0;
452 	}
453 	if (!checkLeftUpDir()) {
454 		specialPlot(_checkX, _checkY);
455 		return 0;
456 	}
457 	if (!checkLeftDownDir()) {
458 		specialPlot(_checkX, _checkY);
459 		return 0;
460 	}
461 	if (!checkLeftDir()) {
462 		specialPlot(_checkX, _checkY);
463 		return 0;
464 	}
465 	return -1;
466 }
467 
rightUpDir()468 int PrinceEngine::rightUpDir() {
469 	if (!checkRightUpDir()) {
470 		specialPlot(_checkX, _checkY);
471 		return 0;
472 	}
473 	if (!checkRightDir()) {
474 		specialPlot(_checkX, _checkY);
475 		return 0;
476 	}
477 	if (!checkUpDir()) {
478 		specialPlot(_checkX, _checkY);
479 		return 0;
480 	}
481 	if (!checkRightDownDir()) {
482 		specialPlot(_checkX, _checkY);
483 		return 0;
484 	}
485 	if (!checkLeftUpDir()) {
486 		specialPlot(_checkX, _checkY);
487 		return 0;
488 	}
489 	if (!checkDownDir()) {
490 		specialPlot(_checkX, _checkY);
491 		return 0;
492 	}
493 	if (!checkLeftDir()) {
494 		specialPlot(_checkX, _checkY);
495 		return 0;
496 	}
497 	if (!checkLeftDownDir()) {
498 		specialPlot(_checkX, _checkY);
499 		return 0;
500 	}
501 	return -1;
502 }
503 
upLeftDir()504 int PrinceEngine::upLeftDir() {
505 	if (!checkLeftUpDir()) {
506 		specialPlot(_checkX, _checkY);
507 		return 0;
508 	}
509 	if (!checkUpDir()) {
510 		specialPlot(_checkX, _checkY);
511 		return 0;
512 	}
513 	if (!checkLeftDir()) {
514 		specialPlot(_checkX, _checkY);
515 		return 0;
516 	}
517 	if (!checkRightUpDir()) {
518 		specialPlot(_checkX, _checkY);
519 		return 0;
520 	}
521 	if (!checkLeftDownDir()) {
522 		specialPlot(_checkX, _checkY);
523 		return 0;
524 	}
525 	if (!checkRightDir()) {
526 		specialPlot(_checkX, _checkY);
527 		return 0;
528 	}
529 	if (!checkDownDir()) {
530 		specialPlot(_checkX, _checkY);
531 		return 0;
532 	}
533 	if (!checkRightDownDir()) {
534 		specialPlot(_checkX, _checkY);
535 		return 0;
536 	}
537 	return -1;
538 }
539 
upDir()540 int PrinceEngine::upDir() {
541 	if (!checkUpDir()) {
542 		specialPlot(_checkX, _checkY);
543 		return 0;
544 	}
545 	if (!checkLeftUpDir()) {
546 		specialPlot(_checkX, _checkY);
547 		return 0;
548 	}
549 	if (!checkRightUpDir()) {
550 		specialPlot(_checkX, _checkY);
551 		return 0;
552 	}
553 	if (!checkLeftDir()) {
554 		specialPlot(_checkX, _checkY);
555 		return 0;
556 	}
557 	if (!checkRightDir()) {
558 		specialPlot(_checkX, _checkY);
559 		return 0;
560 	}
561 	if (!checkLeftDownDir()) {
562 		specialPlot(_checkX, _checkY);
563 		return 0;
564 	}
565 	if (!checkRightDownDir()) {
566 		specialPlot(_checkX, _checkY);
567 		return 0;
568 	}
569 	if (!checkDownDir()) {
570 		specialPlot(_checkX, _checkY);
571 		return 0;
572 	}
573 	return -1;
574 }
575 
upRightDir()576 int PrinceEngine::upRightDir() {
577 	if (!checkRightUpDir()) {
578 		specialPlot(_checkX, _checkY);
579 		return 0;
580 	}
581 	if (!checkUpDir()) {
582 		specialPlot(_checkX, _checkY);
583 		return 0;
584 	}
585 	if (!checkRightDir()) {
586 		specialPlot(_checkX, _checkY);
587 		return 0;
588 	}
589 	if (!checkLeftUpDir()) {
590 		specialPlot(_checkX, _checkY);
591 		return 0;
592 	}
593 	if (!checkRightDownDir()) {
594 		specialPlot(_checkX, _checkY);
595 		return 0;
596 	}
597 	if (!checkLeftDir()) {
598 		specialPlot(_checkX, _checkY);
599 		return 0;
600 	}
601 	if (!checkDownDir()) {
602 		specialPlot(_checkX, _checkY);
603 		return 0;
604 	}
605 	if (!checkLeftDownDir()) {
606 		specialPlot(_checkX, _checkY);
607 		return 0;
608 	}
609 	return -1;
610 }
611 
downLeftDir()612 int PrinceEngine::downLeftDir() {
613 	if (!checkLeftDownDir()) {
614 		specialPlot(_checkX, _checkY);
615 		return 0;
616 	}
617 	if (!checkDownDir()) {
618 		specialPlot(_checkX, _checkY);
619 		return 0;
620 	}
621 	if (!checkLeftDir()) {
622 		specialPlot(_checkX, _checkY);
623 		return 0;
624 	}
625 	if (!checkRightDownDir()) {
626 		specialPlot(_checkX, _checkY);
627 		return 0;
628 	}
629 	if (!checkLeftUpDir()) {
630 		specialPlot(_checkX, _checkY);
631 		return 0;
632 	}
633 	if (!checkRightDir()) {
634 		specialPlot(_checkX, _checkY);
635 		return 0;
636 	}
637 	if (!checkUpDir()) {
638 		specialPlot(_checkX, _checkY);
639 		return 0;
640 	}
641 	if (!checkRightUpDir()) {
642 		specialPlot(_checkX, _checkY);
643 		return 0;
644 	}
645 	return -1;
646 }
647 
downDir()648 int PrinceEngine::downDir() {
649 	if (!checkDownDir()) {
650 		specialPlot(_checkX, _checkY);
651 		return 0;
652 	}
653 	if (!checkRightDownDir()) {
654 		specialPlot(_checkX, _checkY);
655 		return 0;
656 	}
657 	if (!checkLeftDownDir()) {
658 		specialPlot(_checkX, _checkY);
659 		return 0;
660 	}
661 	if (!checkRightDir()) {
662 		specialPlot(_checkX, _checkY);
663 		return 0;
664 	}
665 	if (!checkLeftDir()) {
666 		specialPlot(_checkX, _checkY);
667 		return 0;
668 	}
669 	if (!checkRightUpDir()) {
670 		specialPlot(_checkX, _checkY);
671 		return 0;
672 	}
673 	if (!checkLeftUpDir()) {
674 		specialPlot(_checkX, _checkY);
675 		return 0;
676 	}
677 	if (!checkUpDir()) {
678 		specialPlot(_checkX, _checkY);
679 		return 0;
680 	}
681 	return -1;
682 }
683 
downRightDir()684 int PrinceEngine::downRightDir() {
685 	if (!checkRightDownDir()) {
686 		specialPlot(_checkX, _checkY);
687 		return 0;
688 	}
689 	if (!checkDownDir()) {
690 		specialPlot(_checkX, _checkY);
691 		return 0;
692 	}
693 	if (!checkRightDir()) {
694 		specialPlot(_checkX, _checkY);
695 		return 0;
696 	}
697 	if (!checkLeftDownDir()) {
698 		specialPlot(_checkX, _checkY);
699 		return 0;
700 	}
701 	if (!checkRightUpDir()) {
702 		specialPlot(_checkX, _checkY);
703 		return 0;
704 	}
705 	if (!checkLeftDir()) {
706 		specialPlot(_checkX, _checkY);
707 		return 0;
708 	}
709 	if (!checkUpDir()) {
710 		specialPlot(_checkX, _checkY);
711 		return 0;
712 	}
713 	if (!checkLeftUpDir()) {
714 		specialPlot(_checkX, _checkY);
715 		return 0;
716 	}
717 	return -1;
718 }
719 
cpe()720 int PrinceEngine::cpe() {
721 	if ((*(_checkBitmap - kPBW) & _checkMask)) {
722 		if ((*(_checkBitmap + kPBW) & _checkMask)) {
723 			int value;
724 			switch (_checkMask) {
725 			case 128:
726 				value = READ_LE_UINT16(_checkBitmap - 1);
727 				value &= 0x4001;
728 				if (value != 0x4001) {
729 					return 0;
730 				}
731 				break;
732 			case 64:
733 				value = *_checkBitmap;
734 				value &= 0xA0;
735 				if (value != 0xA0) {
736 					return 0;
737 				}
738 				break;
739 			case 32:
740 				value = *_checkBitmap;
741 				value &= 0x50;
742 				if (value != 0x50) {
743 					return 0;
744 				}
745 				break;
746 			case 16:
747 				value = *_checkBitmap;
748 				value &= 0x28;
749 				if (value != 0x28) {
750 					return 0;
751 				}
752 				break;
753 			case 8:
754 				value = *_checkBitmap;
755 				value &= 0x14;
756 				if (value != 0x14) {
757 					return 0;
758 				}
759 				break;
760 			case 4:
761 				value = *_checkBitmap;
762 				value &= 0xA;
763 				if (value != 0xA) {
764 					return 0;
765 				}
766 				break;
767 			case 2:
768 				value = *_checkBitmap;
769 				value &= 0x5;
770 				if (value != 0x5) {
771 					return 0;
772 				}
773 				break;
774 			case 1:
775 				value = READ_LE_UINT16(_checkBitmap);
776 				value &= 0x8002;
777 				if (value != 0x8002) {
778 					return 0;
779 				}
780 				break;
781 			default:
782 				error("Wrong _checkMask value - cpe()");
783 				break;
784 			}
785 			_checkX = _rembX;
786 			_checkY = _rembY;
787 			_checkBitmapTemp = _rembBitmapTemp;
788 			_checkBitmap = _rembBitmap;
789 			_checkMask = _rembMask;
790 			return -1;
791 		}
792 		return 0;
793 	}
794 	return 0;
795 }
796 
checkLeftDownDir()797 int PrinceEngine::checkLeftDownDir() {
798 	if (_checkX && _checkY != (kMaxPicHeight / 2 - 1)) {
799 		int tempMask = _checkMask;
800 		if (tempMask != 128) {
801 			tempMask <<= 1;
802 			if ((*(_checkBitmap + kPBW) & tempMask)) {
803 				if (!(*(_checkBitmapTemp + kPBW) & tempMask)) {
804 					_checkBitmap += kPBW;
805 					_checkBitmapTemp += kPBW;
806 					_checkMask = tempMask;
807 				} else {
808 					return 1;
809 				}
810 			} else {
811 				return -1;
812 			}
813 		} else {
814 			if ((*(_checkBitmap + kPBW - 1) & 1)) {
815 				if (!(*(_checkBitmapTemp + kPBW - 1) & 1)) {
816 					_checkBitmap += (kPBW - 1);
817 					_checkBitmapTemp += (kPBW - 1);
818 					_checkMask = 1;
819 				} else {
820 					return 1;
821 				}
822 			} else {
823 				return -1;
824 			}
825 		}
826 		_checkX--;
827 		_checkY++;
828 		return cpe();
829 	} else {
830 		return -1;
831 	}
832 }
833 
checkLeftDir()834 int PrinceEngine::checkLeftDir() {
835 	if (_checkX) {
836 		int tempMask = _checkMask;
837 		if (tempMask != 128) {
838 			tempMask <<= 1;
839 			if ((*(_checkBitmap) & tempMask)) {
840 				if (!(*(_checkBitmapTemp) & tempMask)) {
841 					_checkMask = tempMask;
842 				} else {
843 					return 1;
844 				}
845 			} else {
846 				return -1;
847 			}
848 		} else {
849 			if ((*(_checkBitmap - 1) & 1)) {
850 				if (!(*(_checkBitmapTemp - 1) & 1)) {
851 					_checkBitmap--;
852 					_checkBitmapTemp--;
853 					_checkMask = 1;
854 				} else {
855 					return 1;
856 				}
857 			} else {
858 				return -1;
859 			}
860 		}
861 		_checkX--;
862 		return cpe();
863 	} else {
864 		return -1;
865 	}
866 }
867 
checkDownDir()868 int PrinceEngine::checkDownDir() {
869 	if (_checkY != (kMaxPicHeight / 2 - 1)) {
870 		if ((*(_checkBitmap + kPBW) & _checkMask)) {
871 			if (!(*(_checkBitmapTemp + kPBW) & _checkMask)) {
872 				_checkBitmap += kPBW;
873 				_checkBitmapTemp += kPBW;
874 				_checkY++;
875 				return cpe();
876 			} else {
877 				return 1;
878 			}
879 		} else {
880 			return -1;
881 		}
882 	} else {
883 		return -1;
884 	}
885 }
886 
checkUpDir()887 int PrinceEngine::checkUpDir() {
888 	if (_checkY) {
889 		if ((*(_checkBitmap - kPBW) & _checkMask)) {
890 			if (!(*(_checkBitmapTemp - kPBW) & _checkMask)) {
891 				_checkBitmap -= kPBW;
892 				_checkBitmapTemp -= kPBW;
893 				_checkY--;
894 				return cpe();
895 			} else {
896 				return 1;
897 			}
898 		} else {
899 			return -1;
900 		}
901 	} else {
902 		return -1;
903 	}
904 }
905 
checkRightDir()906 int PrinceEngine::checkRightDir() {
907 	if (_checkX != (kMaxPicWidth / 2 - 1)) {
908 		int tempMask = _checkMask;
909 		if (tempMask != 1) {
910 			tempMask >>= 1;
911 			if ((*(_checkBitmap) & tempMask)) {
912 				if (!(*(_checkBitmapTemp) & tempMask)) {
913 					_checkMask = tempMask;
914 				} else {
915 					return 1;
916 				}
917 			} else {
918 				return -1;
919 			}
920 		} else {
921 			if ((*(_checkBitmap + 1) & 128)) {
922 				if (!(*(_checkBitmapTemp + 1) & 128)) {
923 					_checkBitmap++;
924 					_checkBitmapTemp++;
925 					_checkMask = 128;
926 				} else {
927 					return 1;
928 				}
929 			} else {
930 				return -1;
931 			}
932 		}
933 		_checkX++;
934 		return cpe();
935 	} else {
936 		return -1;
937 	}
938 }
939 
checkLeftUpDir()940 int PrinceEngine::checkLeftUpDir() {
941 	if (_checkX && _checkY) {
942 		int tempMask = _checkMask;
943 		if (tempMask != 128) {
944 			tempMask <<= 1;
945 			if ((*(_checkBitmap - kPBW) & tempMask)) {
946 				if (!(*(_checkBitmapTemp - kPBW) & tempMask)) {
947 					_checkBitmap -= kPBW;
948 					_checkBitmapTemp -= kPBW;
949 					_checkMask = tempMask;
950 				} else {
951 					return 1;
952 				}
953 			} else {
954 				return -1;
955 			}
956 		} else {
957 			if ((*(_checkBitmap - (kPBW + 1)) & 1)) {
958 				if (!(*(_checkBitmapTemp - (kPBW + 1)) & 1)) {
959 					_checkBitmap -= (kPBW + 1);
960 					_checkBitmapTemp -= (kPBW + 1);
961 					_checkMask = 1;
962 				} else {
963 					return 1;
964 				}
965 			} else {
966 				return -1;
967 			}
968 		}
969 		_checkX--;
970 		_checkY--;
971 		return cpe();
972 	} else {
973 		return -1;
974 	}
975 }
976 
checkRightDownDir()977 int PrinceEngine::checkRightDownDir() {
978 	if (_checkX != (kMaxPicWidth / 2 - 1) && _checkY != (kMaxPicHeight / 2 - 1)) {
979 		int tempMask = _checkMask;
980 		if (tempMask != 1) {
981 			tempMask >>= 1;
982 			if ((*(_checkBitmap + kPBW) & tempMask)) {
983 				if (!(*(_checkBitmapTemp + kPBW) & tempMask)) {
984 					_checkBitmap += kPBW;
985 					_checkBitmapTemp += kPBW;
986 					_checkMask = tempMask;
987 				} else {
988 					return 1;
989 				}
990 			} else {
991 				return -1;
992 			}
993 		} else {
994 			if ((*(_checkBitmap + kPBW + 1) & 128)) {
995 				if (!(*(_checkBitmapTemp + kPBW + 1) & 128)) {
996 					_checkBitmap += kPBW + 1;
997 					_checkBitmapTemp += kPBW + 1;
998 					_checkMask = 128;
999 				} else {
1000 					return 1;
1001 				}
1002 			} else {
1003 				return -1;
1004 			}
1005 		}
1006 		_checkX++;
1007 		_checkY++;
1008 		return cpe();
1009 	} else {
1010 		return -1;
1011 	}
1012 }
1013 
checkRightUpDir()1014 int PrinceEngine::checkRightUpDir() {
1015 	if (_checkX != (kMaxPicWidth / 2 - 1) && _checkY) {
1016 		int tempMask = _checkMask;
1017 		if (tempMask != 1) {
1018 			tempMask >>= 1;
1019 			if ((*(_checkBitmap - kPBW) & tempMask)) {
1020 				if (!(*(_checkBitmapTemp - kPBW) & tempMask)) {
1021 					_checkBitmap -= kPBW;
1022 					_checkBitmapTemp -= kPBW;
1023 					_checkMask = tempMask;
1024 				} else {
1025 					return 1;
1026 				}
1027 			} else {
1028 				return -1;
1029 			}
1030 		} else {
1031 			if ((*(_checkBitmap - kPBW + 1) & 128)) {
1032 				if (!(*(_checkBitmapTemp - kPBW + 1) & 128)) {
1033 					_checkBitmap -= (kPBW - 1);
1034 					_checkBitmapTemp -= (kPBW - 1);
1035 					_checkMask = 128;
1036 				} else {
1037 					return 1;
1038 				}
1039 			} else {
1040 				return -1;
1041 			}
1042 		}
1043 		_checkX++;
1044 		_checkY--;
1045 		return cpe();
1046 	} else {
1047 		return -1;
1048 	}
1049 }
1050 
tracePath(int x1,int y1,int x2,int y2)1051 bool PrinceEngine::tracePath(int x1, int y1, int x2, int y2) {
1052 	for (uint i = 0; i < kPathBitmapLen; i++) {
1053 		_roomPathBitmapTemp[i] = 0;
1054 	}
1055 	if (x1 != x2 || y1 != y2) {
1056 		if (getPixelAddr(_roomPathBitmap, x1, y1)) {
1057 			if (getPixelAddr(_roomPathBitmap, x2, y2)) {
1058 				_coords = _coordsBuf;
1059 				specialPlot(x1, y1);
1060 
1061 				int x = x1;
1062 				int y = y1;
1063 
1064 				while (1) {
1065 					int btx = x;
1066 					int bty = y;
1067 					byte *bcad = _coords;
1068 
1069 					_traceLineLen = 0;
1070 					_traceLineFirstPointFlag = true;
1071 					int drawLineFlag = drawLine(x, y, x2, y2, &this->plotTraceLine, this);
1072 
1073 					if (!drawLineFlag) {
1074 						return true;
1075 					} else if (drawLineFlag == -1 && _traceLineLen >= 2) {
1076 						byte *tempCorrds = bcad;
1077 						while (tempCorrds != _coords) {
1078 							x = READ_LE_UINT16(tempCorrds);
1079 							y = READ_LE_UINT16(tempCorrds + 2);
1080 							tempCorrds += 4;
1081 							specialPlot2(x, y);
1082 						}
1083 					} else {
1084 						_coords = bcad;
1085 						x = btx;
1086 						y = bty;
1087 					}
1088 
1089 					Direction dir = makeDirection(x, y, x2, y2);
1090 
1091 					_rembBitmapTemp = &_roomPathBitmapTemp[x / 8 + y * 80];
1092 					_rembBitmap = &_roomPathBitmap[x / 8 + y * 80];
1093 					_rembMask = 128 >> (x & 7);
1094 					_rembX = x;
1095 					_rembY = y;
1096 
1097 					_checkBitmapTemp = _rembBitmapTemp;
1098 					_checkBitmap = _rembBitmap;
1099 					_checkMask = _rembMask;
1100 					_checkX = _rembX;
1101 					_checkY = _rembY;
1102 
1103 					int result;
1104 					switch (dir) {
1105 					case kDirLD:
1106 						result = leftDownDir();
1107 						break;
1108 					case kDirL:
1109 						result = leftDir();
1110 						break;
1111 					case kDirLU:
1112 						result = leftUpDir();
1113 						break;
1114 					case kDirRD:
1115 						result = rightDownDir();
1116 						break;
1117 					case kDirR:
1118 						result = rightDir();
1119 						break;
1120 					case kDirRU:
1121 						result = rightUpDir();
1122 						break;
1123 					case kDirUL:
1124 						result = upLeftDir();
1125 						break;
1126 					case kDirU:
1127 						result = upDir();
1128 						break;
1129 					case kDirUR:
1130 						result = upRightDir();
1131 						break;
1132 					case kDirDL:
1133 						result = downLeftDir();
1134 						break;
1135 					case kDirD:
1136 						result = downDir();
1137 						break;
1138 					case kDirDR:
1139 						result = downRightDir();
1140 						break;
1141 					default:
1142 						result = -1;
1143 						error("tracePath: wrong direction %d", dir);
1144 						break;
1145 					}
1146 
1147 					if (result) {
1148 						byte *tempCoords = _coords;
1149 						tempCoords -= 4;
1150 						if (tempCoords > _coordsBuf) {
1151 							int tempX = READ_LE_UINT16(tempCoords);
1152 							int tempY = READ_LE_UINT16(tempCoords + 2);
1153 							if (_checkX == tempX && _checkY == tempY) {
1154 								_coords = tempCoords;
1155 							}
1156 							x = READ_LE_UINT16(tempCoords);
1157 							y = READ_LE_UINT16(tempCoords + 2);
1158 						} else {
1159 							return false;
1160 						}
1161 					} else {
1162 						x = _checkX;
1163 						y = _checkY;
1164 					}
1165 				}
1166 				return true;
1167 			} else {
1168 				error("tracePath: wrong destination point");
1169 			}
1170 		} else {
1171 			error("tracePath: wrong start point");
1172 		}
1173 	} else {
1174 		error("tracePath: same point");
1175 	}
1176 }
1177 
specialPlotInside2(int x,int y)1178 void PrinceEngine::specialPlotInside2(int x, int y) {
1179 	WRITE_LE_UINT16(_coords2, x);
1180 	_coords2 += 2;
1181 	WRITE_LE_UINT16(_coords2, y);
1182 	_coords2 += 2;
1183 }
1184 
plotTracePoint(int x,int y,void * data)1185 int PrinceEngine::plotTracePoint(int x, int y, void *data) {
1186 	PrinceEngine *tracePoint = (PrinceEngine *)data;
1187 	if (!tracePoint->_tracePointFirstPointFlag) {
1188 		if (tracePoint->getPixelAddr(tracePoint->_roomPathBitmap, x, y)) {
1189 			tracePoint->specialPlotInside2(x, y);
1190 			return 0;
1191 		} else {
1192 			return -1;
1193 		}
1194 	} else {
1195 		tracePoint->_tracePointFirstPointFlag = false;
1196 		return 0;
1197 	}
1198 }
1199 
approxPath()1200 void PrinceEngine::approxPath() {
1201 	byte *oldCoords;
1202 	_coords2 = _coordsBuf2;
1203 	byte *tempCoordsBuf = _coordsBuf; // first point on path
1204 	byte *tempCoords = _coords;
1205 	if (tempCoordsBuf != tempCoords) {
1206 		tempCoords -= 4; // last point on path
1207 		while (tempCoordsBuf != tempCoords) {
1208 			int x1 = READ_LE_UINT16(tempCoords);
1209 			int y1 = READ_LE_UINT16(tempCoords + 2);
1210 			int x2 = READ_LE_UINT16(tempCoordsBuf);
1211 			int y2 = READ_LE_UINT16(tempCoordsBuf + 2);
1212 			tempCoordsBuf += 4;
1213 			//TracePoint
1214 			oldCoords = _coords2;
1215 			if (_coords2 == _coordsBuf2) {
1216 				WRITE_LE_UINT16(_coords2, x1);
1217 				WRITE_LE_UINT16(_coords2 + 2, y1);
1218 				_coords2 += 4;
1219 			} else {
1220 				int testX = READ_LE_UINT16(_coords2 - 4);
1221 				int testY = READ_LE_UINT16(_coords2 - 2);
1222 				if (testX != x1 || testY != y1) {
1223 					WRITE_LE_UINT16(_coords2, x1);
1224 					WRITE_LE_UINT16(_coords2 + 2, y1);
1225 					_coords2 += 4;
1226 				}
1227 			}
1228 			_tracePointFirstPointFlag = true;
1229 			bool drawLineFlag = drawLine(x1, y1, x2, y2, &this->plotTracePoint, this);
1230 			if (!drawLineFlag) {
1231 				tempCoords = tempCoordsBuf - 4;
1232 				tempCoordsBuf = _coordsBuf;
1233 			} else {
1234 				_coords2 = oldCoords;
1235 			}
1236 		}
1237 	}
1238 }
1239 
freeDirectionTable()1240 void PrinceEngine::freeDirectionTable() {
1241 	if (_directionTable != nullptr) {
1242 		free(_directionTable);
1243 		_directionTable = nullptr;
1244 	}
1245 }
1246 
scanDirectionsFindNext(byte * tempCoordsBuf,int xDiff,int yDiff)1247 int PrinceEngine::scanDirectionsFindNext(byte *tempCoordsBuf, int xDiff, int yDiff) {
1248 
1249 	int tempX, tempY, direction;
1250 
1251 	tempX = Hero::kHeroDirLeft;
1252 	if (xDiff < 0) {
1253 		tempX = Hero::kHeroDirRight;
1254 	}
1255 
1256 	tempY = Hero::kHeroDirUp;
1257 	if (yDiff < 0) {
1258 		tempY = Hero::kHeroDirDown;
1259 	}
1260 
1261 	while (1) {
1262 		int againPointX1 = READ_LE_UINT16(tempCoordsBuf);
1263 		int againPointY1 = READ_LE_UINT16(tempCoordsBuf + 2);
1264 		tempCoordsBuf += 4;
1265 
1266 		if (tempCoordsBuf == _coords) {
1267 			direction = tempX;
1268 			break;
1269 		}
1270 
1271 		int dX = againPointX1 - READ_LE_UINT16(tempCoordsBuf);
1272 		int dY = againPointY1 - READ_LE_UINT16(tempCoordsBuf + 2);
1273 
1274 		if (dX != xDiff) {
1275 			direction = tempY;
1276 			break;
1277 		}
1278 
1279 		if (dY != yDiff) {
1280 			direction = tempX;
1281 			break;
1282 		}
1283 	}
1284 	return direction;
1285 }
1286 
scanDirections()1287 void PrinceEngine::scanDirections() {
1288 	freeDirectionTable();
1289 	byte *tempCoordsBuf = _coordsBuf;
1290 	if (tempCoordsBuf != _coords) {
1291 		int size = (_coords - tempCoordsBuf) / 4 + 1; // number of coord points plus one for end marker
1292 		_directionTable = (byte *)malloc(size);
1293 		byte *tempDirTab = _directionTable;
1294 		int direction = -1;
1295 		int lastDirection = -1;
1296 
1297 		while (1) {
1298 			int x1 = READ_LE_UINT16(tempCoordsBuf);
1299 			int y1 = READ_LE_UINT16(tempCoordsBuf + 2);
1300 			tempCoordsBuf += 4;
1301 			if (tempCoordsBuf == _coords) {
1302 				break;
1303 			}
1304 			int x2 = READ_LE_UINT16(tempCoordsBuf);
1305 			int y2 = READ_LE_UINT16(tempCoordsBuf + 2);
1306 
1307 			int xDiff = x1 - x2;
1308 			int yDiff = y1 - y2;
1309 
1310 			if (xDiff) {
1311 				if (yDiff) {
1312 					if (lastDirection != -1) {
1313 						direction = lastDirection;
1314 						if (direction == Hero::kHeroDirLeft) {
1315 							if (xDiff < 0) {
1316 								direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff);
1317 							}
1318 						} else if (direction == Hero::kHeroDirRight) {
1319 							if (xDiff >= 0) {
1320 								direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff);
1321 							}
1322 						} else if (direction == Hero::kHeroDirUp) {
1323 							if (yDiff < 0) {
1324 								direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff);
1325 							}
1326 						} else {
1327 							if (yDiff >= 0) {
1328 								direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff);
1329 							}
1330 						}
1331 					} else {
1332 						direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff);
1333 					}
1334 				} else {
1335 					direction = Hero::kHeroDirLeft;
1336 					if (xDiff < 0) {
1337 						direction = Hero::kHeroDirRight;
1338 					}
1339 				}
1340 			} else {
1341 				if (yDiff) {
1342 					direction = Hero::kHeroDirUp;
1343 					if (yDiff < 0) {
1344 						direction = Hero::kHeroDirDown;
1345 					}
1346 				} else {
1347 					direction = lastDirection;
1348 				}
1349 			}
1350 			lastDirection = direction;
1351 			*tempDirTab = direction;
1352 			tempDirTab++;
1353 		}
1354 		*tempDirTab = *(tempDirTab - 1);
1355 		tempDirTab++;
1356 		*tempDirTab = 0;
1357 	}
1358 }
1359 
moveShandria()1360 void PrinceEngine::moveShandria() {
1361 	int shanLen1 = _shanLen;
1362 	if (_flags->getFlagValue(Flags::SHANDOG)) {
1363 		_secondHero->freeHeroAnim();
1364 		_secondHero->freeOldMove();
1365 		byte *shanCoords = _mainHero->_currCoords + shanLen1 * 4 - 4;
1366 		int shanX = READ_LE_UINT16(shanCoords - 4);
1367 		int shanY = READ_LE_UINT16(shanCoords - 2);
1368 		int xDiff = shanX - _secondHero->_middleX;
1369 		if (xDiff < 0) {
1370 			xDiff *= -1;
1371 		}
1372 		int yDiff = shanY - _secondHero->_middleY;
1373 		if (yDiff < 0) {
1374 			yDiff *= -1;
1375 		}
1376 		shanCoords -= 4;
1377 		if (shanCoords != _mainHero->_currCoords) {
1378 			yDiff *= 1.5;
1379 			int shanDis =  xDiff * xDiff + yDiff * yDiff;
1380 			if (shanDis >= kMinDistance) {
1381 				while (1) {
1382 					shanCoords -= 4;
1383 					if (shanCoords == _mainHero->_currCoords) {
1384 						break;
1385 					}
1386 					int x = READ_LE_UINT16(shanCoords);
1387 					int y = READ_LE_UINT16(shanCoords + 2);
1388 					int pointDiffX = x - shanX;
1389 					if (pointDiffX < 0) {
1390 						pointDiffX *= -1;
1391 					}
1392 					int pointDiffY = y - shanY;
1393 					if (pointDiffY < 0) {
1394 						pointDiffY *= -1;
1395 					}
1396 					pointDiffY *= 1.5;
1397 					int distance = pointDiffX * pointDiffX + pointDiffY * pointDiffY;
1398 					if (distance >= kMinDistance) {
1399 						break;
1400 					}
1401 				}
1402 				int pathSizeDiff = (shanCoords - _mainHero->_currCoords) / 4;
1403 				int destDir = *(_mainHero->_currDirTab + pathSizeDiff);
1404 				_secondHero->_destDirection = destDir;
1405 				int destX = READ_LE_UINT16(shanCoords);
1406 				int destY = READ_LE_UINT16(shanCoords + 2);
1407 				_secondHero->_coords = makePath(kSecondHero, _secondHero->_middleX, _secondHero->_middleY, destX, destY);
1408 				if (_secondHero->_coords != nullptr) {
1409 					_secondHero->_currCoords = _secondHero->_coords;
1410 					int delay = shanLen1 - _shanLen;
1411 					if (delay < 6) {
1412 						delay = 6;
1413 					}
1414 					_secondHero->_moveDelay = delay / 2;
1415 					_secondHero->_state = Hero::kHeroStateDelayMove;
1416 					_secondHero->_dirTab = _directionTable;
1417 					_secondHero->_currDirTab = _directionTable;
1418 					_directionTable = nullptr;
1419 				}
1420 			}
1421 		}
1422 	}
1423 }
1424 
makePath(int heroId,int currX,int currY,int destX,int destY)1425 byte *PrinceEngine::makePath(int heroId, int currX, int currY, int destX, int destY) {
1426 	int realDestX = destX;
1427 	int realDestY = destY;
1428 	_flags->setFlagValue(Flags::MOVEDESTX, destX);
1429 	_flags->setFlagValue(Flags::MOVEDESTY, destY);
1430 
1431 	int x1 = currX / 2;
1432 	int y1 = currY / 2;
1433 	int x2 = destX / 2;
1434 	int y2 = destY / 2;
1435 
1436 	if ((x1 != x2) || (y1 != y2)) {
1437 		findPoint(x1, y1);
1438 		if (!getPixelAddr(_roomPathBitmap, _fpX, _fpY)) {
1439 			return nullptr;
1440 		}
1441 		if ((x1 != _fpX) || (y1 != _fpY)) {
1442 			x1 = _fpX;
1443 			y1 = _fpY;
1444 		}
1445 		findPoint(x2, y2);
1446 		if (!getPixelAddr(_roomPathBitmap, _fpX, _fpY)) {
1447 			return nullptr;
1448 		}
1449 		if ((x2 != _fpX) || (y2 != _fpY)) {
1450 			x2 = _fpX;
1451 			y2 = _fpY;
1452 			if (!_flags->getFlagValue(Flags::EXACTMOVE)) {
1453 				realDestX = x2 * 2;
1454 				realDestY = y2 * 2;
1455 				_flags->setFlagValue(Flags::MOVEDESTX, realDestX);
1456 				_flags->setFlagValue(Flags::MOVEDESTY, realDestY);
1457 			} else {
1458 				return nullptr;
1459 			}
1460 		}
1461 
1462 		if ((x1 == x2) && (y1 == y2)) {
1463 			if (!heroId) {
1464 				_mainHero->freeOldMove();
1465 				_mainHero->_state = Hero::kHeroStateTurn;
1466 			} else if (heroId == 1) {
1467 				_secondHero->freeOldMove();
1468 				_secondHero->_state = Hero::kHeroStateTurn;
1469 			}
1470 			return nullptr;
1471 		}
1472 
1473 		int pathLen1 = 0;
1474 		int pathLen2 = 0;
1475 		int stX = x1;
1476 		int stY = y1;
1477 		int sizeCoords2 = 0;
1478 
1479 		if (tracePath(x1, y1, x2, y2)) {
1480 			allocCoords2();
1481 			approxPath();
1482 			sizeCoords2 = _coords2 - _coordsBuf2;
1483 			for (int i = 0; i < sizeCoords2; i++) {
1484 				_coordsBuf[i] = _coordsBuf2[i];
1485 			}
1486 			_coords = _coordsBuf + sizeCoords2;
1487 			approxPath();
1488 			_coordsBuf3 = _coordsBuf2;
1489 			_coordsBuf2 = nullptr;
1490 			_coords3 = _coords2;
1491 			_coords2 = nullptr;
1492 			pathLen1 = _coords3 - _coordsBuf3;
1493 		}
1494 		if (tracePath(x2, y2, x1, y1)) {
1495 			allocCoords2();
1496 			approxPath();
1497 			sizeCoords2 = _coords2 - _coordsBuf2;
1498 			for (int i = 0; i < sizeCoords2; i++) {
1499 				_coordsBuf[i] = _coordsBuf2[i];
1500 			}
1501 			_coords = _coordsBuf + sizeCoords2;
1502 			approxPath();
1503 			pathLen2 = _coords2 - _coordsBuf2;
1504 		}
1505 
1506 		byte *chosenCoordsBuf = _coordsBuf2;
1507 		byte *choosenCoords = _coords2;
1508 		int choosenLength = pathLen1;
1509 		if (pathLen1 < pathLen2) {
1510 			chosenCoordsBuf = _coordsBuf3;
1511 			choosenCoords = _coords3;
1512 			choosenLength = pathLen2;
1513 		}
1514 
1515 		if (choosenLength) {
1516 			if (chosenCoordsBuf != nullptr) {
1517 				int tempXBegin = READ_LE_UINT16(chosenCoordsBuf);
1518 				int tempYBegin = READ_LE_UINT16(chosenCoordsBuf + 2);
1519 				if (stX != tempXBegin || stY != tempYBegin) {
1520 					SWAP(chosenCoordsBuf, choosenCoords);
1521 					chosenCoordsBuf -= 4;
1522 					byte *tempCoordsBuf = _coordsBuf;
1523 					while (1) {
1524 						int cord = READ_LE_UINT32(chosenCoordsBuf);
1525 						WRITE_LE_UINT32(tempCoordsBuf, cord);
1526 						tempCoordsBuf += 4;
1527 						if (chosenCoordsBuf == choosenCoords) {
1528 							break;
1529 						}
1530 						chosenCoordsBuf -= 4;
1531 					}
1532 					_coords = tempCoordsBuf;
1533 				} else {
1534 					int sizeChoosen = choosenCoords - chosenCoordsBuf;
1535 					for (int i = 0; i < sizeChoosen; i++) {
1536 						_coordsBuf[i] = chosenCoordsBuf[i];
1537 					}
1538 					_coords = _coordsBuf + sizeChoosen;
1539 				}
1540 				WRITE_LE_UINT32(_coords, 0xFFFFFFFF);
1541 				freeCoords2();
1542 				freeCoords3();
1543 				scanDirections();
1544 
1545 				byte *tempCoordsBuf = _coordsBuf;
1546 				byte *tempCoords = _coords;
1547 				byte *newCoords;
1548 				if (tempCoordsBuf != tempCoords) {
1549 					int normCoordsSize = _coords - _coordsBuf + 4;
1550 					newCoords = (byte *)malloc(normCoordsSize);
1551 					byte *newCoordsBegin = newCoords;
1552 					while (tempCoordsBuf != tempCoords) {
1553 						int newValueX = READ_LE_UINT16(tempCoordsBuf);
1554 						WRITE_LE_UINT16(newCoords, newValueX * 2);
1555 						newCoords += 2;
1556 						int newValueY = READ_LE_UINT16(tempCoordsBuf + 2);
1557 						WRITE_LE_UINT16(newCoords, newValueY * 2);
1558 						newCoords += 2;
1559 						tempCoordsBuf += 4;
1560 					}
1561 					WRITE_LE_UINT16(newCoords - 4, realDestX);
1562 					WRITE_LE_UINT16(newCoords - 2, realDestY);
1563 					WRITE_LE_UINT32(newCoords, 0xFFFFFFFF);
1564 					newCoords += 4;
1565 					_shanLen = (newCoords - newCoordsBegin);
1566 					_shanLen /= 4;
1567 					return newCoordsBegin;
1568 				}
1569 			}
1570 		}
1571 		_coords = _coordsBuf;
1572 		freeCoords2();
1573 		freeCoords3();
1574 		return nullptr;
1575 	} else {
1576 		if (!heroId) {
1577 			_mainHero->freeOldMove();
1578 			_mainHero->_state = Hero::kHeroStateTurn;
1579 		} else if (heroId == 1) {
1580 			_secondHero->freeOldMove();
1581 			_secondHero->_state = Hero::kHeroStateTurn;
1582 		}
1583 		return nullptr;
1584 	}
1585 }
1586 
allocCoords2()1587 void PrinceEngine::allocCoords2() {
1588 	if (_coordsBuf2 == nullptr) {
1589 		_coordsBuf2 = (byte *)malloc(kTracePts * 4);
1590 		_coords2 = _coordsBuf2;
1591 	}
1592 }
1593 
freeCoords2()1594 void PrinceEngine::freeCoords2() {
1595 	if (_coordsBuf2 != nullptr) {
1596 		free(_coordsBuf2);
1597 		_coordsBuf2 = nullptr;
1598 		_coords2 = nullptr;
1599 	}
1600 }
1601 
freeCoords3()1602 void PrinceEngine::freeCoords3() {
1603 	if (_coordsBuf3 != nullptr) {
1604 		free(_coordsBuf3);
1605 		_coordsBuf3 = nullptr;
1606 		_coords3 = nullptr;
1607 	}
1608 }
1609 
1610 } // End of namespace Prince
1611