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 "common/math.h"
24 
25 #include "petka/walk.h"
26 #include "petka/petka.h"
27 #include "petka/q_manager.h"
28 #include "petka/q_system.h"
29 #include "petka/objects/heroes.h"
30 
31 namespace Petka {
32 
33 const char *const wayPrefixes[] = {"-w-n.", "-w-ne.", "-w-e.", "-w-se.", "-w-s.", "-w-sw.", "-w-w.", "-w-nw."};
34 
35 const double kPI = M_PI;
36 const double k2PI = M_PI * 2;
37 const double kHalfPI = M_PI_2;
38 
39 const double kPiArray[] = {M_PI_2, M_PI_4, 0.0, -M_PI_4, -M_PI_2, -3 * M_PI_4, M_PI, 3 * M_PI_4};
40 
Walk(int id)41 Walk::Walk(int id) { // CHECKED
42 	QManager *mgr = g_vm->resMgr();
43 
44 	Common::String res = mgr->findResourceName(id);
45 	res.toLowercase();
46 	res = res.substr(0, res.find(wayPrefixes[0]));
47 	for (int i = 0; i < 8; ++i) {
48 		waysSizes[i] = readWayFile(res + Common::String(wayPrefixes[i]) + "off", &_off1[i], &_off2[i]) - 1;
49 		readWayFile(res + Common::String(wayPrefixes[i]) + "leg", &_leg1[i], &_leg2[i]);
50 	}
51 
52 	for (int i = 0; i < 8; ++i) {
53 		_offleg1[i] = new int[waysSizes[i] + 1];
54 		_offleg2[i] = new int[waysSizes[i] + 1];
55 		for (int j = 1; j <= waysSizes[i]; ++j) {
56 			_offleg1[i][j] = _leg1[i][j] + _off1[i][j] - _leg1[i][j - 1];
57 			_offleg2[i][j] = _leg2[i][j] + _off2[i][j] - _leg2[i][j - 1];
58 		}
59 		_offleg1[i][0] = _offleg1[i][waysSizes[i]];
60 		_offleg2[i][0] = _offleg2[i][waysSizes[i]];
61 	}
62 	for (int i = 0; i < 8; ++i) {
63 		int v16 = 0;
64 		int v18 = 0;
65 		int idx = 1;
66 		for (int j = 0; j < 150; ++j) {
67 			v16 += _offleg1[i][idx];
68 			v18 += _offleg2[i][idx];
69 			idx = (idx + 1) % waysSizes[i];
70 		}
71 		field_D0[i] = (double)v18 / v16;
72 	}
73 
74 	currX = 0.0;
75 	currY = 0.0;
76 	_bkg3Count = 0;
77 	_bkg2Count = 0;
78 	field_134 = 0;
79 	_bkg1Count = 0;
80 	_bkg3_1 = nullptr;
81 	_bkg3_2 = nullptr;
82 	_bkg2 = nullptr;
83 	_bkg3_3 = nullptr;
84 	_bkg3_4 = nullptr;
85 	_bkg3_5 = nullptr;
86 	_bkg1 = nullptr;
87 	field_190 = 0;
88 	resId = 0;
89 }
90 
~Walk()91 Walk::~Walk() { // CHECKED
92 	clearBackground();
93 	reset();
94 	for (int i = 0; i < 8; ++i) {
95 		delete[] _leg1[i];
96 		delete[] _leg2[i];
97 		delete[] _off1[i];
98 		delete[] _off2[i];
99 		delete[] _offleg1[i];
100 		delete[] _offleg2[i];
101 
102 		_leg1[i] = nullptr;
103 		_leg2[i] = nullptr;
104 		_off1[i] = nullptr;
105 		_off2[i] = nullptr;
106 		_offleg1[i] = nullptr;
107 		_offleg2[i] = nullptr;
108 
109 		waysSizes[i] = 0;
110 	}
111 }
112 
init(Point start,Point end)113 void Walk::init(Point start, Point end) {
114 	reset();
115 	field_134 = 1;
116 
117 	int v5 = sub_424230(&end) ? moveInside(&end) : sub_423600(end);
118 	_bkg3_4[0] = sub_424230(&start) ? moveInside(&start) : sub_423600(start);
119 
120 
121 	destX = end.x;
122 	destY = end.y;
123 
124 	currX = end.x;
125 	currY = end.y;
126 
127 	if (start == end)
128 		return;
129 
130 	if (sub_424160(&start, &end) || v5 != _bkg3_4[0]) {
131 		for (int i = 0; i < _bkg3Count; ++i)
132 			_bkg3_5[i] = -1;
133 
134 		field_134 = 1;
135 		if (_bkg3_4[0] != v5) {
136 			do {
137 				_bkg3_4[field_134] = sub_423970(_bkg3_4[field_134 - 1], _bkg3_5[field_134 - 1]);
138 				if (_bkg3_4[field_134] >= 0) {
139 					_bkg3_5[field_134 - 1] = _bkg3_4[field_134];
140 					if (field_134 <= 1 || _bkg3_4[field_134 - 2] != _bkg3_4[field_134])
141 						field_134++;
142 				} else {
143 					field_134--;
144 					_bkg3_4[field_134] = -1;
145 					_bkg3_5[field_134] = -1;
146 				}
147 
148 			} while (_bkg3_4[field_134 - 1] != v5);
149 		}
150 
151 		int v20 = 1;
152 		int v21 = 4;
153 		int v22 = 1;
154 		int a2 = 4;
155 		_bkg3_3[0] = start;
156 		if (field_134 > 1) {
157 			do {
158 				int v23 = sub_423A30(_bkg3_4[(v21 - 4) / 4], _bkg3_4[v21 / 4]);
159 				_bkg3_3[v22].x = (_bkg1[_bkg2[v23].x].x + _bkg1[_bkg2[v23].y].x) / 2;
160 				_bkg3_3[v22].y = (_bkg1[_bkg2[v23].x].y + _bkg1[_bkg2[v23].y].y) / 2;
161 
162 				if (v22 > 1 && !sub_424160(&_bkg3_3[v22 - 2], &_bkg3_3[v22])) {
163 					v20--;
164 
165 					_bkg3_3[v22 - 1] = _bkg3_3[v22];
166 
167 					v22--;
168 					field_134--;
169 				}
170 
171 				v21 = a2 + 4;
172 				v20++;
173 				v22++;
174 				a2 += 4;
175 			} while (v20 < field_134);
176 		}
177 
178 		_bkg3_3[v20] = end;
179 		if (v20 > 1 && !sub_424160(_bkg3_3 + v20 - 2, _bkg3_3 + v20)) {
180 			_bkg3_3[v20 - 1] = _bkg3_3[v20];
181 			field_134--;
182 		}
183 		field_134++;
184 	} else {
185 		_bkg3_3[0] = start;
186 		_bkg3_3[1] = end;
187 		field_134 = 2;
188 	}
189 
190 	sub_422EA0(_bkg3_3[0], _bkg3_3[1]);
191 	field_14C = 1;
192 }
193 
clearBackground()194 void Walk::clearBackground() { // CHECKED
195 	delete[] _bkg1;
196 	_bkg1 = nullptr;
197 	_bkg1Count = 0;
198 
199 
200 	if (_bkg3_1) {
201 		if (_bkg3_2) {
202 			for (int i = 0; i < _bkg3Count; ++i) {
203 				delete[] _bkg3_2[i];
204 				_bkg3_2[i] = nullptr;
205 			}
206 			delete[] _bkg3_2;
207 			_bkg3_2 = nullptr;
208 		}
209 		delete[] _bkg3_1;
210 		_bkg3_1 = nullptr;
211 		_bkg3Count = 0;
212 	}
213 
214 	delete[] _bkg2;
215 	_bkg2 = nullptr;
216 	_bkg2Count = 0;
217 
218 	delete[] _bkg3_3;
219 	_bkg3_3 = nullptr;
220 
221 	delete[] _bkg3_4;
222 	_bkg3_4 = nullptr;
223 
224 	delete[] _bkg3_5;
225 	_bkg3_5 = nullptr;
226 }
227 
setBackground(Common::String name)228 void Walk::setBackground(Common::String name) { // CHECKED
229 	clearBackground();
230 
231 	name.toLowercase();
232 	name.replace(name.size() - 3, 3, "cvx");
233 
234 	Common::SeekableReadStream *stream = g_vm->openFile(name, false);
235 	if (!stream)
236 		return;
237 
238 	_bkg1Count = stream->readUint32LE();
239 	_bkg1 = new Point[_bkg1Count];
240 
241 	for (int i = 0; i < _bkg1Count; ++i) {
242 		_bkg1[i].x = stream->readUint32LE();
243 		_bkg1[i].y = stream->readUint32LE();
244 	}
245 
246 	_bkg2Count = stream->readUint32LE();
247 	_bkg2 = new Point[_bkg2Count];
248 
249 	for (int i = 0; i < _bkg2Count; ++i) {
250 		_bkg2[i].x = stream->readUint32LE();
251 		_bkg2[i].y = stream->readUint32LE();
252 	}
253 
254 	_bkg3Count = stream->readUint32LE();
255 	_bkg3_1 = new int[_bkg3Count];
256 
257 	stream->read(_bkg3_1, 4 * _bkg3Count);
258 
259 	_bkg3_2 = new int*[_bkg3Count];
260 
261 	for (int i = 0; i < _bkg3Count; ++i) {
262 		_bkg3_2[i] = new int[_bkg3_1[i]];
263 		stream->read(_bkg3_2[i], 4 * _bkg3_1[i]);
264 	}
265 
266 	delete stream;
267 	_bkg3_3 = new Point[_bkg3Count + 1];
268 	_bkg3_4 = new int[_bkg3Count + 1];
269 	_bkg3_5 = new int[_bkg3Count + 1];
270 
271 }
272 
reset()273 void Walk::reset() { // CHECKED
274 	field_140 = 0.0;
275 	field_138 = 0.0;
276 	currX = 0;
277 	currY = 0;
278 	resId = 0;
279 	field_14C = 0;
280 	field_190 = 0;
281 	field_194 = 0;
282 }
283 
currPos()284 Common::Point Walk::currPos() { // CHECKED
285 	return Common::Point(currX, currY);
286 }
287 
getSpriteId()288 int Walk::getSpriteId() { // CHECKED
289 	return resId;
290 }
291 
commonPoint(int idx1,int idx2)292 int Walk::commonPoint(int idx1, int idx2) { // CHECKED
293 	if (_bkg2[idx1].x == _bkg2[idx2].x || _bkg2[idx1].x == _bkg2[idx2].y)
294 		return _bkg2[idx1].x;
295 
296 	if (_bkg2[idx1].y != _bkg2[idx2].x && _bkg2[idx1].y != _bkg2[idx2].y)
297 		return 0;
298 
299 	return _bkg2[idx1].y;
300 }
301 
readWayFile(const Common::String & name,int ** p1,int ** p2)302 int Walk::readWayFile(const Common::String &name, int **p1, int **p2) { // CHECKED
303 	Common::SeekableReadStream *stream = g_vm->openFile(name, false);
304 	if (!stream) {
305 		p1 = nullptr;
306 		p2 = nullptr;
307 		return 0;
308 	}
309 
310 	const uint items = (uint)stream->size() / 8;
311 
312 	*p1 = new int[items];
313 	*p2 = new int[items];
314 
315 	stream->skip(4);
316 	for (uint i = 0; i < items; ++i) {
317 		stream->read(&(*p1)[i], 4);
318 		stream->read(&(*p2)[i], 4);
319 	}
320 
321 	delete stream;
322 	return items;
323 }
324 
sub_422EA0(Point p1,Point p2)325 int Walk::sub_422EA0(Point p1, Point p2) {
326 	if (p1 == p2)
327 		return 0;
328 
329 	Point p = p1;
330 	p.x += 150;
331 
332 	double v5 = angle(p1, p, p2);
333 	double v6;
334 	if (v5 >= 0.0)
335 		v6 = k2PI - v5;
336 	else
337 		v6 = v5 + k2PI;
338 
339 	double v30 = 4.0;
340 	for (uint i = 0; i < ARRAYSIZE(kPiArray); ++i) {
341 		double v9 = v5 - kPiArray[i];
342 		if (v9 < 0.0)
343 			v9 = -v9;
344 		if (v9 < v30) {
345 			v30 = v9;
346 			resId = i;
347 		}
348 
349 		double v10 = v6 - kPiArray[i];
350 		if (v10 < 0.0)
351 			v10 = -v10;
352 		if (v10 < v30) {
353 			v30 = v10;
354 			resId = i;
355 		}
356 	}
357 
358 	double v28 = p2.x - p1.x;
359 	double v26 = p2.y - p1.y;
360 	double v12 = Common::hypotenuse(p2.x - p1.x, p2.y - p1.y);
361 
362 	double v39 = 1.0 / sqrt(field_D0[resId] * field_D0[resId] - -1.0);
363 	if (v39 == 0.0)
364 		field_140 = v28 / v12;
365 	else
366 		field_140 = (field_D0[resId] - -1.0 / (v26 / v28)) * (v26 / v12) * v39;
367 
368 	DBLPoint a1;
369 	DBLPoint a2;
370 	DBLPoint a3;
371 
372 	a1.x = p1.x;
373 	a1.y = p1.y;
374 
375 	a2.x = p2.x;
376 	a2.y = p2.y;
377 
378 	a3.x = p2.x;
379 	a3.y = field_D0[resId] * v28 + p1.y;
380 
381 	double v13 = angle(a1, a2, a3);
382 	field_140 = cos(v13);
383 	field_138 = sin(v13);
384 
385 	double v16 = v13;
386 	if (v13 < -kHalfPI)
387 		v16 = v13 + kPI;
388 	if (v13 > kHalfPI)
389 		v16 = v13 - kPI;
390 
391 	field_140 = cos(v16);
392 	field_138 = sin(v16);
393 
394 	int v32 = 1;
395 	double v34 = 0.0;
396 	double v35 = 0.0;
397 	double v36 = p1.y;
398 	v39 = v28 * v28 + v26 * v26 - -1.0;
399 
400 	int j = 0;
401 	for (int i = 0; i < 10;) {
402 		double k = g_vm->getQSystem()->getPetka()->calcPerspective(v36);
403 
404 		v34 += _offleg1[resId][v32] * k;
405 		v35 += _offleg2[resId][v32] * k;
406 
407 		j++;
408 
409 		v32 = (v32 + 1) % waysSizes[resId];
410 
411 		v36 = v35 * field_140 + v34 * field_138 + p1.y;
412 
413 		double v22 = v34 * field_140 - v35 * field_138 + p1.x - p2.x;
414 		double v38 = v36 - p2.y;
415 
416 		double v23 = v22 * v22 + v38 * v38;
417 		if (v23 >= v39) {
418 			i++;
419 		} else {
420 			v39 = v23;
421 			field_194 = j;
422 			i = 0;
423 		}
424 	}
425 
426 	field_170 = 0;
427 	field_178 = 0;
428 
429 	currX = p1.x;
430 	currY = p1.y;
431 
432 	field_150 = p1.x;
433 	field_158 = p1.y;
434 
435 	field_190 = 0;
436 	field_198 = g_vm->getQSystem()->getPetka()->calcPerspective(p1.y);
437 	return resId;
438 }
439 
sub_423350()440 int Walk::sub_423350() { // CHECKED
441 	field_190 = (field_190 + 1) % waysSizes[resId];
442 
443 	--field_194;
444 	if (field_194 < 0) {
445 		field_14C++;
446 		if (field_14C < field_134) {
447 			int t = field_190;
448 			int id = resId;
449 			if (id == sub_422EA0(_bkg3_3[field_14C - 1], _bkg3_3[field_14C])) {
450 				field_190 = t;
451 				return 1;
452 			}
453 			return 2;
454 		}
455 		return 0;
456 	}
457 
458 	field_198 = g_vm->getQSystem()->getPetka()->calcPerspective(currY);
459 	field_170 = _offleg1[resId][field_190] * field_198 + field_170;
460 	field_178 = _offleg2[resId][field_190] * field_198 + field_178;
461 
462 	currX = field_140 * field_170 - field_178 * field_138 + field_150;
463 	currY = field_140 * field_178 + field_138 * field_170 + field_158;
464 
465 	return 1;
466 }
467 
sub_4234B0()468 Common::Point Walk::sub_4234B0() { // CHECKED
469 	Common::Point p;
470 	field_198 = g_vm->getQSystem()->getPetka()->calcPerspective(currY);
471 	p.x = currX - _leg1[resId][field_190] * field_198;
472 	p.y = currY - _leg2[resId][field_190] * field_198;
473 	return p;
474 }
475 
sub_423570(int i1,int i2)476 bool Walk::sub_423570(int i1, int i2) { // CHECKED
477 	if (i1 == i2)
478 		return false;
479 
480 	if (_bkg2[i1].x == _bkg2[i2].x || _bkg2[i1].x == _bkg2[i2].y)
481 		return true;
482 
483 	return !(_bkg2[i1].y != _bkg2[i2].x && _bkg2[i1].y != _bkg2[i2].y);
484 }
485 
sub_423600(Point p)486 int Walk::sub_423600(Point p) {
487 	int j = 0;
488 	for (int i = 0; i < _bkg3Count; ++i, ++j) {
489 		int *v4 = new int[_bkg3_1[j]];
490 		v4[0] = _bkg3_2[j][0];
491 
492 		for (int k = 0; k < _bkg3_1[j]; ++k) {
493 			if (sub_423570(v4[0], _bkg3_2[j][k])) {
494 				v4[1] = _bkg3_2[j][k];
495 				break;
496 			}
497 		}
498 
499 		for (int k = 2; k < _bkg3_1[j]; ++k) {
500 			for (int l = 0; l < _bkg3_1[j]; ++l) {
501 				if (sub_423570(v4[k - 1], _bkg3_2[j][l]) && v4[k - 2] != _bkg3_2[j][l]) {
502 					v4[k] = _bkg3_2[j][l];
503 					break;
504 				}
505 			}
506 		}
507 
508 		int v11 = commonPoint(v4[_bkg3_1[j] - 1], v4[0]);
509 		int v31 = commonPoint(v4[0], v4[1]);
510 
511 		double v12 = angle(p, _bkg1[v11], _bkg1[v31]);
512 		if (p == _bkg1[v11] || p == _bkg1[v31]) {
513 			delete[] v4;
514 			return i;
515 		}
516 
517 
518 		int k;
519 		for (k = 1; k < _bkg3_1[j] - 1; ++k) {
520 			int v16 = commonPoint(v4[k - 1], v4[k]);
521 			int v32 = commonPoint(v4[k], v4[k + 1]);
522 
523 			v12 += angle(p, _bkg1[v16], _bkg1[v32]);
524 			if (p == _bkg1[v16] || p == _bkg1[v32]) {
525 				delete[] v4;
526 				return i;
527 			}
528 		}
529 
530 		int v19 = commonPoint(v4[k - 1], v4[k]);
531 		int v20 = commonPoint(v4[k], v4[0]);
532 
533 		delete[] v4;
534 
535 		double v23 = angle(p, _bkg1[v19], _bkg2[v20]);
536 		v12 += v23;
537 
538 		if (p == _bkg1[v19] || p == _bkg1[v20])
539 			return i;
540 
541 		if (v12 < 0.0)
542 			v12 = -v12;
543 
544 		if (v12 > kPI)
545 			return i;
546 	}
547 	debug("Walk bug: Point doesn't belong to any convex");
548 
549 	return 0;
550 }
551 
sub_423970(int a1,int a2)552 int Walk::sub_423970(int a1, int a2) { // CHECKED
553 	int index = 0;
554 	if (a2 >= 0) {
555 		int v5 = sub_423A30(a1, a2);
556 		for (int i = 0; i < _bkg3_1[a1]; ++i) {
557 			if (_bkg3_2[a1][i] == v5) {
558 				index = i + 1;
559 				break;
560 			}
561 		}
562 	}
563 
564 	for (int i = index; i < _bkg3_1[a1]; ++i) {
565 		for (int j = 0; j < _bkg3Count; ++j) {
566 			if (j == a1)
567 				continue;
568 
569 			for (int k = 0; k < _bkg3_1[j]; ++k) {
570 				if (_bkg3_2[j][k] == _bkg3_2[a1][i]) {
571 					return j;
572 				}
573 			}
574 		}
575 	}
576 	return -1;
577 }
578 
sub_423A30(int idx1,int idx2)579 int Walk::sub_423A30(int idx1, int idx2) { // CHECKED
580 	for (int i = 0; i < _bkg3_1[idx1]; ++i) {
581 		for (int j = 0; j < _bkg3_1[idx2]; ++j) {
582 			if (_bkg3_2[idx1][i] == _bkg3_2[idx2][j])
583 				return _bkg3_2[idx1][i];
584 		}
585 	}
586 	return 0;
587 }
588 
angle(Point p1,Point p2,Point p3)589 double Walk::angle(Point p1, Point p2, Point p3) { // CHECKED
590 	return angle(DBLPoint(p1), DBLPoint(p2), DBLPoint(p3));
591 }
592 
angle(DBLPoint p1,DBLPoint p2,DBLPoint p3)593 double Walk::angle(DBLPoint p1, DBLPoint p2, DBLPoint p3) { // CHECKED
594 	if (p1 == p2 || p1 == p3)
595 		return 0.0;
596 
597 	double xv1 = p2.x - p1.x;
598 	double xv2 = p3.x - p1.x;
599 
600 	double yv1 = p2.y - p1.y;
601 	double yv2 = p3.y - p1.y;
602 
603 	double mv1 = Common::hypotenuse(xv1, yv1);
604 	double mv2 = Common::hypotenuse(xv2, yv2);
605 	double v13 = (xv1 * xv2 + yv1 * yv2) / (mv1 * mv2);
606 	if ((xv2 / mv2 * (yv1 / mv1) - yv2 / mv2 * (xv1 / mv1)) < 0.0) // Not sure
607 		return -acos(v13);
608 	return acos(v13);
609 }
610 
sub_423E00(Point p1,Point p2,Point p3,Point p4,Point & p5)611 int Walk::sub_423E00(Point p1, Point p2, Point p3, Point p4, Point &p5) {
612 	if (p1.x > p2.x) {
613 		SWAP(p2, p1);
614 	}
615 
616 	if (p3.x > p4.x) {
617 		SWAP(p3, p4);
618 	}
619 
620 	double v11 = (p2.y - p1.y) * (p4.x - p3.x);
621 	double v12 = (p2.x - p1.x) * (p4.y - p3.y);
622 	if (v11 == v12)
623 		return 0;
624 
625 	double v30;
626 	if (p2.x - p1.x) {
627 		if (p4.x - p3.x) {
628 			v30 = ((double)(p3.y - p1.y) * (p4.x - p3.x) * (p2.x - p1.x) + (v11 * p1.x) - (v12 * p3.x)) / (v11 - v12);
629 			if (v30 < p1.x || p3.x > v30 || p2.x < v30 || p4.x < v30)
630 				return 0;
631 		} else {
632 			v30 = p3.x;
633 			if (p3.x < p1.x || p2.x < p3.x)
634 				return 0;
635 		}
636 	} else {
637 		v30 = p1.x;
638 		if (p1.x < p3.x)
639 			return 0;
640 		if (p4.x < p1.x)
641 			return 0;
642 	}
643 
644 	if (p1.y > p2.y) {
645 		SWAP(p1, p2);
646 	}
647 
648 	if (p3.y > p4.y) {
649 		SWAP(p3, p4);
650 	}
651 
652 	if (p2.y - p1.y) {
653 		if (p4.y - p3.y) {
654 			double v21;
655 			if (p2.x - p1.x) {
656 				v21 = (v30 - p1.x) * (p2.y - p1.y) / (p2.x - p1.x) + p1.y;
657 			} else {
658 				v21 = (v30 - p3.x) * (p4.y - p3.y) / (p4.x - p3.x) + p3.y;
659 			}
660 
661 			if (v21 >= p1.y && v21 >= p3.y && v21 <= p2.y && v21 <= p4.y) {
662 				p5.x = v30;
663 				p5.y = v21;
664 				return 1;
665 			}
666 
667 		} else {
668 			if (p3.y >= p1.y) {
669 				if (p3.y > p2.y)
670 					return 0;
671 				p5.x = v30;
672 				p5.y = p3.y;
673 				return 1;
674 			}
675 		}
676 	} else {
677 		if (p1.y >= p3.y) {
678 			if (p1.y <= p4.y) {
679 				p5.x = v30;
680 				p5.y = p1.y;
681 				return 1;
682 			}
683 		}
684 	}
685 
686 	return 0;
687 }
688 
sub_424160(Point * p1,Point * p2)689 bool Walk::sub_424160(Point *p1, Point *p2) { // CHECKED
690 	if (*p1 == *p2)
691 		return false;
692 
693 	Point p;
694 	int v = 1;
695 	if (_bkg1Count <= 1)
696 		return sub_423E00(_bkg1[v - 1], _bkg1[0], *p1, *p2, p) != 0;
697 
698 	while (!sub_423E00(_bkg1[v - 1], _bkg1[v], *p1, *p2, p)) {
699 		if (++v >= _bkg1Count)
700 			return sub_423E00(_bkg1[v - 1], _bkg1[0], *p1, *p2, p) != 0;
701 	}
702 	return true;
703 }
704 
sub_424230(Point * p1)705 bool Walk::sub_424230(Point *p1) { // CHECKED
706 	Point p(0, 0);
707 	int v = sub_424320(p1, &p);
708 
709 	p.y = p1->y;
710 	v = (sub_424320(p1, &p) & 1) + (v & 1);
711 
712 	p.y = 480;
713 	v = (sub_424320(p1, &p) & 1) + v;
714 	v = (sub_424320(p1, &p) & 1) + v;
715 
716 	p.x = 640;
717 	v = (sub_424320(p1, &p) & 1) + v;
718 
719 	p.y = p1->y;
720 	v = (sub_424320(p1, &p) & 1) + v;
721 
722 	p.y = 0;
723 	v = (sub_424320(p1, &p) & 1) + v;
724 
725 	p.x = p1->x;
726 	return (sub_424320(p1, &p) & 1) + v < 4;
727 }
728 
sub_424320(Point * p1,Point * p2)729 int Walk::sub_424320(Point *p1, Point *p2) { // CHECKED
730 	if (*p1 == *p2)
731 		return 0;
732 
733 	int ret = 0;
734 
735 	Point p;
736 
737 	int i;
738 	for (i = 1; i < _bkg1Count; ++i) {
739 		if (sub_423E00(_bkg1[i - 1], _bkg1[i], *p1, *p2, p) && *p1 != p && *p2 != p) {
740 			ret++;
741 		}
742 	}
743 
744 	if (sub_423E00(_bkg1[i - 1], _bkg1[0], *p1, *p2, p) && *p1 != p && *p2 != p) {
745 		ret++;
746 	}
747 
748 	return ret;
749 }
750 
moveInside(Point * p)751 int Walk::moveInside(Point *p) { // CHECKED
752 	DBLPoint dp = sub_424610(_bkg1[_bkg2->x], _bkg1[_bkg2->y].x, _bkg1[_bkg2->y].y, *p);
753 
754 	int index = 0;
755 
756 	double min = (dp.y - p->y) * (dp.y - p->y) + (dp.x - p->x) * (dp.x - p->x);
757 	for (int i = 1; i < _bkg1Count; ++i) {
758 		DBLPoint dp1 = sub_424610(_bkg1[_bkg2[i].x], _bkg1[_bkg2[i].y].x, _bkg1[_bkg2[i].y].y, *p);
759 		double curr = (dp1.y - p->y) * (dp1.y - p->y) + (dp1.x - p->x) * (dp1.x - p->x);
760 		if (curr < min) {
761 			dp = dp1;
762 			min = curr;
763 			index = i;
764 		}
765 
766 	}
767 
768 	p->x = dp.x;
769 	p->y = dp.y;
770 
771 
772 	for (int i = 0; i < _bkg1Count; ++i) {
773 		for (int j = 0; j < _bkg3_1[i]; ++j) {
774 			if (_bkg3_2[i][j] == index)
775 				return i;
776 		}
777 	}
778 
779 	return 0;
780 }
781 
sub_424610(Point p1,int x,int y,Point p2)782 DBLPoint Walk::sub_424610(Point p1, int x, int y, Point p2) { // CHECKED
783 	DBLPoint p;
784 	double v13;
785 	double v14;
786 	if (p1.x == x) {
787 		v13 = p1.x;
788 		v14 = p2.y;
789 	} else {
790 		double v6 = (double)(y - p1.y) / (x - p1.x);
791 		double v7 = p1.y - v6 * p1.x;
792 		v13 = ((p2.y - v7) * v6 + p2.x) / (v6 * v6 - -1.0);
793 		v14 = v13 * v6 + v7;
794 	}
795 	p.x = CLIP<double>(v13, MIN<int>(x, p1.x), MAX<int>(x, p1.x));
796 	p.y = CLIP<double>(v14, MIN<int>(y, p1.y), MAX<int>(y, p1.y));
797 	return p;
798 }
799 
800 } // End of namespace Petka
801