aboutsummaryrefslogtreecommitdiff
path: root/sword2/router.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sword2/router.cpp')
-rw-r--r--sword2/router.cpp3089
1 files changed, 3089 insertions, 0 deletions
diff --git a/sword2/router.cpp b/sword2/router.cpp
new file mode 100644
index 0000000000..cf81c45670
--- /dev/null
+++ b/sword2/router.cpp
@@ -0,0 +1,3089 @@
+/* Copyright (C) 1994-2003 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$
+ */
+
+//--------------------------------------------------------------------------------------
+// ROUTER.CPP by James
+
+// A rehash of Jeremy's original jrouter.c, containing low-level system routines
+// for calculating routes between points inside a walk-grid, and constructing
+// walk animations from mega-sets.
+
+// jrouter.c undwent 2 major reworks from the original:
+// (1) Restructured to allow more flexibility in the mega-sets, ie. more info taken from the walk-data
+// - the new George & Nico mega-sets & walk-data were then tested & tweaked in the Sword1 system
+// (2) Updated for the new Sword2 system, ie. new object structures
+// - now compatible with Sword2, the essential code already having been tested
+
+//--------------------------------------------------------------------------------------
+
+
+/****************************************************************************
+ * JROUTER.C polygon router with modular walks
+ * using a tree of modules
+ * 21 july 94
+ * 3 november 94
+ * System currently works by scanning grid data and coming up with a ROUTE
+ * as a series of way points(nodes), the smoothest eight directional PATH
+ * through these nodes is then found, and a WALK created to fit the PATH.
+ *
+ * Two funtions are called by the user, RouteFinder creates a route as a
+ * module list, HardWalk creates an animation list from the module list.
+ * The split is only provided to allow the possibility of turning the
+ * autorouter over two game cycles.
+ ****************************************************************************
+ *
+ * Routine timings on osborne 486
+ *
+ * Read floor resource (file already loaded) 112 pixels
+ *
+ * Read mega resource (file already loaded) 112 pixels
+ *
+ *
+ *
+ ****************************************************************************
+ *
+ * Modified 12 Oct 95
+ *
+ * Target Points within 1 pixel of a line are ignored ???
+ *
+ * Modules split into Points within 1 pixel of a line are ignored ???
+ *
+ ****************************************************************************
+ *
+ * TOTALLY REHASHED BY JAMES FOR NEW MEGAS USING OLD SYSTEM
+ * THEN REINCARNATED BY JAMES FOR NEW MEGAS USING NEW SYSTEM
+ *
+ ****************************************************************************
+ ****************************************************************************/
+
+
+//#define PLOT_PATHS 1
+
+
+/*
+ * Include Files
+ */
+
+
+#include "driver/driver96.h"
+#include "console.h"
+#include "debug.h"
+#include "defs.h"
+#include "header.h"
+#include "interpreter.h"
+#include "memory.h"
+#include "object.h"
+#include "resman.h"
+#include "router.h"
+
+//#ifdef PLOT_PATHS
+//#include "grengine.h"
+//#endif
+
+#define MAX_FRAMES_PER_CYCLE 16
+#define NO_DIRECTIONS 8
+#define MAX_FRAMES_PER_CHAR (MAX_FRAMES_PER_CYCLE * NO_DIRECTIONS)
+#define ROUTE_END_FLAG 255
+
+
+
+
+//---------------------------------------
+// TEMP!
+int8 forceSlidy; // 1 = force the use of slidy router (so solid path not used when ending walk in ANY direction)
+//---------------------------------------
+
+/*
+ * Type Defines
+ */
+
+#define O_WALKANIM_SIZE 600 // max number of nodes in router output
+#define O_GRID_SIZE 200 // max 200 lines & 200 points
+#define EXTRA_GRID_SIZE 20 // max 20 lines & 20 points
+#define O_ROUTE_SIZE 50 // max number of modules in a route
+
+
+typedef struct
+{
+ int16 x1;
+ int16 y1;
+ int16 x2;
+ int16 y2;
+ int16 xmin;
+ int16 ymin;
+ int16 xmax;
+ int16 ymax;
+ int16 dx; // x2 - x1
+ int16 dy; // y2 - y1
+ int32 co; // co = (y1 *dx)- (x1*dy) from an equation for a line y*dx = x*dy + co
+}_barData;
+
+typedef struct
+{
+ int16 x;
+ int16 y;
+ int16 level;
+ int16 prev;
+ int16 dist;
+}_nodeData;
+
+typedef struct
+{
+ int32 nbars;
+ _barData *bars;
+ int32 nnodes;
+ _nodeData *node;
+} _floorData;
+
+typedef struct
+{
+ int32 x;
+ int32 y;
+ int32 dirS;
+ int32 dirD;
+} _routeData;
+
+typedef struct
+{
+ int32 x;
+ int32 y;
+ int32 dir;
+ int32 num;
+} _pathData;
+
+
+//--------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------
+// Function prototypes
+
+int32 GetRoute(void);
+void ExtractRoute(void);
+void LoadWalkGrid(void);
+void SetUpWalkGrid(Object_mega *ob_mega, int32 x, int32 y, int32 dir);
+void LoadWalkData(Object_walkdata *ob_walkdata);
+void PlotCross(int16 x, int16 y, uint8 colour);
+
+int32 Scan(int32);
+int32 NewCheck(int32, int32 , int32 , int32 , int32);
+int32 LineCheck(int32 , int32 , int32 , int32);
+int32 VertCheck(int32 , int32 , int32);
+int32 HorizCheck(int32 , int32 , int32);
+int32 Check(int32 , int32 , int32 , int32);
+int32 CheckTarget(int32 , int32);
+
+int32 SmoothestPath();
+int32 SlidyPath();
+int32 SolidPath();
+
+int32 SmoothCheck(int32 best, int32 p, int32 dirS, int32 dirD);
+
+int32 AddSlowInFrames(_walkData *walkAnim);
+void AddSlowOutFrames(_walkData *walkAnim);
+void SlidyWalkAnimator(_walkData *walkAnim);
+int32 SolidWalkAnimator(_walkData *walkAnim);
+void RouteLine(int32 x1,int32 y1,int32 x2,int32 y2 ,int32 colour);
+
+//--------------------------------------------------------------------------------------
+#define MAX_WALKGRIDS 10
+
+int32 walkGridList[MAX_WALKGRIDS];
+
+//--------------------------------------------------------------------------------------
+#define TOTAL_ROUTE_SLOTS 2 // because we only have 2 megas in the game!
+
+mem *route_slots[TOTAL_ROUTE_SLOTS]; // stores pointers to mem blocks containing routes created & used by megas (NULL if slot not in use)
+
+//--------------------------------------------------------------------------------------
+// Local Variables
+
+static int32 nbars;
+static int32 nnodes;
+static _barData bars[O_GRID_SIZE+EXTRA_GRID_SIZE]; // because extra bars will be copied into here afer walkgrid loaded
+static _nodeData node[O_GRID_SIZE+EXTRA_GRID_SIZE];
+
+// area for extra route data to block parts of floors and enable routing round mega charaters
+static int32 nExtraBars = 0;
+static int32 nExtraNodes = 0;
+static _barData extraBars[EXTRA_GRID_SIZE];
+static _nodeData extraNode[EXTRA_GRID_SIZE];
+
+static int32 startX;
+static int32 startY;
+static int32 startDir;
+static int32 targetX;
+static int32 targetY;
+static int32 targetDir;
+static int32 scaleA;
+static int32 scaleB;
+static _routeData route[O_ROUTE_SIZE];
+static _pathData smoothPath[O_ROUTE_SIZE];
+static _pathData modularPath[O_ROUTE_SIZE];
+static int32 routeLength;
+
+
+int32 framesPerStep;
+int32 framesPerChar;
+
+uint8 nWalkFrames; // no. of frames per walk cycle
+uint8 usingStandingTurnFrames; // any standing turn frames?
+uint8 usingWalkingTurnFrames; // any walking turn frames?
+uint8 usingSlowInFrames; // any slow-in frames?
+uint8 usingSlowOutFrames; // any slow-out frames?
+int32 dx[NO_DIRECTIONS + MAX_FRAMES_PER_CHAR];
+int32 dy[NO_DIRECTIONS + MAX_FRAMES_PER_CHAR];
+int8 modX[NO_DIRECTIONS];
+int8 modY[NO_DIRECTIONS];
+int32 diagonalx = 0;
+int32 diagonaly = 0;
+
+int32 firstStandFrame;
+
+int32 firstStandingTurnLeftFrame;
+int32 firstStandingTurnRightFrame;
+
+int32 firstWalkingTurnLeftFrame; // left walking turn
+int32 firstWalkingTurnRightFrame; // right walking turn
+
+uint32 firstSlowInFrame[NO_DIRECTIONS];
+uint32 numberOfSlowInFrames[NO_DIRECTIONS];
+
+uint32 leadingLeg[NO_DIRECTIONS];
+
+int32 firstSlowOutFrame;
+int32 numberOfSlowOutFrames; // number of slow-out frames on for each leading-leg in each direction
+
+
+int32 stepCount;
+
+int32 moduleX;
+int32 moduleY;
+int32 currentDir;
+int32 lastCount;
+int32 frame;
+
+// ie. total number of slow-out frames = (numberOfSlowOutFrames * 2 * NO_DIRECTIONS)
+
+/*
+ * CODE
+ */
+
+// **************************************************************************
+
+//--------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------
+uint8 CheckForCollision(void)
+{
+ static uint32 player_pc;
+ static uint32 non_player_pc;
+
+
+ uint8 collision=0;
+
+ return (collision);
+}
+//--------------------------------------------------------------------------------------
+uint8 ReturnSlotNo(uint32 megaId)
+{
+ if (ID==CUR_PLAYER_ID) // George (8)
+ return(0);
+ else // One of Nico's mega id's
+ return(1);
+}
+//--------------------------------------------------------------------------------------
+void AllocateRouteMem(void)
+{
+// uint8 slotNo=0;
+ uint8 slotNo;
+
+ //------------------------------------------
+ // removed (James23June96)
+ /*
+ while (route_slots[slotNo] > 0)
+ {
+ slotNo++;
+
+ #ifdef _DEBUG
+ if (slotNo == TOTAL_ROUTE_SLOTS)
+ Con_fatal_error("ERROR: route_slots[] full in AllocateRouteMem() (%s line %u)",__FILE__,__LINE__);
+ #endif
+ }
+ */
+ //------------------------------------------
+ // added (James23June96)
+ // Player character always always slot 0, while the other mega (normally Nico) always uses slot 1
+ // Better this way, so that if mega object removed from memory while in middle of route,
+ // the old route will be safely cleared from memory just before they create a new one
+
+ slotNo = ReturnSlotNo(ID);
+
+ // if this slot is already used, then it can't be needed any more
+ // because this id is creating a new route!
+ if (route_slots[slotNo])
+ {
+ FreeRouteMem();
+ }
+ //------------------------------------------
+
+ route_slots[slotNo] = Twalloc( 4800, MEM_locked, UID_walk_anim );
+ // 12000 bytes were used for this in Sword1 mega compacts, based on 20 bytes per '_walkData' frame
+ // ie. allowing for 600 frames including end-marker
+ // Now '_walkData' is 8 bytes, so 8*600 = 4800 bytes.
+ // Note that a 600 frame walk lasts about 48 seconds! (600fps / 12.5s = 48s)
+
+// megaObject->route_slot_id = slotNo+1; // mega keeps note of which slot contains the pointer to it's walk animation mem block
+ // +1 so that '0' can mean "not walking"
+}
+//--------------------------------------------------------------------------------------
+_walkData* LockRouteMem(void)
+{
+ uint8 slotNo = ReturnSlotNo(ID);
+
+ Lock_mem( route_slots[slotNo] );
+ return (_walkData *)route_slots[slotNo]->ad;
+}
+//--------------------------------------------------------------------------------------
+void FloatRouteMem(void)
+{
+ uint8 slotNo = ReturnSlotNo(ID);
+
+ Float_mem( route_slots[slotNo] );
+}
+//--------------------------------------------------------------------------------------
+void FreeRouteMem(void)
+{
+ uint8 slotNo = ReturnSlotNo(ID);
+
+ Free_mem( route_slots[slotNo] ); // free the mem block pointed to from this entry of route_slots[]
+ route_slots[slotNo] = NULL; // clear this route_slots[] entry
+}
+//--------------------------------------------------------------------------------------
+void FreeAllRouteMem(void)
+{
+ uint8 slotNo;
+
+ for (slotNo=0; slotNo < TOTAL_ROUTE_SLOTS; slotNo++)
+ {
+ if (route_slots[slotNo])
+ {
+ Free_mem( route_slots[slotNo] ); // free the mem block pointed to from this entry of route_slots[]
+ route_slots[slotNo] = NULL;
+ }
+ }
+}
+//--------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------
+
+// **************************************************************************
+// **************************************************************************
+// **************************************************************************
+// **************************************************************************
+
+int32 RouteFinder(Object_mega *ob_mega, Object_walkdata *ob_walkdata, int32 x, int32 y, int32 dir)
+{
+/****************************************************************************
+ * RouteFinder.C polygon router with modular walks
+ * 21 august 94
+ * 3 november 94
+ * RouteFinder creates a list of modules that enables HardWalk to create
+ * an animation list.
+ *
+ * RouteFinder currently works by scanning grid data and coming up with a ROUTE
+ * as a series of way points(nodes), the smoothest eight directional PATH
+ * through these nodes is then found, this information is made available to
+ * HardWalk for a WALK to be created to fit the PATH.
+ *
+ * 30 november 94 return values modified
+ *
+ * return 0 = failed to find a route
+ *
+ * 1 = found a route
+ *
+ * 2 = mega already at target
+ *
+ ****************************************************************************/
+
+ int32 routeFlag = 0;
+ int32 solidFlag = 0;
+ _walkData *walkAnim;
+
+// megaId = id;
+
+
+ SetUpWalkGrid(ob_mega, x, y, dir);
+ LoadWalkData(ob_walkdata);
+
+ walkAnim = LockRouteMem(); // lock the _walkData array (NB. AFTER loading walkgrid & walkdata!)
+
+// **************************************************************************
+// All route data now loaded start finding a route
+// **************************************************************************
+// **************************************************************************
+// Check if we can get a route through the floor changed 12 Oct95 JPS
+// **************************************************************************
+
+ routeFlag = GetRoute();
+
+
+ if (routeFlag == 2) //special case for zero length route
+ {
+ if (targetDir >7)// if target direction specified as any
+ {
+ targetDir = startDir;
+ }
+ // 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 = startDir;
+ modularPath[0].num = 0;
+ modularPath[0].x = startX;
+ modularPath[0].y = startY;
+ modularPath[1].dir = targetDir;
+ modularPath[1].num = 0;
+ modularPath[1].x = startX;
+ modularPath[1].y = startY;
+ modularPath[2].dir = 9;
+ modularPath[2].num = ROUTE_END_FLAG;
+
+ SlidyWalkAnimator(walkAnim);
+ routeFlag = 2;
+ }
+ else if (routeFlag == 1) // a normal route
+ {
+ SmoothestPath();//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 (!forceSlidy)
+ {
+ if (targetDir == 8) // can end facing ANY direction (ie. exact end position not vital) - so use SOLID walk to avoid sliding to exact position
+ {
+ SolidPath();
+ solidFlag = SolidWalkAnimator(walkAnim);
+ }
+ }
+
+ if(!solidFlag) // if we failed to create a SOLID route, do a SLIDY one instead
+ {
+ SlidyPath();
+ SlidyWalkAnimator(walkAnim);
+ }
+ }
+ else // Route didn't reach target so assume point was off the floor
+ {
+// routeFlag = 0;
+ }
+
+
+ #ifdef PLOT_PATHS
+ #ifdef _WIN32
+ RenderScreenGDK( screenDef.buffer, scroll_offset_x, scroll_offset_y, screenDef.width * XBLOCKSIZE );
+ #else
+ RenderOffScreenBuffer( scroll_offset_x, scroll_offset_y, SCREEN_WIDTH, SCREEN_DEPTH );
+ #endif
+ FlipScreens();
+
+ FlushMouseEvents(); // clear mouse buffer
+ while (!TestForMouseEvent()); // wait for a button press or release
+ FlushMouseEvents(); // clear mouse buffer again to prevent rapid fire!
+ #endif
+
+
+ FloatRouteMem(); // float the _walkData array again
+
+ return routeFlag; // send back null route
+}
+
+/*******************************************************************************
+ *******************************************************************************
+ * GET A ROUTE
+ *******************************************************************************
+ *******************************************************************************/
+
+
+int32 GetRoute(void)
+{
+ /****************************************************************************
+ * GetRoute.C extract a path from walk grid
+ * 12 october 94
+ *
+ * GetRoute currently works by scanning grid data and coming up with a ROUTE
+ * as a series of way points(nodes).
+ * static _routeData route[O_ROUTE_SIZE];
+ *
+ * return 0 = failed to find a route
+ *
+ * 1 = found a route
+ *
+ * 2 = mega already at target
+ *
+ * 3 = failed to find a route because target was on a line
+ *
+ ****************************************************************************/
+ int32 routeGot = 0;
+ int32 level;
+ int32 changed;
+
+ if ((startX == targetX) && (startY == targetY))
+ routeGot = 2;
+
+ else // 'else' added by JEL (23jan96) otherwise 'routeGot' affected even when already set to '2' above - causing some 'turns' to walk downwards on the spot
+ routeGot = CheckTarget(targetX,targetY);// returns 3 if target on a line ( +- 1 pixel )
+
+
+ if (routeGot == 0) //still looking for a route check if target is within a pixel of a line
+ {
+ // scan through the nodes linking each node to its nearest neighbour until no more nodes change
+ // This is the routine that finds a route using Scan()
+ level = 1;
+ do
+ {
+ changed = Scan(level);
+ level =level + 1;
+ }
+ while(changed == 1);
+
+ // Check to see if the route reached the target
+ if (node[nnodes].dist < 9999)
+ {
+ routeGot = 1;
+ ExtractRoute(); // it did so 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
+ }
+ }
+
+ return routeGot;
+}
+
+
+/*******************************************************************************
+ *******************************************************************************
+ * THE SLIDY PATH ROUTINES
+ *******************************************************************************
+ *******************************************************************************/
+
+
+int32 SmoothestPath()
+{
+/*
+ * 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 choosing 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 number 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 p;
+ 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 i;
+ int32 j;
+ 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;
+ p = 0;
+ lastDir = startDir;
+ // for each section of the route
+ do
+ {
+
+ 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;
+ i = 0;
+ do
+ {
+ j = 0;
+ do
+ {
+ 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;
+ }
+ j = j + 1;
+ }
+ while (j < 3);
+ i = i + 1;
+ }
+ while (i < 3);
+
+ // 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);
+
+#ifdef _DEBUG
+ if (options == 0)
+ {
+ Zdebug("BestTurns fail %d %d %d %d",route[p].x, route[p].y, route[p + 1].x, route[p + 1].y);
+ Zdebug("BestTurns fail %d %d %d %d",turns[0],turns[1],turns[2],options);
+ Con_fatal_error("BestTurns failed (%s line %u)",__FILE__,__LINE__);
+ }
+#endif
+
+ i = 0;
+ steps = 0;
+ do
+ {
+ option = 1 << turns[i];
+ if (option & options)
+ steps = SmoothCheck(turns[i],p,dirS,dirD);
+ i = i + 1;
+ }
+ while ((steps == 0) && (i < 4));
+
+#ifdef PLOT_PATHS // plot the best path
+ if (steps != 0)
+ {
+ i = 0;
+ do
+ {
+ RouteLine(smoothPath[i].x, smoothPath[i].y, smoothPath[i+1].x, smoothPath[i+1].y, 228);
+ i = i + 1;
+ }
+ while (i < steps);
+ }
+#endif
+
+
+#ifdef _DEBUG
+ if (steps == 0)
+ {
+ Zdebug("BestTurns failed %d %d %d %d",route[p].x, route[p].y, route[p + 1].x, route[p + 1].y);
+ Zdebug("BestTurns failed %d %d %d %d",turns[0],turns[1],turns[2],options);
+ Con_fatal_error("BestTurns failed (%s line %u)",__FILE__,__LINE__);
+ }
+#endif
+
+ // route.X route.Y route.dir and bestTurns start at far end
+ p = p + 1;
+
+
+ }
+ while (p < (routeLength));
+ // best turns will end heading as near as possible to target dir rest is down to anim for now
+ smoothPath[steps].dir = 9;
+ smoothPath[steps].num = ROUTE_END_FLAG;
+ return 1;
+}
+
+
+
+
+int32 SmoothCheck(int32 best, int32 p, int32 dirS, int32 dirD)
+/****************************************************************************
+ * Slip sliding away
+ * This path checker checks to see if a walk that exactly follows the path
+ * would be valid. This should be inherently true for atleast one of the turn
+ * options.
+ * No longer checks the data it only creates the smoothPath array JPS
+ ****************************************************************************/
+{
+ 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;
+}
+
+int32 SlidyPath()
+{
+/****************************************************************************
+ * 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;
+ return 1;
+
+}
+
+//****************************************************************************
+// SLOW IN
+
+int32 AddSlowInFrames(_walkData *walkAnim)
+{
+ uint32 slowInFrameNo;
+
+
+ if ((usingSlowInFrames) && (modularPath[1].num > 0))
+ {
+ for (slowInFrameNo=0; slowInFrameNo<numberOfSlowInFrames[currentDir]; slowInFrameNo++)
+ {
+ walkAnim[stepCount].frame = firstSlowInFrame[currentDir] + slowInFrameNo;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ return(1);
+ }
+ else
+ {
+ return(0);
+ }
+}
+//----------------------------------------------------------------------------
+void EarlySlowOut(Object_mega *ob_mega, Object_walkdata *ob_walkdata)
+{
+ int32 slowOutFrameNo;
+ int32 walk_pc;
+ _walkData *walkAnim;
+
+
+ //Zdebug("\nEARLY SLOW-OUT");
+
+ LoadWalkData(ob_walkdata);
+
+ //Zdebug("********************************");
+ //Zdebug("framesPerStep =%d",framesPerStep); // 6;
+ //Zdebug("numberOfSlowOutFrames =%d",numberOfSlowOutFrames); // 7;
+ //Zdebug("firstWalkingTurnLeftFrame =%d",firstWalkingTurnLeftFrame); // 120;
+ //Zdebug("firstWalkingTurnRightFrame =%d",firstWalkingTurnRightFrame); // 216;
+ //Zdebug("firstSlowOutFrame =%d",firstSlowOutFrame); // 344;
+ //Zdebug("********************************");
+
+
+ walk_pc = ob_mega->walk_pc;
+
+ walkAnim = LockRouteMem(); // lock the _walkData array (NB. AFTER loading walkgrid & walkdata!)
+
+
+ if (usingSlowOutFrames) // if this mega does actually have slow-out frames
+ {
+ do // overwrite the next step (half a cycle) of the walk (ie .step - 0..5
+ {
+ //Zdebug("\nSTEP NUMBER: walkAnim[%d].step = %d",walk_pc,walkAnim[walk_pc].step);
+ //Zdebug("ORIGINAL FRAME: walkAnim[%d].frame = %d",walk_pc,walkAnim[walk_pc].frame);
+ // map from existing walk frame across to correct frame number of slow-out - remember, there may be more slow-out frames than walk-frames!
+
+ if (walkAnim[walk_pc].frame >= firstWalkingTurnRightFrame) // if it's a walking turn-right, rather than a normal step
+ {
+ walkAnim[walk_pc].frame -= firstWalkingTurnRightFrame; // then map it to a normal step frame first
+ //Zdebug("MAPPED TO WALK: walkAnim[%d].frame = %d (walking turn-right frame --> walk frame)",walk_pc,walkAnim[walk_pc].frame);
+ }
+
+ else if (walkAnim[walk_pc].frame >= firstWalkingTurnLeftFrame) // if it's a walking turn-left, rather than a normal step
+ {
+ walkAnim[walk_pc].frame -= firstWalkingTurnLeftFrame; // then map it to a normal step frame first
+ //Zdebug("MAPPED TO WALK: walkAnim[%d].frame = %d (walking turn-left frame --> walk frame)",walk_pc,walkAnim[walk_pc].frame);
+ }
+
+ walkAnim[walk_pc].frame += firstSlowOutFrame + ((walkAnim[walk_pc].frame / framesPerStep) * (numberOfSlowOutFrames-framesPerStep));
+ walkAnim[walk_pc].step = 0;
+ //Zdebug("SLOW-OUT FRAME: walkAnim[%d].frame = %d",walk_pc,walkAnim[walk_pc].frame);
+ walk_pc += 1;
+ }
+ while(walkAnim[walk_pc].step > 0 );
+
+ //Zdebug("\n");
+
+ for (slowOutFrameNo=framesPerStep; slowOutFrameNo < numberOfSlowOutFrames; slowOutFrameNo++) // add stationary frame(s) (OPTIONAL)
+ {
+ walkAnim[walk_pc].frame = walkAnim[walk_pc-1].frame + 1;
+ //Zdebug("EXTRA FRAME: walkAnim[%d].frame = %d",walk_pc,walkAnim[walk_pc].frame);
+ walkAnim[walk_pc].step = 0;
+ walkAnim[walk_pc].dir = walkAnim[walk_pc-1].dir;
+ walkAnim[walk_pc].x = walkAnim[walk_pc-1].x;
+ walkAnim[walk_pc].y = walkAnim[walk_pc-1].y;
+ walk_pc++;
+ }
+ }
+ else // this mega doesn't have slow-out frames
+ {
+ walkAnim[walk_pc].frame = firstStandFrame + walkAnim[walk_pc-1].dir; // stand in current direction
+ walkAnim[walk_pc].step = 0;
+ walkAnim[walk_pc].dir = walkAnim[walk_pc-1].dir;
+ walkAnim[walk_pc].x = walkAnim[walk_pc-1].x;
+ walkAnim[walk_pc].y = walkAnim[walk_pc-1].y;
+ walk_pc++;
+ }
+
+ walkAnim[walk_pc].frame = 512; // end of sequence
+ walkAnim[walk_pc].step = 99; // so that this doesn't happen again while 'george_walking' is still '2'
+}
+//----------------------------------------------------------------------------
+// SLOW OUT
+
+void AddSlowOutFrames(_walkData *walkAnim)
+{
+ int32 slowOutFrameNo;
+
+
+ if ((usingSlowOutFrames)&&(lastCount>=framesPerStep)) // if the mega did actually walk, we overwrite the last step (half a cycle) with slow-out frames + add any necessary stationary frames
+ {
+ // place stop frames here
+ // slowdown at the end of the last walk
+
+ slowOutFrameNo = lastCount - framesPerStep;
+
+
+ //Zdebug("SLOW OUT: slowOutFrameNo(%d) = lastCount(%d) - framesPerStep(%d)",slowOutFrameNo,lastCount,framesPerStep);
+
+ do // overwrite the last step (half a cycle) of the walk
+ {
+ // map from existing walk frame across to correct frame number of slow-out - remember, there may be more slow-out frames than walk-frames!
+ walkAnim[slowOutFrameNo].frame += firstSlowOutFrame + ((walkAnim[slowOutFrameNo].frame / framesPerStep) * (numberOfSlowOutFrames-framesPerStep));
+ walkAnim[slowOutFrameNo].step = 0; // because no longer a normal walk-step
+ //Zdebug("walkAnim[%d].frame = %d",slowOutFrameNo,walkAnim[slowOutFrameNo].frame);
+ slowOutFrameNo += 1;
+ }
+ while(slowOutFrameNo < lastCount );
+
+ for (slowOutFrameNo=framesPerStep; slowOutFrameNo < numberOfSlowOutFrames; slowOutFrameNo++) // add stationary frame(s) (OPTIONAL)
+ {
+ walkAnim[stepCount].frame = walkAnim[stepCount-1].frame + 1;
+ //Zdebug("EXTRA FRAMES: walkAnim[%d].frame = %d",stepCount,walkAnim[stepCount].frame);
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = walkAnim[stepCount-1].dir;
+ walkAnim[stepCount].x = walkAnim[stepCount-1].x;
+ walkAnim[stepCount].y = walkAnim[stepCount-1].y;
+ stepCount += 1;
+ }
+ }
+}
+//----------------------------------------------------------------------------
+
+void SlidyWalkAnimator(_walkData *walkAnim)
+/****************************************************************************
+ * 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 turnDir;
+ int32 scale;
+ int32 step;
+ int32 module;
+ int32 moduleEnd;
+ int32 module16X;
+ int32 module16Y;
+ int32 stepX;
+ int32 stepY;
+ int32 errorX;
+ int32 errorY;
+ int32 lastErrorX;
+ int32 lastErrorY;
+ int32 frameCount;
+ int32 frames;
+
+
+ p = 0;
+ lastDir = modularPath[0].dir;
+ currentDir = modularPath[1].dir;
+ if (currentDir == NO_DIRECTIONS)
+ {
+ currentDir = lastDir;
+ }
+ moduleX = startX;
+ moduleY = 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
+ //****************************************************************************
+ //Zdebug("\nSLIDY: STARTING THE WALK");
+ module = 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
+ //****************************************************************************
+ //Zdebug("\nSLIDY: TURNING 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 (usingStandingTurnFrames)
+ {
+ if ( turnDir < 0) // new frames for turn frames 29oct95jps
+ {
+ module = firstStandingTurnLeftFrame + lastDir;
+ }
+ else
+ {
+ module = firstStandingTurnRightFrame + 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 = firstStandingTurnLeftFrame + lastDir;
+ }
+ else
+ {
+ if ( lastDir > 7)
+ lastDir -= NO_DIRECTIONS;
+ module = firstStandingTurnRightFrame + 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 SLOW IN
+
+ AddSlowInFrames(walkAnim);
+ //****************************************************************************
+
+ //****************************************************************************
+ // SLIDY
+ // THE WALK
+ //****************************************************************************
+
+ //Zdebug("\nSLIDY: THE WALK");
+
+ //---------------------------------------------------
+ // start the walk on the left or right leg, depending on how the slow-in frames were drawn
+
+ if (leadingLeg[currentDir]==0) // (0=left; 1=right)
+ left = 0; // start the walk on the left leg (ie. at beginning of the first step of the walk cycle)
+ else
+ left = framesPerStep; // start the walk on the right leg (ie. at beginning of the second step of the walk cycle)
+ //---------------------------------------------------
+
+
+ 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)
+ {
+ 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 * framesPerStep * 2 + left;
+ if (left == 0)
+ left = framesPerStep;
+ else
+ left = 0;
+ moduleEnd = module + framesPerStep;
+ step = 0;
+ scale = (scaleA * moduleY + scaleB);
+ do
+ {
+ module16X += dx[module]*scale;
+ module16Y += dy[module]*scale;
+ moduleX = module16X >> 16;
+ moduleY = module16Y >> 16;
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = step; // normally 0,1,2,3,4,5,0,1,2,etc
+ 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 > 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 -= framesPerStep;
+ if (left == 0)
+ left = framesPerStep;
+ else
+ left = 0;
+ }
+ }
+ else
+ {
+ if (3*abs(lastErrorX) < abs(errorX)) //the last stop was closest
+ {
+ stepCount -= framesPerStep;
+ if (left == 0)
+ left = 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 < 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)) && (usingWalkingTurnFrames)) // 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 - framesPerStep;
+ do
+ {
+ walkAnim[frame].frame += firstWalkingTurnLeftFrame; //was 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 - framesPerStep;
+ do
+ {
+ walkAnim[frame].frame += firstWalkingTurnRightFrame; // was 200; // turning right
+ 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);
+
+
+
+#ifdef _DEBUG
+ if (lastRealDir == 99)
+ {
+ Con_fatal_error("SlidyWalkAnimatorlast direction error (%s line %u)",__FILE__,__LINE__);
+ }
+#endif
+
+ //****************************************************************************
+ // SLIDY: THE SLOW OUT
+ AddSlowOutFrames(walkAnim);
+
+ //****************************************************************************
+ // SLIDY
+ // TURNS TO END THE WALK ?
+ //****************************************************************************
+
+ // We've done the walk now put in any turns at the end
+
+
+ if (targetDir == 8) // ANY direction -> stand in the last direction
+ {
+ module = firstStandFrame + lastRealDir;
+ 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 (targetDir == 9) // 'stance' was non-zero
+ {
+ if (stepCount == 0)
+ {
+ module = 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 (targetDir != lastRealDir) // rotate to targetDir
+ {
+ // rotate to target direction
+ turnDir = 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 (usingStandingTurnFrames)
+ {
+ if ( turnDir < 0) // new frames for turn frames 29oct95jps
+ {
+ module = firstStandingTurnLeftFrame + lastDir;
+ }
+ else
+ {
+ module = firstStandingTurnRightFrame + 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 != targetDir)
+ {
+ lastRealDir += turnDir;
+ if ( turnDir < 0) // new frames for turn frames 29oct95jps
+ {
+ if ( lastRealDir < 0)
+ lastRealDir += NO_DIRECTIONS;
+ module = firstStandingTurnLeftFrame + lastRealDir;
+ }
+ else
+ {
+ if ( lastRealDir > 7)
+ lastRealDir -= NO_DIRECTIONS;
+ module = firstStandingTurnRightFrame + lastRealDir;
+ }
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastRealDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ module = firstStandFrame + lastRealDir;
+ walkAnim[stepCount-1].frame = module;
+ }
+ else // just stand at the end
+ {
+ module = firstStandFrame + 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;
+ walkAnim[stepCount].step = 99;
+ stepCount += 1;
+ walkAnim[stepCount].frame = 512;
+ walkAnim[stepCount].step = 99;
+ stepCount += 1;
+ walkAnim[stepCount].frame = 512;
+ walkAnim[stepCount].step = 99;
+
+
+ //-------------------------------------------
+ // write all the frames to "debug.txt"
+
+ //Zdebug("\nTHE WALKDATA:");
+ for (frame=0; frame<=stepCount; frame++)
+ {
+ //Zdebug("walkAnim[%d].frame=%d",frame,walkAnim[frame].frame);
+ }
+ //-------------------------------------------
+
+
+// Zdebug("RouteFinder RouteSize is %d", stepCount);
+ return;
+}
+
+
+/*******************************************************************************
+ *******************************************************************************
+ * THE SOLID PATH ROUTINES
+ *******************************************************************************
+ *******************************************************************************/
+
+int32 SolidPath()
+{
+/****************************************************************************
+ * 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;
+
+ // strip out the short sections
+ 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 SolidWalkAnimator(_walkData *walkAnim)
+{
+/****************************************************************************
+ * SolidWalk creates an animation based on whole steps with no sliding to get
+ * as near as possible to the target without any sliding this routine is
+ * is intended for use when just clicking about.
+ *
+ * produce a module list from the line data
+ *
+ * returns 0 if solid route not found
+ ****************************************************************************/
+
+ int32 p;
+ int32 i;
+ int32 left;
+ int32 lastDir;
+ int32 turnDir;
+ int32 scale;
+ int32 step;
+ int32 module;
+ int32 module16X;
+ int32 module16Y;
+ int32 errorX;
+ int32 errorY;
+ int32 moduleEnd;
+ int32 slowStart=0;
+
+
+
+ // start at the beginning for a change
+ lastDir = modularPath[0].dir;
+ p = 1;
+ currentDir = modularPath[1].dir;
+ module = framesPerChar + lastDir;
+ moduleX = startX;
+ moduleY = startY;
+ module16X = moduleX << 16;
+ module16Y = moduleY << 16;
+ 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
+ //****************************************************************************
+
+ //Zdebug("\nSOLID: STARTING THE WALK");
+ 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
+ //****************************************************************************
+ //Zdebug("\nSOLID: TURNING 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 (usingStandingTurnFrames)
+ {
+ if ( turnDir < 0) // new frames for turn frames 29oct95jps
+ {
+ module = firstStandingTurnLeftFrame + lastDir;
+ }
+ else
+ {
+ module = firstStandingTurnRightFrame + 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 = firstStandingTurnLeftFrame + lastDir;
+ }
+ else
+ {
+ if ( lastDir > 7)
+ lastDir -= NO_DIRECTIONS;
+ module = firstStandingTurnRightFrame + 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
+
+ slowStart = AddSlowInFrames(walkAnim);
+
+ //****************************************************************************
+ // SOLID
+ // THE WALK
+ //****************************************************************************
+
+ //Zdebug("\nSOLID: THE WALK");
+
+ //---------------------------------------------------
+ // start the walk on the left or right leg, depending on how the slow-in frames were drawn
+
+ if (leadingLeg[currentDir]==0) // (0=left; 1=right)
+ left = 0; // start the walk on the left leg (ie. at beginning of the first step of the walk cycle)
+ else
+ left = framesPerStep; // start the walk on the right leg (ie. at beginning of the second step of the walk cycle)
+ //---------------------------------------------------
+
+
+ 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 * framesPerStep * 2 + left;
+ if (left == 0)
+ left = framesPerStep;
+ else
+ left = 0;
+ moduleEnd = module + framesPerStep;
+ step = 0;
+ scale = (scaleA * moduleY + scaleB);
+ do
+ {
+ module16X += dx[module]*scale;
+ module16Y += dy[module]*scale;
+ moduleX = module16X >> 16;
+ moduleY = module16Y >> 16;
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = step; // normally 0,1,2,3,4,5,0,1,2,etc
+ 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 -= framesPerStep;
+ if (left == 0)
+ left = 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) < framesPerStep)// no step taken
+ {
+ if (slowStart == 1)// clean up if a slow in but no walk
+ {
+ //stepCount -= 3;
+ stepCount -= numberOfSlowInFrames[currentDir]; // (James08sep97)
+ //lastCount -= 3;
+ lastCount -= numberOfSlowInFrames[currentDir]; // (James08sep97)
+ slowStart = 0;
+ }
+ currentDir = 99;// this ensures that we don't put in turn frames for this walk or the next
+ }
+ // check each turn condition in turn
+ if (((lastDir != 99) && (currentDir != 99)) && (usingWalkingTurnFrames)) // 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 - framesPerStep;
+ do
+ {
+ walkAnim[frame].frame += firstWalkingTurnLeftFrame; // was 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 - framesPerStep;
+ do
+ {
+ walkAnim[frame].frame += firstWalkingTurnRightFrame; // was 200; // turning right
+ 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
+ AddSlowOutFrames(walkAnim);
+
+ //****************************************************************************
+
+ module = 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;
+ walkAnim[stepCount].step = 99;
+ stepCount += 1;
+ walkAnim[stepCount].frame = 512;
+ walkAnim[stepCount].step = 99;
+ stepCount += 1;
+ walkAnim[stepCount].frame = 512;
+ walkAnim[stepCount].step = 99;
+
+ //-------------------------------------------
+ // write all the frames to "debug.txt"
+
+ //Zdebug("\nTHE WALKDATA:");
+ for (frame=0; frame<=stepCount; frame++)
+ {
+ //Zdebug("walkAnim[%d].frame=%d",frame,walkAnim[frame].frame);
+ }
+ //-------------------------------------------
+
+ //****************************************************************************
+ // SOLID
+ // NO END TURNS
+ //****************************************************************************
+
+// Zdebug("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;
+ #ifdef PLOT_PATHS
+ RouteLine(modularPath[i].x, modularPath[i].y, modularPath[i+1].x, modularPath[i+1].y, 227);
+ #endif
+ i += 1;
+ }
+ while(i<p-1);
+ if (p != 0)
+ {
+ targetDir = modularPath[p-1].dir;
+ }
+ if (p != 0)
+ {
+ if (CheckTarget(moduleX,moduleY) == 3)// new target on a line
+ {
+ p = 0;
+ //Zdebug("Solid walk target was on a line %d %d", moduleX, moduleY);
+ }
+ }
+
+ return p;
+}
+
+
+/*******************************************************************************
+ *******************************************************************************
+ * THE SCAN ROUTINES
+ *******************************************************************************
+ *******************************************************************************/
+
+int32 Scan(int32 level)
+/*******************************************************************************
+ * Called successively from RouteFinder until no more changes take place in the
+ * grid array ie he best path has been found
+ *
+ * Scans through every point in the node array and checks if there is a route
+ * between each point and if this route gives a new route.
+ *
+ * This routine could probably halve its processing time if it doubled up on the
+ * checks after each route check
+ *
+ *******************************************************************************/
+{
+ int32 i;
+ int32 k;
+ int32 x1;
+ int32 y1;
+ int32 x2;
+ int32 y2;
+ int32 distance;
+ int32 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.
+ i = 0;
+ do
+ {
+ if ((node[i].dist < node[nnodes].dist) && (node[i].level == level))
+ {
+ x1 = node[i].x;
+ y1 = node[i].y;
+ k=nnodes;
+ do
+ {
+ if (node[k].dist > node[i].dist)
+ {
+ x2 = node[k].x;
+ 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 (NewCheck(0, x1,y1,x2,y2))
+ {
+ node[k].level = level + 1;
+ node[k].dist = distance + node[i].dist;
+ node[k].prev = i;
+ changed = 1;
+ }
+ }
+ }
+ k-=1;
+ }
+ while(k > 0);
+ }
+ i=i+1;
+ }
+ while(i < nnodes);
+ return changed;
+}
+
+
+int32 NewCheck(int32 status, int32 x1 , int32 y1 , int32 x2 ,int32 y2)
+/*******************************************************************************
+ * 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
+ *******************************************************************************/
+{
+ int32 dx;
+ int32 dy;
+ int32 dlx;
+ int32 dly;
+ int32 dirX;
+ int32 dirY;
+ int32 step1;
+ int32 step2;
+ int32 step3;
+ int32 steps;
+ int32 options;
+
+ steps = 0;
+ options = 0;
+ dx = x2 - x1;
+ dy = y2 - y1;
+ dirX = 1;
+ dirY = 1;
+ if (dx < 0)
+ {
+ dx = -dx;
+ dirX = -1;
+ }
+
+ if (dy < 0)
+ {
+ dy = -dy;
+ dirY = -1;
+ }
+
+ //make the route options
+ if ((diagonaly * dx) > (diagonalx * dy)) // dir = 1,2 or 2,3 or 5,6 or 6,7
+ {
+ dly = dy;
+ dlx = (dy*diagonalx)/diagonaly;
+ dx = dx - dlx;
+ dlx = dlx * dirX;
+ dly = dly * dirY;
+ dx = dx * dirX;
+ dy = 0;
+
+ //options are
+ //square, diagonal a code 1 route
+ step1 = Check(x1, y1, x1+dx, y1);
+ if (step1 != 0)
+ {
+ step2 = Check(x1+dx, y1, x2, y2);
+ if (step2 != 0)
+ {
+ steps = step1 + step2; // yes
+ options = options + 2;
+ #ifdef PLOT_PATHS
+ if (status == 1)
+ {
+ RouteLine(x1, y1, x1+dx, y1, 231);
+ RouteLine(x1+dx, y1, x2, y2, 231);
+ }
+ #endif
+ }
+ }
+ //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; // yes
+ options = options + 4;
+ #ifdef PLOT_PATHS
+ if (status == 1)
+ {
+ RouteLine(x1, y1, x1+dlx,y1+dly, 231);
+ RouteLine(x1+dlx, y2, x2, y2, 231);
+ }
+ #endif
+ }
+ }
+ }
+ //halfsquare, diagonal, halfsquare a code 0 route
+ if ((steps == 0) || (status == 1))
+ {
+ step1 = Check(x1, y1, x1+dx/2, y1);
+ if (step1 != 0)
+ {
+ step2 = Check(x1+dx/2, y1, x1+dx/2+dlx, y2);
+ if (step2 != 0)
+ {
+ step3 = Check(x1+dx/2+dlx, y2, x2, y2);
+ if (step3 != 0)
+ {
+ steps = step1 + step2 + step3; // yes
+ options = options + 1;
+ #ifdef PLOT_PATHS
+ if (status == 1)
+ {
+ RouteLine(x1, y1, x1+dx/2, y1, 231);
+ RouteLine(x1+dx/2, y1, x1+dx/2+dlx, y2, 231);
+ RouteLine(x1+dx/2+dlx, y2, x2, y2, 231);
+ }
+ #endif
+ }
+ }
+ }
+ }
+ //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+dx+dlx/2, y1+dly/2);
+ if (step2 != 0)
+ {
+ step3 = Check(x1+dx+dlx/2, y1+dly/2, x2, y2);
+ if (step3 != 0)
+ {
+ steps = step1 + step2 + step3; // yes
+ #ifdef PLOT_PATHS
+ if (status == 1)
+ {
+ RouteLine(x1, y1, x1+dlx/2, y1+dly/2, 231);
+ RouteLine(x1+dlx/2, y1+dly/2, x1+dx+dlx/2, y1+dly/2, 231);
+ RouteLine(x1+dx+dlx/2, y1+dly/2, x2, y2, 231);
+ }
+ #endif
+ options = options + 8;
+ }
+ }
+ }
+ }
+ }
+ else // dir = 7,0 or 0,1 or 3,4 or 4,5
+ {
+ dlx = dx;
+ dly = (dx*diagonaly)/diagonalx;
+ dy = dy - dly;
+ dlx = dlx * dirX;
+ dly = dly * dirY;
+ dy = dy * dirY;
+ dx = 0;
+
+ //options are
+ //square, diagonal a code 1 route
+ step1 = Check(x1 ,y1 ,x1 ,y1+dy );
+ if (step1 != 0)
+ {
+ step2 = Check(x1 ,y1+dy ,x2,y2);
+ if (step2 != 0)
+ {
+ steps = step1 + step2; // yes
+ #ifdef PLOT_PATHS
+ if (status == 1)
+ {
+ RouteLine(x1 ,y1 ,x1 ,y1+dy, 231);
+ RouteLine(x1 ,y1+dy ,x2, y2, 231);
+ }
+ #endif
+ 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; // yes
+ #ifdef PLOT_PATHS
+ if (status == 1)
+ {
+ RouteLine(x1, y1, x2, y1+dly, 231);
+ RouteLine(x2, y1+dly, x2, y2, 231);
+ }
+ #endif
+ options = options + 4;
+ }
+ }
+ }
+ //halfsquare, diagonal, halfsquare a code 0 route
+ if ((steps == 0) || (status == 1))
+ {
+ step1 = Check(x1, y1, x1, y1+dy/2);
+ if (step1 != 0)
+ {
+ step2 = Check(x1, y1+dy/2, x2, y1+dy/2+dly);
+ if (step2 != 0)
+ {
+ step3 = Check(x2, y1+dy/2+dly, x2, y2);
+ if (step3 != 0)
+ {
+ steps = step1 + step2 + step3; // yes
+ #ifdef PLOT_PATHS
+ if (status == 1)
+ {
+ RouteLine(x1, y1, x1, y1+dy/2, 231);
+ RouteLine(x1, y1+dy/2, x2, y1+dy/2+dly, 231);
+ RouteLine(x2, y1+dy/2+dly, x2, y2, 231);
+ }
+ #endif
+ options = options + 1;
+ }
+ }
+ }
+ }
+ //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+dy+dly/2);
+ if (step2 != 0)
+ {
+ step3 = Check(x1+dlx/2, y1+dy+dly/2, x2, y2);
+ if (step3 != 0)
+ {
+ steps = step1 + step2 + step3; // yes
+ options = options + 8;
+ #ifdef PLOT_PATHS
+ if (status == 1)
+ {
+ RouteLine(x1, y1, x1+dlx/2, y1+dly/2, 231);
+ RouteLine(x1+dlx/2, y1+dly/2, x1+dlx/2, y1+dy+dly/2, 231);
+ RouteLine(x1+dlx/2, y1+dy+dly/2, x2, y2, 231);
+ }
+ #endif
+ }
+ }
+ }
+ }
+ }
+ if (status == 0)
+ {
+ status = steps;
+ }
+ else
+ {
+ status = options;
+ }
+ return status;
+}
+
+
+/*******************************************************************************
+ *******************************************************************************
+ * CHECK ROUTINES
+ *******************************************************************************
+ *******************************************************************************/
+
+
+int32 Check(int32 x1 , int32 y1 , int32 x2 ,int32 y2)
+{
+//call the fastest line check for the given line
+//returns 1 if line didn't cross any bars
+ int32 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;
+
+}
+
+
+int32 LineCheck(int32 x1 , int32 y1 , int32 x2 ,int32 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
+ {
+ // this is the inner inner loop
+ if ((xmax >= bars[i].xmin) && ( xmin <= bars[i].xmax)) //skip if not on module
+ {
+ if ((ymax >= bars[i].ymin) && ( ymin <= bars[i].ymax)) //skip if not on module
+ {
+ // okay its a valid line calculate an intersept
+ // wow but all this arithmatic we must have loads of time
+ slope = (bars[i].dx * diry) - (bars[i].dy *dirx);// slope it he slope between the two lines
+ if (slope != 0)//assuming parallel lines don't cross
+ {
+ //calculate x intercept and check its on both lines
+ xc = ((bars[i].co * dirx) - (co * bars[i].dx)) / slope;
+
+ if ((xc >= xmin-1) && (xc <= xmax+1)) //skip if not on module
+ {
+ if ((xc >= bars[i].xmin-1) && (xc <= bars[i].xmax+1)) //skip if not on line
+ {
+
+ yc = ((bars[i].co * diry) - (co * bars[i].dy)) / slope;
+
+ if ((yc >= ymin-1) && (yc <= ymax+1)) //skip if not on module
+ {
+ if ((yc >= bars[i].ymin-1) && (yc <= bars[i].ymax+1)) //skip if not on line
+ {
+ linesCrossed = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ i = i + 1;
+ }
+ while((i < nbars) && linesCrossed);
+
+ return linesCrossed;
+}
+
+
+int32 HorizCheck(int32 x1 , int32 y , int32 x2)
+{
+ int32 dy;
+ 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
+ {
+ // this is the inner inner loop
+ if ((xmax >= bars[i].xmin) && ( xmin <= bars[i].xmax)) //skip if not on module
+ {
+ if ((y >= bars[i].ymin) && ( y <= bars[i].ymax)) //skip if not on module
+ {
+ // okay its a valid line calculate an intersept
+ // wow but all this arithmatic we must have loads of time
+ if (bars[i].dy == 0)
+ {
+ linesCrossed = 0;
+ }
+ else
+ {
+ dy = y-bars[i].y1;
+ xc = bars[i].x1 + (bars[i].dx * dy)/bars[i].dy;
+ if ((xc >= xmin-1) && (xc <= xmax+1)) //skip if not on module
+ {
+ linesCrossed = 0;
+ }
+ }
+ }
+ }
+ i = i + 1;
+ }
+ while((i < nbars) && linesCrossed);
+
+ return linesCrossed;
+}
+
+
+int32 VertCheck(int32 x, int32 y1, int32 y2)
+{
+ int32 dx;
+ 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 // this is the inner inner loop
+ {
+ if ((x >= bars[i].xmin) && ( x <= bars[i].xmax)) //overlapping
+ {
+ if ((ymax >= bars[i].ymin) && ( ymin <= bars[i].ymax)) //skip if not on module
+ {
+ // okay its a valid line calculate an intersept
+ // wow but all this arithmatic we must have loads of time
+ if (bars[i].dx == 0)//both lines vertical and overlap in x and y so they cross
+ {
+ linesCrossed = 0;
+ }
+ else
+ {
+ dx = x-bars[i].x1;
+ yc = bars[i].y1 + (bars[i].dy * dx)/bars[i].dx;
+ if ((yc >= ymin-1) && (yc <= ymax+1)) //the intersept overlaps
+ {
+ linesCrossed = 0;
+ }
+ }
+ }
+ }
+ i = i + 1;
+ }
+ while((i < nbars) && linesCrossed);
+
+ return linesCrossed;
+}
+
+int32 CheckTarget(int32 x , int32 y)
+/*******************************************************************************
+ *******************************************************************************/
+{
+ int32 dx;
+ int32 dy;
+ int32 i;
+ int32 xc;
+ int32 yc;
+ int32 xmin;
+ int32 xmax;
+ int32 ymin;
+ int32 ymax;
+ int32 onLine = 0;
+
+ xmin = x - 1;
+ xmax = x + 1;
+ ymin = y - 1;
+ ymax = y + 1;
+
+ // check if point +- 1 is on the line
+ //so ignore if it hits anything
+
+ i = 0;
+ do
+ {
+
+ // this is the inner inner loop
+
+ 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
+ //Zdebug("RouteFail due to target on a line %d %d",x,y);
+ }
+ 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
+ //Zdebug("RouteFail due to target on a line %d %d",x,y);
+ }
+ }
+ }
+ }
+ i = i + 1;
+ }
+ while((i < nbars) && (onLine == 0));
+
+
+ return onLine;
+}
+
+/*******************************************************************************
+ *******************************************************************************
+ * THE SETUP ROUTINES
+ *******************************************************************************
+ *******************************************************************************/
+//------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------
+
+void LoadWalkData(Object_walkdata *ob_walkdata)
+{
+ uint8 direction;
+ uint16 firstFrameOfDirection;
+ uint16 walkFrameNo;
+ uint32 frameCounter = 0; // starts at frame 0 of mega set (16sep96 JEL)
+
+
+ nWalkFrames = ob_walkdata->nWalkFrames;
+ usingStandingTurnFrames = ob_walkdata->usingStandingTurnFrames;
+ usingWalkingTurnFrames = ob_walkdata->usingWalkingTurnFrames;
+ usingSlowInFrames = ob_walkdata->usingSlowInFrames;
+ usingSlowOutFrames = ob_walkdata->usingSlowOutFrames;
+ numberOfSlowOutFrames = usingSlowOutFrames; // 0 = not using slow out frames; non-zero = using that many frames for each leading leg for each direction
+
+ memcpy(&numberOfSlowInFrames[0],ob_walkdata->nSlowInFrames,NO_DIRECTIONS*sizeof(numberOfSlowInFrames[0]));
+ memcpy(&leadingLeg[0],ob_walkdata->leadingLeg,NO_DIRECTIONS*sizeof(leadingLeg[0]));
+ memcpy(&dx[0],ob_walkdata->dx,NO_DIRECTIONS*(nWalkFrames+1)*sizeof(dx[0]));
+ memcpy(&dy[0],ob_walkdata->dy,NO_DIRECTIONS*(nWalkFrames+1)*sizeof(dy[0]));
+
+ //---------------------------------------------------------
+
+ for (direction=0; direction<NO_DIRECTIONS; direction++)
+ {
+ firstFrameOfDirection = direction * nWalkFrames;
+
+ modX[direction]=0;
+ modY[direction]=0;
+
+ for (walkFrameNo=firstFrameOfDirection; walkFrameNo < (firstFrameOfDirection + (nWalkFrames/2)); walkFrameNo++ )
+ {
+ modX[direction] += dx[walkFrameNo]; // eg. modX[0] is the sum of the x-step sizes for the first half of the walk cycle for direction 0
+ modY[direction] += dy[walkFrameNo];
+ }
+ }
+
+ diagonalx = modX[3];
+ diagonaly = modY[3];
+
+ //----------------------------------------------------
+ // interpret the walk data
+ //----------------------------------------------------
+
+ framesPerStep = nWalkFrames/2;
+ framesPerChar = nWalkFrames * NO_DIRECTIONS;
+
+ // offset pointers added Oct 30 95 JPS
+ // mega id references removed 16sep96 by JEL
+
+ //---------------------
+ // WALK FRAMES
+ // start on frame 0
+ frameCounter += framesPerChar;
+
+ //---------------------
+ // STAND FRAMES
+ firstStandFrame = frameCounter; // stand frames come after the walk frames
+ frameCounter += NO_DIRECTIONS; // one stand frame for each direction
+
+ //---------------------
+ // STANDING TURN FRAMES - OPTIONAL!
+ if (usingStandingTurnFrames)
+ {
+ firstStandingTurnLeftFrame = frameCounter; // standing turn-left frames come after the slow-out frames
+ frameCounter += NO_DIRECTIONS; // one for each direction
+
+ firstStandingTurnRightFrame = frameCounter; // standing turn-left frames come after the standing turn-right frames
+ frameCounter += NO_DIRECTIONS; // one for each direction
+ }
+ else
+ {
+ firstStandingTurnLeftFrame = firstStandFrame; // refer instead to the normal stand frames
+ firstStandingTurnRightFrame = firstStandFrame; // -"-
+ }
+ //---------------------
+ // WALKING TURN FRAMES - OPTIONAL!
+ if (usingWalkingTurnFrames)
+ {
+ firstWalkingTurnLeftFrame = frameCounter; // walking left-turn frames come after the stand frames
+ frameCounter += framesPerChar;
+
+ firstWalkingTurnRightFrame = frameCounter; // walking right-turn frames come after the walking left-turn frames
+ frameCounter += framesPerChar;
+ }
+ else
+ {
+ firstWalkingTurnLeftFrame = 0;
+ firstWalkingTurnRightFrame = 0;
+ }
+ //---------------------
+ // SLOW-IN FRAMES - OPTIONAL!
+
+ if (usingSlowInFrames) // slow-in frames come after the walking right-turn frames
+ {
+ for (direction=0; direction<NO_DIRECTIONS; direction++)
+ {
+ firstSlowInFrame[direction] = frameCounter; // make note of frame number of first slow-in frame for each direction
+ frameCounter += numberOfSlowInFrames[direction]; // can be a different number of slow-in frames in each direction
+ }
+ }
+ //---------------------
+ // SLOW-OUT FRAMES - OPTIONAL!
+
+ if (usingSlowOutFrames)
+ {
+ firstSlowOutFrame = frameCounter; // slow-out frames come after the slow-in frames
+ }
+ //---------------------
+}
+
+
+/*******************************************************************************
+ *******************************************************************************
+ * THE ROUTE EXTRACTOR
+ *******************************************************************************
+ *******************************************************************************/
+
+void ExtractRoute()
+/****************************************************************************
+ * 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 prev;
+ int32 prevx;
+ int32 prevy;
+ int32 last;
+ int32 point;
+ int32 p;
+ int32 dirx;
+ int32 diry;
+ int32 dir;
+ int32 dx;
+ int32 dy;
+
+
+ // 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;
+ do
+ {
+ 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;
+ }
+ while (prev > 0);
+
+ // now shuffle route down in the buffer
+ 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);
+ routeLength = routeLength - 1;
+
+ // okay the route exists as a series point now put in some directions
+ p = 0;
+ do
+ {
+ #ifdef PLOT_PATHS
+ BresenhamLine(route[p+1].x-128,route[p+1].y-128, route[p].x-128,route[p].y-128, (uint8*)screen_ad, true_pixel_size_x, pixel_size_y, ROUTE_END_FLAG);
+ #endif
+ dx = route[p+1].x - route[p].x;
+ 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;
+ }
+ p = p + 1;
+ }
+ while (p < (routeLength));
+ // set the last dir to continue previous route unless specified
+ if (targetDir == 8) // ANY direction
+ {
+ route[p].dirS = route[p-1].dirS;
+ route[p].dirD = route[p-1].dirD;
+ }
+ else
+ {
+ route[p].dirS = targetDir;
+ route[p].dirD = targetDir;
+ }
+ return;
+}
+
+//*******************************************************************************
+
+void RouteLine(int32 x1,int32 y1,int32 x2,int32 y2 ,int32 colour)
+{
+ if (x1);
+ if (x2);
+ if (y1);
+ if (y2);
+ if (colour);
+// BresenhamLine(x1-128, y1-128, x2-128, y2-128, (uint8*)screen_ad, true_pixel_size_x, pixel_size_y, colour);
+ return;
+}
+
+//*******************************************************************************
+
+void SetUpWalkGrid(Object_mega *ob_mega, int32 x, int32 y, int32 dir)
+{
+ int32 i;
+
+
+ LoadWalkGrid(); // get walk grid file + extra grid into 'bars' & 'node' arrays
+
+
+ // copy the mega structure into the local variables for use in all subroutines
+
+ startX = ob_mega->feet_x;
+ startY = ob_mega->feet_y;
+ startDir = ob_mega->current_dir;
+ targetX = x;
+ targetY = y;
+ targetDir = dir;
+
+ scaleA = ob_mega->scale_a;
+ scaleB = ob_mega->scale_b;
+
+
+ // mega's current position goes into first node
+ node[0].x = startX;
+ node[0].y = startY;
+ node[0].level = 1;
+ node[0].prev = 0;
+ node[0].dist = 0;
+
+ // reset other nodes
+ for (i=1; i<nnodes; i++)
+ {
+ node[i].level = 0;
+ node[i].prev = 0;
+ node[i].dist = 9999;
+ }
+
+ // target position goes into final node
+ node[nnodes].x = targetX;
+ node[nnodes].y = targetY;
+ node[nnodes].level = 0;
+ node[nnodes].prev = 0;
+ node[nnodes].dist = 9999;
+}
+
+//------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------
+void PlotWalkGrid(void)
+{
+ int32 j;
+
+
+ LoadWalkGrid(); // get walk grid file + extra grid into 'bars' & 'node' arrays
+
+ //-------------------------------
+ // lines
+
+ for (j=0; j<nbars; j++)
+ {
+ DrawLine(bars[j].x1,bars[j].y1, bars[j].x2,bars[j].y2, 254);
+ }
+ //-------------------------------
+ // nodes
+
+ for (j=1; j<nnodes; j++) // leave node 0 for start node
+ {
+ PlotCross(node[j].x,node[j].y, 184);
+ }
+ //-------------------------------
+}
+//------------------------------------------------------------------------------------------
+void PlotCross(int16 x, int16 y, uint8 colour)
+{
+ DrawLine(x-1, y-1, x+1, y+1, colour);
+ DrawLine(x+1, y-1, x-1, y+1, colour);
+}
+//------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------
+
+void LoadWalkGrid(void)
+{
+// _standardHeader header;
+ _walkGridHeader floorHeader;
+ uint32 j;
+ uint8 *fPolygrid;
+ int entry;
+ uint32 theseBars;
+ uint32 theseNodes;
+
+
+ nbars = 0; // reset counts
+ nnodes = 1; // leave node 0 for start-node
+
+ //-------------------------------
+ // STATIC GRIDS (added/removed by object logics)
+
+ for (entry=0; entry < MAX_WALKGRIDS; entry++) // go through walkgrid list
+ {
+ if (walkGridList[entry])
+ {
+ fPolygrid = res_man.Res_open(walkGridList[entry]); // open walk grid file
+
+ // memmove( (uint8*)&header, fPolygrid, sizeof(_standardHeader) );
+ fPolygrid += sizeof(_standardHeader);
+
+ memmove( (uint8*)&floorHeader, fPolygrid, sizeof(_walkGridHeader) );
+ fPolygrid += sizeof(_walkGridHeader);
+
+ //-------------------------------
+ // how many bars & nodes are we getting from this walkgrid file
+
+ theseBars = floorHeader.numBars;
+ theseNodes = floorHeader.numNodes;
+
+ //-------------------------------
+ // check that we're not going to exceed the max allowed in the complete walkgrid arrays
+
+ #ifdef _DEBUG
+ if ((nbars+theseBars) >= O_GRID_SIZE)
+ Con_fatal_error("Adding walkgrid(%d): %d+%d bars exceeds max %d (%s line %u)", walkGridList[entry], nbars, theseBars, O_GRID_SIZE, __FILE__, __LINE__);
+
+ if ((nnodes+theseNodes) >= O_GRID_SIZE)
+ Con_fatal_error("Adding walkgrid(%d): %d+%d nodes exceeds max %d (%s line %u)", walkGridList[entry], nnodes, theseBars, O_GRID_SIZE, __FILE__, __LINE__);
+ #endif
+
+ //-------------------------------
+ // lines
+
+ memmove( (uint8*)&bars[nbars], fPolygrid, theseBars*sizeof(_barData) );
+ fPolygrid += theseBars*sizeof(_barData);//move pointer to start of node data
+
+ //-------------------------------
+ // nodes
+
+ for (j=0; j<theseNodes; j++) // leave node 0 for start node
+ {
+ memmove( (uint8*)&node[nnodes+j].x, fPolygrid, 2*sizeof(int16) );
+ fPolygrid += 2*sizeof(int16);
+ }
+
+ //-------------------------------
+
+ res_man.Res_close(walkGridList[entry]); // close walk grid file
+
+ nbars += theseBars; // increment counts of total bars & nodes in whole walkgrid
+ nnodes += theseNodes;
+ }
+ }
+
+ //-------------------------------
+ // EXTRA GRIDS (moveable grids added by megas)
+
+ // Note that these will be checked against allowed max at the time of creating them
+
+ //-------------------------------
+ // extra lines
+
+ memmove((uint8 *) &bars[nbars], (uint8 *) &extraBars[0], nExtraBars*sizeof(_barData));
+ nbars += nExtraBars;
+
+ //-------------------------------
+ // extra nodes
+
+ memmove((uint8 *) &node[nnodes], (uint8 *) &extraNode[0], nExtraNodes*sizeof(_nodeData));
+ nnodes += nExtraNodes;
+
+ //-------------------------------
+}
+
+//------------------------------------------------------------------------------------------
+void ClearWalkGridList(void)
+{
+ int entry;
+
+ for (entry=0; entry < MAX_WALKGRIDS; entry++)
+ walkGridList[entry] = 0;
+}
+//------------------------------------------------------------------------------------------
+// called from FN_add_walkgrid
+void AddWalkGrid(int32 gridResource)
+{
+ int entry;
+
+ // first, scan list to see if this grid is already included
+ entry=0;
+ while ((entry < MAX_WALKGRIDS) && (walkGridList[entry] != gridResource))
+ entry++;
+
+ if (entry == MAX_WALKGRIDS) // if this new resource isn't already in the list, then add it, (otherwise finish)
+ {
+ // scan the list for a free slot
+ entry=0;
+ while ((entry < MAX_WALKGRIDS) && (walkGridList[entry]))
+ entry++;
+
+ if (entry < MAX_WALKGRIDS) // if we found a free slot
+ walkGridList[entry] = gridResource;
+ else
+ Con_fatal_error("ERROR: walkGridList[] full in %s line %d",__FILE__,__LINE__);
+ }
+}
+//--------------------------------------------------------------------------------------
+// called from FN_remove_walkgrid
+void RemoveWalkGrid(int32 gridResource)
+{
+ int entry;
+
+ // first, scan list to see if this grid is actually there
+ entry=0;
+ while ((entry < MAX_WALKGRIDS) && (walkGridList[entry] != gridResource))
+ entry++;
+
+ if (entry < MAX_WALKGRIDS) // if we've found it in the list, reset entry to zero (otherwise just ignore the request)
+ walkGridList[entry] = 0;
+}
+//--------------------------------------------------------------------------------------
+