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