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