aboutsummaryrefslogtreecommitdiff
path: root/sword1/router.cpp
diff options
context:
space:
mode:
authorRobert Göffringmann2003-12-16 02:10:15 +0000
committerRobert Göffringmann2003-12-16 02:10:15 +0000
commit189e08bc7985fc5664e7ab95195bbade07488f48 (patch)
treef12049da0a8e600bcdd425e4c314c50b5c9922f7 /sword1/router.cpp
parentc3a9b2df6789055325b7fea6dd591cea1d419682 (diff)
downloadscummvm-rg350-189e08bc7985fc5664e7ab95195bbade07488f48.tar.gz
scummvm-rg350-189e08bc7985fc5664e7ab95195bbade07488f48.tar.bz2
scummvm-rg350-189e08bc7985fc5664e7ab95195bbade07488f48.zip
Broken Sword 1: initial import
svn-id: r11664
Diffstat (limited to 'sword1/router.cpp')
-rw-r--r--sword1/router.cpp1968
1 files changed, 1968 insertions, 0 deletions
diff --git a/sword1/router.cpp b/sword1/router.cpp
new file mode 100644
index 0000000000..cd2c2e5ed3
--- /dev/null
+++ b/sword1/router.cpp
@@ -0,0 +1,1968 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) Revolution Software Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#include "stdafx.h"
+#include "router.h"
+#include "util.h"
+#include "objectman.h"
+#include "resman.h"
+#include "sworddefs.h"
+
+#define SLOW_IN 3
+#define SLOW_OUT 7
+
+SwordRouter::SwordRouter(ObjectMan *pObjMan, ResMan *pResMan) {
+ _objMan = pObjMan;
+ _resMan = pResMan;
+ _numExtraBars = _numExtraNodes = 0;
+ _nNodes = _nBars = 0;
+ _playerTargetX = _playerTargetY = _playerTargetDir = _playerTargetStance = 0;
+}
+
+int SwordRouter::routeFinder(int32 id, BsObject *mega, int32 x, int32 y, int32 targetDir) {
+ loadWalkResources(id, mega, x, y, targetDir); // init vars for subs
+ // init offset pointers
+ FrameInfos frameInfo;
+
+ frameInfo.framesPerStep = _nWalkFrames / 2;
+ frameInfo.framesPerChar = _nWalkFrames * NO_DIRECTIONS;
+ frameInfo.standFrames = frameInfo.framesPerChar;
+ frameInfo.turnFramesLeft = frameInfo.framesPerChar;
+ frameInfo.turnFramesRight = frameInfo.framesPerChar;
+ frameInfo.walkFramesLeft = 0;
+ frameInfo.walkFramesRight = 0;
+ frameInfo.slowInFrames = 0;
+ frameInfo.slowOutFrames = 0;
+ frameInfo.startX = mega->o_xcoord;
+ frameInfo.startY = mega->o_ycoord;
+ frameInfo.targetX = x;
+ frameInfo.targetY = y;
+ frameInfo.targetDir = targetDir;
+ frameInfo.scaleA = mega->o_scale_a;
+ frameInfo.scaleB = mega->o_scale_b;
+
+ if (id == GEORGE) {
+ frameInfo.turnFramesLeft = 3 * frameInfo.framesPerChar + NO_DIRECTIONS + 2 * SLOW_IN + 4 * SLOW_OUT;
+ frameInfo.turnFramesRight = 3 * frameInfo.framesPerChar + NO_DIRECTIONS + 2 * SLOW_IN + 4 * SLOW_OUT + NO_DIRECTIONS;
+ frameInfo.walkFramesLeft = frameInfo.framesPerChar + NO_DIRECTIONS;
+ frameInfo.walkFramesRight = 2 * frameInfo.framesPerChar + NO_DIRECTIONS;
+ frameInfo.slowInFrames = 3 * frameInfo.framesPerChar + NO_DIRECTIONS;
+ frameInfo.slowOutFrames = 3 * frameInfo.framesPerChar + NO_DIRECTIONS + 2 * SLOW_IN;
+ } else if (id == NICO) {
+ frameInfo.turnFramesLeft = frameInfo.framesPerChar + NO_DIRECTIONS;
+ frameInfo.turnFramesRight = frameInfo.framesPerChar + 2 * NO_DIRECTIONS;
+ frameInfo.walkFramesLeft = 0;
+ frameInfo.walkFramesRight = 0;
+ frameInfo.slowInFrames = 0;
+ frameInfo.slowOutFrames = 0;
+ }
+ int32 routeFlag = getRoute();
+ int32 routeLength;
+ if (routeFlag == 1) {
+ // extract the route as nodes and the directions to go between each node
+ // route.X,route.Y and route.Dir now hold all the route infomation with
+ // the target dir or route continuation
+ routeLength = extractRoute(targetDir);
+ }
+ int32 solidFlag = 0;
+ if (routeFlag == 2) //special case for zero length route
+ {
+ if (targetDir >7)// if target direction specified as any
+ targetDir = mega->o_dir;
+ // just a turn on the spot is required set an end module for the route let the animator deal with it
+ // modularPath is normally set by ExtractRoute
+ _modularPath[0].dir = mega->o_dir;
+ _modularPath[0].num = 0;
+ _modularPath[0].x = mega->o_xcoord;
+ _modularPath[0].y = mega->o_ycoord;
+ _modularPath[1].dir = targetDir;
+ _modularPath[1].num = 0;
+ _modularPath[1].x = mega->o_xcoord;
+ _modularPath[1].y = mega->o_ycoord;
+ _modularPath[2].dir = 9;
+ _modularPath[2].num = ROUTE_END_FLAG;
+
+ slidyWalkAnimator(mega->o_route, &frameInfo, id);
+ routeFlag = 2;
+ } else if (routeFlag == 1) { // a normal route
+ smoothestPath(mega->o_xcoord, mega->o_ycoord, mega->o_dir, routeLength);//Converts the route to an exact path
+ // The Route had waypoints and direction options
+ // The Path is an exact set of lines in 8 directions that reach the target.
+ // The path is in module format, but steps taken in each direction are not accurate
+ // if target dir = 8 then the walk isn't linked to an anim so
+ // we can create a route without sliding and miss the exact target
+ if (targetDir == NO_DIRECTIONS) {
+ solidPath(mega->o_scale_a, mega->o_scale_b);
+ solidFlag = solidWalkAnimator(mega->o_route, &frameInfo, id);
+ }
+
+ if (!solidFlag) {
+ slidyPath(mega->o_scale_a, mega->o_scale_b, targetDir);
+ slidyWalkAnimator(mega->o_route, &frameInfo, id);
+ }
+ }
+ return routeFlag;
+}
+
+void SwordRouter::slidyPath(int32 scaleA, int32 scaleB, uint16 targetDir) {
+ /****************************************************************************
+ * SlidyPath creates a path based on part steps with no sliding to get
+ * as near as possible to the target without any sliding this routine is
+ * currently unused, but is intended for use when just clicking about.
+ *
+ * produce a module list from the line data
+ *
+ ****************************************************************************/
+ int32 smooth;
+ int32 slidy;
+ int32 scale;
+ int32 stepX;
+ int32 stepY;
+ int32 deltaX;
+ int32 deltaY;
+
+ // strip out the short sections
+ slidy = 1;
+ smooth = 1;
+ _modularPath[0].x = _smoothPath[0].x;
+ _modularPath[0].y = _smoothPath[0].y;
+ _modularPath[0].dir = _smoothPath[0].dir;
+ _modularPath[0].num = 0;
+
+ while (_smoothPath[smooth].num < ROUTE_END_FLAG)
+ {
+ scale = scaleA * _smoothPath[smooth].y + scaleB;
+ deltaX = _smoothPath[smooth].x - _modularPath[slidy-1].x;
+ deltaY = _smoothPath[smooth].y - _modularPath[slidy-1].y;
+ stepX = _modX[_smoothPath[smooth].dir];
+ stepY = _modY[_smoothPath[smooth].dir];
+ stepX = stepX * scale;
+ stepY = stepY * scale;
+ stepX = stepX >> 19;// quarter a step minimum
+ stepY = stepY >> 19;
+ if ((abs(deltaX)>=abs(stepX)) && (abs(deltaY)>=abs(stepY)))
+ {
+ _modularPath[slidy].x = _smoothPath[smooth].x;
+ _modularPath[slidy].y = _smoothPath[smooth].y;
+ _modularPath[slidy].dir = _smoothPath[smooth].dir;
+ _modularPath[slidy].num = 1;
+ slidy += 1;
+ }
+ smooth += 1;
+ }
+ // in case the last bit had no steps
+ if (slidy > 1)
+ {
+ _modularPath[slidy-1].x = _smoothPath[smooth-1].x;
+ _modularPath[slidy-1].y = _smoothPath[smooth-1].y;
+ }
+ // set up the end of the walk
+ _modularPath[slidy].x = _smoothPath[smooth-1].x;
+ _modularPath[slidy].y = _smoothPath[smooth-1].y;
+ _modularPath[slidy].dir = targetDir;
+ _modularPath[slidy].num = 0;
+ slidy += 1;
+ _modularPath[slidy].x = _smoothPath[smooth-1].x;
+ _modularPath[slidy].y = _smoothPath[smooth-1].y;
+ _modularPath[slidy].dir = 9;
+ _modularPath[slidy].num = ROUTE_END_FLAG;
+}
+
+int32 SwordRouter::solidPath(int32 scaleA, int32 scaleB) {
+/****************************************************************************
+ * SolidPath creates a path based on whole steps with no sliding to get
+ * as near as possible to the target without any sliding this routine is
+ * currently unused, but is intended for use when just clicking about.
+ *
+ * produce a module list from the line data
+ *
+ ****************************************************************************/
+ int32 smooth;
+ int32 solid;
+ int32 scale;
+ int32 stepX;
+ int32 stepY;
+ int32 deltaX;
+ int32 deltaY;
+
+ solid = 1;
+ smooth = 1;
+ _modularPath[0].x = _smoothPath[0].x;
+ _modularPath[0].y = _smoothPath[0].y;
+ _modularPath[0].dir = _smoothPath[0].dir;
+ _modularPath[0].num = 0;
+
+ do {
+ scale = scaleA * _smoothPath[smooth].y + scaleB;
+ deltaX = _smoothPath[smooth].x - _modularPath[solid-1].x;
+ deltaY = _smoothPath[smooth].y - _modularPath[solid-1].y;
+ stepX = _modX[_smoothPath[smooth].dir];
+ stepY = _modY[_smoothPath[smooth].dir];
+ stepX = stepX * scale;
+ stepY = stepY * scale;
+ stepX = stepX >> 16;
+ stepY = stepY >> 16;
+ if ((abs(deltaX)>=abs(stepX)) && (abs(deltaY)>=abs(stepY))) {
+ _modularPath[solid].x = _smoothPath[smooth].x;
+ _modularPath[solid].y = _smoothPath[smooth].y;
+ _modularPath[solid].dir = _smoothPath[smooth].dir;
+ _modularPath[solid].num = 1;
+ solid += 1;
+ }
+ smooth += 1;
+ } while (_smoothPath[smooth].num < ROUTE_END_FLAG);
+ // in case the last bit had no steps
+ if (solid == 1) { //there were no paths so put in a dummy end
+ solid = 2;
+ _modularPath[1].dir = _smoothPath[0].dir;
+ _modularPath[1].num = 0;
+ }
+ _modularPath[solid-1].x = _smoothPath[smooth-1].x;
+ _modularPath[solid-1].y = _smoothPath[smooth-1].y;
+ // set up the end of the walk
+ _modularPath[solid].x = _smoothPath[smooth-1].x;
+ _modularPath[solid].y = _smoothPath[smooth-1].y;
+ _modularPath[solid].dir = 9;
+ _modularPath[solid].num = ROUTE_END_FLAG;
+ return 1;
+}
+
+int32 SwordRouter::solidWalkAnimator(WalkData *walkAnim, FrameInfos *frInfo, int32 megaId) {
+ int32 p;
+ int32 i;
+ int32 left;
+ int32 lastDir;
+ int32 currentDir;
+ int32 turnDir;
+ int32 scale;
+ int32 step;
+ int32 module;
+ int32 moduleX;
+ int32 moduleY;
+ int32 module16X;
+ int32 module16Y;
+ int32 errorX;
+ int32 errorY;
+ int32 moduleEnd;
+ int32 slowStart;
+ int32 stepCount;
+ int32 lastCount;
+ int32 frame;
+// start at the begining for a change
+ lastDir = _modularPath[0].dir;
+ p = 1;
+ currentDir = _modularPath[1].dir;
+ module = frInfo->framesPerChar + lastDir;
+ moduleX = frInfo->startX;
+ moduleY = frInfo->startY;
+ module16X = moduleX << 16;
+ module16Y = moduleY << 16;
+ slowStart = 0;
+ stepCount = 0;
+
+ //****************************************************************************
+ // SOLID
+ // START THE WALK WITH THE FIRST STANDFRAME THIS MAY CAUSE A DELAY
+ // BUT IT STOPS THE PLAYER MOVING FOR COLLISIONS ARE DETECTED
+ //****************************************************************************
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+
+ //****************************************************************************
+ // SOLID
+ // TURN TO START THE WALK
+ //****************************************************************************
+ // rotate if we need to
+ if (lastDir != currentDir)
+ {
+ // get the direction to turn
+ turnDir = currentDir - lastDir;
+ if ( turnDir < 0)
+ turnDir += NO_DIRECTIONS;
+
+ if (turnDir > 4)
+ turnDir = -1;
+ else if (turnDir > 0)
+ turnDir = 1;
+
+ // rotate to new walk direction
+ // for george and nico put in a head turn at the start
+ if ((megaId == GEORGE) || (megaId == NICO))
+ {
+ if ( turnDir < 0) // new frames for turn frames 29oct95jps
+ {
+ module = frInfo->turnFramesLeft + lastDir;
+ }
+ else
+ {
+ module = frInfo->turnFramesRight + lastDir;
+ }
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+
+ // rotate till were facing new dir then go back 45 degrees
+ while (lastDir != currentDir)
+ {
+ lastDir += turnDir;
+ if ( turnDir < 0) // new frames for turn frames 29oct95jps
+ {
+ if ( lastDir < 0)
+ lastDir += NO_DIRECTIONS;
+ module = frInfo->turnFramesLeft + lastDir;
+ }
+ else
+ {
+ if ( lastDir > 7)
+ lastDir -= NO_DIRECTIONS;
+ module = frInfo->turnFramesRight + lastDir;
+ }
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ // the back 45 degrees bit
+ stepCount -= 1;// step back one because new head turn for george takes us past the new dir
+ }
+
+ //****************************************************************************
+ // SOLID
+ // THE SLOW IN
+ //****************************************************************************
+
+ // do start frames if its george and left or right
+ if (megaId == GEORGE)
+ {
+ if (_modularPath[1].num > 0)
+ {
+ if (currentDir == 2) // only for george
+ {
+ slowStart = 1;
+ walkAnim[stepCount].frame = 296;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ walkAnim[stepCount].frame = 297;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ walkAnim[stepCount].frame = 298;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ else if (currentDir == 6) // only for george
+ {
+ slowStart = 1;
+ walkAnim[stepCount].frame = 299;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ walkAnim[stepCount].frame = 300;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ walkAnim[stepCount].frame = 301;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ }
+ }
+ //****************************************************************************
+ // SOLID
+ // THE WALK
+ //****************************************************************************
+
+ if (currentDir > 4)
+ left = frInfo->framesPerStep;
+ else
+ left = 0;
+
+ lastCount = stepCount;
+ lastDir = 99;// this ensures that we don't put in turn frames for the start
+ currentDir = 99;// this ensures that we don't put in turn frames for the start
+
+ do
+ {
+ while(_modularPath[p].num > 0)
+ {
+ currentDir = _modularPath[p].dir;
+ if (currentDir< NO_DIRECTIONS)
+ {
+
+ module = currentDir * frInfo->framesPerStep * 2 + left;
+ if (left == 0)
+ left = frInfo->framesPerStep;
+ else
+ left = 0;
+ moduleEnd = module + frInfo->framesPerStep;
+ step = 0;
+ scale = (frInfo->scaleA * moduleY + frInfo->scaleB);
+ do
+ {
+ module16X += _dx[module]*scale;
+ module16Y += _dy[module]*scale;
+ moduleX = module16X >> 16;
+ moduleY = module16Y >> 16;
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = step;
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ module += 1;
+ step += 1;
+ }
+ while( module < moduleEnd) ;
+ errorX = _modularPath[p].x - moduleX;
+ errorX = errorX * _modX[_modularPath[p].dir];
+ errorY = _modularPath[p].y - moduleY;
+ errorY = errorY * _modY[_modularPath[p].dir];
+ if ((errorX < 0) || (errorY < 0))
+ {
+ _modularPath[p].num = 0;
+ stepCount -= frInfo->framesPerStep;
+ if (left == 0)
+ left = frInfo->framesPerStep;
+ else
+ left = 0;
+ // Okay this is the end of a section
+ moduleX = walkAnim[stepCount-1].x;
+ moduleY = walkAnim[stepCount-1].y;
+ module16X = moduleX << 16;
+ module16Y = moduleY << 16;
+ _modularPath[p].x =moduleX;
+ _modularPath[p].y =moduleY;
+ // Now is the time to put in the turn frames for the last turn
+ if ((stepCount - lastCount) < frInfo->framesPerStep)// no step taken
+ {
+ currentDir = 99;// this ensures that we don't put in turn frames for this walk or the next
+ if (slowStart == 1)// clean up if a slow in but no walk
+ {
+ stepCount -= 3;
+ lastCount -= 3;
+ slowStart = 0;
+ }
+ }
+ // check each turn condition in turn
+ if (((lastDir != 99) && (currentDir != 99)) && (megaId == GEORGE)) // only for george
+ {
+ lastDir = currentDir - lastDir;//1 and -7 going right -1 and 7 going left
+ if (((lastDir == -1) || (lastDir == 7)) || ((lastDir == -2) || (lastDir == 6)))
+ {
+ // turn at the end of the last walk
+ frame = lastCount - frInfo->framesPerStep;
+ do
+ {
+ walkAnim[frame].frame += 104;//turning left
+ frame += 1;
+ }
+ while(frame < lastCount );
+ }
+ if (((lastDir == 1) || (lastDir == -7)) || ((lastDir == 2) || (lastDir == -6)))
+ {
+ // turn at the end of the current walk
+ frame = lastCount - frInfo->framesPerStep;
+ do
+ {
+ walkAnim[frame].frame += 200; //was 60 now 116
+ frame += 1;
+ }
+ while(frame < lastCount );
+ }
+ }
+ // all turns checked
+ lastCount = stepCount;
+ }
+ }
+ }
+ p = p + 1;
+ lastDir = currentDir;
+ slowStart = 0; //can only be valid first time round
+ }
+ while (_modularPath[p].dir < NO_DIRECTIONS);
+
+ //****************************************************************************
+ // SOLID
+ // THE SLOW OUT
+ //****************************************************************************
+
+ if ((currentDir == 2) && (megaId == GEORGE)) // only for george
+ {
+ // place stop frames here
+ // slowdown at the end of the last walk
+ frame = lastCount - frInfo->framesPerStep;
+ if (walkAnim[frame].frame == 24)
+ {
+ do
+ {
+ walkAnim[frame].frame += 278;//stopping right
+ frame += 1;
+ }
+ while(frame < lastCount );
+ walkAnim[stepCount].frame = 308;
+ walkAnim[stepCount].step = 7;
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ else if (walkAnim[frame].frame == 30)
+ {
+ do
+ {
+ walkAnim[frame].frame += 279;//stopping right
+ frame += 1;
+ }
+ while(frame < lastCount );
+ walkAnim[stepCount].frame = 315;
+ walkAnim[stepCount].step = 7;
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ }
+ else if ((currentDir == 6) && (megaId == GEORGE)) // only for george
+ {
+ // place stop frames here
+ // slowdown at the end of the last walk
+ frame = lastCount - frInfo->framesPerStep;
+ if (walkAnim[frame].frame == 72)
+ {
+ do
+ {
+ walkAnim[frame].frame += 244;//stopping left
+ frame += 1;
+ }
+ while(frame < lastCount );
+ walkAnim[stepCount].frame = 322;
+ walkAnim[stepCount].step = 7;
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ else if (walkAnim[frame].frame == 78)
+ {
+ do
+ {
+ walkAnim[frame].frame += 245;//stopping left
+ frame += 1;
+ }
+ while(frame < lastCount );
+ walkAnim[stepCount].frame = 329;
+ walkAnim[stepCount].step = 7;
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ }
+ module = frInfo->framesPerChar + _modularPath[p-1].dir;
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = _modularPath[p-1].dir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+
+ walkAnim[stepCount].frame = 512;
+ stepCount += 1;
+ walkAnim[stepCount].frame = 512;
+ stepCount += 1;
+ walkAnim[stepCount].frame = 512;
+
+ //****************************************************************************
+ // SOLID
+ // NO END TURNS
+ //****************************************************************************
+
+// Tdebug("RouteFinder RouteSize is %d", stepCount);
+// now check the route
+ i = 0;
+ do
+ {
+ if (!check(_modularPath[i].x, _modularPath[i].y, _modularPath[i+1].x, _modularPath[i+1].y))
+ p=0;
+ i += 1;
+ }
+ while(i<p-1);
+ if (p != 0) {
+ frInfo->targetDir = _modularPath[p-1].dir;
+ if (checkTarget(moduleX,moduleY) == 3)// new target on a line
+ p = 0;
+ }
+
+ return p;
+}
+
+int32 SwordRouter::smoothestPath(uint16 startX, uint16 startY, uint16 startDir, int32 routeLength) {
+/*
+ * This is the second big part of the route finder and the the only bit that tries to be clever
+ * (the other bits are clever).
+ * This part of the autorouter creates a list of modules from a set of lines running across the screen
+ * The task is complicated by two things;
+ * Firstly in chosing a route through the maze of nodes the routine tries to minimise the amount of each
+ * individual turn avoiding 90 degree and greater turns (where possible) and reduces the total nuber of
+ * turns (subject to two 45 degree turns being better than one 90 degree turn).
+ * Secondly when walking in a given direction the number of steps required to reach the end of that run
+ * is not calculated accurately. This is because I was unable to derive a function to relate number of
+ * steps taken between two points to the shrunken step size
+ *
+ */
+ int32 dirS;
+ int32 dirD;
+ int32 dS;
+ int32 dD;
+ int32 dSS;
+ int32 dSD;
+ int32 dDS;
+ int32 dDD;
+ int32 SS;
+ int32 SD;
+ int32 DS;
+ int32 DD;
+ int32 temp;
+ int32 steps;
+ int32 option;
+ int32 options;
+ int32 lastDir;
+ int32 nextDirS;
+ int32 nextDirD;
+ int32 tempturns[4];
+ int32 turns[4];
+ int32 turntable[NO_DIRECTIONS] = {0,1,3,5,7,5,3,1};
+
+ // route.X route.Y and route.Dir start at far end
+ _smoothPath[0].x = startX;
+ _smoothPath[0].y = startY;
+ _smoothPath[0].dir = startDir;
+ _smoothPath[0].num = 0;
+ lastDir = startDir;
+ // for each section of the route
+ for (int32 p = 0; p < routeLength; p++) {
+ dirS = _route[p].dirS;
+ dirD = _route[p].dirD;
+ nextDirS = _route[p+1].dirS;
+ nextDirD = _route[p+1].dirD;
+
+ // Check directions into and out of a pair of nodes
+ // going in
+ dS = dirS - lastDir;
+ if ( dS < 0)
+ dS = dS + NO_DIRECTIONS;
+
+ dD = dirD - lastDir;
+ if ( dD < 0)
+ dD = dD + NO_DIRECTIONS;
+
+ // coming out
+ dSS = dirS - nextDirS;
+ if ( dSS < 0)
+ dSS = dSS + NO_DIRECTIONS;
+
+ dDD = dirD - nextDirD;
+ if ( dDD < 0)
+ dDD = dDD + NO_DIRECTIONS;
+
+ dSD = dirS - nextDirD;
+ if ( dSD < 0)
+ dSD = dSD + NO_DIRECTIONS;
+
+ dDS = dirD - nextDirS;
+ if ( dDS < 0)
+ dDS = dDS + NO_DIRECTIONS;
+
+ // Determine the amount of turning involved in each possible path
+ dS = turntable[dS];
+ dD = turntable[dD];
+ dSS = turntable[dSS];
+ dDD = turntable[dDD];
+ dSD = turntable[dSD];
+ dDS = turntable[dDS];
+ // get the best path out ie assume next section uses best direction
+ if (dSD < dSS)
+ dSS = dSD;
+ if (dDS < dDD)
+ dDD = dDS;
+ // rate each option
+ SS = dS + dSS + 3; // Split routes look crap so weight against them
+ SD = dS + dDD;
+ DS = dD + dSS;
+ DD = dD + dDD + 3;
+ // set up turns as a sorted array of the turn values
+ tempturns[0] = SS;
+ turns[0] = 0;
+ tempturns[1] = SD;
+ turns[1] = 1;
+ tempturns[2] = DS;
+ turns[2] = 2;
+ tempturns[3] = DD;
+ turns[3] = 3;
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ if (tempturns[j] > tempturns[j + 1]) {
+ temp = turns[j];
+ turns[j] = turns[j+1];
+ turns[j+1] = temp;
+ temp = tempturns[j];
+ tempturns[j] = tempturns[j+1];
+ tempturns[j+1] = temp;
+ }
+ }
+ }
+
+ // best option matched in order of the priority we would like to see on the screen
+ // but each option must be checked to see if it can be walked
+
+ options = newCheck(1, _route[p].x, _route[p].y, _route[p + 1].x, _route[p + 1].y);
+
+ if (options == 0)
+ error("BestTurns failed");
+ steps = 0;
+ for (int i = 0; (i < 4) && (steps == 0); i++) {
+ option = 1 << turns[i];
+ if (option & options)
+ steps = smoothCheck(turns[i],p,dirS,dirD);
+ }
+
+ if (steps == 0)
+ error("BestTurns failed");
+ // route.X route.Y route.dir and bestTurns start at far end
+ }
+ _smoothPath[steps].dir = 9;
+ _smoothPath[steps].num = ROUTE_END_FLAG;
+ return 1;
+}
+
+int32 SwordRouter::smoothCheck(int32 best, int32 p, int32 dirS, int32 dirD) {
+ static int32 k;
+ int32 tempK;
+ int32 x;
+ int32 y;
+ int32 x2;
+ int32 y2;
+ int32 dx;
+ int32 dy;
+ int32 dsx;
+ int32 dsy;
+ int32 ddx;
+ int32 ddy;
+ int32 dirX;
+ int32 dirY;
+ int32 ss0;
+ int32 ss1;
+ int32 ss2;
+ int32 sd0;
+ int32 sd1;
+ int32 sd2;
+
+ if (p == 0)
+ k = 1;
+ tempK = 0;
+ x = _route[p].x;
+ y = _route[p].y;
+ x2 = _route[p + 1].x;
+ y2 = _route[p + 1].y;
+ dx = x2 - x;
+ dy = y2 - y;
+ dirX = 1;
+ dirY = 1;
+ if (dx < 0) {
+ dx = -dx;
+ dirX = -1;
+ }
+
+ if (dy < 0) {
+ dy = -dy;
+ dirY = -1;
+ }
+
+// set up sd0-ss2 to reflect possible movement in each direction
+ if ((dirS == 0) || (dirS == 4)) { // vert and diag
+ ddx = dx;
+ ddy = (dx*_diagonaly)/_diagonalx;
+ dsy = dy - ddy;
+ ddx = ddx * dirX;
+ ddy = ddy * dirY;
+ dsy = dsy * dirY;
+ dsx = 0;
+
+ sd0 = (ddx + _modX[dirD]/2) / _modX[dirD];
+ ss0 = (dsy + _modY[dirS]/2) / _modY[dirS];
+ sd1 = sd0/2;
+ ss1 = ss0/2;
+ sd2 = sd0 - sd1;
+ ss2 = ss0 - ss1;
+ } else {
+ ddy = dy;
+ ddx = (dy*_diagonalx)/_diagonaly;
+ dsx = dx - ddx;
+ ddy = ddy * dirY;
+ ddx = ddx * dirX;
+ dsx = dsx * dirX;
+ dsy = 0;
+
+ sd0 = (ddy + _modY[dirD]/2) / _modY[dirD];
+ ss0 = (dsx + _modX[dirS]/2) / _modX[dirS];
+ sd1 = sd0/2;
+ ss1 = ss0/2;
+ sd2 = sd0 - sd1;
+ ss2 = ss0 - ss1;
+ }
+
+ if (best == 0) { //halfsquare, diagonal, halfsquare
+ _smoothPath[k].x = x+dsx/2;
+ _smoothPath[k].y = y+dsy/2;
+ _smoothPath[k].dir = dirS;
+ _smoothPath[k].num = ss1;
+ k = k + 1;
+ _smoothPath[k].x = x+dsx/2+ddx;
+ _smoothPath[k].y = y+dsy/2+ddy;
+ _smoothPath[k].dir = dirD;
+ _smoothPath[k].num = sd0;
+ k = k + 1;
+ _smoothPath[k].x = x+dsx+ddx;
+ _smoothPath[k].y = y+dsy+ddy;
+ _smoothPath[k].dir = dirS;
+ _smoothPath[k].num = ss2;
+ k = k + 1;
+ tempK = k;
+ } else if (best == 1) { //square, diagonal
+ _smoothPath[k].x = x+dsx;
+ _smoothPath[k].y = y+dsy;
+ _smoothPath[k].dir = dirS;
+ _smoothPath[k].num = ss0;
+ k = k + 1;
+ _smoothPath[k].x = x2;
+ _smoothPath[k].y = y2;
+ _smoothPath[k].dir = dirD;
+ _smoothPath[k].num = sd0;
+ k = k + 1;
+ tempK = k;
+ } else if (best == 2) { //diagonal square
+ _smoothPath[k].x = x+ddx;
+ _smoothPath[k].y = y+ddy;
+ _smoothPath[k].dir = dirD;
+ _smoothPath[k].num = sd0;
+ k = k + 1;
+ _smoothPath[k].x = x2;
+ _smoothPath[k].y = y2;
+ _smoothPath[k].dir = dirS;
+ _smoothPath[k].num = ss0;
+ k = k + 1;
+ tempK = k;
+ } else { //halfdiagonal, square, halfdiagonal
+ _smoothPath[k].x = x+ddx/2;
+ _smoothPath[k].y = y+ddy/2;
+ _smoothPath[k].dir = dirD;
+ _smoothPath[k].num = sd1;
+ k = k + 1;
+ _smoothPath[k].x = x+dsx+ddx/2;
+ _smoothPath[k].y = y+dsy+ddy/2;
+ _smoothPath[k].dir = dirS;
+ _smoothPath[k].num = ss0;
+ k = k + 1;
+ _smoothPath[k].x = x2;
+ _smoothPath[k].y = y2;
+ _smoothPath[k].dir = dirD;
+ _smoothPath[k].num = sd2;
+ k = k + 1;
+ tempK = k;
+ }
+ return tempK;
+}
+
+void SwordRouter::slidyWalkAnimator(WalkData *walkAnim, FrameInfos *frInfo, int32 megaId) {
+/****************************************************************************
+ * Skidding every where HardWalk creates an animation that exactly fits the
+ * smoothPath and uses foot slipping to fit whole steps into the route
+ * Parameters: georgeg,mouseg
+ * Returns: rout
+ *
+ * produce a module list from the line data
+ *
+ ****************************************************************************/
+ static int32 left = 0;
+ int32 p;
+ int32 lastDir;
+ int32 lastRealDir;
+ int32 currentDir;
+ int32 turnDir;
+ int32 scale;
+ int32 step;
+ int32 module;
+ int32 moduleEnd;
+ int32 moduleX;
+ int32 moduleY;
+ int32 module16X = 0;
+ int32 module16Y = 0;
+ int32 stepX;
+ int32 stepY;
+ int32 errorX;
+ int32 errorY;
+ int32 lastErrorX;
+ int32 lastErrorY;
+ int32 lastCount;
+ int32 stepCount;
+ int32 frameCount;
+ int32 frames;
+ int32 frame;
+
+ lastDir = _modularPath[0].dir;
+ currentDir = _modularPath[1].dir;
+ if (currentDir == NO_DIRECTIONS)
+ currentDir = lastDir;
+ moduleX = frInfo->startX;
+ moduleY = frInfo->startY;
+ module16X = moduleX << 16;
+ module16Y = moduleY << 16;
+ stepCount = 0;
+ //****************************************************************************
+ // SLIDY
+ // START THE WALK WITH THE FIRST STANDFRAME THIS MAY CAUSE A DELAY
+ // BUT IT STOPS THE PLAYER MOVING FOR COLLISIONS ARE DETECTED
+ //****************************************************************************
+ module = frInfo->framesPerChar + lastDir;
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+
+ //****************************************************************************
+ // SLIDY
+ // TURN TO START THE WALK
+ //****************************************************************************
+ // rotate if we need to
+ if (lastDir != currentDir)
+ {
+ // get the direction to turn
+ turnDir = currentDir - lastDir;
+ if ( turnDir < 0)
+ turnDir += NO_DIRECTIONS;
+
+ if (turnDir > 4)
+ turnDir = -1;
+ else if (turnDir > 0)
+ turnDir = 1;
+
+ // rotate to new walk direction
+ // for george and nico put in a head turn at the start
+ if ((megaId == GEORGE) || (megaId == NICO))
+ {
+ if ( turnDir < 0) // new frames for turn frames 29oct95jps
+ {
+ module = frInfo->turnFramesLeft + lastDir;
+ }
+ else
+ {
+ module = frInfo->turnFramesRight + lastDir;
+ }
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+
+ // rotate till were facing new dir then go back 45 degrees
+ while (lastDir != currentDir) {
+ lastDir += turnDir;
+ if ( turnDir < 0) { // new frames for turn frames
+ if ( lastDir < 0)
+ lastDir += NO_DIRECTIONS;
+ module = frInfo->turnFramesLeft + lastDir;
+ } else {
+ if ( lastDir > 7)
+ lastDir -= NO_DIRECTIONS;
+ module = frInfo->turnFramesRight + lastDir;
+ }
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ // the back 45 degrees bit
+ stepCount -= 1;// step back one because new head turn for george takes us past the new dir
+ }
+ // his head is in the right direction
+ lastRealDir = currentDir;
+
+ //****************************************************************************
+ // SLIDY
+ // THE WALK
+ //****************************************************************************
+
+ if (left == 0)
+ left = frInfo->framesPerStep;
+ else
+ left = 0;
+
+ lastCount = stepCount;
+ lastDir = 99;// this ensures that we don't put in turn frames for the start
+ currentDir = 99;// this ensures that we don't put in turn frames for the start
+ p = 0;
+ do
+ {
+ while (_modularPath[p].num == 0)
+ {
+ p = p + 1;
+ if (currentDir != 99)
+ lastRealDir = currentDir;
+ lastDir = currentDir;
+ lastCount = stepCount;
+ }
+ //calculate average amount to lose in each step on the way to the next node
+ currentDir = _modularPath[p].dir;
+ if (currentDir < NO_DIRECTIONS)
+ {
+ module = currentDir * frInfo->framesPerStep * 2 + left;
+ if (left == 0)
+ left = frInfo->framesPerStep;
+ else
+ left = 0;
+ moduleEnd = module + frInfo->framesPerStep;
+ step = 0;
+ scale = (frInfo->scaleA * moduleY + frInfo->scaleB);
+ do {
+ module16X += _dx[module]*scale;
+ module16Y += _dy[module]*scale;
+ moduleX = module16X >> 16;
+ moduleY = module16Y >> 16;
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = step;
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ step += 1;
+ module += 1;
+ } while( module < moduleEnd);
+ stepX = _modX[_modularPath[p].dir];
+ stepY = _modY[_modularPath[p].dir];
+ errorX = _modularPath[p].x - moduleX;
+ errorX = errorX * stepX;
+ errorY = _modularPath[p].y - moduleY;
+ errorY = errorY * stepY;
+ if ((errorX < 0) || (errorY < 0)) {
+ _modularPath[p].num = 0; // the end of the path
+ // okay those last steps took us past our target but do we want to scoot or moonwalk
+ frames = stepCount - lastCount;
+ errorX = _modularPath[p].x - walkAnim[stepCount-1].x;
+ errorY = _modularPath[p].y - walkAnim[stepCount-1].y;
+
+ if (frames > frInfo->framesPerStep) {
+ lastErrorX = _modularPath[p].x - walkAnim[stepCount-7].x;
+ lastErrorY = _modularPath[p].y - walkAnim[stepCount-7].y;
+ if (stepX==0) {
+ if (3*abs(lastErrorY) < abs(errorY)) { //the last stop was closest
+ stepCount -= frInfo->framesPerStep;
+ if (left == 0)
+ left = frInfo->framesPerStep;
+ else
+ left = 0;
+ }
+ } else {
+ if (3*abs(lastErrorX) < abs(errorX)) { //the last stop was closest
+ stepCount -= frInfo->framesPerStep;
+ if (left == 0)
+ left = frInfo->framesPerStep;
+ else
+ left = 0;
+ }
+ }
+ }
+ errorX = _modularPath[p].x - walkAnim[stepCount-1].x;
+ errorY = _modularPath[p].y - walkAnim[stepCount-1].y;
+ // okay we've reached the end but we still have an error
+ if (errorX != 0) {
+ frameCount = 0;
+ frames = stepCount - lastCount;
+ do {
+ frameCount += 1;
+ walkAnim[lastCount + frameCount - 1].x += errorX*frameCount/frames;
+ } while(frameCount<frames);
+ }
+ if (errorY != 0) {
+ frameCount = 0;
+ frames = stepCount - lastCount;
+ do {
+ frameCount += 1;
+ walkAnim[lastCount + frameCount-1].y += errorY*frameCount/frames;
+ } while(frameCount<frames);
+ }
+ // Now is the time to put in the turn frames for the last turn
+ if (frames < frInfo->framesPerStep)
+ currentDir = 99;// this ensures that we don't put in turn frames for this walk or the next
+ if (currentDir != 99)
+ lastRealDir = currentDir;
+ // check each turn condition in turn
+ if (((lastDir != 99) && (currentDir != 99)) && (megaId == GEORGE)) { // only for george
+ lastDir = currentDir - lastDir;//1 and -7 going right -1 and 7 going left
+ if (((lastDir == -1) || (lastDir == 7)) || ((lastDir == -2) || (lastDir == 6))) {
+ // turn at the end of the last walk
+ frame = lastCount - frInfo->framesPerStep;
+ do {
+ walkAnim[frame].frame += 104;//turning left
+ frame += 1;
+ } while(frame < lastCount );
+ }
+ if (((lastDir == 1) || (lastDir == -7)) || ((lastDir == 2) || (lastDir == -6))) {
+ // turn at the end of the current walk
+ frame = lastCount - frInfo->framesPerStep;
+ do {
+ walkAnim[frame].frame += 200; //was 60 now 116
+ frame += 1;
+ } while(frame < lastCount );
+ }
+ lastDir = currentDir;
+ }
+ // all turns checked
+
+ lastCount = stepCount;
+ moduleX = walkAnim[stepCount-1].x;
+ moduleY = walkAnim[stepCount-1].y;
+ module16X = moduleX << 16;
+ module16Y = moduleY << 16;
+ }
+ }
+ } while (_modularPath[p].dir < NO_DIRECTIONS);
+
+ if (lastRealDir == 99)
+ error("SlidyWalkAnimator direction error");
+
+ if (frInfo->targetDir == NO_DIRECTIONS) { // stand in the last direction
+ module = frInfo->standFrames + lastRealDir;
+ frInfo->targetDir = lastRealDir;
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastRealDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ if (frInfo->targetDir == 9) {
+ if (stepCount == 0) {
+ module = frInfo->framesPerChar + lastRealDir;
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastRealDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ } else if (frInfo->targetDir != lastRealDir) { // rotate to targetDir
+ // rotate to target direction
+ turnDir = frInfo->targetDir - lastRealDir;
+ if ( turnDir < 0)
+ turnDir += NO_DIRECTIONS;
+
+ if (turnDir > 4)
+ turnDir = -1;
+ else if (turnDir > 0)
+ turnDir = 1;
+
+ // rotate to target direction
+ // for george and nico put in a head turn at the start
+ if ((megaId == GEORGE) || (megaId == NICO)) {
+ if ( turnDir < 0) // new frames for turn frames 29oct95jps
+ module = frInfo->turnFramesLeft + lastDir;
+ else
+ module = frInfo->turnFramesRight + lastDir;
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastRealDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+
+ // rotate if we need to
+ while (lastRealDir != frInfo->targetDir) {
+ lastRealDir += turnDir;
+ if ( turnDir < 0) { // new frames for turn frames 29oct95jps
+ if ( lastRealDir < 0)
+ lastRealDir += NO_DIRECTIONS;
+ module = frInfo->turnFramesLeft + lastRealDir;
+ } else {
+ if ( lastRealDir > 7)
+ lastRealDir -= NO_DIRECTIONS;
+ module = frInfo->turnFramesRight + lastRealDir;
+ }
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastRealDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ module = frInfo->standFrames + lastRealDir;
+ walkAnim[stepCount-1].frame = module;
+ } else { // just stand at the end
+ module = frInfo->standFrames + lastRealDir;
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastRealDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+
+ walkAnim[stepCount].frame = 512;
+ stepCount += 1;
+ walkAnim[stepCount].frame = 512;
+ stepCount += 1;
+ walkAnim[stepCount].frame = 512;
+}
+
+/****************************************************************************
+ * ExtractRoute gets route from the node data after a full scan, route is
+ * written with just the basic way points and direction options for heading
+ * to the next point.
+ ****************************************************************************/
+int32 SwordRouter::extractRoute(int32 targetDir) {
+ int32 prev;
+ int32 prevx;
+ int32 prevy;
+ int32 last;
+ int32 point;
+ int32 dirx;
+ int32 diry;
+ int32 dir;
+
+ // extract the route from the node data
+ prev = _nNodes;
+ last = prev;
+ point = O_ROUTE_SIZE - 1;
+ _route[point].x = _node[last].x;
+ _route[point].y = _node[last].y;
+ while (prev > 0) {
+ point = point - 1;
+ prev = _node[last].prev;
+ prevx = _node[prev].x;
+ prevy = _node[prev].y;
+ _route[point].x = prevx;
+ _route[point].y = prevy;
+ last = prev;
+ }
+
+ int32 routeLength = 0;
+ do {
+ _route[routeLength].x = _route[point].x;
+ _route[routeLength].y = _route[point].y;
+ point = point + 1;
+ routeLength = routeLength + 1;
+ } while (point < O_ROUTE_SIZE);
+
+ for (int p = 0; p < routeLength; p++) {
+ int32 dx = _route[p+1].x - _route[p].x;
+ int32 dy = _route[p+1].y - _route[p].y;
+ dirx = 1;
+ diry = 1;
+ if (dx < 0)
+ {
+ dx = -dx;
+ dirx = -1;
+ }
+ if (dy < 0)
+ {
+ dy = -dy;
+ diry = -1;
+ }
+
+ if ((_diagonaly * dx) > (_diagonalx * dy)) // dir = 1,2 or 2,3 or 5,6 or 6,7
+ {
+ dir = 4 - 2 * dirx; // 2 or 6
+ _route[p].dirS = dir;
+ dir = dir + diry * dirx; // 1,3,5 or 7
+ _route[p].dirD = dir;
+ }
+ else // dir = 7,0 or 0,1 or 3,4 or 4,5
+ {
+ dir = 2 + 2 * diry; // 0 or 4
+ _route[p].dirS = dir;
+ dir = 4 - 2 * dirx; // 2 or 6
+ dir = dir + diry * dirx; // 1,3,5 or 7
+ _route[p].dirD = dir;
+ }
+ }
+ if (targetDir == 8) // ANY direction
+ {
+ _route[routeLength].dirS = _route[routeLength-1].dirS;
+ _route[routeLength].dirD = _route[routeLength-1].dirD;
+ }
+ else
+ {
+ _route[routeLength].dirS = targetDir;
+ _route[routeLength].dirD = targetDir;
+ }
+ return routeLength;
+}
+
+int SwordRouter::getRoute() {
+ int32 routeRes;
+ if ((_node[0].x == _node[_nNodes].x) && (_node[0].y == _node[_nNodes].y))
+ routeRes = 2; // start is the same as destination
+ else
+ routeRes = checkTarget(_node[_nNodes].x, _node[_nNodes].y);
+
+ if (routeRes == 0) { // still looking for a route check if target is within a pixel of a line
+ int32 level = 1;
+ int changed;
+ do
+ {
+ changed = scan(level);
+ level++;
+ } while(changed == 1);
+ if (_node[_nNodes].dist < 9999) // did we reach the target?
+ routeRes = 1;
+ }
+ return routeRes;
+}
+
+int SwordRouter::scan(int32 level) {
+ int32 distance;
+ int changed = 0;
+ // For all the nodes that have new values and a distance less than enddist
+ // ie dont check for new routes from a point we checked before or from a point
+ // that is already further away than the best route so far.
+ for (int32 i = 0; i < _nNodes; i++) {
+ if ((_node[i].dist < _node[_nNodes].dist) && (_node[i].level == level)) {
+ int16 x1 = _node[i].x;
+ int16 y1 = _node[i].y;
+
+ for (int32 k = _nNodes; k > 0; k--) {
+ if (_node[k].dist > _node[i].dist) {
+ int16 x2 = _node[k].x;
+ int16 y2 = _node[k].y;
+ if (abs(x2 - x1) > (4.5 * abs(y2 - y1)))
+ distance = (8 * abs(x2 - x1) + 18 * abs(y2 - y1)) / (54 * 8) + 1;
+ else
+ distance = (6 * abs(x2 - x1) + 36 * abs(y2 - y1)) / (36 * 14) + 1;
+
+ if ((distance + _node[i].dist < _node[_nNodes].dist) && (distance + _node[i].dist < _node[k].dist)) {
+ //if (int temp = newCheck(0, x1, y1, x2, y2)) {
+ if (newCheck(0, x1, y1, x2, y2)) {
+ _node[k].level = level + 1;
+ _node[k].dist = distance + _node[i].dist;
+ _node[k].prev = i;
+ changed = 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ return changed;
+}
+
+/*******************************************************************************
+ * NewCheck routine checks if the route between two points can be achieved
+ * without crossing any of the bars in the Bars array.
+ *
+ * NewCheck differs from check in that that 4 route options are considered
+ * corresponding to actual walked routes.
+ *
+ * Note distance doesnt take account of shrinking ???
+ *
+ * Note Bars array must be properly calculated ie min max dx dy co
+ *******************************************************************************/
+int SwordRouter::newCheck(int32 status, int16 x1, int16 x2, int16 y1, int16 y2) {
+
+ int32 ldx;
+ int32 ldy;
+ int32 dlx;
+ int32 dly;
+ int32 dirX;
+ int32 dirY;
+ int32 step1;
+ int32 step2;
+ int32 step3;
+ int32 steps;
+ int32 options;
+
+ steps = 0;
+ options = 0;
+ ldx = x2 - x1;
+ ldy = y2 - y1;
+ dirX = 1;
+ dirY = 1;
+
+ if (ldx < 0) {
+ ldx = -ldx;
+ dirX = -1;
+ }
+
+ if (ldy < 0) {
+ ldy = -ldy;
+ dirY = -1;
+ }
+
+ // make the route options
+
+ if (_diagonaly * ldx > _diagonalx * ldy) {
+ // dir = 1,2 or 2,3 or 5,6 or 6,7
+
+ dly = ldy;
+ dlx = (ldy * _diagonalx) / _diagonaly;
+ ldx = ldx - dlx;
+ dlx = dlx * dirX;
+ dly = dly * dirY;
+ ldx = ldx * dirX;
+ ldy = 0;
+
+ //options are
+ //square, diagonal a code 1 route
+
+ step1 = check(x1, y1, x1 + ldx, y1);
+ if (step1 != 0) {
+ step2 = check(x1 + ldx, y1, x2, y2);
+ if (step2 != 0) {
+ steps = step1 + step2;
+ options = options + 2;
+ }
+ }
+
+ //diagonal, square a code 2 route
+
+ if (steps == 0 || status == 1) {
+ step1 = check(x1, y1, x1 + dlx, y1 + dly);
+ if (step1 != 0) {
+ step2 = check(x1 + dlx, y2, x2, y2);
+ if (step2 != 0) {
+ steps = step1 + step2;
+ options = options + 4;
+ }
+ }
+ }
+
+ //halfsquare, diagonal, halfsquare a code 0 route
+
+ if (steps == 0 || status == 1) {
+ step1 = check(x1, y1, x1 + ldx / 2, y1);
+ if (step1 != 0) {
+ step2 = check(x1 + ldx / 2, y1, x1 + ldx / 2 + dlx, y2);
+ if (step2 != 0) {
+ step3 = check(x1 + ldx / 2 + dlx, y2, x2, y2);
+ if (step3 != 0) {
+ steps = step1 + step2 + step3;
+ options++;
+ }
+ }
+ }
+ }
+
+ //halfdiagonal, square, halfdiagonal a code 3 route
+
+ if (steps == 0 || status == 1) {
+ step1 = check(x1, y1, x1 + dlx / 2, y1 + dly / 2);
+ if (step1 != 0) {
+ step2 = check(x1 + dlx / 2, y1 + dly / 2, x1 + ldx + dlx / 2, y1 + dly / 2);
+ if (step2 != 0) {
+ step3 = check(x1 + ldx + dlx / 2, y1 + dly / 2, x2, y2);
+ if (step3 != 0) {
+ steps = step1 + step2 + step3;
+ options = options + 8;
+ }
+ }
+ }
+ }
+ } else {
+ // dir = 7,0 or 0,1 or 3,4 or 4,5
+
+ dlx = ldx;
+ dly = (ldx * _diagonaly) / _diagonalx;
+ ldy = ldy - dly;
+ dlx = dlx * dirX;
+ dly = dly * dirY;
+ ldy = ldy * dirY;
+ ldx = 0;
+
+ //options are
+ //square, diagonal a code 1 route
+
+ step1 = check(x1 ,y1, x1, y1 + ldy);
+ if (step1 != 0) {
+ step2 = check(x1, y1 + ldy, x2, y2);
+ if (step2 != 0) {
+ steps = step1 + step2;
+ options = options + 2;
+ }
+ }
+
+ //diagonal, square a code 2 route
+
+ if (steps == 0 || status == 1) {
+ step1 = check(x1, y1, x2, y1 + dly);
+ if (step1 != 0) {
+ step2 = check(x2, y1 + dly, x2, y2);
+ if (step2 != 0) {
+ steps = step1 + step2;
+ options = options + 4;
+ }
+ }
+ }
+
+ //halfsquare, diagonal, halfsquare a code 0 route
+
+ if (steps == 0 || status == 1) {
+ step1 = check(x1, y1, x1, y1 + ldy / 2);
+ if (step1 != 0) {
+ step2 = check(x1, y1 + ldy / 2, x2, y1 + ldy / 2 + dly);
+ if (step2 != 0) {
+ step3 = check(x2, y1 + ldy / 2 + dly, x2, y2);
+ if (step3 != 0) {
+ steps = step1 + step2 + step3;
+ options++;
+ }
+ }
+ }
+ }
+
+ //halfdiagonal, square, halfdiagonal a code 3 route
+
+ if (steps == 0 || status == 1) {
+ step1 = check(x1, y1, x1 + dlx / 2, y1 + dly / 2);
+ if (step1 != 0) {
+ step2 = check(x1 + dlx / 2, y1 + dly / 2, x1 + dlx / 2, y1 + ldy + dly / 2);
+ if (step2 != 0) {
+ step3 = check(x1 + dlx / 2, y1 + ldy + dly / 2, x2, y2);
+ if (step3 != 0) {
+ steps = step1 + step2 + step3;
+ options = options + 8;
+ }
+ }
+ }
+ }
+ }
+
+ if (status == 0)
+ status = steps;
+ else
+ status = options;
+
+ return status;
+}
+
+int SwordRouter::check(int16 x1, int16 y1, int16 x2, int16 y2) {
+ //call the fastest line check for the given line
+ //returns 1 if line didn't cross any bars
+ int steps;
+
+ if ((x1 == x2) && (y1 == y2))
+ steps = 1;
+ else if (x1 == x2)
+ steps = vertCheck(x1, y1, y2);
+ else if (y1 == y2)
+ steps = horizCheck(x1, y1, x2);
+ else
+ steps = lineCheck(x1, y1, x2, y2);
+ return steps;
+}
+
+int SwordRouter::horizCheck(int16 x1, int16 y, int16 x2) {
+ int32 ldy;
+ int32 i;
+ int32 xc;
+ int32 xmin;
+ int32 xmax;
+ int32 linesCrossed = 1;
+
+ if (x1 > x2) {
+ xmin = x2;
+ xmax = x1;
+ } else {
+ xmin = x1;
+ xmax = x2;
+ }
+
+ // line set to go one step in chosen direction
+ // so ignore if it hits anything
+
+ i = 0;
+
+ do {
+ // skip if not on module
+ if (xmax >= _bars[i].xmin && xmin <= _bars[i].xmax) {
+ // skip if not on module
+ if (y >= _bars[i].ymin && y <= _bars[i].ymax) {
+ // okay its a valid line calculate an intercept
+ // wow but all this arithmetic we must have
+ // loads of time
+
+ if (_bars[i].dy == 0)
+ linesCrossed = 0;
+ else {
+ ldy = y - _bars[i].y1;
+ xc = _bars[i].x1 + (_bars[i].dx * ldy) / _bars[i].dy;
+ // skip if not on module
+ if (xc >= xmin - 1 && xc <= xmax + 1)
+ linesCrossed = 0;
+ }
+ }
+ }
+ i++;
+ } while (i < _nBars && linesCrossed);
+
+ return linesCrossed;
+}
+
+int SwordRouter::vertCheck(int16 x, int16 y1, int16 y2) {
+ int32 ldx;
+ int32 i;
+ int32 yc;
+ int32 ymin;
+ int32 ymax;
+ int32 linesCrossed = 1;
+
+ if (y1 > y2) {
+ ymin = y2;
+ ymax = y1;
+ } else {
+ ymin = y1;
+ ymax = y2;
+ }
+
+ // line set to go one step in chosen direction
+ // so ignore if it hits anything
+
+ i = 0;
+
+ do {
+ if (x >= _bars[i].xmin && x <= _bars[i].xmax) {
+ // overlapping
+ // skip if not on module
+ if (ymax >= _bars[i].ymin && ymin <= _bars[i].ymax) {
+ // okay its a valid line calculate an intercept
+ // wow but all this arithmetic we must have
+ // loads of time
+
+ // both lines vertical and overlap in x and y
+ // so they cross
+
+ if (_bars[i].dx == 0)
+ linesCrossed = 0;
+ else {
+ ldx = x - _bars[i].x1;
+ yc = _bars[i].y1 + (_bars[i].dy * ldx) / _bars[i].dx;
+ // the intercept overlaps
+ if (yc >= ymin - 1 && yc <= ymax + 1)
+ linesCrossed = 0;
+ }
+ }
+ }
+ i++;
+ } while (i < _nBars && linesCrossed);
+
+ return linesCrossed;
+}
+
+int SwordRouter::lineCheck(int16 x1, int16 y1, int16 x2, int16 y2) {
+ int32 dirx;
+ int32 diry;
+ int32 co;
+ int32 slope;
+ int32 i;
+ int32 xc;
+ int32 yc;
+ int32 xmin;
+ int32 ymin;
+ int32 xmax;
+ int32 ymax;
+ int32 linesCrossed = 1;
+
+ if (x1 > x2) {
+ xmin = x2;
+ xmax = x1;
+ } else {
+ xmin = x1;
+ xmax = x2;
+ }
+
+ if (y1 > y2) {
+ ymin = y2;
+ ymax = y1;
+ } else {
+ ymin = y1;
+ ymax = y2;
+ }
+
+ // line set to go one step in chosen direction
+ // so ignore if it hits anything
+
+ dirx = x2 - x1;
+ diry = y2 - y1;
+
+ co = (y1 * dirx)- (x1 * diry); // new line equation
+
+ i = 0;
+
+ do {
+ // skip if not on module
+ if (xmax >= _bars[i].xmin && xmin <= _bars[i].xmax) {
+ // skip if not on module
+ if (ymax >= _bars[i].ymin && ymin <= _bars[i].ymax) {
+ // okay its a valid line calculate an intercept
+ // wow but all this arithmetic we must have
+ // loads of time
+
+ // slope it he slope between the two lines
+ slope = (_bars[i].dx * diry) - (_bars[i].dy *dirx);
+ // assuming parallel lines don't cross
+ if (slope != 0) {
+ // calculate x intercept and check its
+ // on both lines
+ xc = ((_bars[i].co * dirx) - (co * _bars[i].dx)) / slope;
+
+ // skip if not on module
+ if (xc >= xmin - 1 && xc <= xmax + 1) {
+ // skip if not on line
+ if (xc >= _bars[i].xmin - 1 && xc <= _bars[i].xmax + 1) {
+ yc = ((_bars[i].co * diry) - (co * _bars[i].dy)) / slope;
+
+ // skip if not on module
+ if (yc >= ymin - 1 && yc <= ymax + 1) {
+ // skip if not on line
+ if (yc >= _bars[i].ymin - 1 && yc <= _bars[i].ymax + 1) {
+ linesCrossed = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ i++;
+ } while (i < _nBars && linesCrossed);
+
+ return linesCrossed;
+}
+
+int SwordRouter::checkTarget(int16 x, int16 y) {
+ int32 dx, dy, xc, yc, xmin, xmax, ymin, ymax;
+ int32 onLine = 0;
+
+ xmin = x - 1;
+ xmax = x + 1;
+ ymin = y - 1;
+ ymax = y + 1;
+
+ for (int i = 0; (i < _nBars) && (onLine == 0); i++) {
+ if ((xmax >= _bars[i].xmin) && (xmin <= _bars[i].xmax)) { //overlapping line
+ if ((ymax >= _bars[i].ymin) && ( ymin <= _bars[i].ymax)) { //overlapping line
+ // okay this line overlaps the target, calculate an y intersept for x
+
+ if (_bars[i].dx == 0) // vertical line so we know it overlaps y
+ yc = 0;
+ else {
+ dx = x - _bars[i].x1;
+ yc = _bars[i].y1 + (_bars[i].dy * dx) / _bars[i].dx;
+ }
+ if ((yc >= ymin) && (yc <= ymax)) //overlapping point for y
+ onLine = 3; // target on a line so drop out
+ else {
+ if (_bars[i].dy == 0) // vertical line so we know it overlaps y
+ xc = 0;
+ else {
+ dy = y- _bars[i].y1;
+ xc = _bars[i].x1 + (_bars[i].dx * dy) / _bars[i].dy;
+ }
+ if ((xc >= xmin) && (xc <= xmax)) //skip if not on module
+ onLine = 3;// target on a line so drop out
+ }
+ }
+ }
+ }
+ return onLine;
+}
+
+void SwordRouter::resetExtraData(void) {
+ _numExtraBars = _numExtraNodes = 0;
+}
+
+void SwordRouter::setPlayerTarget(int32 x, int32 y, int32 dir, int32 stance) {
+ _playerTargetX = x;
+ _playerTargetY = y;
+ _playerTargetDir = dir;
+ _playerTargetStance = stance;
+}
+
+void SwordRouter::loadWalkResources(int32 megaId, BsObject *mega, int32 x, int32 y, int32 dir) {
+ WalkGridHeader *floorHeader;
+
+ int32 walkGridId = _objMan->fetchObject(mega->o_place)->o_resource;
+
+ uint8 *fPolyGrid = (uint8*)_resMan->openFetchRes(walkGridId);
+ floorHeader = (WalkGridHeader*)(fPolyGrid + sizeof(Header));
+ fPolyGrid += sizeof(WalkGridHeader) + sizeof(Header);
+
+ _nBars = FROM_LE_32(floorHeader->numBars);
+ _nNodes = FROM_LE_32(floorHeader->numNodes) + 1;
+ if ((_nBars >= O_GRID_SIZE) || (_nNodes >= O_GRID_SIZE))
+ error("loadWalkResources: resource has %d bars and %d nodes", _nBars, _nNodes);
+
+ for (int32 cnt = 0; cnt < _nBars; cnt++) {
+ _bars[cnt].x1 = READ_LE_UINT16(fPolyGrid); fPolyGrid += 2;
+ _bars[cnt].y1 = READ_LE_UINT16(fPolyGrid); fPolyGrid += 2;
+ _bars[cnt].x2 = READ_LE_UINT16(fPolyGrid); fPolyGrid += 2;
+ _bars[cnt].y2 = READ_LE_UINT16(fPolyGrid); fPolyGrid += 2;
+ _bars[cnt].xmin = READ_LE_UINT16(fPolyGrid); fPolyGrid += 2;
+ _bars[cnt].ymin = READ_LE_UINT16(fPolyGrid); fPolyGrid += 2;
+ _bars[cnt].xmax = READ_LE_UINT16(fPolyGrid); fPolyGrid += 2;
+ _bars[cnt].ymax = READ_LE_UINT16(fPolyGrid); fPolyGrid += 2;
+ _bars[cnt].dx = READ_LE_UINT16(fPolyGrid); fPolyGrid += 2;
+ _bars[cnt].dy = READ_LE_UINT16(fPolyGrid); fPolyGrid += 2;
+ _bars[cnt].co = READ_LE_UINT32(fPolyGrid); fPolyGrid += 4;
+ }
+ //_nBars = 0;
+
+ // leave node 0 for start node
+ for (int32 cnt = 1; cnt < _nNodes; cnt++) {
+ _node[cnt].x = READ_LE_UINT16(fPolyGrid); fPolyGrid += 2;
+ _node[cnt].y = READ_LE_UINT16(fPolyGrid); fPolyGrid += 2;
+ }
+ _resMan->resClose(walkGridId);
+
+ // floor grid loaded. Copy george's extra bars and nodes.
+ if (megaId == GEORGE) {
+ memcpy(_bars + _nBars, _extraBars, _numExtraBars * sizeof(BarData));
+ _nBars += _numExtraBars;
+ for (int32 cnt = 0; cnt < _numExtraNodes; cnt++) {
+ _node[_nNodes + cnt].x = _extraNodes[cnt].x;
+ _node[_nNodes + cnt].y = _extraNodes[cnt].y;
+ }
+ _nNodes += _numExtraNodes;
+ }
+
+ uint8 *walkData = (uint8*)_resMan->openFetchRes(mega->o_mega_resource);
+ _nWalkFrames = walkData[0];
+ _nTurnFrames = walkData[1];
+ walkData += 2;
+
+ for (int32 cnt = 0; cnt < NO_DIRECTIONS * (_nWalkFrames + 1 + _nTurnFrames); cnt++) {
+ _dx[cnt] = READ_LE_UINT32(walkData);
+ walkData += 4;
+ }
+ for (int32 cnt = 0; cnt < NO_DIRECTIONS * (_nWalkFrames + 1 + _nTurnFrames); cnt++) {
+ _dy[cnt] = READ_LE_UINT32(walkData);
+ walkData += 4;
+ }
+ for (int32 cnt = 0; cnt < NO_DIRECTIONS; cnt++) {
+ _modX[cnt] = READ_LE_UINT32(walkData);
+ walkData += 4;
+ }
+ for (int32 cnt = 0; cnt < NO_DIRECTIONS; cnt++) {
+ _modY[cnt] = READ_LE_UINT32(walkData);
+ walkData += 4;
+ }
+ _resMan->resClose(mega->o_mega_resource);
+ _diagonalx = _modX[3];
+ _diagonaly = _modY[3];
+ if ((_diagonalx != 36) || (_diagonaly != 8))
+ warning("DiagX = %d, DiagY = %d", _diagonalx, _diagonaly);
+ // mega data ready
+ // finish setting grid by putting mega node at begining
+ // and target node at end and reset current values
+
+ _node[0].x = mega->o_xcoord; // the start
+ _node[0].y = mega->o_ycoord; //
+ _node[0].dist = 0;
+ _node[0].prev = 0;
+ _node[0].level = 1;
+
+ for (int32 cnt = 1; cnt <= _nNodes; cnt++) {
+ _node[cnt].dist = 9999;
+ _node[cnt].prev = 0;
+ _node[cnt].level = 0;
+ }
+ _node[_nNodes].x = x; // the destination
+ _node[_nNodes].y = y; //
+}
+
+int SwordRouter::whatTarget(int32 startX, int32 startY, int32 destX, int32 destY) {
+ int tar_dir;
+//setting up
+ int deltaX = destX-startX;
+ int deltaY = destY-startY;
+ int signX = (deltaX > 0);
+ int signY = (deltaY > 0);
+ int slope;
+
+ if ( (abs(deltaY) * _diagonalx ) < (abs(deltaX) * _diagonaly / 2))
+ slope = 0;// its flat
+ else if ( (abs(deltaY) * _diagonalx / 2) > (abs(deltaX) * _diagonaly ) )
+ slope = 2;// its vertical
+ else
+ slope = 1;// its diagonal
+
+ if (slope == 0) { //flat
+ if (signX == 1) // going right
+ tar_dir = 2;
+ else
+ tar_dir = 6;
+ } else if (slope == 2) { //vertical
+ if (signY == 1) // going down
+ tar_dir = 4;
+ else
+ tar_dir = 0;
+ } else if (signX == 1) { //right diagonal
+ if (signY == 1) // going down
+ tar_dir = 3;
+ else
+ tar_dir = 1;
+ } else { //left diagonal
+ if (signY == 1) // going down
+ tar_dir = 5;
+ else
+ tar_dir = 7;
+ }
+ return tar_dir;
+}