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  * Additional copyright for this file:
8  * Copyright (C) 1994-1998 Revolution Software Ltd.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  */
24 
25 
26 #include "common/memstream.h"
27 #include "common/textconsole.h"
28 
29 #include "sword2/sword2.h"
30 #include "sword2/defs.h"
31 #include "sword2/header.h"
32 #include "sword2/logic.h"
33 #include "sword2/resman.h"
34 #include "sword2/router.h"
35 #include "sword2/screen.h"
36 
37 namespace Sword2 {
38 
39 // ---------------------------------------------------------------------------
40 // ROUTER.CPP by James
41 //
42 // A rehash of Jeremy's original jrouter.c, containing low-level system
43 // routines for calculating routes between points inside a walk-grid, and
44 // constructing walk animations from mega-sets.
45 //
46 // jrouter.c underwent 2 major reworks from the original:
47 // (1)	Restructured to allow more flexibility in the mega-sets, ie. more info
48 //      taken from the walk-data
49 //	- the new George & Nico mega-sets & walk-data were then tested &
50 //        tweaked in the Sword1 system
51 // (2)	Updated for the new Sword2 system, ie. new object structures
52 //	- now compatible with Sword2, the essential code already having been
53 //        tested
54 //
55 // ---------------------------------------------------------------------------
56 
57 /****************************************************************************
58  *    JROUTER.C				polygon router with modular walks
59  *							using a tree of modules
60  *							21 july 94
61  *  3  november 94
62  *  System currently works by scanning grid data and coming up with a	ROUTE
63  *  as a series of way points(nodes), the smoothest eight directional PATH
64  *	through these nodes is then found, and a WALK created to fit the PATH.
65  *
66  *	Two funtions are called by the user, RouteFinder creates a route as a
67  *	module list, HardWalk creates an animation list from the module list.
68  *	The split is only provided to allow the possibility of turning the
69  *	autorouter over two game cycles.
70  ****************************************************************************
71  *
72  *	Routine timings on osborne 486
73  *
74  *	Read floor resource (file already loaded)	 112 pixels
75  *
76  *	Read mega resource (file already loaded)	 112 pixels
77  *
78  *
79  *
80  ****************************************************************************
81  *
82  *  Modified 12 Oct 95
83  *
84  *	Target Points within 1 pixel of a line are ignored ???
85  *
86  *	Modules split into  Points within 1 pixel of a line are ignored ???
87  *
88  ****************************************************************************
89  *
90  *  TOTALLY REHASHED BY JAMES FOR NEW MEGAS USING OLD SYSTEM
91  *  THEN REINCARNATED BY JAMES FOR NEW MEGAS USING NEW SYSTEM
92  *
93  ****************************************************************************/
94 
95 //----------------------------------------------------------
96 // (4) WALK-GRID FILES
97 //----------------------------------------------------------
98 // a walk-grid file consists of:
99 //
100 // standard file header
101 // walk-grid file header
102 // walk-grid data
103 
104 // Walk-Grid Header - taken directly from old "header.h" in STD_INC
105 
106 struct WalkGridHeader {
107 	int32 numBars;		// number of bars on the floor
108 	int32 numNodes;		// number of nodes
109 };
110 
returnSlotNo(uint32 megaId)111 uint8 Router::returnSlotNo(uint32 megaId) {
112 	if (_vm->_logic->readVar(ID) == CUR_PLAYER_ID) {
113 		// George (8)
114 		return 0;
115 	} else {
116 		// One of Nico's mega id's
117 		return 1;
118 	}
119 }
120 
allocateRouteMem()121 void Router::allocateRouteMem() {
122 	uint8 slotNo;
123 
124 	// Player character always always slot 0, while the other mega
125 	// (normally Nico) always uses slot 1
126 	// Better this way, so that if mega object removed from memory while
127 	// in middle of route, the old route will be safely cleared from
128 	// memory just before they create a new one
129 
130 	slotNo = returnSlotNo(_vm->_logic->readVar(ID));
131 
132 	// if this slot is already used, then it can't be needed any more
133 	// because this id is creating a new route!
134 
135 	if (_routeSlots[slotNo])
136 		freeRouteMem();
137 
138 	_routeSlots[slotNo] = (WalkData *)malloc(sizeof(WalkData) * O_WALKANIM_SIZE);
139 
140 	// 12000 bytes were used for this in Sword1 mega compacts, based on
141 	// 20 bytes per 'WalkData' frame
142 	// ie. allowing for 600 frames including end-marker
143 	// Now 'WalkData' is 8 bytes, so 8*600 = 4800 bytes.
144 	// Note that a 600 frame walk lasts about 48 seconds!
145 	// (600fps / 12.5s = 48s)
146 
147 	// mega keeps note of which slot contains the pointer to it's walk
148 	// animation mem block
149 	// +1 so that '0' can mean "not walking"
150 	// megaObject->route_slot_id = slotNo + 1;
151 }
152 
getRouteMem()153 WalkData *Router::getRouteMem() {
154 	uint8 slotNo = returnSlotNo(_vm->_logic->readVar(ID));
155 
156 	return (WalkData *)_routeSlots[slotNo];
157 }
158 
freeRouteMem()159 void Router::freeRouteMem() {
160 	uint8 slotNo = returnSlotNo(_vm->_logic->readVar(ID));
161 
162 	free(_routeSlots[slotNo]);
163 	_routeSlots[slotNo] = NULL;
164 }
165 
freeAllRouteMem()166 void Router::freeAllRouteMem() {
167 	for (int i = 0; i < TOTAL_ROUTE_SLOTS; i++) {
168 		free(_routeSlots[i]);
169 		_routeSlots[i] = NULL;
170 	}
171 }
172 
routeFinder(byte * ob_mega,byte * ob_walkdata,int32 x,int32 y,int32 dir)173 int32 Router::routeFinder(byte *ob_mega, byte *ob_walkdata, int32 x, int32 y, int32 dir) {
174 	/*********************************************************************
175 	 * RouteFinder.C		polygon router with modular walks
176 	 *						21 august 94
177 	 *						3  november 94
178 	 * routeFinder creates a list of modules that enables HardWalk to
179 	 * create an animation list.
180 	 *
181 	 * routeFinder currently works by scanning grid data and coming up
182 	 * with a ROUTE as a series of way points(nodes), the smoothest eight
183 	 * directional PATH through these nodes is then found, this
184 	 * information is made available to HardWalk for a WALK to be created
185 	 * to fit the PATH.
186 	 *
187 	 * 30 november 94 return values modified
188 	 *
189 	 * return	0 = failed to find a route
190 	 *
191 	 *			1 = found a route
192 	 *
193 	 *			2 = mega already at target
194 	 *
195 	 *********************************************************************/
196 
197 	int32 routeFlag = 0;
198 	int32 solidFlag = 0;
199 	WalkData *walkAnim;
200 
201 	// megaId = id;
202 
203 	setUpWalkGrid(ob_mega, x, y, dir);
204 	loadWalkData(ob_walkdata);
205 
206 	walkAnim = getRouteMem();
207 
208 	// All route data now loaded start finding a route
209 
210 	// Check if we can get a route through the floor. changed 12 Oct95 JPS
211 
212 	routeFlag = getRoute();
213 
214 	switch (routeFlag) {
215 	case 2:
216 		// special case for zero length route
217 
218 		// if target direction specified as any
219 		if (_targetDir > 7)
220 			_targetDir = _startDir;
221 
222 		// just a turn on the spot is required set an end module for
223 		// the route let the animator deal with it
224 		// modularPath is normally set by extractRoute
225 
226 		_modularPath[0].dir = _startDir;
227 		_modularPath[0].num = 0;
228 		_modularPath[0].x = _startX;
229 		_modularPath[0].y = _startY;
230 		_modularPath[1].dir = _targetDir;
231 		_modularPath[1].num = 0;
232 		_modularPath[1].x = _startX;
233 		_modularPath[1].y = _startY;
234 		_modularPath[2].dir = 9;
235 		_modularPath[2].num = ROUTE_END_FLAG;
236 
237 		slidyWalkAnimator(walkAnim);
238 		routeFlag = 2;
239 		break;
240 	case 1:
241 		// A normal route. Convert the route to an exact path
242 		smoothestPath();
243 
244 		// The Route had waypoints and direction options
245 
246 		// The Path is an exact set of lines in 8 directions that
247 		// reach the target.
248 
249 		// The path is in module format, but steps taken in each
250 		// direction are not accurate
251 
252 		// if target dir = 8 then the walk isn't linked to an anim so
253 		// we can create a route without sliding and miss the exact
254 		// target
255 
256 #ifndef FORCE_SLIDY
257 		if (_targetDir == 8) {
258 			// can end facing ANY direction (ie. exact end
259 			// position not vital) - so use SOLID walk to
260 			// avoid sliding to exact position
261 
262 			solidPath();
263 			solidFlag = solidWalkAnimator(walkAnim);
264 		}
265 #endif
266 
267 		if (!solidFlag) {
268 			// if we failed to create a SOLID route, do a SLIDY
269 			// one instead
270 
271 			slidyPath();
272 			slidyWalkAnimator(walkAnim);
273 		}
274 
275 		break;
276 	default:
277 		// Route didn't reach target so assume point was off the floor
278 		// routeFlag = 0;
279 		break;
280 	}
281 
282 	return routeFlag;	// send back null route
283 }
284 
getRoute()285 int32 Router::getRoute() {
286 	/*********************************************************************
287 	 * GetRoute.C				extract a path from walk grid
288 	 *							12 october 94
289 	 *
290 	 * GetRoute currently works by scanning grid data and coming up with
291 	 * a ROUTE as a series of way points(nodes).
292 	 *
293 	 * static routeData _route[O_ROUTE_SIZE];
294 	 *
295 	 * return	0 = failed to find a route
296 	 *
297 	 *		1 = found a route
298 	 *
299 	 *		2 = mega already at target
300 	 *
301 	 *		3 = failed to find a route because target was on a line
302 	 *
303 	 *********************************************************************/
304 
305 	int32 routeGot = 0;
306 
307 	if (_startX == _targetX && _startY == _targetY)
308 		routeGot = 2;
309 	else {
310 		// 'else' added by JEL (23jan96) otherwise 'routeGot' affected
311 		// even when already set to '2' above - causing some 'turns'
312 		// to walk downwards on the spot
313 
314 		// returns 3 if target on a line ( +- 1 pixel )
315 		routeGot = checkTarget(_targetX, _targetY);
316 	}
317 
318 	if (routeGot == 0) {
319 		// still looking for a route check if target is within a pixel
320 		// of a line
321 
322 		// scan through the nodes linking each node to its nearest
323 		// neighbor until no more nodes change
324 
325 		// This is the routine that finds a route using scan()
326 
327 		int32 level = 1;
328 
329 		while (scan(level))
330 			level++;
331 
332 		// Check to see if the route reached the target
333 
334 		if (_node[_nNodes].dist < 9999) {
335 			// it did so extract the route as nodes and the
336 			// directions to go between each node
337 
338 			routeGot = 1;
339 			extractRoute();
340 
341 			// route.X,route.Y and route.Dir now hold all the
342 			// route infomation with the target dir or route
343 			// continuation
344 		}
345 	}
346 
347 	return routeGot;
348 }
349 
350 // THE SLIDY PATH ROUTINES
351 
smoothestPath()352 int32 Router::smoothestPath() {
353 	// This is the second big part of the route finder and the the only
354 	// bit that tries to be clever (the other bits are clever).
355 	//
356 	// This part of the autorouter creates a list of modules from a set of
357 	// lines running across the screen. The task is complicated by two
358 	// things:
359 	//
360 	// Firstly in choosing a route through the maze of nodes the routine
361 	// tries to minimise the amount of each individual turn avoiding 90
362 	// degree and greater turns (where possible) and reduces the total
363 	// number of turns (subject to two 45 degree turns being better than
364 	// one 90 degree turn).
365 	//
366 	// Secondly when walking in a given direction the number of steps
367 	// required to reach the end of that run is not calculated accurately.
368 	// This is because I was unable to derive a function to relate number
369 	// of steps taken between two points to the shrunken step size
370 
371 	int i;
372 	int32 steps = 0;
373 	int32 lastDir;
374 	int32 tempturns[4];
375 	int32 turns[4];
376 	const int32 turntable[NO_DIRECTIONS] = { 0, 1, 3, 5, 7, 5, 3, 1 };
377 
378 	// route.X route.Y and route.Dir start at far end
379 
380 	_smoothPath[0].x = _startX;
381 	_smoothPath[0].y = _startY;
382 	_smoothPath[0].dir = _startDir;
383 	_smoothPath[0].num = 0;
384 
385 	lastDir = _startDir;
386 
387 	// for each section of the route
388 
389 	for (int p = 0; p < _routeLength; p++) {
390 		int32 dirS = _route[p].dirS;
391 		int32 dirD = _route[p].dirD;
392 		int32 nextDirS = _route[p + 1].dirS;
393 		int32 nextDirD = _route[p + 1].dirD;
394 
395 		// Check directions into and out of a pair of nodes going in
396 		int32 dS = dirS - lastDir;
397 		if (dS < 0)
398 			dS = dS + NO_DIRECTIONS;
399 
400 		int32 dD = dirD - lastDir;
401 		if (dD < 0)
402 			dD = dD + NO_DIRECTIONS;
403 
404 		// coming out
405 		int32 dSS = dirS - nextDirS;
406 		if (dSS < 0)
407 			dSS = dSS + NO_DIRECTIONS;
408 
409 		int32 dDD = dirD - nextDirD;
410 		if (dDD < 0)
411 			dDD = dDD + NO_DIRECTIONS;
412 
413 		int32 dSD = dirS - nextDirD;
414 		if (dSD < 0)
415 			dSD = dSD + NO_DIRECTIONS;
416 
417 		int32 dDS = dirD - nextDirS;
418 		if (dDS < 0)
419 			dDS = dDS + NO_DIRECTIONS;
420 
421 		// Determine the amount of turning involved in each possible path
422 		dS = turntable[dS];
423 		dD = turntable[dD];
424 		dSS = turntable[dSS];
425 		dDD = turntable[dDD];
426 		dSD = turntable[dSD];
427 		dDS = turntable[dDS];
428 
429 		// get the best path out ie assume next section uses best direction
430 		if (dSD < dSS)
431 			dSS = dSD;
432 		if (dDS < dDD)
433 			dDD = dDS;
434 
435 		// Rate each option. Split routes look crap so weight against them
436 		tempturns[0] = dS + dSS + 3;
437 		turns[0] = 0;
438 		tempturns[1] = dS + dDD;
439 		turns[1] = 1;
440 		tempturns[2] = dD + dSS;
441 		turns[2] = 2;
442 		tempturns[3] = dD + dDD + 3;
443 		turns[3] = 3;
444 
445 		// set up turns as a sorted array of the turn values
446 		for (i = 0; i < 3; i++) {
447 			for (int j = 0; j < 3; j++) {
448 				if (tempturns[j] > tempturns[j + 1]) {
449 					SWAP(turns[j], turns[j + 1]);
450 					SWAP(tempturns[j], tempturns[j + 1]);
451 				}
452 			}
453 		}
454 
455 		// best option matched in order of the priority we would like
456 		// to see on the screen but each option must be checked to see
457 		// if it can be walked
458 
459 		int32 options = newCheck(1, _route[p].x, _route[p].y, _route[p + 1].x, _route[p + 1].y);
460 
461 		assert(options);
462 
463 		for (i = 0; i < 4; ++i) {
464 			int32 opt = 1 << turns[i];
465 			if (options & opt) {
466 				smoothCheck(steps, turns[i], p, dirS, dirD);
467 				break;
468 			}
469 		}
470 
471 		assert(i < 4);
472 
473 		// route.X route.Y route.dir and bestTurns start at far end
474 	}
475 
476 	// best turns will end heading as near as possible to target dir rest
477 	// is down to anim for now
478 
479 	_smoothPath[steps].dir = 9;
480 	_smoothPath[steps].num = ROUTE_END_FLAG;
481 	return 1;
482 }
483 
smoothCheck(int32 & k,int32 best,int32 p,int32 dirS,int32 dirD)484 void Router::smoothCheck(int32 &k, int32 best, int32 p, int32 dirS, int32 dirD) {
485 	/*********************************************************************
486 	 * Slip sliding away
487 	 * This path checker checks to see if a walk that exactly follows the
488 	 * path would be valid. This should be inherently true for atleast one
489 	 * of the turn options.
490 	 * No longer checks the data it only creates the smoothPath array JPS
491 	 *********************************************************************/
492 
493 	int32 dsx, dsy;
494 	int32 ddx, ddy;
495 	int32 ss0, ss1, ss2;
496 	int32 sd0, sd1, sd2;
497 
498 	if (p == 0)
499 		k = 1;
500 
501 	int32 x = _route[p].x;
502 	int32 y = _route[p].y;
503 	int32 x2 = _route[p + 1].x;
504 	int32 y2 = _route[p + 1].y;
505 	int32 ldx = x2 - x;
506 	int32 ldy = y2 - y;
507 	int32 dirX = 1;
508 	int32 dirY = 1;
509 
510 	if (ldx < 0) {
511 		ldx = -ldx;
512 		dirX = -1;
513 	}
514 
515 	if (ldy < 0) {
516 		ldy = -ldy;
517 		dirY = -1;
518 	}
519 
520 	// set up sd0-ss2 to reflect possible movement in each direction
521 
522 	if (dirS == 0 || dirS == 4) {	// vert and diag
523 		ddx = ldx;
524 		ddy = (ldx * _diagonaly) / _diagonalx;
525 		dsy = ldy - ddy;
526 		ddx = ddx * dirX;
527 		ddy = ddy * dirY;
528 		dsy = dsy * dirY;
529 		dsx = 0;
530 
531 		sd0 = (ddx + _modX[dirD] / 2) / _modX[dirD];
532 		ss0 = (dsy + _modY[dirS] / 2) / _modY[dirS];
533 		sd1 = sd0 / 2;
534 		ss1 = ss0 / 2;
535 		sd2 = sd0 - sd1;
536 		ss2 = ss0 - ss1;
537 	} else {
538 		ddy = ldy;
539 		ddx = (ldy * _diagonalx) / _diagonaly;
540 		dsx = ldx - ddx;
541 		ddy = ddy * dirY;
542 		ddx = ddx * dirX;
543 		dsx = dsx * dirX;
544 		dsy = 0;
545 
546 		sd0 = (ddy + _modY[dirD] / 2) / _modY[dirD];
547 		ss0 = (dsx + _modX[dirS] / 2) / _modX[dirS];
548 		sd1 = sd0 / 2;
549 		ss1 = ss0 / 2;
550 		sd2 = sd0 - sd1;
551 		ss2 = ss0 - ss1;
552 	}
553 
554 	switch (best) {
555 	case 0:		// halfsquare, diagonal, halfsquare
556 		_smoothPath[k].x = x + dsx / 2;
557 		_smoothPath[k].y = y + dsy / 2;
558 		_smoothPath[k].dir = dirS;
559 		_smoothPath[k].num = ss1;
560 		k++;
561 
562 		_smoothPath[k].x = x + dsx / 2 + ddx;
563 		_smoothPath[k].y = y + dsy / 2 + ddy;
564 		_smoothPath[k].dir = dirD;
565 		_smoothPath[k].num = sd0;
566 		k++;
567 
568 		_smoothPath[k].x = x + dsx + ddx;
569 		_smoothPath[k].y = y + dsy + ddy;
570 		_smoothPath[k].dir = dirS;
571 		_smoothPath[k].num = ss2;
572 		k++;
573 
574 		break;
575 	case 1:		// square, diagonal
576 		_smoothPath[k].x = x + dsx;
577 		_smoothPath[k].y = y + dsy;
578 		_smoothPath[k].dir = dirS;
579 		_smoothPath[k].num = ss0;
580 		k++;
581 
582 		_smoothPath[k].x = x2;
583 		_smoothPath[k].y = y2;
584 		_smoothPath[k].dir = dirD;
585 		_smoothPath[k].num = sd0;
586 		k++;
587 
588 		break;
589 	case 2:		// diagonal square
590 		_smoothPath[k].x = x + ddx;
591 		_smoothPath[k].y = y + ddy;
592 		_smoothPath[k].dir = dirD;
593 		_smoothPath[k].num = sd0;
594 		k++;
595 
596 		_smoothPath[k].x = x2;
597 		_smoothPath[k].y = y2;
598 		_smoothPath[k].dir = dirS;
599 		_smoothPath[k].num = ss0;
600 		k++;
601 
602 		break;
603 	default:	// halfdiagonal, square, halfdiagonal
604 		_smoothPath[k].x = x + ddx / 2;
605 		_smoothPath[k].y = y + ddy / 2;
606 		_smoothPath[k].dir = dirD;
607 		_smoothPath[k].num = sd1;
608 		k++;
609 
610 		_smoothPath[k].x = x + dsx + ddx / 2;
611 		_smoothPath[k].y = y + dsy + ddy / 2;
612 		_smoothPath[k].dir = dirS;
613 		_smoothPath[k].num = ss0;
614 		k++;
615 
616 		_smoothPath[k].x = x2;
617 		_smoothPath[k].y = y2;
618 		_smoothPath[k].dir = dirD;
619 		_smoothPath[k].num = sd2;
620 		k++;
621 
622 		break;
623 	}
624 }
625 
slidyPath()626 void Router::slidyPath() {
627 	/*********************************************************************
628 	 * slidyPath creates a path based on part steps with no sliding to get
629 	 * as near as possible to the target without any sliding this routine
630 	 * is intended for use when just clicking about.
631 	 *
632 	 * produce a module list from the line data
633 	 *********************************************************************/
634 
635 	int32 smooth = 1;
636 	int32 slidy = 1;
637 
638 	// strip out the short sections
639 
640 	_modularPath[0].x = _smoothPath[0].x;
641 	_modularPath[0].y = _smoothPath[0].y;
642 	_modularPath[0].dir = _smoothPath[0].dir;
643 	_modularPath[0].num = 0;
644 
645 	while (_smoothPath[smooth].num < ROUTE_END_FLAG) {
646 		int32 scale = _scaleA * _smoothPath[smooth].y + _scaleB;
647 		int32 deltaX = _smoothPath[smooth].x - _modularPath[slidy - 1].x;
648 		int32 deltaY = _smoothPath[smooth].y - _modularPath[slidy - 1].y;
649 		// quarter a step minimum
650 		int32 stepX = (scale * _modX[_smoothPath[smooth].dir]) >> 19;
651 		int32 stepY = (scale * _modY[_smoothPath[smooth].dir]) >> 19;
652 
653 		if (ABS(deltaX) >= ABS(stepX) && ABS(deltaY) >= ABS(stepY)) {
654 			_modularPath[slidy].x = _smoothPath[smooth].x;
655 			_modularPath[slidy].y = _smoothPath[smooth].y;
656 			_modularPath[slidy].dir = _smoothPath[smooth].dir;
657 			_modularPath[slidy].num = 1;
658 			slidy++;
659 		}
660 		smooth++;
661 	}
662 
663 	// in case the last bit had no steps
664 
665 	if (slidy > 1) {
666 		_modularPath[slidy - 1].x = _smoothPath[smooth - 1].x;
667 		_modularPath[slidy - 1].y = _smoothPath[smooth - 1].y;
668 	}
669 
670 	// set up the end of the walk
671 
672 	_modularPath[slidy].x = _smoothPath[smooth - 1].x;
673 	_modularPath[slidy].y = _smoothPath[smooth - 1].y;
674 	_modularPath[slidy].dir = _targetDir;
675 	_modularPath[slidy].num = 0;
676 	slidy++;
677 
678 	_modularPath[slidy].x = _smoothPath[smooth - 1].x;
679 	_modularPath[slidy].y = _smoothPath[smooth - 1].y;
680 	_modularPath[slidy].dir = 9;
681 	_modularPath[slidy].num = ROUTE_END_FLAG;
682 }
683 
684 // SLOW IN
685 
addSlowInFrames(WalkData * walkAnim)686 bool Router::addSlowInFrames(WalkData *walkAnim) {
687 	if (_walkData.usingSlowInFrames && _modularPath[1].num > 0) {
688 		for (int slowInFrameNo = 0; slowInFrameNo < _walkData.nSlowInFrames[_currentDir]; slowInFrameNo++) {
689 			walkAnim[_stepCount].frame = _firstSlowInFrame[_currentDir] + slowInFrameNo;
690 			walkAnim[_stepCount].step = 0;
691 			walkAnim[_stepCount].dir = _currentDir;
692 			walkAnim[_stepCount].x = _moduleX;
693 			walkAnim[_stepCount].y = _moduleY;
694 			_stepCount++;
695 		}
696 		return true;
697 	}
698 
699 	return false;
700 }
701 
earlySlowOut(byte * ob_mega,byte * ob_walkdata)702 void Router::earlySlowOut(byte *ob_mega, byte *ob_walkdata) {
703 	int32 slowOutFrameNo;
704 	int32 walk_pc;
705 	WalkData *walkAnim;
706 
707 	ObjectMega obMega(ob_mega);
708 
709 	debug(5, "EARLY SLOW-OUT");
710 
711 	loadWalkData(ob_walkdata);
712 
713 	debug(5, "********************************");
714 	debug(5, "_framesPerStep = %d", _framesPerStep);
715 	debug(5, "_numberOfSlowOutFrames = %d", _numberOfSlowOutFrames);
716 	debug(5, "_firstWalkingTurnLeftFrame = %d", _firstWalkingTurnLeftFrame);
717 	debug(5, "_firstWalkingTurnRightFrame = %d", _firstWalkingTurnRightFrame);
718 	debug(5, "_firstSlowOutFrame = %d", _firstSlowOutFrame);
719 	debug(5, "********************************");
720 
721 	walk_pc = obMega.getWalkPc();
722 
723 	walkAnim = getRouteMem();
724 
725 	// if this mega does actually have slow-out frames
726 	if (_walkData.usingSlowOutFrames) {
727 		// overwrite the next step (half a cycle) of the walk
728 		// (ie .step - 0..5)
729 
730 		do {
731 			debug(5, "STEP NUMBER: walkAnim[%d].step = %d", walk_pc, walkAnim[walk_pc].step);
732 			debug(5, "ORIGINAL FRAME: walkAnim[%d].frame = %d", walk_pc, walkAnim[walk_pc].frame);
733 
734 			// map from existing walk frame across to correct
735 			// frame number of slow-out - remember, there may be
736 			// more slow-out frames than walk-frames!
737 
738 			if (walkAnim[walk_pc].frame >= _firstWalkingTurnRightFrame) {
739 				// if it's a walking turn-right, rather than a
740 				// normal step, then map it to a normal step
741 				// frame first
742 
743 				walkAnim[walk_pc].frame -= _firstWalkingTurnRightFrame;
744 				debug(5, "MAPPED TO WALK: walkAnim[%d].frame = %d  (walking turn-right frame --> walk frame)", walk_pc, walkAnim[walk_pc].frame);
745 			} else if (walkAnim[walk_pc].frame >= _firstWalkingTurnLeftFrame) {
746 				// if it's a walking turn-left, rather than a
747 				// normal step, then map it to a normal step
748 				// frame first
749 
750 				walkAnim[walk_pc].frame -= _firstWalkingTurnLeftFrame;
751 				debug(5, "MAPPED TO WALK: walkAnim[%d].frame = %d  (walking turn-left frame --> walk frame)", walk_pc, walkAnim[walk_pc].frame);
752 			}
753 
754 			walkAnim[walk_pc].frame += _firstSlowOutFrame + ((walkAnim[walk_pc].frame / _framesPerStep) * (_numberOfSlowOutFrames - _framesPerStep));
755 			walkAnim[walk_pc].step = 0;
756 			debug(5, "SLOW-OUT FRAME: walkAnim[%d].frame = %d",walk_pc, walkAnim[walk_pc].frame);
757 			walk_pc++;
758 		} while (walkAnim[walk_pc].step > 0);
759 
760 		// add stationary frame(s) (OPTIONAL)
761 
762 		for (slowOutFrameNo = _framesPerStep; slowOutFrameNo < _numberOfSlowOutFrames; slowOutFrameNo++) {
763 			walkAnim[walk_pc].frame = walkAnim[walk_pc - 1].frame + 1;
764 			debug(5, "EXTRA FRAME: walkAnim[%d].frame = %d", walk_pc, walkAnim[walk_pc].frame);
765 			walkAnim[walk_pc].step = 0;
766 			walkAnim[walk_pc].dir = walkAnim[walk_pc - 1].dir;
767 			walkAnim[walk_pc].x = walkAnim[walk_pc - 1].x;
768 			walkAnim[walk_pc].y = walkAnim[walk_pc - 1].y;
769 			walk_pc++;
770 		}
771 	} else {
772 		// this mega doesn't have slow-out frames
773 		// stand in current direction
774 
775 		walkAnim[walk_pc].frame = _firstStandFrame + walkAnim[walk_pc - 1].dir;
776 		walkAnim[walk_pc].step = 0;
777 		walkAnim[walk_pc].dir = walkAnim[walk_pc - 1].dir;
778 		walkAnim[walk_pc].x = walkAnim[walk_pc - 1].x;
779 		walkAnim[walk_pc].y = walkAnim[walk_pc - 1].y;
780 		walk_pc++;
781 	}
782 
783 	// end of sequence
784 	walkAnim[walk_pc].frame	= 512;
785 
786 	// so that this doesn't happen again while 'george_walking' is still
787 	// '2'
788 	walkAnim[walk_pc].step = 99;
789 }
790 
791 // SLOW OUT
792 
addSlowOutFrames(WalkData * walkAnim)793 void Router::addSlowOutFrames(WalkData *walkAnim) {
794 	int32 slowOutFrameNo;
795 
796 	// if the mega did actually walk, we overwrite the last step (half a
797 	// cycle) with slow-out frames + add any necessary stationary frames
798 
799 	if (_walkData.usingSlowOutFrames && _lastCount >= _framesPerStep) {
800 		// place stop frames here
801 		// slowdown at the end of the last walk
802 
803 		slowOutFrameNo = _lastCount - _framesPerStep;
804 
805 		debug(5, "SLOW OUT: slowOutFrameNo(%d) = _lastCount(%d) - _framesPerStep(%d)", slowOutFrameNo, _lastCount, _framesPerStep);
806 
807 		// overwrite the last step (half a cycle) of the walk
808 
809 		do {
810 			// map from existing walk frame across to correct
811 			// frame number of slow-out - remember, there may be
812 			// more slow-out frames than walk-frames!
813 
814 			walkAnim[slowOutFrameNo].frame += _firstSlowOutFrame + ((walkAnim[slowOutFrameNo].frame / _framesPerStep) * (_numberOfSlowOutFrames - _framesPerStep));
815 
816 			// because no longer a normal walk-step
817 			walkAnim[slowOutFrameNo].step = 0;
818 
819 			debug(5, "walkAnim[%d].frame = %d",slowOutFrameNo,walkAnim[slowOutFrameNo].frame);
820 			slowOutFrameNo++;
821 		} while (slowOutFrameNo < _lastCount);
822 
823 		// add stationary frame(s) (OPTIONAL)
824 
825 		for (slowOutFrameNo = _framesPerStep; slowOutFrameNo < _numberOfSlowOutFrames; slowOutFrameNo++) {
826 			walkAnim[_stepCount].frame = walkAnim[_stepCount - 1].frame + 1;
827 
828 			debug(5, "EXTRA FRAMES: walkAnim[%d].frame = %d", _stepCount, walkAnim[_stepCount].frame);
829 
830 			walkAnim[_stepCount].step = 0;
831 			walkAnim[_stepCount].dir = walkAnim[_stepCount - 1].dir;
832 			walkAnim[_stepCount].x = walkAnim[_stepCount - 1].x;
833 			walkAnim[_stepCount].y = walkAnim[_stepCount - 1].y;
834 			_stepCount++;
835 		}
836 	}
837 }
838 
slidyWalkAnimator(WalkData * walkAnim)839 void Router::slidyWalkAnimator(WalkData *walkAnim) {
840 	/*********************************************************************
841 	 * Skidding every where HardWalk creates an animation that exactly
842 	 * fits the smoothPath and uses foot slipping to fit whole steps into
843 	 * the route
844 	 *
845 	 *	Parameters:	georgeg, mouseg
846 	 *	Returns:	rout
847 	 *
848 	 * produce a module list from the line data
849 	 *********************************************************************/
850 
851 	int32 left;
852 	int32 p;
853 	int32 lastDir;
854 	int32 lastRealDir;
855 	int32 turnDir;
856 	int32 scale;
857 	int32 step;
858 	int32 module;
859 	int32 moduleEnd;
860 	int32 module16X;
861 	int32 module16Y;
862 	int32 stepX;
863 	int32 stepY;
864 	int32 errorX;
865 	int32 errorY;
866 	int32 lastErrorX;
867 	int32 lastErrorY;
868 	int32 frameCount;
869 	int32 frames;
870 
871 	p = 0;
872 	lastDir = _modularPath[0].dir;
873 	_currentDir = _modularPath[1].dir;
874 
875 	if (_currentDir == NO_DIRECTIONS)
876 		_currentDir = lastDir;
877 
878 	_moduleX = _startX;
879 	_moduleY = _startY;
880 	module16X = _moduleX << 16;
881 	module16Y = _moduleY << 16;
882 	_stepCount = 0;
883 
884 	// START THE WALK WITH THE FIRST STANDFRAME THIS MAY CAUSE A DELAY
885 	// BUT IT STOPS THE PLAYER MOVING FOR COLLISIONS ARE DETECTED
886 
887 	debug(5, "SLIDY: STARTING THE WALK");
888 
889 	module = _framesPerChar + lastDir;
890 	walkAnim[_stepCount].frame = module;
891 	walkAnim[_stepCount].step = 0;
892 	walkAnim[_stepCount].dir = lastDir;
893 	walkAnim[_stepCount].x = _moduleX;
894 	walkAnim[_stepCount].y = _moduleY;
895 	_stepCount++;
896 
897 	// TURN TO START THE WALK
898 
899 	debug(5, "SLIDY: TURNING TO START THE WALK");
900 	// rotate if we need to
901 
902 	if (lastDir != _currentDir) {
903 		// get the direction to turn
904 		turnDir = _currentDir - lastDir;
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 new walk direction
914 		// for george and nico put in a head turn at the start
915 
916 		if (_walkData.usingStandingTurnFrames) {
917 			// new frames for turn frames	29oct95jps
918 			if (turnDir < 0)
919 				module = _firstStandingTurnLeftFrame + lastDir;
920 			else
921 				module = _firstStandingTurnRightFrame + lastDir;
922 
923 			walkAnim[_stepCount].frame = module;
924 			walkAnim[_stepCount].step = 0;
925 			walkAnim[_stepCount].dir = lastDir;
926 			walkAnim[_stepCount].x = _moduleX;
927 			walkAnim[_stepCount].y = _moduleY;
928 			_stepCount++;
929 		}
930 
931 		// rotate till were facing new dir then go back 45 degrees
932 		while (lastDir != _currentDir) {
933 			lastDir += turnDir;
934 
935 			// new frames for turn frames	29oct95jps
936 			if (turnDir < 0) {
937 				if (lastDir < 0)
938 					lastDir += NO_DIRECTIONS;
939 				module = _firstStandingTurnLeftFrame + lastDir;
940 			} else {
941 				if (lastDir > 7)
942 					lastDir -= NO_DIRECTIONS;
943 				module = _firstStandingTurnRightFrame + lastDir;
944 			}
945 
946 			walkAnim[_stepCount].frame = module;
947 			walkAnim[_stepCount].step = 0;
948 			walkAnim[_stepCount].dir = lastDir;
949 			walkAnim[_stepCount].x = _moduleX;
950 			walkAnim[_stepCount].y = _moduleY;
951 			_stepCount++;
952 		}
953 
954 		// the back 45 degrees bit
955 		// step back one because new head turn for george takes us
956 		// past the new dir
957 		_stepCount--;
958 	}
959 
960 	// his head is in the right direction
961 	lastRealDir = _currentDir;
962 
963 	// SLIDY: THE SLOW IN
964 
965 	addSlowInFrames(walkAnim);
966 
967 	// THE WALK
968 
969 	debug(5, "SLIDY: THE WALK");
970 
971 	// start the walk on the left or right leg, depending on how the
972 	// slow-in frames were drawn
973 
974 	// (0 = left; 1 = right)
975 
976 	if (_walkData.leadingLeg[_currentDir] == 0) {
977 		// start the walk on the left leg (ie. at beginning of the
978 		// first step of the walk cycle)
979 		left = 0;
980 	} else {
981 		// start the walk on the right leg (ie. at beginning of the
982 		// second step of the walk cycle)
983 		left = 1;
984 	}
985 
986 	_lastCount = _stepCount;
987 
988 	// this ensures that we don't put in turn frames for the start
989 	lastDir = 99;
990 
991 	// this ensures that we don't put in turn frames for the start
992 	_currentDir = 99;
993 
994 	do {
995 		assert(_stepCount < O_WALKANIM_SIZE);
996 		while (_modularPath[p].num == 0) {
997 			p++;
998 			if (_currentDir != 99)
999 				lastRealDir = _currentDir;
1000 			lastDir = _currentDir;
1001 			_lastCount = _stepCount;
1002 		}
1003 
1004 		// calculate average amount to lose in each step on the way
1005 		// to the next node
1006 
1007 		_currentDir = _modularPath[p].dir;
1008 
1009 		if (_currentDir < NO_DIRECTIONS) {
1010 			module = _currentDir * _framesPerStep * 2 + left * _framesPerStep;
1011 
1012 			left = !left;
1013 
1014 			moduleEnd = module + _framesPerStep;
1015 			step = 0;
1016 			scale = (_scaleA * _moduleY + _scaleB);
1017 
1018 			do {
1019 				module16X += _walkData.dx[module] * scale;
1020 				module16Y += _walkData.dy[module] * scale;
1021 				_moduleX = module16X >> 16;
1022 				_moduleY = module16Y >> 16;
1023 				walkAnim[_stepCount].frame = module;
1024 				walkAnim[_stepCount].step = step;	// normally 0,1,2,3,4,5,0,1,2,etc
1025 				walkAnim[_stepCount].dir = _currentDir;
1026 				walkAnim[_stepCount].x = _moduleX;
1027 				walkAnim[_stepCount].y = _moduleY;
1028 				_stepCount++;
1029 				step++;
1030 				module++;
1031 			} while (module < moduleEnd);
1032 
1033 			stepX = _modX[_modularPath[p].dir];
1034 			stepY = _modY[_modularPath[p].dir];
1035 			errorX = _modularPath[p].x - _moduleX;
1036 			errorX = errorX * stepX;
1037 			errorY = _modularPath[p].y - _moduleY;
1038 			errorY = errorY * stepY;
1039 
1040 			if (errorX < 0 || errorY < 0) {
1041 				_modularPath[p].num = 0;	// the end of the path
1042 
1043 				// okay those last steps took us past our
1044 				// target but do we want to scoot or moonwalk
1045 
1046 				frames = _stepCount - _lastCount;
1047 				errorX = _modularPath[p].x - walkAnim[_stepCount - 1].x;
1048 				errorY = _modularPath[p].y - walkAnim[_stepCount - 1].y;
1049 
1050 				if (frames > _framesPerStep) {
1051 					lastErrorX = _modularPath[p].x - walkAnim[_stepCount - 7].x;
1052 					lastErrorY = _modularPath[p].y - walkAnim[_stepCount - 7].y;
1053 
1054 					if (stepX == 0) {
1055 						if (3 * ABS(lastErrorY) < ABS(errorY)) {
1056 							// the last stop was
1057 							// closest
1058 							_stepCount -= _framesPerStep;
1059 							left = !left;
1060 						}
1061 					} else {
1062 						if (3 * ABS(lastErrorX) < ABS(errorX)) {
1063 							//the last stop was
1064 							// closest
1065 							_stepCount -= _framesPerStep;
1066 							left = !left;
1067 						}
1068 					}
1069 				}
1070 
1071 				errorX = _modularPath[p].x - walkAnim[_stepCount-1].x;
1072 				errorY = _modularPath[p].y - walkAnim[_stepCount-1].y;
1073 
1074 				// okay we've reached the end but we still
1075 				// have an error
1076 
1077 				if (errorX != 0) {
1078 					frameCount = 0;
1079 					frames = _stepCount - _lastCount;
1080 
1081 					do {
1082 						frameCount++;
1083 						walkAnim[_lastCount + frameCount - 1].x += errorX * frameCount / frames;
1084 					} while (frameCount < frames);
1085 				}
1086 
1087 				if (errorY != 0) {
1088 					frameCount = 0;
1089 					frames = _stepCount - _lastCount;
1090 					do {
1091 						frameCount++;
1092 						walkAnim[_lastCount + frameCount - 1].y += errorY * frameCount / frames;
1093 					} while (frameCount < frames);
1094 				}
1095 
1096 				// Now is the time to put in the turn frames
1097 				// for the last turn
1098 
1099 				if (frames < _framesPerStep) {
1100 					// this ensures that we don't put in
1101 					// turn frames for this walk or the
1102 					// next
1103 					_currentDir = 99;
1104 				}
1105 
1106 				if (_currentDir != 99)
1107 					lastRealDir = _currentDir;
1108 
1109 				// check each turn condition in turn
1110 
1111 				 // only for george
1112 				if (lastDir != 99 && _currentDir != 99 && _walkData.usingWalkingTurnFrames) {
1113 					// 1 and -7 going right -1 and 7 going
1114 					// left
1115 					lastDir = _currentDir - lastDir;
1116 
1117 					if (lastDir == -1 || lastDir == 7 || lastDir == -2 || lastDir == 6) {
1118 						// turn at the end of the last
1119 						// walk
1120 
1121 						_frame = _lastCount - _framesPerStep;
1122 						do {
1123 							// turning left
1124 							walkAnim[_frame].frame += _firstWalkingTurnLeftFrame;
1125 							_frame++;
1126 						} while (_frame < _lastCount);
1127 					} else if (lastDir == 1 || lastDir == -7 || lastDir == 2 || lastDir == -6) {
1128 						// turn at the end of the
1129 						// current walk
1130 
1131 						_frame = _lastCount - _framesPerStep;
1132 						do {
1133 							// turning right
1134 							walkAnim[_frame].frame += _firstWalkingTurnRightFrame;
1135 							_frame++;
1136 						} while (_frame < _lastCount);
1137 					}
1138 					lastDir = _currentDir;
1139 				}
1140 
1141 				// all turns checked
1142 
1143 				_lastCount = _stepCount;
1144 				_moduleX = walkAnim[_stepCount - 1].x;
1145 				_moduleY = walkAnim[_stepCount - 1].y;
1146 				module16X = _moduleX << 16;
1147 				module16Y = _moduleY << 16;
1148 			}
1149 		}
1150 	} while (_modularPath[p].dir < NO_DIRECTIONS);
1151 
1152 #ifdef SWORD2_DEBUG
1153 	if (lastRealDir == 99)
1154 		error("slidyWalkAnimatorlast direction error");
1155 #endif
1156 
1157 	// THE SLOW OUT
1158 	addSlowOutFrames(walkAnim);
1159 
1160 	// TURNS TO END THE WALK ?
1161 
1162 	// We've done the walk now put in any turns at the end
1163 
1164 	if (_targetDir == 8) {
1165 		// ANY direction -> stand in the last direction
1166 
1167 		module = _firstStandFrame + lastRealDir;
1168 		_targetDir = lastRealDir;
1169 		walkAnim[_stepCount].frame = module;
1170 		walkAnim[_stepCount].step = 0;
1171 		walkAnim[_stepCount].dir = lastRealDir;
1172 		walkAnim[_stepCount].x = _moduleX;
1173 		walkAnim[_stepCount].y = _moduleY;
1174 		_stepCount++;
1175 	}
1176 
1177 	if (_targetDir == 9) {
1178 		// 'stance' was non-zero
1179 		if (_stepCount == 0) {
1180 			module = _framesPerChar + lastRealDir;
1181 			walkAnim[_stepCount].frame = module;
1182 			walkAnim[_stepCount].step = 0;
1183 			walkAnim[_stepCount].dir = lastRealDir;
1184 			walkAnim[_stepCount].x = _moduleX;
1185 			walkAnim[_stepCount].y = _moduleY;
1186 			_stepCount++;
1187 		}
1188 	} else if (_targetDir != lastRealDir) {
1189 		// rotate to target direction
1190 		turnDir = _targetDir - lastRealDir;
1191 		if (turnDir < 0)
1192 			turnDir += NO_DIRECTIONS;
1193 
1194 		if (turnDir > 4)
1195 			turnDir = -1;
1196 		else if (turnDir > 0)
1197 			turnDir = 1;
1198 
1199 		// rotate to target direction
1200 		// for george and nico put in a head turn at the start
1201 
1202 		if (_walkData.usingStandingTurnFrames) {
1203 			// new frames for turn frames	29oct95jps
1204 			if (turnDir < 0)
1205 				module = _firstStandingTurnLeftFrame + lastDir;
1206 			else
1207 				module = _firstStandingTurnRightFrame + lastDir;
1208 
1209 			walkAnim[_stepCount].frame = module;
1210 			walkAnim[_stepCount].step = 0;
1211 			walkAnim[_stepCount].dir = lastRealDir;
1212 			walkAnim[_stepCount].x = _moduleX;
1213 			walkAnim[_stepCount].y = _moduleY;
1214 			_stepCount++;
1215 		}
1216 
1217 		// rotate if we need to
1218 
1219 		while (lastRealDir != _targetDir) {
1220 			lastRealDir += turnDir;
1221 
1222 			// new frames for turn frames	29oct95jps
1223 			if (turnDir < 0) {
1224 				if (lastRealDir < 0)
1225 					lastRealDir += NO_DIRECTIONS;
1226 				module = _firstStandingTurnLeftFrame + lastRealDir;
1227 			} else {
1228 				if (lastRealDir > 7)
1229 					lastRealDir -= NO_DIRECTIONS;
1230 				module = _firstStandingTurnRightFrame + lastRealDir;
1231 			}
1232 
1233 			walkAnim[_stepCount].frame = module;
1234 			walkAnim[_stepCount].step = 0;
1235 			walkAnim[_stepCount].dir = lastRealDir;
1236 			walkAnim[_stepCount].x = _moduleX;
1237 			walkAnim[_stepCount].y = _moduleY;
1238 			_stepCount++;
1239 		}
1240 
1241 		module = _firstStandFrame + lastRealDir;
1242 		walkAnim[_stepCount - 1].frame = module;
1243 	} else {
1244 		// just stand at the end
1245 		module = _firstStandFrame + lastRealDir;
1246 		walkAnim[_stepCount].frame = module;
1247 		walkAnim[_stepCount].step = 0;
1248 		walkAnim[_stepCount].dir = lastRealDir;
1249 		walkAnim[_stepCount].x = _moduleX;
1250 		walkAnim[_stepCount].y = _moduleY;
1251 		_stepCount++;
1252 	}
1253 
1254 	walkAnim[_stepCount].frame = 512;
1255 	walkAnim[_stepCount].step = 99;
1256 	_stepCount++;
1257 
1258 	walkAnim[_stepCount].frame = 512;
1259 	walkAnim[_stepCount].step = 99;
1260 	_stepCount++;
1261 
1262 	walkAnim[_stepCount].frame = 512;
1263 	walkAnim[_stepCount].step = 99;
1264 
1265 	// write all the frames to "debug.txt"
1266 	debug(5, "THE WALKDATA:");
1267 
1268 	for (_frame = 0; _frame <= _stepCount; _frame++)
1269 		debug(5, "walkAnim[%d].frame=%d", _frame, walkAnim[_frame].frame);
1270 
1271 	debug(5, "routeFinder RouteSize is %d", _stepCount);
1272 	return;
1273 }
1274 
1275 #ifndef FORCE_SLIDY
1276 
1277 // THE SOLID PATH ROUTINES
1278 
solidPath()1279 void Router::solidPath() {
1280 	/*********************************************************************
1281 	 * SolidPath creates a path based on whole steps with no sliding to
1282 	 * get as near as possible to the target without any sliding this
1283 	 * routine is currently unused, but is intended for use when just
1284 	 * clicking about.
1285 	 *
1286 	 * produce a module list from the line data
1287 	 *********************************************************************/
1288 
1289 	int32 smooth;
1290 	int32 solid;
1291 	int32 scale;
1292 	int32 stepX;
1293 	int32 stepY;
1294 	int32 deltaX;
1295 	int32 deltaY;
1296 
1297 	// strip out the short sections
1298 
1299 	solid = 1;
1300 	smooth = 1;
1301 	_modularPath[0].x = _smoothPath[0].x;
1302 	_modularPath[0].y = _smoothPath[0].y;
1303 	_modularPath[0].dir = _smoothPath[0].dir;
1304 	_modularPath[0].num = 0;
1305 
1306 	do {
1307 		scale = _scaleA * _smoothPath[smooth].y + _scaleB;
1308 		deltaX = _smoothPath[smooth].x - _modularPath[solid - 1].x;
1309 		deltaY = _smoothPath[smooth].y - _modularPath[solid - 1].y;
1310 		stepX = _modX[_smoothPath[smooth].dir];
1311 		stepY = _modY[_smoothPath[smooth].dir];
1312 		stepX = stepX * scale;
1313 		stepY = stepY * scale;
1314 		stepX = stepX >> 16;
1315 		stepY = stepY >> 16;
1316 
1317 		if (ABS(deltaX) >= ABS(stepX) && ABS(deltaY) >= ABS(stepY)) {
1318 			_modularPath[solid].x = _smoothPath[smooth].x;
1319 			_modularPath[solid].y = _smoothPath[smooth].y;
1320 			_modularPath[solid].dir = _smoothPath[smooth].dir;
1321 			_modularPath[solid].num = 1;
1322 			solid++;
1323 		}
1324 
1325 		smooth++;
1326 	} while (_smoothPath[smooth].num < ROUTE_END_FLAG);
1327 
1328 	// in case the last bit had no steps
1329 
1330 	if (solid == 1) {
1331 		// there were no paths so put in a dummy end
1332 		solid = 2;
1333 		_modularPath[1].dir = _smoothPath[0].dir;
1334 		_modularPath[1].num = 0;
1335 	}
1336 
1337 	_modularPath[solid - 1].x = _smoothPath[smooth - 1].x;
1338 	_modularPath[solid - 1].y = _smoothPath[smooth - 1].y;
1339 
1340 	// set up the end of the walk
1341 	_modularPath[solid].x = _smoothPath[smooth - 1].x;
1342 	_modularPath[solid].y = _smoothPath[smooth - 1].y;
1343 	_modularPath[solid].dir = 9;
1344 	_modularPath[solid].num = ROUTE_END_FLAG;
1345 }
1346 
solidWalkAnimator(WalkData * walkAnim)1347 int32 Router::solidWalkAnimator(WalkData *walkAnim) {
1348 	/*********************************************************************
1349 	 * SolidWalk creates an animation based on whole steps with no sliding
1350 	 * to get as near as possible to the target without any sliding. This
1351 	 * routine is is intended for use when just clicking about.
1352 	 *
1353 	 * produce a module list from the line data
1354 	 *
1355 	 * returns 0 if solid route not found
1356 	 *********************************************************************/
1357 
1358 	int32 left;
1359 	int32 turnDir;
1360 	int32 scale;
1361 	int32 step;
1362 	int32 errorX;
1363 	int32 errorY;
1364 	int32 moduleEnd;
1365 	bool slowStart = false;
1366 
1367 	// start at the beginning for a change
1368 
1369 	int32 lastDir = _modularPath[0].dir;
1370 	int32 module = _framesPerChar + lastDir;
1371 
1372 	_currentDir = _modularPath[1].dir;
1373 	_moduleX = _startX;
1374 	_moduleY = _startY;
1375 	_stepCount = 0;
1376 
1377 	int32 module16X = _moduleX << 16;
1378 	int32 module16Y = _moduleY << 16;
1379 
1380 	// START THE WALK WITH THE FIRST STANDFRAME THIS MAY CAUSE A DELAY
1381 	// BUT IT STOPS THE PLAYER MOVING FOR COLLISIONS ARE DETECTED
1382 
1383 	debug(5, "SOLID: STARTING THE WALK");
1384 	walkAnim[_stepCount].frame = module;
1385 	walkAnim[_stepCount].step = 0;
1386 	walkAnim[_stepCount].dir = lastDir;
1387 	walkAnim[_stepCount].x = _moduleX;
1388 	walkAnim[_stepCount].y = _moduleY;
1389 	_stepCount++;
1390 
1391 	// TURN TO START THE WALK
1392 
1393 	debug(5, "SOLID: TURNING TO START THE WALK");
1394 
1395 	// rotate if we need to
1396 
1397 	if (lastDir != _currentDir) {
1398 		// get the direction to turn
1399 		turnDir = _currentDir - lastDir;
1400 		if (turnDir < 0)
1401 			turnDir += NO_DIRECTIONS;
1402 
1403 		if (turnDir > 4)
1404 			turnDir = -1;
1405 		else if (turnDir > 0)
1406 			turnDir = 1;
1407 
1408 		// rotate to new walk direction
1409 		// for george and nico put in a head turn at the start
1410 
1411 		if (_walkData.usingStandingTurnFrames) {
1412 			// new frames for turn frames	29oct95jps
1413 			if (turnDir < 0)
1414 				module = _firstStandingTurnLeftFrame + lastDir;
1415 			else
1416 				module = _firstStandingTurnRightFrame + lastDir;
1417 
1418 			walkAnim[_stepCount].frame = module;
1419 			walkAnim[_stepCount].step = 0;
1420 			walkAnim[_stepCount].dir = lastDir;
1421 			walkAnim[_stepCount].x = _moduleX;
1422 			walkAnim[_stepCount].y = _moduleY;
1423 			_stepCount++;
1424 		}
1425 
1426 		// rotate till were facing new dir then go back 45 degrees
1427 
1428 		while (lastDir != _currentDir) {
1429 			lastDir += turnDir;
1430 
1431 			// new frames for turn frames
1432 			if (turnDir < 0) {
1433 				if (lastDir < 0)
1434 					lastDir += NO_DIRECTIONS;
1435 				module = _firstStandingTurnLeftFrame + lastDir;
1436 			} else {
1437 				if (lastDir > 7)
1438 					lastDir -= NO_DIRECTIONS;
1439 				module = _firstStandingTurnRightFrame + lastDir;
1440 			}
1441 
1442 			walkAnim[_stepCount].frame = module;
1443 			walkAnim[_stepCount].step = 0;
1444 			walkAnim[_stepCount].dir = lastDir;
1445 			walkAnim[_stepCount].x = _moduleX;
1446 			walkAnim[_stepCount].y = _moduleY;
1447 			_stepCount++;
1448 		}
1449 
1450 		// the back 45 degrees bit
1451 		// step back one because new head turn for george takes us
1452 		// past the new dir
1453 
1454 		_stepCount--;
1455 	}
1456 
1457 	// THE SLOW IN
1458 
1459 	slowStart = addSlowInFrames(walkAnim);
1460 
1461 	// THE WALK
1462 
1463 	debug(5, "SOLID: THE WALK");
1464 
1465 	// start the walk on the left or right leg, depending on how the
1466 	// slow-in frames were drawn
1467 
1468 	// (0 = left; 1 = right)
1469 	if (_walkData.leadingLeg[_currentDir] == 0) {
1470 		// start the walk on the left leg (ie. at beginning of the
1471 		// first step of the walk cycle)
1472 		left = 0;
1473 	} else {
1474 		// start the walk on the right leg (ie. at beginning of the
1475 		// second step of the walk cycle)
1476 		left = 1;
1477 	}
1478 
1479 	_lastCount = _stepCount;
1480 
1481 	// this ensures that we don't put in turn frames for the start
1482 	lastDir = 99;
1483 
1484 	// this ensures that we don't put in turn frames for the start
1485 	_currentDir = 99;
1486 
1487 	int32 p;
1488 
1489 	 for (p = 1; _modularPath[p].dir < NO_DIRECTIONS; ++p) {
1490 		while (_modularPath[p].num > 0) {
1491 			_currentDir = _modularPath[p].dir;
1492 			if (_currentDir < NO_DIRECTIONS) {
1493 				module = _currentDir * _framesPerStep * 2 + left * _framesPerStep;
1494 
1495 				left = !left;
1496 
1497 				moduleEnd = module + _framesPerStep;
1498 				step = 0;
1499 				scale = (_scaleA * _moduleY + _scaleB);
1500 
1501 				do {
1502 					module16X += _walkData.dx[module] * scale;
1503 					module16Y += _walkData.dy[module] * scale;
1504 					_moduleX = module16X >> 16;
1505 					_moduleY = module16Y >> 16;
1506 					walkAnim[_stepCount].frame = module;
1507 					walkAnim[_stepCount].step = step;	// normally 0,1,2,3,4,5,0,1,2,etc
1508 					walkAnim[_stepCount].dir = _currentDir;
1509 					walkAnim[_stepCount].x = _moduleX;
1510 					walkAnim[_stepCount].y = _moduleY;
1511 					_stepCount++;
1512 					module++;
1513 					step++;
1514 				} while (module < moduleEnd);
1515 
1516 				errorX = _modularPath[p].x - _moduleX;
1517 				errorX = errorX * _modX[_modularPath[p].dir];
1518 				errorY = _modularPath[p].y - _moduleY;
1519 				errorY = errorY * _modY[_modularPath[p].dir];
1520 
1521 				if (errorX < 0 || errorY < 0) {
1522 					_modularPath[p].num = 0;
1523 					_stepCount -= _framesPerStep;
1524 
1525 					left = !left;
1526 
1527 					// Okay this is the end of a section
1528 
1529 					_moduleX = walkAnim[_stepCount - 1].x;
1530 					_moduleY = walkAnim[_stepCount - 1].y;
1531 					module16X = _moduleX << 16;
1532 					module16Y = _moduleY << 16;
1533 					_modularPath[p].x = _moduleX;
1534 					_modularPath[p].y = _moduleY;
1535 
1536 					// Now is the time to put in the turn
1537 					// frames for the last turn
1538 
1539 					if (_stepCount - _lastCount < _framesPerStep) {
1540 						// no step taken
1541 
1542 						// clean up if a slow in but no
1543 						// walk
1544 
1545 						if (slowStart) {
1546 							_stepCount -= _walkData.nSlowInFrames[_currentDir];
1547 							_lastCount -= _walkData.nSlowInFrames[_currentDir];
1548 							slowStart = false;
1549 						}
1550 
1551 						// this ensures that we don't
1552 						// put in turn frames for this
1553 						// walk or the next
1554 
1555 						_currentDir = 99;
1556 					}
1557 
1558 					// check each turn condition in turn
1559 					if (lastDir != 99 && _currentDir != 99 && _walkData.usingWalkingTurnFrames) {
1560 						// only for george
1561 						// 1 and -7 going right -1 and
1562 						// 7 going left
1563 
1564 						lastDir = _currentDir - lastDir;
1565 
1566 						if (lastDir == -1 || lastDir == 7 || lastDir == -2 || lastDir == 6) {
1567 							// turn at the end of
1568 							// the last walk
1569 
1570 							_frame = _lastCount - _framesPerStep;
1571 
1572 							do {
1573 								// turning left
1574 								walkAnim[_frame].frame += _firstWalkingTurnLeftFrame;
1575 								_frame++;
1576 							} while (_frame < _lastCount);
1577 						} else if (lastDir == 1 || lastDir == -7 || lastDir == 2 || lastDir == -6) {
1578 							// turn at the end of
1579 							// the current walk
1580 
1581 							_frame = _lastCount - _framesPerStep;
1582 							do {
1583 								// turning right
1584 								walkAnim[_frame].frame += _firstWalkingTurnRightFrame;
1585 								_frame++;
1586 							} while (_frame < _lastCount);
1587 						}
1588 					}
1589 
1590 					// all turns checked
1591 					_lastCount = _stepCount;
1592 				}
1593 			}
1594 		}
1595 		lastDir = _currentDir;
1596 
1597 		// can only be valid first time round
1598 		slowStart = false;
1599 	}
1600 
1601 	// THE SLOW OUT
1602 
1603 	addSlowOutFrames(walkAnim);
1604 
1605 	module = _framesPerChar + _modularPath[p - 1].dir;
1606 	walkAnim[_stepCount].frame = module;
1607 	walkAnim[_stepCount].step = 0;
1608 	walkAnim[_stepCount].dir = _modularPath[p - 1].dir;
1609 	walkAnim[_stepCount].x = _moduleX;
1610 	walkAnim[_stepCount].y = _moduleY;
1611 	_stepCount++;
1612 
1613 	walkAnim[_stepCount].frame = 512;
1614 	walkAnim[_stepCount].step = 99;
1615 	_stepCount++;
1616 
1617 	walkAnim[_stepCount].frame = 512;
1618 	walkAnim[_stepCount].step = 99;
1619 	_stepCount++;
1620 
1621 	walkAnim[_stepCount].frame = 512;
1622 	walkAnim[_stepCount].step = 99;
1623 
1624 	debug(5, "THE WALKDATA:");
1625 
1626 	for (_frame = 0; _frame <= _stepCount; _frame++)
1627 		debug(5, "walkAnim[%d].frame=%d", _frame, walkAnim[_frame].frame);
1628 
1629 	// NO END TURNS
1630 
1631 	debug(5, "routeFinder RouteSize is %d", _stepCount);
1632 	// now check the route
1633 
1634 	for (int i = 0; i < p - 1; ++i) {
1635 		if (!check(_modularPath[i].x, _modularPath[i].y, _modularPath[i + 1].x, _modularPath[i + 1].y))
1636 			p = 0;
1637 	}
1638 
1639 	if (p != 0) {
1640 		_targetDir = _modularPath[p - 1].dir;
1641 		if (checkTarget(_moduleX, _moduleY) == 3) {
1642 			// new target on a line
1643 			p = 0;
1644 			debug(5, "Solid walk target was on a line %d %d", _moduleX, _moduleY);
1645 		}
1646 	}
1647 
1648 	return p;
1649 }
1650 #endif
1651 
1652 // THE SCAN ROUTINES
1653 
scan(int32 level)1654 bool Router::scan(int32 level) {
1655 	/*********************************************************************
1656 	 * Called successively from routeFinder	until no more changes take
1657 	 * place in the grid array, ie he best path has been found
1658 	 *
1659 	 * Scans through every point in the node array and checks if there is
1660 	 * a route between each point and if this route gives a new route.
1661 	 *
1662 	 * This routine could probably halve its processing time if it doubled
1663 	 * up on the checks after each route check
1664 	 *
1665 	 *********************************************************************/
1666 
1667 	int32 x1, y1, x2, y2;
1668 	int32 distance;
1669 	bool changed = false;
1670 
1671 	// For all the nodes that have new values and a distance less than
1672 	// enddist, ie dont check for new routes from a point we checked
1673 	// before or from a point that is already further away than the best
1674 	// route so far.
1675 
1676 	for (int i = 0; i < _nNodes; i++) {
1677 		if (_node[i].dist < _node[_nNodes].dist && _node[i].level == level) {
1678 			x1 = _node[i].x;
1679 			y1 = _node[i].y;
1680 
1681 			for (int j = _nNodes; j > 0; j--) {
1682 				if (_node[j].dist > _node[i].dist) {
1683 					x2 = _node[j].x;
1684 					y2 = _node[j].y;
1685 
1686 					if (ABS(x2 - x1) > 4.5 * ABS(y2 - y1))
1687 						distance = (8 * ABS(x2 - x1) + 18 * ABS(y2 - y1)) / (54 * 8) + 1;
1688 					else
1689 						distance = (6 * ABS(x2 - x1) + 36 * ABS(y2 - y1)) / (36 * 14) + 1;
1690 
1691 					if (distance + _node[i].dist < _node[_nNodes].dist && distance + _node[i].dist < _node[j].dist) {
1692 						if (newCheck(0, x1, y1, x2, y2)) {
1693 							_node[j].level = level + 1;
1694 							_node[j].dist = distance + _node[i].dist;
1695 							_node[j].prev = i;
1696 							changed = true;
1697 						}
1698 					}
1699 				}
1700 			}
1701 		}
1702 	}
1703 
1704 	return changed;
1705 }
1706 
newCheck(int32 status,int32 x1,int32 y1,int32 x2,int32 y2)1707 int32 Router::newCheck(int32 status, int32 x1, int32 y1, int32 x2, int32 y2) {
1708 	/*********************************************************************
1709 	 * newCheck routine checks if the route between two points can be
1710 	 * achieved without crossing any of the bars in the Bars array.
1711 	 *
1712 	 * newCheck differs from check in that that 4 route options are
1713 	 * considered corresponding to actual walked routes.
1714 	 *
1715 	 * Note distance doesn't take account of shrinking ???
1716 	 *
1717 	 * Note Bars array must be properly calculated ie min max dx dy co
1718 	 *********************************************************************/
1719 
1720 	int32 ldx;
1721 	int32 ldy;
1722 	int32 dlx;
1723 	int32 dly;
1724 	int32 dirX;
1725 	int32 dirY;
1726 	int32 step1;
1727 	int32 step2;
1728 	int32 step3;
1729 	int32 steps;
1730 	int32 options;
1731 
1732 	steps = 0;
1733 	options = 0;
1734 	ldx = x2 - x1;
1735 	ldy = y2 - y1;
1736 	dirX = 1;
1737 	dirY = 1;
1738 
1739 	if (ldx < 0) {
1740 		ldx = -ldx;
1741 		dirX = -1;
1742 	}
1743 
1744 	if (ldy < 0) {
1745 		ldy = -ldy;
1746 		dirY = -1;
1747 	}
1748 
1749 	// make the route options
1750 
1751 	if (_diagonaly * ldx > _diagonalx * ldy) {
1752 		// dir  = 1,2 or 2,3 or 5,6 or 6,7
1753 
1754 		dly = ldy;
1755 		dlx = (ldy * _diagonalx) / _diagonaly;
1756 		ldx = ldx - dlx;
1757 		dlx = dlx * dirX;
1758 		dly = dly * dirY;
1759 		ldx = ldx * dirX;
1760 		ldy = 0;
1761 
1762 		// options are square, diagonal a code 1 route
1763 		step1 = check(x1, y1, x1 + ldx, y1);
1764 		if (step1 != 0) {
1765 			step2 = check(x1 + ldx, y1, x2, y2);
1766 			if (step2 != 0) {
1767 				steps = step1 + step2;
1768 				options |= 2;
1769 			}
1770 		}
1771 
1772 		// diagonal, square a code 2 route
1773 		if (steps == 0 || status == 1) {
1774 			step1 = check(x1, y1, x1 + dlx, y1 + dly);
1775 			if (step1 != 0) {
1776 				step2 = check(x1 + dlx, y2, x2, y2);
1777 				if (step2 != 0) {
1778 					steps = step1 + step2;
1779 					options |= 4;
1780 				}
1781 			}
1782 		}
1783 
1784 		// halfsquare, diagonal, halfsquare a code 0 route
1785 		if (steps == 0 || status == 1) {
1786 			step1 = check(x1, y1, x1 + ldx / 2, y1);
1787 			if (step1 != 0) {
1788 				step2 = check(x1 + ldx / 2, y1, x1 + ldx / 2 + dlx, y2);
1789 				if (step2 != 0) {
1790 					step3 = check(x1 + ldx / 2 + dlx, y2, x2, y2);
1791 					if (step3 != 0)	{
1792 						steps = step1 + step2 + step3;
1793 						options |= 1;
1794 					}
1795 				}
1796 			}
1797 		}
1798 
1799 		// halfdiagonal, square, halfdiagonal a code 3 route
1800 		if (steps == 0 || status == 1) {
1801 			step1 = check(x1, y1, x1 + dlx / 2, y1 + dly / 2);
1802 			if (step1 != 0) {
1803 				step2 = check(x1 + dlx / 2, y1 + dly / 2, x1 + ldx + dlx / 2, y1 + dly / 2);
1804 				if (step2 != 0) {
1805 					step3 = check(x1 + ldx + dlx / 2, y1 + dly / 2, x2, y2);
1806 					if (step3 != 0) {
1807 						steps = step1 + step2 + step3;
1808 						options |= 8;
1809 					}
1810 				}
1811 			}
1812 		}
1813 	} else {
1814 		// dir  = 7,0 or 0,1 or 3,4 or 4,5
1815 
1816 		dlx = ldx;
1817 		dly = (ldx * _diagonaly) / _diagonalx;
1818 		ldy = ldy - dly;
1819 		dlx = dlx * dirX;
1820 		dly = dly * dirY;
1821 		ldy = ldy * dirY;
1822 		ldx = 0;
1823 
1824 		// options are square, diagonal a code 1 route
1825 		step1 = check(x1 ,y1, x1, y1 + ldy);
1826 		if (step1 != 0)	{
1827 			step2 = check(x1, y1 + ldy, x2, y2);
1828 			if (step2 != 0) {
1829 				steps = step1 + step2;
1830 				options |= 2;
1831 			}
1832 		}
1833 
1834 		// diagonal, square a code 2 route
1835 		if (steps == 0 || status == 1) {
1836 			step1 = check(x1, y1, x2, y1 + dly);
1837 			if (step1 != 0) {
1838 				step2 = check(x2, y1 + dly, x2, y2);
1839 				if (step2 != 0) {
1840 					steps = step1 + step2;
1841 					options |= 4;
1842 				}
1843 			}
1844 		}
1845 
1846 		// halfsquare, diagonal, halfsquare a code 0 route
1847 		if (steps == 0 || status == 1) {
1848 			step1 = check(x1, y1, x1, y1 + ldy / 2);
1849 			if (step1 != 0) {
1850 				step2 = check(x1, y1 + ldy / 2, x2, y1 + ldy / 2 + dly);
1851 				if (step2 != 0) {
1852 					step3 = check(x2, y1 + ldy / 2 + dly, x2, y2);
1853 					if (step3 != 0) {
1854 						steps = step1 + step2 + step3;
1855 						options |= 1;
1856 					}
1857 				}
1858 			}
1859 		}
1860 
1861 		// halfdiagonal, square, halfdiagonal a code 3 route
1862 		if (steps == 0 || status == 1) {
1863 			step1 = check(x1, y1, x1 + dlx / 2, y1 + dly / 2);
1864 			if (step1 != 0) {
1865 				step2 = check(x1 + dlx / 2, y1 + dly / 2, x1 + dlx / 2, y1 + ldy + dly / 2);
1866 				if (step2 != 0) {
1867 					step3 = check(x1 + dlx / 2, y1 + ldy + dly / 2, x2, y2);
1868 					if (step3 != 0)	{
1869 						steps = step1 + step2 + step3;
1870 						options |= 8;
1871 					}
1872 				}
1873 			}
1874 		}
1875 	}
1876 
1877 	if (status == 0)
1878 		status = steps;
1879 	else
1880 		status = options;
1881 
1882 	return status;
1883 }
1884 
1885 // CHECK ROUTINES
1886 
check(int32 x1,int32 y1,int32 x2,int32 y2)1887 bool Router::check(int32 x1, int32 y1, int32 x2, int32 y2) {
1888 	// call the fastest line check for the given line
1889 	// returns true if line didn't cross any bars
1890 
1891 	if (x1 == x2 && y1 == y2)
1892 		return true;
1893 
1894 	if (x1 == x2)
1895 		return vertCheck(x1, y1, y2);
1896 
1897 	if (y1 == y2)
1898 		return horizCheck(x1, y1, x2);
1899 
1900 	return lineCheck(x1, y1, x2, y2);
1901 }
1902 
lineCheck(int32 x1,int32 y1,int32 x2,int32 y2)1903 bool Router::lineCheck(int32 x1, int32 y1, int32 x2, int32 y2) {
1904 	bool linesCrossed = true;
1905 
1906 	int32 xmin = MIN(x1, x2);
1907 	int32 xmax = MAX(x1, x2);
1908 	int32 ymin = MIN(y1, y2);
1909 	int32 ymax = MAX(y1, y2);
1910 
1911 	// Line set to go one step in chosen direction so ignore if it hits
1912 	// anything
1913 
1914 	int32 dirx = x2 - x1;
1915 	int32 diry = y2 - y1;
1916 
1917 	int32 co = (y1 * dirx) - (x1 * diry);		// new line equation
1918 
1919 	for (int i = 0; i < _nBars && linesCrossed; i++) {
1920 		// skip if not on module
1921 		if (xmax >= _bars[i].xmin && xmin <= _bars[i].xmax && ymax >= _bars[i].ymin && ymin <= _bars[i].ymax) {
1922 			// Okay, it's a valid line. Calculate an intercept. Wow
1923 			// but all this arithmetic we must have loads of time
1924 
1925 			// slope it he slope between the two lines
1926 			int32 slope = (_bars[i].dx * diry) - (_bars[i].dy *dirx);
1927 			// assuming parallel lines don't cross
1928 			if (slope != 0) {
1929 				// calculate x intercept and check its on both
1930 				// lines
1931 				int32 xc = ((_bars[i].co * dirx) - (co * _bars[i].dx)) / slope;
1932 
1933 				// skip if not on module
1934 				if (xc >= xmin - 1 && xc <= xmax + 1) {
1935 					// skip if not on line
1936 					if (xc >= _bars[i].xmin - 1 && xc <= _bars[i].xmax + 1) {
1937 						int32 yc = ((_bars[i].co * diry) - (co * _bars[i].dy)) / slope;
1938 
1939 						// skip if not on module
1940 						if (yc >= ymin - 1 && yc <= ymax + 1) {
1941 							// skip if not on line
1942 							if (yc >= _bars[i].ymin - 1 && yc <= _bars[i].ymax + 1) {
1943 								linesCrossed = false;
1944 							}
1945 						}
1946 					}
1947 				}
1948 			}
1949 		}
1950 	}
1951 
1952 	return linesCrossed;
1953 }
1954 
horizCheck(int32 x1,int32 y,int32 x2)1955 bool Router::horizCheck(int32 x1, int32 y, int32 x2) {
1956 	bool linesCrossed = true;
1957 
1958 	int32 xmin = MIN(x1, x2);
1959 	int32 xmax = MAX(x1, x2);
1960 
1961 	// line set to go one step in chosen direction so ignore if it hits
1962 	// anything
1963 
1964 	for (int i = 0; i < _nBars && linesCrossed; i++) {
1965 		// skip if not on module
1966 		if (xmax >= _bars[i].xmin && xmin <= _bars[i].xmax && y >= _bars[i].ymin && y <= _bars[i].ymax) {
1967 			// Okay, it's a valid line calculate an intercept. Wow
1968 			// but all this arithmetic we must have loads of time
1969 
1970 			if (_bars[i].dy == 0)
1971 				linesCrossed = false;
1972 			else {
1973 				int32 ldy = y - _bars[i].y1;
1974 				int32 xc = _bars[i].x1 + (_bars[i].dx * ldy) / _bars[i].dy;
1975 				// skip if not on module
1976 				if (xc >= xmin - 1 && xc <= xmax + 1)
1977 					linesCrossed = false;
1978 			}
1979 		}
1980 	}
1981 
1982 	return linesCrossed;
1983 }
1984 
vertCheck(int32 x,int32 y1,int32 y2)1985 bool Router::vertCheck(int32 x, int32 y1, int32 y2) {
1986 	bool linesCrossed = true;
1987 
1988 	int32 ymin = MIN(y1, y2);
1989 	int32 ymax = MAX(y1, y2);
1990 
1991 	// Line set to go one step in chosen direction so ignore if it hits
1992 	// anything
1993 
1994 	for (int i = 0; i < _nBars && linesCrossed; i++) {
1995 		// skip if not on module
1996 		if (x >= _bars[i].xmin && x <= _bars[i].xmax && ymax >= _bars[i].ymin && ymin <= _bars[i].ymax) {
1997 			// Okay, it's a valid line calculate an intercept. Wow
1998 			// but all this arithmetic we must have loads of time
1999 
2000 			// both lines vertical and overlap in x and y so they
2001 			// cross
2002 
2003 			if (_bars[i].dx == 0)
2004 				linesCrossed = false;
2005 			else {
2006 				int32 ldx = x - _bars[i].x1;
2007 				int32 yc = _bars[i].y1 + (_bars[i].dy * ldx) / _bars[i].dx;
2008 				// the intercept overlaps
2009 				if (yc >= ymin - 1 && yc <= ymax + 1)
2010 					linesCrossed = false;
2011 			}
2012 		}
2013 	}
2014 
2015 	return linesCrossed;
2016 }
2017 
checkTarget(int32 x,int32 y)2018 int32 Router::checkTarget(int32 x, int32 y) {
2019 	int32 onLine = 0;
2020 
2021 	int32 xmin = x - 1;
2022 	int32 xmax = x + 1;
2023 	int32 ymin = y - 1;
2024 	int32 ymax = y + 1;
2025 
2026 	// check if point +- 1 is on the line
2027 	// so ignore if it hits anything
2028 
2029 	for (int i = 0; i < _nBars && onLine == 0; i++) {
2030 		// overlapping line
2031 		if (xmax >= _bars[i].xmin && xmin <= _bars[i].xmax && ymax >= _bars[i].ymin && ymin <= _bars[i].ymax) {
2032 			int32 xc, yc;
2033 
2034 			// okay this line overlaps the target calculate an y intercept for x
2035 
2036 			// vertical line so we know it overlaps y
2037 			if (_bars[i].dx == 0)
2038 				yc = 0;
2039 			else {
2040 				int ldx = x - _bars[i].x1;
2041 				yc = _bars[i].y1 + (_bars[i].dy * ldx) / _bars[i].dx;
2042 			}
2043 
2044 			// overlapping point for y
2045 			if (yc >= ymin && yc <= ymax) {
2046 				// target on a line so drop out
2047 				onLine = 3;
2048 				debug(5, "RouteFail due to target on a line %d %d", x, y);
2049 			} else {
2050 				// vertical line so we know it overlaps y
2051 				if (_bars[i].dy == 0)
2052 					xc = 0;
2053 				else {
2054 					int32 ldy = y - _bars[i].y1;
2055 					xc = _bars[i].x1 + (_bars[i].dx * ldy) / _bars[i].dy;
2056 				}
2057 
2058 				// skip if not on module
2059 				if (xc >= xmin && xc <= xmax) {
2060 					// target on a line so drop out
2061 					onLine = 3;
2062 					debug(5, "RouteFail due to target on a line %d %d", x, y);
2063 				}
2064 			}
2065 		}
2066 	}
2067 
2068 	return onLine;
2069 }
2070 
2071 // THE SETUP ROUTINES
2072 
loadWalkData(byte * ob_walkdata)2073 void Router::loadWalkData(byte *ob_walkdata) {
2074 	uint16 firstFrameOfDirection;
2075 	uint16 walkFrameNo;
2076 	uint32 frameCounter = 0; // starts at frame 0 of mega set
2077 	int i;
2078 
2079 	_walkData.read(ob_walkdata);
2080 
2081 	// 0 = not using slow out frames; non-zero = using that many frames
2082 	// for each leading leg for each direction
2083 
2084 	_numberOfSlowOutFrames = _walkData.usingSlowOutFrames;
2085 
2086 	for (i = 0; i < NO_DIRECTIONS; i++) {
2087 		firstFrameOfDirection = i * _walkData.nWalkFrames;
2088 
2089 		_modX[i] = 0;
2090 		_modY[i] = 0;
2091 
2092 		for (walkFrameNo = firstFrameOfDirection; walkFrameNo < firstFrameOfDirection + _walkData.nWalkFrames / 2; walkFrameNo++) {
2093 			// eg. _modX[0] is the sum of the x-step sizes for the
2094 			// first half of the walk cycle for direction 0
2095 			_modX[i] += _walkData.dx[walkFrameNo];
2096 			_modY[i] += _walkData.dy[walkFrameNo];
2097 		}
2098 	}
2099 
2100 	_diagonalx = _modX[3];
2101 	_diagonaly = _modY[3];
2102 
2103 	// interpret the walk data
2104 
2105 	_framesPerStep = _walkData.nWalkFrames / 2;
2106 	_framesPerChar = _walkData.nWalkFrames * NO_DIRECTIONS;
2107 
2108 	// offset pointers added Oct 30 95 JPS
2109 	// mega id references removed 16sep96 by JEL
2110 
2111 	// WALK FRAMES
2112 	// start on frame 0
2113 
2114 	frameCounter += _framesPerChar;
2115 
2116 	// STAND FRAMES
2117 	// stand frames come after the walk frames
2118 	// one stand frame for each direction
2119 
2120 	_firstStandFrame = frameCounter;
2121 	frameCounter += NO_DIRECTIONS;
2122 
2123 	// STANDING TURN FRAMES - OPTIONAL!
2124 	// standing turn-left frames come after the slow-out frames
2125 	// one for each direction
2126 	// standing turn-left frames come after the standing turn-right frames
2127 	// one for each direction
2128 
2129 	if (_walkData.usingStandingTurnFrames) {
2130 		_firstStandingTurnLeftFrame = frameCounter;
2131 		frameCounter += NO_DIRECTIONS;
2132 
2133 		_firstStandingTurnRightFrame = frameCounter;
2134 		frameCounter += NO_DIRECTIONS;
2135 	} else {
2136 		// refer instead to the normal stand frames
2137 		_firstStandingTurnLeftFrame = _firstStandFrame;
2138 		_firstStandingTurnRightFrame = _firstStandFrame;
2139 	}
2140 
2141 	// WALKING TURN FRAMES - OPTIONAL!
2142 	// walking left-turn frames come after the stand frames
2143 	// walking right-turn frames come after the walking left-turn frames
2144 
2145 	if (_walkData.usingWalkingTurnFrames) {
2146 		_firstWalkingTurnLeftFrame = frameCounter;
2147 		frameCounter += _framesPerChar;
2148 
2149 		_firstWalkingTurnRightFrame = frameCounter;
2150 		frameCounter += _framesPerChar;
2151 	} else {
2152 		_firstWalkingTurnLeftFrame = 0;
2153 		_firstWalkingTurnRightFrame = 0;
2154 	}
2155 
2156 	// SLOW-IN FRAMES - OPTIONAL!
2157 	// slow-in frames come after the walking right-turn frames
2158 
2159 	if (_walkData.usingSlowInFrames) {
2160 		// Make note of frame number of first slow-in frame for each
2161 		// direction. There may be a different number of slow-in
2162 		// frames in each direction
2163 
2164 		for (i = 0; i < NO_DIRECTIONS; i++) {
2165 			_firstSlowInFrame[i] = frameCounter;
2166 			frameCounter += _walkData.nSlowInFrames[i];
2167 		}
2168 	}
2169 
2170 	// SLOW-OUT FRAMES - OPTIONAL!
2171 	// slow-out frames come after the slow-in frames
2172 
2173 	if (_walkData.usingSlowOutFrames)
2174 		_firstSlowOutFrame = frameCounter;
2175 }
2176 
2177 // THE ROUTE EXTRACTOR
2178 
extractRoute()2179 void Router::extractRoute() {
2180 	/*********************************************************************
2181 	 * extractRoute gets route from the node data after a full scan, route
2182 	 * is written with just the basic way points and direction options for
2183 	 * heading to the next point.
2184 	 *********************************************************************/
2185 
2186 	int32 prev;
2187 	int32 prevx;
2188 	int32 prevy;
2189 	int32 last;
2190 	int32 point;
2191 	int32 dirx;
2192 	int32 diry;
2193 	int32 dir;
2194 	int32 ldx;
2195 	int32 ldy;
2196 	int32 p;
2197 
2198 	// extract the route from the node data
2199 
2200 	prev = _nNodes;
2201 	last = prev;
2202 	point = O_ROUTE_SIZE - 1;
2203 	_route[point].x = _node[last].x;
2204 	_route[point].y = _node[last].y;
2205 
2206 	do {
2207 		point--;
2208 		prev = _node[last].prev;
2209 		prevx = _node[prev].x;
2210 		prevy = _node[prev].y;
2211 		_route[point].x = prevx;
2212 		_route[point].y = prevy;
2213 		last = prev;
2214 	} while (prev > 0);
2215 
2216 	// now shuffle route down in the buffer
2217 	_routeLength = 0;
2218 
2219 	do {
2220 		_route[_routeLength].x = _route[point].x;
2221 		_route[_routeLength].y = _route[point].y;
2222 		point++;
2223 		_routeLength++;
2224 	} while (point < O_ROUTE_SIZE);
2225 
2226 	_routeLength--;
2227 
2228 	// okay the route exists as a series point now put in some directions
2229 	for (p = 0; p < _routeLength; ++p) {
2230 		ldx = _route[p + 1].x - _route[p].x;
2231 		ldy = _route[p + 1].y - _route[p].y;
2232 		dirx = 1;
2233 		diry = 1;
2234 
2235 		if (ldx < 0) {
2236 			ldx = -ldx;
2237 			dirx = -1;
2238 		}
2239 
2240 		if (ldy < 0) {
2241 			ldy = -ldy;
2242 			diry = -1;
2243 		}
2244 
2245 		if (_diagonaly * ldx > _diagonalx * ldy) {
2246 			// dir  = 1,2 or 2,3 or 5,6 or 6,7
2247 
2248 			// 2 or 6
2249 			dir = 4 - 2 * dirx;
2250 			_route[p].dirS = dir;
2251 
2252 			// 1, 3, 5 or 7
2253 			dir = dir + diry * dirx;
2254 			_route[p].dirD = dir;
2255 		} else {
2256 			// dir  = 7,0 or 0,1 or 3,4 or 4,5
2257 
2258 			// 0 or 4
2259 			dir = 2 + 2 * diry;
2260 			_route[p].dirS = dir;
2261 
2262 			// 2 or 6
2263 			dir = 4 - 2 * dirx;
2264 
2265 			// 1, 3, 5 or 7
2266 			dir = dir + diry * dirx;
2267 			_route[p].dirD = dir;
2268 		}
2269 	}
2270 
2271 	// set the last dir to continue previous route unless specified
2272 	if (_targetDir == NO_DIRECTIONS) {
2273 		// ANY direction
2274 		_route[p].dirS = _route[p - 1].dirS;
2275 		_route[p].dirD = _route[p - 1].dirD;
2276 	} else {
2277 		_route[p].dirS = _targetDir;
2278 		_route[p].dirD = _targetDir;
2279 	}
2280 
2281 	return;
2282 }
2283 
setUpWalkGrid(byte * ob_mega,int32 x,int32 y,int32 dir)2284 void Router::setUpWalkGrid(byte *ob_mega, int32 x, int32 y, int32 dir) {
2285 	ObjectMega obMega(ob_mega);
2286 
2287 	// get walk grid file + extra grid into 'bars' & 'node' arrays
2288 	loadWalkGrid();
2289 
2290 	// copy the mega structure into the local variables for use in all
2291 	// subroutines
2292 
2293 	_startX = obMega.getFeetX();
2294 	_startY = obMega.getFeetY();
2295 	_startDir = obMega.getCurDir();
2296 	_targetX = x;
2297 	_targetY = y;
2298 	_targetDir = dir;
2299 
2300 	_scaleA = obMega.getScaleA();
2301 	_scaleB = obMega.getScaleB();
2302 
2303 	// mega's current position goes into first node
2304 
2305 	_node[0].x = _startX;
2306 	_node[0].y = _startY;
2307 	_node[0].level = 1;
2308 	_node[0].prev = 0;
2309 	_node[0].dist = 0;
2310 
2311 	// reset other nodes
2312 
2313 	for (int i = 1; i < _nNodes; i++) {
2314 		_node[i].level = 0;
2315 		_node[i].prev = 0;
2316 		_node[i].dist = 9999;
2317 	}
2318 
2319 	// target position goes into final node
2320 	_node[_nNodes].x = _targetX;
2321 	_node[_nNodes].y = _targetY;
2322 	_node[_nNodes].level = 0;
2323 	_node[_nNodes].prev = 0;
2324 	_node[_nNodes].dist = 9999;
2325 }
2326 
plotWalkGrid()2327 void Router::plotWalkGrid() {
2328 	int32 i;
2329 
2330 	// get walk grid file + extra grid into 'bars' & 'node' arrays
2331 	loadWalkGrid();
2332 
2333 	// lines
2334 
2335 	for (i = 0; i < _nBars; i++)
2336 		_vm->_screen->drawLine(_bars[i].x1, _bars[i].y1, _bars[i].x2, _bars[i].y2, 254);
2337 
2338 	// nodes
2339 
2340 	// leave node 0 for start node
2341 	for (i = 1; i < _nNodes; i++)
2342 		plotCross(_node[i].x, _node[i].y, 184);
2343 }
2344 
plotCross(int16 x,int16 y,uint8 color)2345 void Router::plotCross(int16 x, int16 y, uint8 color) {
2346 	_vm->_screen->drawLine(x - 1, y - 1, x + 1, y + 1, color);
2347 	_vm->_screen->drawLine(x + 1, y - 1, x - 1, y + 1, color);
2348 }
2349 
loadWalkGrid()2350 void Router::loadWalkGrid() {
2351 	WalkGridHeader floorHeader;
2352 	byte *fPolygrid;
2353 	uint16 fPolygridLen;
2354 
2355 	_nBars	= 0;	// reset counts
2356 	_nNodes	= 1;	// leave node 0 for start-node
2357 
2358 	// STATIC GRIDS (added/removed by object logics)
2359 
2360 	// go through walkgrid list
2361 	for (int i = 0; i < MAX_WALKGRIDS; i++) {
2362 		if (_walkGridList[i]) {
2363 			int j;
2364 
2365 			// open walk grid file
2366 			fPolygrid = _vm->_resman->openResource(_walkGridList[i]);
2367 			fPolygridLen = _vm->_resman->fetchLen(_walkGridList[i]);
2368 
2369 			Common::MemoryReadStream readS(fPolygrid, fPolygridLen);
2370 
2371 			readS.seek(ResHeader::size());
2372 
2373 			floorHeader.numBars = readS.readSint32LE();
2374 			floorHeader.numNodes = readS.readSint32LE();
2375 
2376 			// check that we're not going to exceed the max
2377 			// allowed in the complete walkgrid arrays
2378 
2379 			assert(_nBars + floorHeader.numBars < O_GRID_SIZE);
2380 			assert(_nNodes + floorHeader.numNodes < O_GRID_SIZE);
2381 
2382 			// lines
2383 
2384 			for (j = 0; j < floorHeader.numBars; j++) {
2385 				_bars[_nBars + j].x1 = readS.readSint16LE();
2386 				_bars[_nBars + j].y1 = readS.readSint16LE();
2387 				_bars[_nBars + j].x2 = readS.readSint16LE();
2388 				_bars[_nBars + j].y2 = readS.readSint16LE();
2389 				_bars[_nBars + j].xmin = readS.readSint16LE();
2390 				_bars[_nBars + j].ymin = readS.readSint16LE();
2391 				_bars[_nBars + j].xmax = readS.readSint16LE();
2392 				_bars[_nBars + j].ymax = readS.readSint16LE();
2393 				_bars[_nBars + j].dx = readS.readSint16LE();
2394 				_bars[_nBars + j].dy = readS.readSint16LE();
2395 				_bars[_nBars + j].co = readS.readSint32LE();
2396 			}
2397 
2398 			// nodes
2399 
2400 			// leave node 0 for start node
2401 			for (j = 0; j < floorHeader.numNodes; j++) {
2402 				_node[_nNodes + j].x = readS.readSint16LE();
2403 				_node[_nNodes + j].y = readS.readSint16LE();
2404 			}
2405 
2406 			// close walk grid file
2407 			_vm->_resman->closeResource(_walkGridList[i]);
2408 
2409 			// increment counts of total bars & nodes in whole
2410 			// walkgrid
2411 
2412 			_nBars += floorHeader.numBars;
2413 			_nNodes	+= floorHeader.numNodes;
2414 		}
2415 	}
2416 }
2417 
clearWalkGridList()2418 void Router::clearWalkGridList() {
2419 	memset(_walkGridList, 0, sizeof(_walkGridList));
2420 }
2421 
2422 // called from fnAddWalkGrid
2423 
addWalkGrid(int32 gridResource)2424 void Router::addWalkGrid(int32 gridResource) {
2425 	int i;
2426 	// First, scan the list to see if this grid is already included
2427 
2428 	for (i = 0; i < MAX_WALKGRIDS; i++) {
2429 		if (_walkGridList[i] == gridResource)
2430 			return;
2431 	}
2432 
2433 	// Scan the list for a free slot
2434 
2435 	for (i = 0; i < MAX_WALKGRIDS; i++) {
2436 		if (_walkGridList[i] == 0) {
2437 			_walkGridList[i] = gridResource;
2438 			return;
2439 		}
2440 	}
2441 
2442 	error("_walkGridList[] full");
2443 }
2444 
2445 // called from fnRemoveWalkGrid
2446 
removeWalkGrid(int32 gridResource)2447 void Router::removeWalkGrid(int32 gridResource) {
2448 	for (int i = 0; i < MAX_WALKGRIDS; i++) {
2449 		if (_walkGridList[i] == gridResource) {
2450 			// If we've found it in the list, reset entry to zero.
2451 			// Otherwise just ignore the request.
2452 			_walkGridList[i] = 0;
2453 			break;
2454 		}
2455 	}
2456 }
2457 
2458 } // End of namespace Sword2
2459