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