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/debug.h"
24 #include "common/textconsole.h"
25 #include "common/util.h"
26
27 #include "sword1/router.h"
28 #include "sword1/swordres.h"
29 #include "sword1/sworddefs.h"
30 #include "sword1/objectman.h"
31 #include "sword1/resman.h"
32
33 namespace Sword1 {
34
35 /****************************************************************************
36 * JROUTER.C polygon router with modular walks
37 * using a tree of modules
38 * 21 july 94
39 * 3 november 94
40 * System currently works by scanning grid data and coming up with a ROUTE
41 * as a series of way points(nodes), the smoothest eight directional PATH
42 * through these nodes is then found, and a WALK created to fit the PATH.
43 *
44 * Two funtions are called by the user, RouteFinder creates a route as a
45 * module list, HardWalk creates an animation list from the module list.
46 * The split is only provided to allow the possibility of turning the
47 * autorouter over two game cycles.
48 ****************************************************************************
49 *
50 * Routine timings on osborne 486
51 *
52 * Read floor resource (file already loaded) 112 pixels
53 *
54 * Read mega resource (file already loaded) 112 pixels
55 *
56 *
57 *
58 ****************************************************************************
59 *
60 * Modified 12 Oct 95
61 *
62 * Target Points within 1 pixel of a line are ignored ???
63 *
64 * Modules split into Points within 1 pixel of a line are ignored ???
65 *
66 ****************************************************************************/
67
68 #define NO_DIRECTIONS 8
69 #define SLOW_IN 3
70 #define SLOW_OUT 7
71 #define ROUTE_END_FLAG 255
72
Router(ObjectMan * pObjMan,ResMan * pResMan)73 Router::Router(ObjectMan *pObjMan, ResMan *pResMan) {
74 _objMan = pObjMan;
75 _resMan = pResMan;
76 _nNodes = _nBars = 0;
77 _playerTargetX = _playerTargetY = _playerTargetDir = _playerTargetStance = 0;
78 _diagonalx = _diagonaly = 0;
79 _slidyWalkAnimatorState = false;
80 }
81
82 /*
83 * CODE
84 */
85
routeFinder(int32 id,Object * megaObject,int32 x,int32 y,int32 dir)86 int32 Router::routeFinder(int32 id, Object *megaObject, int32 x, int32 y, int32 dir) {
87 /*********************************************************************
88 * RouteFinder.C polygon router with modular walks
89 * 21 august 94
90 * 3 november 94
91 * routeFinder creates a list of modules that enables HardWalk to
92 * create an animation list.
93 *
94 * routeFinder currently works by scanning grid data and coming up
95 * with a ROUTE as a series of way points(nodes), the smoothest eight
96 * directional PATH through these nodes is then found, this
97 * information is made available to HardWalk for a WALK to be created
98 * to fit the PATH.
99 *
100 * 30 november 94 return values modified
101 *
102 * return 0 = failed to find a route
103 *
104 * 1 = found a route
105 *
106 * 2 = mega already at target
107 *
108 *********************************************************************/
109
110 int32 routeFlag = 0;
111 int32 solidFlag = 0;
112 WalkData *walkAnim;
113
114 megaId = id;
115
116 LoadWalkResources(megaObject, x, y, dir);
117
118 walkAnim = megaObject->o_route;
119
120 _framesPerStep = _nWalkFrames / 2;
121 _framesPerChar = _nWalkFrames * NO_DIRECTIONS;
122
123 // offset pointers added Oct 30 95 JPS
124 standFrames = _framesPerChar;
125 turnFramesLeft = standFrames;
126 turnFramesRight = standFrames;
127 walkFramesLeft = 0;
128 walkFramesRight = 0;
129 slowInFrames = 0;
130 slowOutFrames = 0;
131
132 if (megaId == GEORGE) {
133 turnFramesLeft = 3 * _framesPerChar + NO_DIRECTIONS + 2 * SLOW_IN + 4 * SLOW_OUT;
134 turnFramesRight = 3 * _framesPerChar + NO_DIRECTIONS + 2 * SLOW_IN + 4 * SLOW_OUT + NO_DIRECTIONS;
135 walkFramesLeft = _framesPerChar + NO_DIRECTIONS;
136 walkFramesRight = 2 * _framesPerChar + NO_DIRECTIONS;
137 slowInFrames = 3 * _framesPerChar + NO_DIRECTIONS;
138 slowOutFrames = 3 * _framesPerChar + NO_DIRECTIONS + 2 * SLOW_IN;
139 } else if (megaId == NICO) {
140 turnFramesLeft = _framesPerChar + NO_DIRECTIONS;
141 turnFramesRight = _framesPerChar + 2 * NO_DIRECTIONS;
142 walkFramesLeft = 0;
143 walkFramesRight = 0;
144 slowInFrames = 0;
145 slowOutFrames = 0;
146 }
147
148 // **************************************************************************
149 // All route data now loaded start finding a route
150 // **************************************************************************
151 // **************************************************************************
152 // check if we can get a route through the floor changed 12 Oct95 JPS
153 // **************************************************************************
154
155 routeFlag = getRoute();
156
157 switch (routeFlag) {
158 case 2:
159 // special case for zero length route
160
161 // if target direction specified as any
162 if (_targetDir > 7)
163 _targetDir = _startDir;
164
165 // just a turn on the spot is required set an end module for
166 // the route let the animator deal with it
167 // modularPath is normally set by extractRoute
168
169 _modularPath[0].dir = _startDir;
170 _modularPath[0].num = 0;
171 _modularPath[0].x = _startX;
172 _modularPath[0].y = _startY;
173 _modularPath[1].dir = _targetDir;
174 _modularPath[1].num = 0;
175 _modularPath[1].x = _startX;
176 _modularPath[1].y = _startY;
177 _modularPath[2].dir = 9;
178 _modularPath[2].num = ROUTE_END_FLAG;
179
180 slidyWalkAnimator(walkAnim);
181 routeFlag = 2;
182 break;
183 case 1:
184 // A normal route. Convert the route to an exact path
185 smoothestPath();
186
187 // The Route had waypoints and direction options
188
189 // The Path is an exact set of lines in 8 directions that
190 // reach the target.
191
192 // The path is in module format, but steps taken in each
193 // direction are not accurate
194
195 // if target dir = 8 then the walk isn't linked to an anim so
196 // we can create a route without sliding and miss the exact
197 // target
198
199 if (_targetDir == NO_DIRECTIONS) {
200 // can end facing ANY direction (ie. exact end
201 // position not vital) - so use SOLID walk to
202 // avoid sliding to exact position
203
204 solidPath();
205 solidFlag = solidWalkAnimator(walkAnim);
206 }
207
208 if (!solidFlag) {
209 // if we failed to create a SOLID route, do a SLIDY
210 // one instead
211
212 slidyPath();
213 slidyWalkAnimator(walkAnim);
214 }
215
216 break;
217 default:
218 // Route didn't reach target so assume point was off the floor
219 // routeFlag = 0;
220 break;
221 }
222
223 return routeFlag; // send back null route
224 }
225
getRoute()226 int32 Router::getRoute() {
227 /*********************************************************************
228 * GetRoute.C extract a path from walk grid
229 * 12 october 94
230 *
231 * GetRoute currently works by scanning grid data and coming up with
232 * a ROUTE as a series of way points(nodes).
233 *
234 * static routeData _route[O_ROUTE_SIZE];
235 *
236 * return 0 = failed to find a route
237 *
238 * 1 = found a route
239 *
240 * 2 = mega already at target
241 *
242 * 3 = failed to find a route because target was on a line
243 *
244 *********************************************************************/
245
246 int32 routeGot = 0;
247
248 if (_startX == _targetX && _startY == _targetY)
249 routeGot = 2;
250 else {
251 // 'else' added by JEL (23jan96) otherwise 'routeGot' affected
252 // even when already set to '2' above - causing some 'turns'
253 // to walk downwards on the spot
254
255 // returns 3 if target on a line ( +- 1 pixel )
256 routeGot = checkTarget(_targetX, _targetY);
257 }
258
259 if (routeGot == 0) {
260 // still looking for a route check if target is within a pixel
261 // of a line
262
263 // scan through the nodes linking each node to its nearest
264 // neighbor until no more nodes change
265
266 // This is the routine that finds a route using scan()
267
268 int32 level = 1;
269
270 while (scan(level))
271 level++;
272
273 // Check to see if the route reached the target
274
275 if (_node[_nNodes].dist < 9999) {
276 // it did so extract the route as nodes and the
277 // directions to go between each node
278
279 routeGot = 1;
280 extractRoute();
281
282 // route.X,route.Y and route.Dir now hold all the
283 // route infomation with the target dir or route
284 // continuation
285 }
286 }
287
288 return routeGot;
289 }
290
291 // THE SLIDY PATH ROUTINES
292
smoothestPath()293 int32 Router::smoothestPath() {
294 // This is the second big part of the route finder and the the only
295 // bit that tries to be clever (the other bits are clever).
296 //
297 // This part of the autorouter creates a list of modules from a set of
298 // lines running across the screen. The task is complicated by two
299 // things:
300 //
301 // Firstly in choosing a route through the maze of nodes the routine
302 // tries to minimise the amount of each individual turn avoiding 90
303 // degree and greater turns (where possible) and reduces the total
304 // number of turns (subject to two 45 degree turns being better than
305 // one 90 degree turn).
306 //
307 // Secondly when walking in a given direction the number of steps
308 // required to reach the end of that run is not calculated accurately.
309 // This is because I was unable to derive a function to relate number
310 // of steps taken between two points to the shrunken step size
311
312 int i;
313 int32 steps = 0;
314 int32 lastDir;
315 int32 tempturns[4];
316 int32 turns[4];
317 const int32 turntable[NO_DIRECTIONS] = { 0, 1, 3, 5, 7, 5, 3, 1 };
318
319 // route.X route.Y and route.Dir start at far end
320
321 _smoothPath[0].x = _startX;
322 _smoothPath[0].y = _startY;
323 _smoothPath[0].dir = _startDir;
324 _smoothPath[0].num = 0;
325
326 lastDir = _startDir;
327
328 // for each section of the route
329 for (int p = 0; p < _routeLength; p++) {
330 int32 dirS = _route[p].dirS;
331 int32 dirD = _route[p].dirD;
332 int32 nextDirS = _route[p + 1].dirS;
333 int32 nextDirD = _route[p + 1].dirD;
334
335 // Check directions into and out of a pair of nodes going in
336 int32 dS = dirS - lastDir;
337 if (dS < 0)
338 dS = dS + NO_DIRECTIONS;
339
340 int32 dD = dirD - lastDir;
341 if (dD < 0)
342 dD = dD + NO_DIRECTIONS;
343
344 // coming out
345 int32 dSS = dirS - nextDirS;
346 if (dSS < 0)
347 dSS = dSS + NO_DIRECTIONS;
348
349 int32 dDD = dirD - nextDirD;
350 if (dDD < 0)
351 dDD = dDD + NO_DIRECTIONS;
352
353 int32 dSD = dirS - nextDirD;
354 if (dSD < 0)
355 dSD = dSD + NO_DIRECTIONS;
356
357 int32 dDS = dirD - nextDirS;
358 if (dDS < 0)
359 dDS = dDS + NO_DIRECTIONS;
360
361 // Determine the amount of turning involved in each possible path
362 dS = turntable[dS];
363 dD = turntable[dD];
364 dSS = turntable[dSS];
365 dDD = turntable[dDD];
366 dSD = turntable[dSD];
367 dDS = turntable[dDS];
368
369 // get the best path out ie assume next section uses best direction
370 if (dSD < dSS)
371 dSS = dSD;
372 if (dDS < dDD)
373 dDD = dDS;
374
375 // Rate each option. Split routes look crap so weight against them
376 tempturns[0] = dS + dSS + 3;
377 turns[0] = 0;
378 tempturns[1] = dS + dDD;
379 turns[1] = 1;
380 tempturns[2] = dD + dSS;
381 turns[2] = 2;
382 tempturns[3] = dD + dDD + 3;
383 turns[3] = 3;
384
385 // set up turns as a sorted array of the turn values
386 for (i = 0; i < 3; i++) {
387 for (int j = 0; j < 3; j++) {
388 if (tempturns[j] > tempturns[j + 1]) {
389 SWAP(turns[j], turns[j + 1]);
390 SWAP(tempturns[j], tempturns[j + 1]);
391 }
392 }
393 }
394
395 // best option matched in order of the priority we would like
396 // to see on the screen but each option must be checked to see
397 // if it can be walked
398
399 int32 options = newCheck(1, _route[p].x, _route[p].y, _route[p + 1].x, _route[p + 1].y);
400
401 assert(options);
402
403 for (i = 0; i < 4; ++i) {
404 int32 opt = 1 << turns[i];
405 if (options & opt) {
406 smoothCheck(steps, turns[i], p, dirS, dirD);
407 break;
408 }
409 }
410
411 assert(i < 4);
412
413 // route.X route.Y route.dir and bestTurns start at far end
414 }
415
416 // best turns will end heading as near as possible to target dir rest
417 // is down to anim for now
418
419 _smoothPath[steps].dir = 9;
420 _smoothPath[steps].num = ROUTE_END_FLAG;
421 return 1;
422 }
423
smoothCheck(int32 & k,int32 best,int32 p,int32 dirS,int32 dirD)424 void Router::smoothCheck(int32 &k, int32 best, int32 p, int32 dirS, int32 dirD) {
425 /*********************************************************************
426 * Slip sliding away
427 * This path checker checks to see if a walk that exactly follows the
428 * path would be valid. This should be inherently true for atleast one
429 * of the turn options.
430 * No longer checks the data it only creates the smoothPath array JPS
431 *********************************************************************/
432
433 int32 dsx, dsy;
434 int32 ddx, ddy;
435 int32 ss0, ss1, ss2;
436 int32 sd0, sd1, sd2;
437
438 if (p == 0)
439 k = 1;
440
441 int32 x = _route[p].x;
442 int32 y = _route[p].y;
443 int32 x2 = _route[p + 1].x;
444 int32 y2 = _route[p + 1].y;
445 int32 ldx = x2 - x;
446 int32 ldy = y2 - y;
447 int32 dirX = 1;
448 int32 dirY = 1;
449
450 if (ldx < 0) {
451 ldx = -ldx;
452 dirX = -1;
453 }
454
455 if (ldy < 0) {
456 ldy = -ldy;
457 dirY = -1;
458 }
459
460 // set up sd0-ss2 to reflect possible movement in each direction
461
462 if (dirS == 0 || dirS == 4) { // vert and diag
463 ddx = ldx;
464 ddy = (ldx * _diagonaly) / _diagonalx;
465 dsy = ldy - ddy;
466 ddx = ddx * dirX;
467 ddy = ddy * dirY;
468 dsy = dsy * dirY;
469 dsx = 0;
470
471 sd0 = (ddx + _modX[dirD] / 2) / _modX[dirD];
472 ss0 = (dsy + _modY[dirS] / 2) / _modY[dirS];
473 sd1 = sd0 / 2;
474 ss1 = ss0 / 2;
475 sd2 = sd0 - sd1;
476 ss2 = ss0 - ss1;
477 } else {
478 ddy = ldy;
479 ddx = (ldy * _diagonalx) / _diagonaly;
480 dsx = ldx - ddx;
481 ddy = ddy * dirY;
482 ddx = ddx * dirX;
483 dsx = dsx * dirX;
484 dsy = 0;
485
486 sd0 = (ddy + _modY[dirD] / 2) / _modY[dirD];
487 ss0 = (dsx + _modX[dirS] / 2) / _modX[dirS];
488 sd1 = sd0 / 2;
489 ss1 = ss0 / 2;
490 sd2 = sd0 - sd1;
491 ss2 = ss0 - ss1;
492 }
493
494 switch (best) {
495 case 0: // halfsquare, diagonal, halfsquare
496 _smoothPath[k].x = x + dsx / 2;
497 _smoothPath[k].y = y + dsy / 2;
498 _smoothPath[k].dir = dirS;
499 _smoothPath[k].num = ss1;
500 k++;
501
502 _smoothPath[k].x = x + dsx / 2 + ddx;
503 _smoothPath[k].y = y + dsy / 2 + ddy;
504 _smoothPath[k].dir = dirD;
505 _smoothPath[k].num = sd0;
506 k++;
507
508 _smoothPath[k].x = x + dsx + ddx;
509 _smoothPath[k].y = y + dsy + ddy;
510 _smoothPath[k].dir = dirS;
511 _smoothPath[k].num = ss2;
512 k++;
513
514 break;
515 case 1: // square, diagonal
516 _smoothPath[k].x = x + dsx;
517 _smoothPath[k].y = y + dsy;
518 _smoothPath[k].dir = dirS;
519 _smoothPath[k].num = ss0;
520 k++;
521
522 _smoothPath[k].x = x2;
523 _smoothPath[k].y = y2;
524 _smoothPath[k].dir = dirD;
525 _smoothPath[k].num = sd0;
526 k++;
527
528 break;
529 case 2: // diagonal square
530 _smoothPath[k].x = x + ddx;
531 _smoothPath[k].y = y + ddy;
532 _smoothPath[k].dir = dirD;
533 _smoothPath[k].num = sd0;
534 k++;
535
536 _smoothPath[k].x = x2;
537 _smoothPath[k].y = y2;
538 _smoothPath[k].dir = dirS;
539 _smoothPath[k].num = ss0;
540 k++;
541
542 break;
543 default: // halfdiagonal, square, halfdiagonal
544 _smoothPath[k].x = x + ddx / 2;
545 _smoothPath[k].y = y + ddy / 2;
546 _smoothPath[k].dir = dirD;
547 _smoothPath[k].num = sd1;
548 k++;
549
550 _smoothPath[k].x = x + dsx + ddx / 2;
551 _smoothPath[k].y = y + dsy + ddy / 2;
552 _smoothPath[k].dir = dirS;
553 _smoothPath[k].num = ss0;
554 k++;
555
556 _smoothPath[k].x = x2;
557 _smoothPath[k].y = y2;
558 _smoothPath[k].dir = dirD;
559 _smoothPath[k].num = sd2;
560 k++;
561
562 break;
563 }
564 }
565
slidyPath()566 void Router::slidyPath() {
567 /*********************************************************************
568 * slidyPath creates a path based on part steps with no sliding to get
569 * as near as possible to the target without any sliding this routine
570 * is intended for use when just clicking about.
571 *
572 * produce a module list from the line data
573 *********************************************************************/
574
575 int32 smooth = 1;
576 int32 slidy = 1;
577
578 // strip out the short sections
579
580 _modularPath[0].x = _smoothPath[0].x;
581 _modularPath[0].y = _smoothPath[0].y;
582 _modularPath[0].dir = _smoothPath[0].dir;
583 _modularPath[0].num = 0;
584
585 while (_smoothPath[smooth].num < ROUTE_END_FLAG) {
586 int32 scale = _scaleA * _smoothPath[smooth].y + _scaleB;
587 int32 deltaX = _smoothPath[smooth].x - _modularPath[slidy - 1].x;
588 int32 deltaY = _smoothPath[smooth].y - _modularPath[slidy - 1].y;
589 // quarter a step minimum
590 int32 stepX = (scale * _modX[_smoothPath[smooth].dir]) >> 19;
591 int32 stepY = (scale * _modY[_smoothPath[smooth].dir]) >> 19;
592
593 if (ABS(deltaX) >= ABS(stepX) && ABS(deltaY) >= ABS(stepY)) {
594 _modularPath[slidy].x = _smoothPath[smooth].x;
595 _modularPath[slidy].y = _smoothPath[smooth].y;
596 _modularPath[slidy].dir = _smoothPath[smooth].dir;
597 _modularPath[slidy].num = 1;
598 slidy++;
599 }
600 smooth++;
601 }
602
603 // in case the last bit had no steps
604
605 if (slidy > 1) {
606 _modularPath[slidy - 1].x = _smoothPath[smooth - 1].x;
607 _modularPath[slidy - 1].y = _smoothPath[smooth - 1].y;
608 }
609
610 // set up the end of the walk
611
612 _modularPath[slidy].x = _smoothPath[smooth - 1].x;
613 _modularPath[slidy].y = _smoothPath[smooth - 1].y;
614 _modularPath[slidy].dir = _targetDir;
615 _modularPath[slidy].num = 0;
616 slidy++;
617
618 _modularPath[slidy].x = _smoothPath[smooth - 1].x;
619 _modularPath[slidy].y = _smoothPath[smooth - 1].y;
620 _modularPath[slidy].dir = 9;
621 _modularPath[slidy].num = ROUTE_END_FLAG;
622 }
623
slidyWalkAnimator(WalkData * walkAnim)624 void Router::slidyWalkAnimator(WalkData *walkAnim) {
625 /*********************************************************************
626 * Skidding every where HardWalk creates an animation that exactly
627 * fits the smoothPath and uses foot slipping to fit whole steps into
628 * the route
629 *
630 * Parameters: georgeg, mouseg
631 * Returns: rout
632 *
633 * produce a module list from the line data
634 *********************************************************************/
635
636 int32 p;
637 int32 lastDir;
638 int32 lastRealDir;
639 int32 currentDir;
640 int32 turnDir;
641 int32 scale;
642 int32 step;
643 int32 module;
644 int32 moduleEnd;
645 int32 moduleX;
646 int32 moduleY;
647 int32 module16X = 0;
648 int32 module16Y = 0;
649 int32 stepX;
650 int32 stepY;
651 int32 errorX;
652 int32 errorY;
653 int32 lastErrorX;
654 int32 lastErrorY;
655 int32 lastCount;
656 int32 stepCount;
657 int32 frameCount;
658 int32 frames;
659 int32 frame;
660
661 // start at the begining for a change
662 p = 0;
663 lastDir = _modularPath[0].dir;
664 currentDir = _modularPath[1].dir;
665
666 if (currentDir == NO_DIRECTIONS)
667 currentDir = lastDir;
668
669 moduleX = _startX;
670 moduleY = _startY;
671 module16X = moduleX << 16;
672 module16Y = moduleY << 16;
673 stepCount = 0;
674
675 //****************************************************************************
676 // SLIDY
677 // START THE WALK WITH THE FIRST STANDFRAME THIS MAY CAUSE A DELAY
678 // BUT IT STOPS THE PLAYER MOVING FOR COLLISIONS ARE DETECTED
679 //****************************************************************************
680 module = _framesPerChar + lastDir;
681 walkAnim[stepCount].frame = module;
682 walkAnim[stepCount].step = 0;
683 walkAnim[stepCount].dir = lastDir;
684 walkAnim[stepCount].x = moduleX;
685 walkAnim[stepCount].y = moduleY;
686 stepCount += 1;
687
688 //****************************************************************************
689 // SLIDY
690 // TURN TO START THE WALK
691 //****************************************************************************
692 // rotate if we need to
693 if (lastDir != currentDir) {
694 // get the direction to turn
695 turnDir = currentDir - lastDir;
696 if (turnDir < 0)
697 turnDir += NO_DIRECTIONS;
698
699 if (turnDir > 4)
700 turnDir = -1;
701 else if (turnDir > 0)
702 turnDir = 1;
703
704 // rotate to new walk direction
705 // for george and nico put in a head turn at the start
706 if ((megaId == GEORGE) || (megaId == NICO)) {
707 if (turnDir < 0) { // new frames for turn frames 29oct95jps
708 module = turnFramesLeft + lastDir;
709 } else {
710 module = turnFramesRight + lastDir;
711 }
712 walkAnim[stepCount].frame = module;
713 walkAnim[stepCount].step = 0;
714 walkAnim[stepCount].dir = lastDir;
715 walkAnim[stepCount].x = moduleX;
716 walkAnim[stepCount].y = moduleY;
717 stepCount += 1;
718 }
719
720 // rotate till were facing new dir then go back 45 degrees
721 while (lastDir != currentDir) {
722 lastDir += turnDir;
723 if (turnDir < 0) { // new frames for turn frames 29oct95jps
724 if (lastDir < 0)
725 lastDir += NO_DIRECTIONS;
726 module = turnFramesLeft + lastDir;
727 } else {
728 if (lastDir > 7)
729 lastDir -= NO_DIRECTIONS;
730 module = turnFramesRight + lastDir;
731 }
732 walkAnim[stepCount].frame = module;
733 walkAnim[stepCount].step = 0;
734 walkAnim[stepCount].dir = lastDir;
735 walkAnim[stepCount].x = moduleX;
736 walkAnim[stepCount].y = moduleY;
737 stepCount += 1;
738 }
739 // the back 45 degrees bit
740 stepCount -= 1;// step back one because new head turn for george takes us past the new dir
741 }
742 // his head is in the right direction
743 lastRealDir = currentDir;
744
745 //****************************************************************************
746 // SLIDY
747 // THE WALK
748 //****************************************************************************
749
750 _slidyWalkAnimatorState = !_slidyWalkAnimatorState;
751
752 lastCount = stepCount;
753 lastDir = 99;// this ensures that we don't put in turn frames for the start
754 currentDir = 99;// this ensures that we don't put in turn frames for the start
755 do {
756 while (_modularPath[p].num == 0) {
757 p = p + 1;
758 if (currentDir != 99)
759 lastRealDir = currentDir;
760 lastDir = currentDir;
761 lastCount = stepCount;
762 }
763 //calculate average amount to lose in each step on the way to the next _node
764 currentDir = _modularPath[p].dir;
765 if (currentDir < NO_DIRECTIONS) {
766 module = currentDir * _framesPerStep * 2 + _slidyWalkAnimatorState * _framesPerStep;
767 _slidyWalkAnimatorState = !_slidyWalkAnimatorState;
768 moduleEnd = module + _framesPerStep;
769 step = 0;
770 scale = (_scaleA * moduleY + _scaleB);
771 do {
772 module16X += _dx[module] * scale;
773 module16Y += _dy[module] * scale;
774 moduleX = module16X >> 16;
775 moduleY = module16Y >> 16;
776 walkAnim[stepCount].frame = module;
777 walkAnim[stepCount].step = step;
778 walkAnim[stepCount].dir = currentDir;
779 walkAnim[stepCount].x = moduleX;
780 walkAnim[stepCount].y = moduleY;
781 stepCount += 1;
782 step += 1;
783 module += 1;
784 } while (module < moduleEnd);
785 stepX = _modX[_modularPath[p].dir];
786 stepY = _modY[_modularPath[p].dir];
787 errorX = _modularPath[p].x - moduleX;
788 errorX = errorX * stepX;
789 errorY = _modularPath[p].y - moduleY;
790 errorY = errorY * stepY;
791 if ((errorX < 0) || (errorY < 0)) {
792 _modularPath[p].num = 0; // the end of the path
793 // okay those last steps took us past our target but do we want to scoot or moonwalk
794 frames = stepCount - lastCount;
795 errorX = _modularPath[p].x - walkAnim[stepCount - 1].x;
796 errorY = _modularPath[p].y - walkAnim[stepCount - 1].y;
797
798 if (frames > _framesPerStep) {
799 lastErrorX = _modularPath[p].x - walkAnim[stepCount - 7].x;
800 lastErrorY = _modularPath[p].y - walkAnim[stepCount - 7].y;
801 if (stepX == 0) {
802 if (3 * ABS(lastErrorY) < ABS(errorY)) { //the last stop was closest
803 stepCount -= _framesPerStep;
804 _slidyWalkAnimatorState = !_slidyWalkAnimatorState;
805 }
806 } else {
807 if (3 * ABS(lastErrorX) < ABS(errorX)) { //the last stop was closest
808 stepCount -= _framesPerStep;
809 _slidyWalkAnimatorState = !_slidyWalkAnimatorState;
810 }
811 }
812 }
813 errorX = _modularPath[p].x - walkAnim[stepCount - 1].x;
814 errorY = _modularPath[p].y - walkAnim[stepCount - 1].y;
815 // okay we've reached the end but we still have an error
816 if (errorX != 0) {
817 frameCount = 0;
818 frames = stepCount - lastCount;
819 do {
820 frameCount += 1;
821 walkAnim[lastCount + frameCount - 1].x += errorX * frameCount / frames;
822 } while (frameCount < frames);
823 }
824 if (errorY != 0) {
825 frameCount = 0;
826 frames = stepCount - lastCount;
827 do {
828 frameCount += 1;
829 walkAnim[lastCount + frameCount - 1].y += errorY * frameCount / frames;
830 } while (frameCount < frames);
831 }
832 // Now is the time to put in the turn frames for the last turn
833 if (frames < _framesPerStep)
834 currentDir = 99;// this ensures that we don't put in turn frames for this walk or the next
835 if (currentDir != 99)
836 lastRealDir = currentDir;
837 // check each turn condition in turn
838 if (((lastDir != 99) && (currentDir != 99)) && (megaId == GEORGE)) { // only for george
839 lastDir = currentDir - lastDir;//1 and -7 going right -1 and 7 going left
840 if (((lastDir == -1) || (lastDir == 7)) || ((lastDir == -2) || (lastDir == 6))) {
841 // turn at the end of the last walk
842 frame = lastCount - _framesPerStep;
843 do {
844 walkAnim[frame].frame += 104;//turning left
845 frame += 1;
846 } while (frame < lastCount);
847 }
848 if (((lastDir == 1) || (lastDir == -7)) || ((lastDir == 2) || (lastDir == -6))) {
849 // turn at the end of the current walk
850 frame = lastCount - _framesPerStep;
851 do {
852 walkAnim[frame].frame += 200; //was 60 now 116
853 frame += 1;
854 } while (frame < lastCount);
855 }
856 lastDir = currentDir;
857 }
858 // all turns checked
859
860 lastCount = stepCount;
861 moduleX = walkAnim[stepCount - 1].x;
862 moduleY = walkAnim[stepCount - 1].y;
863 module16X = moduleX << 16;
864 module16Y = moduleY << 16;
865 }
866 }
867 } while (_modularPath[p].dir < NO_DIRECTIONS);
868
869
870
871 if (lastRealDir == 99) {
872 error("SlidyWalkAnimatorlast direction error");
873 }
874 //****************************************************************************
875 // SLIDY
876 // TURNS TO END THE WALK ?
877 //****************************************************************************
878
879 // We've done the walk now put in any turns at the end
880
881
882 if (_targetDir == NO_DIRECTIONS) { // stand in the last direction
883 module = standFrames + lastRealDir;
884 _targetDir = lastRealDir;
885 walkAnim[stepCount].frame = module;
886 walkAnim[stepCount].step = 0;
887 walkAnim[stepCount].dir = lastRealDir;
888 walkAnim[stepCount].x = moduleX;
889 walkAnim[stepCount].y = moduleY;
890 stepCount += 1;
891 }
892 if (_targetDir == 9) {
893 if (stepCount == 0) {
894 module = _framesPerChar + lastRealDir;
895 walkAnim[stepCount].frame = module;
896 walkAnim[stepCount].step = 0;
897 walkAnim[stepCount].dir = lastRealDir;
898 walkAnim[stepCount].x = moduleX;
899 walkAnim[stepCount].y = moduleY;
900 stepCount += 1;
901 }
902 } else if (_targetDir != lastRealDir) { // rotate to _targetDir
903 // rotate to target direction
904 turnDir = _targetDir - lastRealDir;
905 if (turnDir < 0)
906 turnDir += NO_DIRECTIONS;
907
908 if (turnDir > 4)
909 turnDir = -1;
910 else if (turnDir > 0)
911 turnDir = 1;
912
913 // rotate to target direction
914 // for george and nico put in a head turn at the start
915 if ((megaId == GEORGE) || (megaId == NICO)) {
916 if (turnDir < 0) { // new frames for turn frames 29oct95jps
917 module = turnFramesLeft + lastDir;
918 } else {
919 module = turnFramesRight + lastDir;
920 }
921 walkAnim[stepCount].frame = module;
922 walkAnim[stepCount].step = 0;
923 walkAnim[stepCount].dir = lastRealDir;
924 walkAnim[stepCount].x = moduleX;
925 walkAnim[stepCount].y = moduleY;
926 stepCount += 1;
927 }
928
929 // rotate if we need to
930 while (lastRealDir != _targetDir) {
931 lastRealDir += turnDir;
932 if (turnDir < 0) { // new frames for turn frames 29oct95jps
933 if (lastRealDir < 0)
934 lastRealDir += NO_DIRECTIONS;
935 module = turnFramesLeft + lastRealDir;
936 } else {
937 if (lastRealDir > 7)
938 lastRealDir -= NO_DIRECTIONS;
939 module = turnFramesRight + lastRealDir;
940 }
941 walkAnim[stepCount].frame = module;
942 walkAnim[stepCount].step = 0;
943 walkAnim[stepCount].dir = lastRealDir;
944 walkAnim[stepCount].x = moduleX;
945 walkAnim[stepCount].y = moduleY;
946 stepCount += 1;
947 }
948 module = standFrames + lastRealDir;
949 walkAnim[stepCount - 1].frame = module;
950 } else { // just stand at the end
951 module = standFrames + lastRealDir;
952 walkAnim[stepCount].frame = module;
953 walkAnim[stepCount].step = 0;
954 walkAnim[stepCount].dir = lastRealDir;
955 walkAnim[stepCount].x = moduleX;
956 walkAnim[stepCount].y = moduleY;
957 stepCount += 1;
958 }
959
960 walkAnim[stepCount].frame = 512;
961 stepCount += 1;
962 walkAnim[stepCount].frame = 512;
963 stepCount += 1;
964 walkAnim[stepCount].frame = 512;
965 //Tdebug("RouteFinder RouteSize is %d", stepCount);
966 return;
967 }
968
969 // ****************************************************************************
970 // * THE SOLID PATH ROUTINES
971 // ****************************************************************************
972
solidPath()973 void Router::solidPath() {
974 /*********************************************************************
975 * SolidPath creates a path based on whole steps with no sliding to
976 * get as near as possible to the target without any sliding this
977 * routine is currently unused, but is intended for use when just
978 * clicking about.
979 *
980 * produce a module list from the line data
981 *********************************************************************/
982
983 int32 smooth;
984 int32 solid;
985 int32 scale;
986 int32 stepX;
987 int32 stepY;
988 int32 deltaX;
989 int32 deltaY;
990
991 // strip out the short sections
992
993 solid = 1;
994 smooth = 1;
995 _modularPath[0].x = _smoothPath[0].x;
996 _modularPath[0].y = _smoothPath[0].y;
997 _modularPath[0].dir = _smoothPath[0].dir;
998 _modularPath[0].num = 0;
999
1000 do {
1001 scale = _scaleA * _smoothPath[smooth].y + _scaleB;
1002 deltaX = _smoothPath[smooth].x - _modularPath[solid - 1].x;
1003 deltaY = _smoothPath[smooth].y - _modularPath[solid - 1].y;
1004 stepX = _modX[_smoothPath[smooth].dir];
1005 stepY = _modY[_smoothPath[smooth].dir];
1006 stepX = stepX * scale;
1007 stepY = stepY * scale;
1008 stepX = stepX >> 16;
1009 stepY = stepY >> 16;
1010
1011 if (ABS(deltaX) >= ABS(stepX) && ABS(deltaY) >= ABS(stepY)) {
1012 _modularPath[solid].x = _smoothPath[smooth].x;
1013 _modularPath[solid].y = _smoothPath[smooth].y;
1014 _modularPath[solid].dir = _smoothPath[smooth].dir;
1015 _modularPath[solid].num = 1;
1016 solid++;
1017 }
1018
1019 smooth++;
1020 } while (_smoothPath[smooth].num < ROUTE_END_FLAG);
1021
1022 // in case the last bit had no steps
1023
1024 if (solid == 1) {
1025 // there were no paths so put in a dummy end
1026 solid = 2;
1027 _modularPath[1].dir = _smoothPath[0].dir;
1028 _modularPath[1].num = 0;
1029 }
1030
1031 _modularPath[solid - 1].x = _smoothPath[smooth - 1].x;
1032 _modularPath[solid - 1].y = _smoothPath[smooth - 1].y;
1033
1034 // set up the end of the walk
1035 _modularPath[solid].x = _smoothPath[smooth - 1].x;
1036 _modularPath[solid].y = _smoothPath[smooth - 1].y;
1037 _modularPath[solid].dir = 9;
1038 _modularPath[solid].num = ROUTE_END_FLAG;
1039 }
1040
solidWalkAnimator(WalkData * walkAnim)1041 int32 Router::solidWalkAnimator(WalkData *walkAnim) {
1042 /*********************************************************************
1043 * SolidWalk creates an animation based on whole steps with no sliding
1044 * to get as near as possible to the target without any sliding. This
1045 * routine is is intended for use when just clicking about.
1046 *
1047 * produce a module list from the line data
1048 *
1049 * returns 0 if solid route not found
1050 *********************************************************************/
1051
1052 int32 left;
1053 int32 lastDir;
1054 int32 currentDir;
1055 int32 turnDir;
1056 int32 scale;
1057 int32 step;
1058 int32 module;
1059 int32 moduleX;
1060 int32 moduleY;
1061 int32 module16X;
1062 int32 module16Y;
1063 int32 errorX;
1064 int32 errorY;
1065 int32 moduleEnd;
1066 int32 slowStart;
1067 int32 stepCount;
1068 int32 lastCount;
1069 int32 frame;
1070
1071 // start at the begining for a change
1072 lastDir = _modularPath[0].dir;
1073 currentDir = _modularPath[1].dir;
1074 module = _framesPerChar + lastDir;
1075 moduleX = _startX;
1076 moduleY = _startY;
1077 module16X = moduleX << 16;
1078 module16Y = moduleY << 16;
1079 slowStart = 0;
1080 stepCount = 0;
1081
1082 //****************************************************************************
1083 // SOLID
1084 // START THE WALK WITH THE FIRST STANDFRAME THIS MAY CAUSE A DELAY
1085 // BUT IT STOPS THE PLAYER MOVING FOR COLLISIONS ARE DETECTED
1086 //****************************************************************************
1087 walkAnim[stepCount].frame = module;
1088 walkAnim[stepCount].step = 0;
1089 walkAnim[stepCount].dir = lastDir;
1090 walkAnim[stepCount].x = moduleX;
1091 walkAnim[stepCount].y = moduleY;
1092 stepCount += 1;
1093
1094 //****************************************************************************
1095 // SOLID
1096 // TURN TO START THE WALK
1097 //****************************************************************************
1098 // rotate if we need to
1099 if (lastDir != currentDir) {
1100 // get the direction to turn
1101 turnDir = currentDir - lastDir;
1102 if (turnDir < 0)
1103 turnDir += NO_DIRECTIONS;
1104
1105 if (turnDir > 4)
1106 turnDir = -1;
1107 else if (turnDir > 0)
1108 turnDir = 1;
1109
1110 // rotate to new walk direction
1111 // for george and nico put in a head turn at the start
1112 if ((megaId == GEORGE) || (megaId == NICO)) {
1113 if (turnDir < 0) { // new frames for turn frames 29oct95jps
1114 module = turnFramesLeft + lastDir;
1115 } else {
1116 module = turnFramesRight + lastDir;
1117 }
1118 walkAnim[stepCount].frame = module;
1119 walkAnim[stepCount].step = 0;
1120 walkAnim[stepCount].dir = lastDir;
1121 walkAnim[stepCount].x = moduleX;
1122 walkAnim[stepCount].y = moduleY;
1123 stepCount += 1;
1124 }
1125
1126 // rotate till were facing new dir then go back 45 degrees
1127 while (lastDir != currentDir) {
1128 lastDir += turnDir;
1129 if (turnDir < 0) { // new frames for turn frames 29oct95jps
1130 if (lastDir < 0)
1131 lastDir += NO_DIRECTIONS;
1132 module = turnFramesLeft + lastDir;
1133 } else {
1134 if (lastDir > 7)
1135 lastDir -= NO_DIRECTIONS;
1136 module = turnFramesRight + lastDir;
1137 }
1138 walkAnim[stepCount].frame = module;
1139 walkAnim[stepCount].step = 0;
1140 walkAnim[stepCount].dir = lastDir;
1141 walkAnim[stepCount].x = moduleX;
1142 walkAnim[stepCount].y = moduleY;
1143 stepCount += 1;
1144 }
1145 // the back 45 degrees bit
1146 stepCount -= 1;// step back one because new head turn for george takes us past the new dir
1147 }
1148
1149 //****************************************************************************
1150 // SOLID
1151 // THE SLOW IN
1152 //****************************************************************************
1153
1154 // do start frames if its george and left or right
1155 if (megaId == GEORGE) {
1156 if (_modularPath[1].num > 0) {
1157 if (currentDir == 2) { // only for george
1158 slowStart = 1;
1159 walkAnim[stepCount].frame = 296;
1160 walkAnim[stepCount].step = 0;
1161 walkAnim[stepCount].dir = currentDir;
1162 walkAnim[stepCount].x = moduleX;
1163 walkAnim[stepCount].y = moduleY;
1164 stepCount += 1;
1165 walkAnim[stepCount].frame = 297;
1166 walkAnim[stepCount].step = 0;
1167 walkAnim[stepCount].dir = currentDir;
1168 walkAnim[stepCount].x = moduleX;
1169 walkAnim[stepCount].y = moduleY;
1170 stepCount += 1;
1171 walkAnim[stepCount].frame = 298;
1172 walkAnim[stepCount].step = 0;
1173 walkAnim[stepCount].dir = currentDir;
1174 walkAnim[stepCount].x = moduleX;
1175 walkAnim[stepCount].y = moduleY;
1176 stepCount += 1;
1177 } else if (currentDir == 6) { // only for george
1178 slowStart = 1;
1179 walkAnim[stepCount].frame = 299;
1180 walkAnim[stepCount].step = 0;
1181 walkAnim[stepCount].dir = currentDir;
1182 walkAnim[stepCount].x = moduleX;
1183 walkAnim[stepCount].y = moduleY;
1184 stepCount += 1;
1185 walkAnim[stepCount].frame = 300;
1186 walkAnim[stepCount].step = 0;
1187 walkAnim[stepCount].dir = currentDir;
1188 walkAnim[stepCount].x = moduleX;
1189 walkAnim[stepCount].y = moduleY;
1190 stepCount += 1;
1191 walkAnim[stepCount].frame = 301;
1192 walkAnim[stepCount].step = 0;
1193 walkAnim[stepCount].dir = currentDir;
1194 walkAnim[stepCount].x = moduleX;
1195 walkAnim[stepCount].y = moduleY;
1196 stepCount += 1;
1197 }
1198 }
1199 }
1200 //****************************************************************************
1201 // SOLID
1202 // THE WALK
1203 //****************************************************************************
1204
1205 if (currentDir > 4)
1206 left = 1;
1207 else
1208 left = 0;
1209
1210 lastCount = stepCount;
1211 lastDir = 99;// this ensures that we don't put in turn frames for the start
1212 currentDir = 99;// this ensures that we don't put in turn frames for the start
1213
1214 int32 p;
1215
1216 for (p = 1; _modularPath[p].dir < NO_DIRECTIONS; ++p) {
1217 while (_modularPath[p].num > 0) {
1218 currentDir = _modularPath[p].dir;
1219 if (currentDir < NO_DIRECTIONS) {
1220
1221 module = currentDir * _framesPerStep * 2 + left * _framesPerStep;
1222 left = !left;
1223 moduleEnd = module + _framesPerStep;
1224 step = 0;
1225 scale = (_scaleA * moduleY + _scaleB);
1226 do {
1227 module16X += _dx[module] * scale;
1228 module16Y += _dy[module] * scale;
1229 moduleX = module16X >> 16;
1230 moduleY = module16Y >> 16;
1231 walkAnim[stepCount].frame = module;
1232 walkAnim[stepCount].step = step;
1233 walkAnim[stepCount].dir = currentDir;
1234 walkAnim[stepCount].x = moduleX;
1235 walkAnim[stepCount].y = moduleY;
1236 stepCount += 1;
1237 module += 1;
1238 step += 1;
1239 } while (module < moduleEnd);
1240 errorX = _modularPath[p].x - moduleX;
1241 errorX = errorX * _modX[_modularPath[p].dir];
1242 errorY = _modularPath[p].y - moduleY;
1243 errorY = errorY * _modY[_modularPath[p].dir];
1244 if ((errorX < 0) || (errorY < 0)) {
1245 _modularPath[p].num = 0;
1246 stepCount -= _framesPerStep;
1247 left = !left;
1248 // Okay this is the end of a section
1249 moduleX = walkAnim[stepCount - 1].x;
1250 moduleY = walkAnim[stepCount - 1].y;
1251 module16X = moduleX << 16;
1252 module16Y = moduleY << 16;
1253 _modularPath[p].x = moduleX;
1254 _modularPath[p].y = moduleY;
1255 // Now is the time to put in the turn frames for the last turn
1256 if ((stepCount - lastCount) < _framesPerStep) { // no step taken
1257 currentDir = 99;// this ensures that we don't put in turn frames for this walk or the next
1258 if (slowStart == 1) { // clean up if a slow in but no walk
1259 stepCount -= 3;
1260 lastCount -= 3;
1261 slowStart = 0;
1262 }
1263 }
1264 // check each turn condition in turn
1265 if (((lastDir != 99) && (currentDir != 99)) && (megaId == GEORGE)) { // only for george
1266 lastDir = currentDir - lastDir;//1 and -7 going right -1 and 7 going left
1267 if (((lastDir == -1) || (lastDir == 7)) || ((lastDir == -2) || (lastDir == 6))) {
1268 // turn at the end of the last walk
1269 frame = lastCount - _framesPerStep;
1270 do {
1271 walkAnim[frame].frame += 104;//turning left
1272 frame += 1;
1273 } while (frame < lastCount);
1274 }
1275 if (((lastDir == 1) || (lastDir == -7)) || ((lastDir == 2) || (lastDir == -6))) {
1276 // turn at the end of the current walk
1277 frame = lastCount - _framesPerStep;
1278 do {
1279 walkAnim[frame].frame += 200; //was 60 now 116
1280 frame += 1;
1281 } while (frame < lastCount);
1282 }
1283 }
1284 // all turns checked
1285 lastCount = stepCount;
1286 }
1287 }
1288 }
1289 lastDir = currentDir;
1290 slowStart = 0; //can only be valid first time round
1291 }
1292
1293 //****************************************************************************
1294 // SOLID
1295 // THE SLOW OUT
1296 //****************************************************************************
1297
1298 if ((currentDir == 2) && (megaId == GEORGE)) { // only for george
1299 // place stop frames here
1300 // slowdown at the end of the last walk
1301 frame = lastCount - _framesPerStep;
1302 if (walkAnim[frame].frame == 24) {
1303 do {
1304 walkAnim[frame].frame += 278;//stopping right
1305 frame += 1;
1306 } while (frame < lastCount);
1307 walkAnim[stepCount].frame = 308;
1308 walkAnim[stepCount].step = 7;
1309 walkAnim[stepCount].dir = currentDir;
1310 walkAnim[stepCount].x = moduleX;
1311 walkAnim[stepCount].y = moduleY;
1312 stepCount += 1;
1313 } else if (walkAnim[frame].frame == 30) {
1314 do {
1315 walkAnim[frame].frame += 279;//stopping right
1316 frame += 1;
1317 } while (frame < lastCount);
1318 walkAnim[stepCount].frame = 315;
1319 walkAnim[stepCount].step = 7;
1320 walkAnim[stepCount].dir = currentDir;
1321 walkAnim[stepCount].x = moduleX;
1322 walkAnim[stepCount].y = moduleY;
1323 stepCount += 1;
1324 }
1325 } else if ((currentDir == 6) && (megaId == GEORGE)) { // only for george
1326 // place stop frames here
1327 // slowdown at the end of the last walk
1328 frame = lastCount - _framesPerStep;
1329 if (walkAnim[frame].frame == 72) {
1330 do {
1331 walkAnim[frame].frame += 244;//stopping left
1332 frame += 1;
1333 } while (frame < lastCount);
1334 walkAnim[stepCount].frame = 322;
1335 walkAnim[stepCount].step = 7;
1336 walkAnim[stepCount].dir = currentDir;
1337 walkAnim[stepCount].x = moduleX;
1338 walkAnim[stepCount].y = moduleY;
1339 stepCount += 1;
1340 } else if (walkAnim[frame].frame == 78) {
1341 do {
1342 walkAnim[frame].frame += 245;//stopping left
1343 frame += 1;
1344 } while (frame < lastCount);
1345 walkAnim[stepCount].frame = 329;
1346 walkAnim[stepCount].step = 7;
1347 walkAnim[stepCount].dir = currentDir;
1348 walkAnim[stepCount].x = moduleX;
1349 walkAnim[stepCount].y = moduleY;
1350 stepCount += 1;
1351 }
1352 }
1353 module = _framesPerChar + _modularPath[p - 1].dir;
1354 walkAnim[stepCount].frame = module;
1355 walkAnim[stepCount].step = 0;
1356 walkAnim[stepCount].dir = _modularPath[p - 1].dir;
1357 walkAnim[stepCount].x = moduleX;
1358 walkAnim[stepCount].y = moduleY;
1359 stepCount += 1;
1360
1361 walkAnim[stepCount].frame = 512;
1362 stepCount += 1;
1363 walkAnim[stepCount].frame = 512;
1364 stepCount += 1;
1365 walkAnim[stepCount].frame = 512;
1366
1367 //****************************************************************************
1368 // SOLID
1369 // NO END TURNS
1370 //****************************************************************************
1371
1372 debug(5, "routeFinder RouteSize is %d", stepCount);
1373 // now check the route
1374
1375 for (int i = 0; i < p - 1; ++i) {
1376 if (!check(_modularPath[i].x, _modularPath[i].y, _modularPath[i + 1].x, _modularPath[i + 1].y))
1377 p = 0;
1378 }
1379
1380 if (p != 0) {
1381 _targetDir = _modularPath[p - 1].dir;
1382 if (checkTarget(moduleX, moduleY) == 3) {
1383 // new target on a line
1384 p = 0;
1385 debug(5, "Solid walk target was on a line %d %d", moduleX, moduleY);
1386 }
1387 }
1388
1389 return p;
1390 }
1391
1392 // ****************************************************************************
1393 // * THE SCAN ROUTINES
1394 // ****************************************************************************
1395
scan(int32 level)1396 bool Router::scan(int32 level) {
1397 /*********************************************************************
1398 * Called successively from routeFinder until no more changes take
1399 * place in the grid array, ie he best path has been found
1400 *
1401 * Scans through every point in the node array and checks if there is
1402 * a route between each point and if this route gives a new route.
1403 *
1404 * This routine could probably halve its processing time if it doubled
1405 * up on the checks after each route check
1406 *
1407 *********************************************************************/
1408
1409 int32 x1, y1, x2, y2;
1410 int32 distance;
1411 bool changed = false;
1412
1413 // For all the nodes that have new values and a distance less than
1414 // enddist, ie dont check for new routes from a point we checked
1415 // before or from a point that is already further away than the best
1416 // route so far.
1417
1418 for (int i = 0; i < _nNodes; i++) {
1419 if (_node[i].dist < _node[_nNodes].dist && _node[i].level == level) {
1420 x1 = _node[i].x;
1421 y1 = _node[i].y;
1422
1423 for (int j = _nNodes; j > 0; j--) {
1424 if (_node[j].dist > _node[i].dist) {
1425 x2 = _node[j].x;
1426 y2 = _node[j].y;
1427
1428 if (ABS(x2 - x1) > 4.5 * ABS(y2 - y1))
1429 distance = (8 * ABS(x2 - x1) + 18 * ABS(y2 - y1)) / (54 * 8) + 1;
1430 else
1431 distance = (6 * ABS(x2 - x1) + 36 * ABS(y2 - y1)) / (36 * 14) + 1;
1432
1433 if (distance + _node[i].dist < _node[_nNodes].dist && distance + _node[i].dist < _node[j].dist) {
1434 if (newCheck(0, x1, y1, x2, y2)) {
1435 _node[j].level = level + 1;
1436 _node[j].dist = distance + _node[i].dist;
1437 _node[j].prev = i;
1438 changed = true;
1439 }
1440 }
1441 }
1442 }
1443 }
1444 }
1445
1446 return changed;
1447 }
1448
1449
newCheck(int32 status,int32 x1,int32 y1,int32 x2,int32 y2)1450 int32 Router::newCheck(int32 status, int32 x1, int32 y1, int32 x2, int32 y2) {
1451 /*********************************************************************
1452 * newCheck routine checks if the route between two points can be
1453 * achieved without crossing any of the bars in the Bars array.
1454 *
1455 * newCheck differs from check in that that 4 route options are
1456 * considered corresponding to actual walked routes.
1457 *
1458 * Note distance doesn't take account of shrinking ???
1459 *
1460 * Note Bars array must be properly calculated ie min max dx dy co
1461 *********************************************************************/
1462
1463 int32 ldx;
1464 int32 ldy;
1465 int32 dlx;
1466 int32 dly;
1467 int32 dirX;
1468 int32 dirY;
1469 int32 step1;
1470 int32 step2;
1471 int32 step3;
1472 int32 steps;
1473 int32 options;
1474
1475 steps = 0;
1476 options = 0;
1477 ldx = x2 - x1;
1478 ldy = y2 - y1;
1479 dirX = 1;
1480 dirY = 1;
1481
1482 if (ldx < 0) {
1483 ldx = -ldx;
1484 dirX = -1;
1485 }
1486
1487 if (ldy < 0) {
1488 ldy = -ldy;
1489 dirY = -1;
1490 }
1491
1492 // make the route options
1493
1494 if (_diagonaly * ldx > _diagonalx * ldy) {
1495 // dir = 1,2 or 2,3 or 5,6 or 6,7
1496
1497 dly = ldy;
1498 dlx = (ldy * _diagonalx) / _diagonaly;
1499 ldx = ldx - dlx;
1500 dlx = dlx * dirX;
1501 dly = dly * dirY;
1502 ldx = ldx * dirX;
1503 ldy = 0;
1504
1505 // options are square, diagonal a code 1 route
1506 step1 = check(x1, y1, x1 + ldx, y1);
1507 if (step1 != 0) {
1508 step2 = check(x1 + ldx, y1, x2, y2);
1509 if (step2 != 0) {
1510 steps = step1 + step2;
1511 options |= 2;
1512 }
1513 }
1514
1515 // diagonal, square a code 2 route
1516 if (steps == 0 || status == 1) {
1517 step1 = check(x1, y1, x1 + dlx, y1 + dly);
1518 if (step1 != 0) {
1519 step2 = check(x1 + dlx, y2, x2, y2);
1520 if (step2 != 0) {
1521 steps = step1 + step2;
1522 options |= 4;
1523 }
1524 }
1525 }
1526
1527 // halfsquare, diagonal, halfsquare a code 0 route
1528 if (steps == 0 || status == 1) {
1529 step1 = check(x1, y1, x1 + ldx / 2, y1);
1530 if (step1 != 0) {
1531 step2 = check(x1 + ldx / 2, y1, x1 + ldx / 2 + dlx, y2);
1532 if (step2 != 0) {
1533 step3 = check(x1 + ldx / 2 + dlx, y2, x2, y2);
1534 if (step3 != 0) {
1535 steps = step1 + step2 + step3;
1536 options |= 1;
1537 }
1538 }
1539 }
1540 }
1541
1542 // halfdiagonal, square, halfdiagonal a code 3 route
1543 if (steps == 0 || status == 1) {
1544 step1 = check(x1, y1, x1 + dlx / 2, y1 + dly / 2);
1545 if (step1 != 0) {
1546 step2 = check(x1 + dlx / 2, y1 + dly / 2, x1 + ldx + dlx / 2, y1 + dly / 2);
1547 if (step2 != 0) {
1548 step3 = check(x1 + ldx + dlx / 2, y1 + dly / 2, x2, y2);
1549 if (step3 != 0) {
1550 steps = step1 + step2 + step3;
1551 options |= 8;
1552 }
1553 }
1554 }
1555 }
1556 } else {
1557 // dir = 7,0 or 0,1 or 3,4 or 4,5
1558
1559 dlx = ldx;
1560 dly = (ldx * _diagonaly) / _diagonalx;
1561 ldy = ldy - dly;
1562 dlx = dlx * dirX;
1563 dly = dly * dirY;
1564 ldy = ldy * dirY;
1565 ldx = 0;
1566
1567 // options are square, diagonal a code 1 route
1568 step1 = check(x1 , y1, x1, y1 + ldy);
1569 if (step1 != 0) {
1570 step2 = check(x1, y1 + ldy, x2, y2);
1571 if (step2 != 0) {
1572 steps = step1 + step2;
1573 options |= 2;
1574 }
1575 }
1576
1577 // diagonal, square a code 2 route
1578 if (steps == 0 || status == 1) {
1579 step1 = check(x1, y1, x2, y1 + dly);
1580 if (step1 != 0) {
1581 step2 = check(x2, y1 + dly, x2, y2);
1582 if (step2 != 0) {
1583 steps = step1 + step2;
1584 options |= 4;
1585 }
1586 }
1587 }
1588
1589 // halfsquare, diagonal, halfsquare a code 0 route
1590 if (steps == 0 || status == 1) {
1591 step1 = check(x1, y1, x1, y1 + ldy / 2);
1592 if (step1 != 0) {
1593 step2 = check(x1, y1 + ldy / 2, x2, y1 + ldy / 2 + dly);
1594 if (step2 != 0) {
1595 step3 = check(x2, y1 + ldy / 2 + dly, x2, y2);
1596 if (step3 != 0) {
1597 steps = step1 + step2 + step3;
1598 options |= 1;
1599 }
1600 }
1601 }
1602 }
1603
1604 // halfdiagonal, square, halfdiagonal a code 3 route
1605 if (steps == 0 || status == 1) {
1606 step1 = check(x1, y1, x1 + dlx / 2, y1 + dly / 2);
1607 if (step1 != 0) {
1608 step2 = check(x1 + dlx / 2, y1 + dly / 2, x1 + dlx / 2, y1 + ldy + dly / 2);
1609 if (step2 != 0) {
1610 step3 = check(x1 + dlx / 2, y1 + ldy + dly / 2, x2, y2);
1611 if (step3 != 0) {
1612 steps = step1 + step2 + step3;
1613 options |= 8;
1614 }
1615 }
1616 }
1617 }
1618 }
1619
1620 if (status == 0)
1621 status = steps;
1622 else
1623 status = options;
1624
1625 return status;
1626 }
1627
1628 // ****************************************************************************
1629 // * CHECK ROUTINES
1630 // ****************************************************************************
1631
check(int32 x1,int32 y1,int32 x2,int32 y2)1632 bool Router::check(int32 x1, int32 y1, int32 x2, int32 y2) {
1633 // call the fastest line check for the given line
1634 // returns true if line didn't cross any bars
1635
1636 if (x1 == x2 && y1 == y2)
1637 return true;
1638
1639 if (x1 == x2)
1640 return vertCheck(x1, y1, y2);
1641
1642 if (y1 == y2)
1643 return horizCheck(x1, y1, x2);
1644
1645 return lineCheck(x1, y1, x2, y2);
1646 }
1647
lineCheck(int32 x1,int32 y1,int32 x2,int32 y2)1648 bool Router::lineCheck(int32 x1, int32 y1, int32 x2, int32 y2) {
1649 bool linesCrossed = true;
1650
1651 int32 xmin = MIN(x1, x2);
1652 int32 xmax = MAX(x1, x2);
1653 int32 ymin = MIN(y1, y2);
1654 int32 ymax = MAX(y1, y2);
1655
1656 // Line set to go one step in chosen direction so ignore if it hits
1657 // anything
1658
1659 int32 dirx = x2 - x1;
1660 int32 diry = y2 - y1;
1661
1662 int32 co = (y1 * dirx) - (x1 * diry); // new line equation
1663
1664 for (int i = 0; i < _nBars && linesCrossed; i++) {
1665 // skip if not on module
1666 if (xmax >= _bars[i].xmin && xmin <= _bars[i].xmax && ymax >= _bars[i].ymin && ymin <= _bars[i].ymax) {
1667 // Okay, it's a valid line. Calculate an intercept. Wow
1668 // but all this arithmetic we must have loads of time
1669
1670 // slope it he slope between the two lines
1671 int32 slope = (_bars[i].dx * diry) - (_bars[i].dy * dirx);
1672 // assuming parallel lines don't cross
1673 if (slope != 0) {
1674 // calculate x intercept and check its on both
1675 // lines
1676 int32 xc = ((_bars[i].co * dirx) - (co * _bars[i].dx)) / slope;
1677
1678 // skip if not on module
1679 if (xc >= xmin - 1 && xc <= xmax + 1) {
1680 // skip if not on line
1681 if (xc >= _bars[i].xmin - 1 && xc <= _bars[i].xmax + 1) {
1682 int32 yc = ((_bars[i].co * diry) - (co * _bars[i].dy)) / slope;
1683
1684 // skip if not on module
1685 if (yc >= ymin - 1 && yc <= ymax + 1) {
1686 // skip if not on line
1687 if (yc >= _bars[i].ymin - 1 && yc <= _bars[i].ymax + 1) {
1688 linesCrossed = false;
1689 }
1690 }
1691 }
1692 }
1693 }
1694 }
1695 }
1696
1697 return linesCrossed;
1698 }
1699
horizCheck(int32 x1,int32 y,int32 x2)1700 bool Router::horizCheck(int32 x1, int32 y, int32 x2) {
1701 bool linesCrossed = true;
1702
1703 int32 xmin = MIN(x1, x2);
1704 int32 xmax = MAX(x1, x2);
1705
1706 // line set to go one step in chosen direction so ignore if it hits
1707 // anything
1708
1709 for (int i = 0; i < _nBars && linesCrossed; i++) {
1710 // skip if not on module
1711 if (xmax >= _bars[i].xmin && xmin <= _bars[i].xmax && y >= _bars[i].ymin && y <= _bars[i].ymax) {
1712 // Okay, it's a valid line calculate an intercept. Wow
1713 // but all this arithmetic we must have loads of time
1714
1715 if (_bars[i].dy == 0)
1716 linesCrossed = false;
1717 else {
1718 int32 ldy = y - _bars[i].y1;
1719 int32 xc = _bars[i].x1 + (_bars[i].dx * ldy) / _bars[i].dy;
1720 // skip if not on module
1721 if (xc >= xmin - 1 && xc <= xmax + 1)
1722 linesCrossed = false;
1723 }
1724 }
1725 }
1726
1727 return linesCrossed;
1728 }
1729
vertCheck(int32 x,int32 y1,int32 y2)1730 bool Router::vertCheck(int32 x, int32 y1, int32 y2) {
1731 bool linesCrossed = true;
1732
1733 int32 ymin = MIN(y1, y2);
1734 int32 ymax = MAX(y1, y2);
1735
1736 // Line set to go one step in chosen direction so ignore if it hits
1737 // anything
1738
1739 for (int i = 0; i < _nBars && linesCrossed; i++) {
1740 // skip if not on module
1741 if (x >= _bars[i].xmin && x <= _bars[i].xmax && ymax >= _bars[i].ymin && ymin <= _bars[i].ymax) {
1742 // Okay, it's a valid line calculate an intercept. Wow
1743 // but all this arithmetic we must have loads of time
1744
1745 // both lines vertical and overlap in x and y so they
1746 // cross
1747
1748 if (_bars[i].dx == 0)
1749 linesCrossed = false;
1750 else {
1751 int32 ldx = x - _bars[i].x1;
1752 int32 yc = _bars[i].y1 + (_bars[i].dy * ldx) / _bars[i].dx;
1753 // the intercept overlaps
1754 if (yc >= ymin - 1 && yc <= ymax + 1)
1755 linesCrossed = false;
1756 }
1757 }
1758 }
1759
1760 return linesCrossed;
1761 }
1762
checkTarget(int32 x,int32 y)1763 int32 Router::checkTarget(int32 x, int32 y) {
1764 int32 onLine = 0;
1765
1766 int32 xmin = x - 1;
1767 int32 xmax = x + 1;
1768 int32 ymin = y - 1;
1769 int32 ymax = y + 1;
1770
1771 // check if point +- 1 is on the line
1772 // so ignore if it hits anything
1773
1774 for (int i = 0; i < _nBars && onLine == 0; i++) {
1775 // overlapping line
1776 if (xmax >= _bars[i].xmin && xmin <= _bars[i].xmax && ymax >= _bars[i].ymin && ymin <= _bars[i].ymax) {
1777 int32 xc, yc;
1778
1779 // okay this line overlaps the target calculate an y intercept for x
1780
1781 // vertical line so we know it overlaps y
1782 if (_bars[i].dx == 0)
1783 yc = 0;
1784 else {
1785 int ldx = x - _bars[i].x1;
1786 yc = _bars[i].y1 + (_bars[i].dy * ldx) / _bars[i].dx;
1787 }
1788
1789 // overlapping point for y
1790 if (yc >= ymin && yc <= ymax) {
1791 // target on a line so drop out
1792 onLine = 3;
1793 debug(5, "RouteFail due to target on a line %d %d", x, y);
1794 } else {
1795 // vertical line so we know it overlaps y
1796 if (_bars[i].dy == 0)
1797 xc = 0;
1798 else {
1799 int32 ldy = y - _bars[i].y1;
1800 xc = _bars[i].x1 + (_bars[i].dx * ldy) / _bars[i].dy;
1801 }
1802
1803 // skip if not on module
1804 if (xc >= xmin && xc <= xmax) {
1805 // target on a line so drop out
1806 onLine = 3;
1807 debug(5, "RouteFail due to target on a line %d %d", x, y);
1808 }
1809 }
1810 }
1811 }
1812
1813 return onLine;
1814 }
1815
1816 // ****************************************************************************
1817 // * THE SETUP ROUTINES
1818 // ****************************************************************************
1819
LoadWalkResources(Object * megaObject,int32 x,int32 y,int32 dir)1820 int32 Router::LoadWalkResources(Object *megaObject, int32 x, int32 y, int32 dir) {
1821 WalkGridHeader floorHeader;
1822 int32 i;
1823 uint8 *fPolygrid;
1824 uint8 *fMegaWalkData;
1825
1826 int32 floorId;
1827 int32 walkGridResourceId;
1828 Object *floorObject;
1829
1830 int32 cnt;
1831 uint32 cntu;
1832
1833 // load in floor grid for current mega
1834
1835 floorId = megaObject->o_place;
1836
1837 //floorObject = (object *)Lock_object(floorId);
1838 floorObject = _objMan->fetchObject(floorId);
1839 walkGridResourceId = floorObject->o_resource;
1840 //Unlock_object(floorId);
1841
1842 //ResOpen(walkGridResourceId); // mouse wiggle
1843 //fPolygrid = ResLock(walkGridResourceId); // mouse wiggle
1844 fPolygrid = (uint8 *)_resMan->openFetchRes(walkGridResourceId);
1845
1846
1847 fPolygrid += sizeof(Header);
1848 memcpy(&floorHeader, fPolygrid, sizeof(WalkGridHeader));
1849 fPolygrid += sizeof(WalkGridHeader);
1850 _nBars = _resMan->getUint32(floorHeader.numBars);
1851
1852 if (_nBars >= O_GRID_SIZE) {
1853 #ifdef DEBUG //check for id > number in file,
1854 error("RouteFinder Error too many _bars %d", _nBars);
1855 #endif
1856 _nBars = 0;
1857 }
1858
1859 _nNodes = _resMan->getUint32(floorHeader.numNodes) + 1; //array starts at 0 begins at a start _node has nnodes nodes and a target _node
1860
1861 if (_nNodes >= O_GRID_SIZE) {
1862 #ifdef DEBUG //check for id > number in file,
1863 error("RouteFinder Error too many nodes %d", _nNodes);
1864 #endif
1865 _nNodes = 0;
1866 }
1867
1868 /*memmove(&_bars[0],fPolygrid,_nBars*sizeof(BarData));
1869 fPolygrid += _nBars*sizeof(BarData);//move pointer to start of _node data*/
1870 for (cnt = 0; cnt < _nBars; cnt++) {
1871 _bars[cnt].x1 = _resMan->readUint16(fPolygrid); fPolygrid += 2;
1872 _bars[cnt].y1 = _resMan->readUint16(fPolygrid); fPolygrid += 2;
1873 _bars[cnt].x2 = _resMan->readUint16(fPolygrid); fPolygrid += 2;
1874 _bars[cnt].y2 = _resMan->readUint16(fPolygrid); fPolygrid += 2;
1875 _bars[cnt].xmin = _resMan->readUint16(fPolygrid); fPolygrid += 2;
1876 _bars[cnt].ymin = _resMan->readUint16(fPolygrid); fPolygrid += 2;
1877 _bars[cnt].xmax = _resMan->readUint16(fPolygrid); fPolygrid += 2;
1878 _bars[cnt].ymax = _resMan->readUint16(fPolygrid); fPolygrid += 2;
1879 _bars[cnt].dx = _resMan->readUint16(fPolygrid); fPolygrid += 2;
1880 _bars[cnt].dy = _resMan->readUint16(fPolygrid); fPolygrid += 2;
1881 _bars[cnt].co = _resMan->readUint32(fPolygrid); fPolygrid += 4;
1882 }
1883
1884 /*j = 1;// leave _node 0 for start _node
1885 do {
1886 memmove(&_node[j].x,fPolygrid,2*sizeof(int16));
1887 fPolygrid += 2*sizeof(int16);
1888 j ++;
1889 } while (j < _nNodes);//array starts at 0*/
1890 for (cnt = 1; cnt < _nNodes; cnt++) {
1891 _node[cnt].x = _resMan->readUint16(fPolygrid); fPolygrid += 2;
1892 _node[cnt].y = _resMan->readUint16(fPolygrid); fPolygrid += 2;
1893 }
1894
1895 //ResUnlock(walkGridResourceId); // mouse wiggle
1896 //ResClose(walkGridResourceId); // mouse wiggle
1897 _resMan->resClose(walkGridResourceId);
1898
1899
1900 // floor grid loaded
1901
1902 // copy the mega structure into the local variables for use in all subroutines
1903
1904 _startX = megaObject->o_xcoord;
1905 _startY = megaObject->o_ycoord;
1906 _startDir = megaObject->o_dir;
1907 _targetX = x;
1908 _targetY = y;
1909 _targetDir = dir;
1910
1911 _scaleA = megaObject->o_scale_a;
1912 _scaleB = megaObject->o_scale_b;
1913
1914 //ResOpen(megaObject->o_mega_resource); // mouse wiggle
1915 //fMegaWalkData = ResLock(megaObject->o_mega_resource); // mouse wiggle
1916 fMegaWalkData = (uint8 *)_resMan->openFetchRes(megaObject->o_mega_resource);
1917 // Apparently this resource is in little endian in both the Mac and the PC version
1918
1919 _nWalkFrames = fMegaWalkData[0];
1920 _nTurnFrames = fMegaWalkData[1];
1921 fMegaWalkData += 2;
1922 for (cnt = 0; cnt < NO_DIRECTIONS * (_nWalkFrames + 1 + _nTurnFrames); cnt++) {
1923 _dx[cnt] = (int32)_resMan->readLEUint32(fMegaWalkData);
1924 fMegaWalkData += 4;
1925 }
1926 for (cnt = 0; cnt < NO_DIRECTIONS * (_nWalkFrames + 1 + _nTurnFrames); cnt++) {
1927 _dy[cnt] = (int32)_resMan->readLEUint32(fMegaWalkData);
1928 fMegaWalkData += 4;
1929 }
1930 /*memmove(&_dx[0],fMegaWalkData,NO_DIRECTIONS*(_nWalkFrames+1+_nTurnFrames)*sizeof(int32));
1931 fMegaWalkData += NO_DIRECTIONS*(_nWalkFrames+1+_nTurnFrames)*sizeof(int32);
1932 memmove(&_dy[0],fMegaWalkData,NO_DIRECTIONS*(_nWalkFrames+1+_nTurnFrames)*sizeof(int32));
1933 fMegaWalkData += NO_DIRECTIONS*(_nWalkFrames+1+_nTurnFrames)*sizeof(int32);*/
1934
1935 for (cntu = 0; cntu < NO_DIRECTIONS; cntu++) {
1936 _modX[cntu] = (int32)_resMan->readLEUint32(fMegaWalkData);
1937 fMegaWalkData += 4;
1938 }
1939 for (cntu = 0; cntu < NO_DIRECTIONS; cntu++) {
1940 _modY[cntu] = (int32)_resMan->readLEUint32(fMegaWalkData);
1941 fMegaWalkData += 4;
1942 }
1943 /*memmove(&_modX[0],fMegaWalkData,NO_DIRECTIONS*sizeof(int32));
1944 fMegaWalkData += NO_DIRECTIONS*sizeof(int32);
1945 memmove(&_modY[0],fMegaWalkData,NO_DIRECTIONS*sizeof(int32));
1946 fMegaWalkData += NO_DIRECTIONS*sizeof(int32);*/
1947
1948 //ResUnlock(megaObject->o_mega_resource); // mouse wiggle
1949 //ResClose(megaObject->o_mega_resource); // mouse wiggle
1950 _resMan->resClose(megaObject->o_mega_resource);
1951
1952 _diagonalx = _modX[3]; //36
1953 _diagonaly = _modY[3]; //8
1954
1955 // mega data ready
1956
1957 // finish setting grid by putting mega _node at begining
1958 // and target _node at end and reset current values
1959 _node[0].x = _startX;
1960 _node[0].y = _startY;
1961 _node[0].level = 1;
1962 _node[0].prev = 0;
1963 _node[0].dist = 0;
1964 i = 1;
1965 do {
1966 _node[i].level = 0;
1967 _node[i].prev = 0;
1968 _node[i].dist = 9999;
1969 i = i + 1;
1970 } while (i < _nNodes);
1971 _node[_nNodes].x = _targetX;
1972 _node[_nNodes].y = _targetY;
1973 _node[_nNodes].level = 0;
1974 _node[_nNodes].prev = 0;
1975 _node[_nNodes].dist = 9999;
1976
1977 return 1;
1978 }
1979
1980 // ****************************************************************************
1981 // * THE ROUTE EXTRACTOR
1982 // ****************************************************************************
1983
extractRoute()1984 void Router::extractRoute() {
1985 /*********************************************************************
1986 * extractRoute gets route from the node data after a full scan, route
1987 * is written with just the basic way points and direction options for
1988 * heading to the next point.
1989 *********************************************************************/
1990
1991 int32 prev;
1992 int32 prevx;
1993 int32 prevy;
1994 int32 last;
1995 int32 point;
1996 int32 dirx;
1997 int32 diry;
1998 int32 dir;
1999 int32 ldx;
2000 int32 ldy;
2001 int32 p;
2002
2003 // extract the route from the _node data
2004 prev = _nNodes;
2005 last = prev;
2006 point = O_ROUTE_SIZE - 1;
2007 _route[point].x = _node[last].x;
2008 _route[point].y = _node[last].y;
2009
2010 do {
2011 point--;
2012 prev = _node[last].prev;
2013 prevx = _node[prev].x;
2014 prevy = _node[prev].y;
2015 _route[point].x = prevx;
2016 _route[point].y = prevy;
2017 last = prev;
2018 } while (prev > 0);
2019
2020 // now shuffle route down in the buffer
2021 _routeLength = 0;
2022
2023 do {
2024 _route[_routeLength].x = _route[point].x;
2025 _route[_routeLength].y = _route[point].y;
2026 point++;
2027 _routeLength++;
2028 } while (point < O_ROUTE_SIZE);
2029
2030 _routeLength--;
2031
2032 // okay the route exists as a series point now put in some directions
2033 for (p = 0; p < _routeLength; ++p) {
2034 ldx = _route[p + 1].x - _route[p].x;
2035 ldy = _route[p + 1].y - _route[p].y;
2036 dirx = 1;
2037 diry = 1;
2038
2039 if (ldx < 0) {
2040 ldx = -ldx;
2041 dirx = -1;
2042 }
2043
2044 if (ldy < 0) {
2045 ldy = -ldy;
2046 diry = -1;
2047 }
2048
2049 if (_diagonaly * ldx > _diagonalx * ldy) {
2050 // dir = 1,2 or 2,3 or 5,6 or 6,7
2051
2052 // 2 or 6
2053 dir = 4 - 2 * dirx;
2054 _route[p].dirS = dir;
2055
2056 // 1, 3, 5 or 7
2057 dir = dir + diry * dirx;
2058 _route[p].dirD = dir;
2059 } else {
2060 // dir = 7,0 or 0,1 or 3,4 or 4,5
2061
2062 // 0 or 4
2063 dir = 2 + 2 * diry;
2064 _route[p].dirS = dir;
2065
2066 // 2 or 6
2067 dir = 4 - 2 * dirx;
2068
2069 // 1, 3, 5 or 7
2070 dir = dir + diry * dirx;
2071 _route[p].dirD = dir;
2072 }
2073 }
2074
2075 // set the last dir to continue previous route unless specified
2076 if (_targetDir == NO_DIRECTIONS) {
2077 // ANY direction
2078 _route[p].dirS = _route[p - 1].dirS;
2079 _route[p].dirD = _route[p - 1].dirD;
2080 } else {
2081 _route[p].dirS = _targetDir;
2082 _route[p].dirD = _targetDir;
2083 }
2084 return;
2085 }
2086
2087 #define DIAGONALX 36
2088 #define DIAGONALY 8
whatTarget(int32 startX,int32 startY,int32 destX,int32 destY)2089 int whatTarget(int32 startX, int32 startY, int32 destX, int32 destY) {
2090 int tar_dir;
2091 //setting up
2092 int deltaX = destX - startX;
2093 int deltaY = destY - startY;
2094 int signX = (deltaX > 0);
2095 int signY = (deltaY > 0);
2096 int slope;
2097
2098 if ((ABS(deltaY) * DIAGONALX) < (ABS(deltaX) * DIAGONALY / 2))
2099 slope = 0;// its flat
2100 else if ((ABS(deltaY) * DIAGONALX / 2) > (ABS(deltaX) * DIAGONALY))
2101 slope = 2;// its vertical
2102 else
2103 slope = 1;// its diagonal
2104
2105 if (slope == 0) { //flat
2106 if (signX == 1) // going right
2107 tar_dir = 2;
2108 else
2109 tar_dir = 6;
2110 } else if (slope == 2) { //vertical
2111 if (signY == 1) // going down
2112 tar_dir = 4;
2113 else
2114 tar_dir = 0;
2115 } else if (signX == 1) { //right diagonal
2116 if (signY == 1) // going down
2117 tar_dir = 3;
2118 else
2119 tar_dir = 1;
2120 } else { //left diagonal
2121 if (signY == 1) // going down
2122 tar_dir = 5;
2123 else
2124 tar_dir = 7;
2125 }
2126 return tar_dir;
2127 }
2128
setPlayerTarget(int32 x,int32 y,int32 dir,int32 stance)2129 void Router::setPlayerTarget(int32 x, int32 y, int32 dir, int32 stance) {
2130 _playerTargetX = x;
2131 _playerTargetY = y;
2132 _playerTargetDir = dir;
2133 _playerTargetStance = stance;
2134 }
2135
2136 } // End of namespace Sword1
2137