diff options
Diffstat (limited to 'sword2/router.cpp')
| -rw-r--r-- | sword2/router.cpp | 2506 |
1 files changed, 0 insertions, 2506 deletions
diff --git a/sword2/router.cpp b/sword2/router.cpp deleted file mode 100644 index bbca609e3c..0000000000 --- a/sword2/router.cpp +++ /dev/null @@ -1,2506 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 The ScummVM project - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -// --------------------------------------------------------------------------- -// 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 underwent 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 - * - ****************************************************************************/ - -#include "common/stdafx.h" -#include "common/stream.h" -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/logic.h" -#include "sword2/resman.h" -#include "sword2/router.h" - -namespace Sword2 { - -//---------------------------------------------------------- -// (4) WALK-GRID FILES -//---------------------------------------------------------- -// a walk-grid file consists of: -// -// standard file header -// walk-grid file header -// walk-grid data - -// Walk-Grid Header - taken directly from old "header.h" in STD_INC - -struct WalkGridHeader { - int32 numBars; // number of bars on the floor - int32 numNodes; // number of nodes -}; - -uint8 Router::returnSlotNo(uint32 megaId) { - if (_vm->_logic->readVar(ID) == CUR_PLAYER_ID) { - // George (8) - return 0; - } else { - // One of Nico's mega id's - return 1; - } -} - -void Router::allocateRouteMem() { - uint8 slotNo; - - // 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(_vm->_logic->readVar(ID)); - - // if this slot is already used, then it can't be needed any more - // because this id is creating a new route! - - if (_routeSlots[slotNo]) - freeRouteMem(); - - _routeSlots[slotNo] = (WalkData *)malloc(sizeof(WalkData) * O_WALKANIM_SIZE); - - // 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) - - // mega keeps note of which slot contains the pointer to it's walk - // animation mem block - // +1 so that '0' can mean "not walking" - // megaObject->route_slot_id = slotNo + 1; -} - -WalkData *Router::getRouteMem() { - uint8 slotNo = returnSlotNo(_vm->_logic->readVar(ID)); - - return (WalkData *)_routeSlots[slotNo]; -} - -void Router::freeRouteMem() { - uint8 slotNo = returnSlotNo(_vm->_logic->readVar(ID)); - - free(_routeSlots[slotNo]); - _routeSlots[slotNo] = NULL; -} - -void Router::freeAllRouteMem() { - for (int i = 0; i < TOTAL_ROUTE_SLOTS; i++) { - free(_routeSlots[i]); - _routeSlots[i] = NULL; - } -} - -int32 Router::routeFinder(byte *ob_mega, byte *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 = getRouteMem(); - - // 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(); - - switch (routeFlag) { - case 2: - // special case for zero length route - - // if target direction specified as any - if (_targetDir > 7) - _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; - break; - case 1: - // A normal route. Convert the route to an exact path - smoothestPath(); - - // 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 - -#ifndef FORCE_SLIDY - 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); - } -#endif - - if (!solidFlag) { - // if we failed to create a SOLID route, do a SLIDY - // one instead - - slidyPath(); - slidyWalkAnimator(walkAnim); - } - - break; - default: - // Route didn't reach target so assume point was off the floor - // routeFlag = 0; - break; - } - - return routeFlag; // send back null route -} - -int32 Router::getRoute() { - /********************************************************************* - * 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; - - 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 - - // returns 3 if target on a line ( +- 1 pixel ) - routeGot = checkTarget(_targetX, _targetY); - } - - 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() - - int32 level = 1; - - while (scan(level)) - level++; - - // Check to see if the route reached the target - - if (_node[_nNodes].dist < 9999) { - // it did so extract the route as nodes and the - // directions to go between each node - - routeGot = 1; - extractRoute(); - - // 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 Router::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 - - int i; - int32 steps = 0; - int32 lastDir; - 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 (int p = 0; p < _routeLength; p++) { - int32 dirS = _route[p].dirS; - int32 dirD = _route[p].dirD; - int32 nextDirS = _route[p + 1].dirS; - int32 nextDirD = _route[p + 1].dirD; - - // Check directions into and out of a pair of nodes going in - int32 dS = dirS - lastDir; - if (dS < 0) - dS = dS + NO_DIRECTIONS; - - int32 dD = dirD - lastDir; - if (dD < 0) - dD = dD + NO_DIRECTIONS; - - // coming out - int32 dSS = dirS - nextDirS; - if (dSS < 0) - dSS = dSS + NO_DIRECTIONS; - - int32 dDD = dirD - nextDirD; - if (dDD < 0) - dDD = dDD + NO_DIRECTIONS; - - int32 dSD = dirS - nextDirD; - if (dSD < 0) - dSD = dSD + NO_DIRECTIONS; - - int32 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. Split routes look crap so weight against - // them - - int32 SS = dS + dSS + 3; - int32 SD = dS + dDD; - int32 DS = dD + dSS; - int32 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 (i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - if (tempturns[j] > tempturns[j + 1]) { - SWAP(turns[j], turns[j + 1]); - SWAP(tempturns[j], tempturns[j + 1]); - } - } - } - - // 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 - - int32 options = newCheck(1, _route[p].x, _route[p].y, _route[p + 1].x, _route[p + 1].y); - - assert(options); - - i = 0; - steps = 0; - - do { - int32 opt = 1 << turns[i]; - if (options & opt) - steps = smoothCheck(turns[i], p, dirS, dirD); - i++; - } while (steps == 0 && i < 4); - - assert(steps); - - // route.X route.Y route.dir and bestTurns start at far end - } - - // 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 Router::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 dsx, dsy; - int32 ddx, ddy; - int32 ss0, ss1, ss2; - int32 sd0, sd1, sd2; - - if (p == 0) - k = 1; - - int32 x = _route[p].x; - int32 y = _route[p].y; - int32 x2 = _route[p + 1].x; - int32 y2 = _route[p + 1].y; - int32 ldx = x2 - x; - int32 ldy = y2 - y; - int32 dirX = 1; - int32 dirY = 1; - - if (ldx < 0) { - ldx = -ldx; - dirX = -1; - } - - if (ldy < 0) { - ldy = -ldy; - dirY = -1; - } - - // set up sd0-ss2 to reflect possible movement in each direction - - if (dirS == 0 || dirS == 4) { // vert and diag - ddx = ldx; - ddy = (ldx * _diagonaly) / _diagonalx; - dsy = ldy - 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 = ldy; - ddx = (ldy * _diagonalx) / _diagonaly; - dsx = ldx - 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; - } - - switch (best) { - case 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++; - - _smoothPath[k].x = x + dsx / 2 + ddx; - _smoothPath[k].y = y + dsy / 2 + ddy; - _smoothPath[k].dir = dirD; - _smoothPath[k].num = sd0; - k++; - - _smoothPath[k].x = x + dsx + ddx; - _smoothPath[k].y = y + dsy + ddy; - _smoothPath[k].dir = dirS; - _smoothPath[k].num = ss2; - k++; - - break; - case 1: // square, diagonal - _smoothPath[k].x = x + dsx; - _smoothPath[k].y = y + dsy; - _smoothPath[k].dir = dirS; - _smoothPath[k].num = ss0; - k++; - - _smoothPath[k].x = x2; - _smoothPath[k].y = y2; - _smoothPath[k].dir = dirD; - _smoothPath[k].num = sd0; - k++; - - break; - case 2: // diagonal square - _smoothPath[k].x = x + ddx; - _smoothPath[k].y = y + ddy; - _smoothPath[k].dir = dirD; - _smoothPath[k].num = sd0; - k++; - - _smoothPath[k].x = x2; - _smoothPath[k].y = y2; - _smoothPath[k].dir = dirS; - _smoothPath[k].num = ss0; - k++; - - break; - default: // halfdiagonal, square, halfdiagonal - _smoothPath[k].x = x + ddx / 2; - _smoothPath[k].y = y + ddy / 2; - _smoothPath[k].dir = dirD; - _smoothPath[k].num = sd1; - k++; - - _smoothPath[k].x = x + dsx + ddx / 2; - _smoothPath[k].y = y + dsy + ddy / 2; - _smoothPath[k].dir = dirS; - _smoothPath[k].num = ss0; - k++; - - _smoothPath[k].x = x2; - _smoothPath[k].y = y2; - _smoothPath[k].dir = dirD; - _smoothPath[k].num = sd2; - k++; - - break; - } - - return k; -} - -void Router::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 intended for use when just clicking about. - * - * produce a module list from the line data - *********************************************************************/ - - int32 smooth = 1; - int32 slidy = 1; - - // strip out the short sections - - _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) { - int32 scale = _scaleA * _smoothPath[smooth].y + _scaleB; - int32 deltaX = _smoothPath[smooth].x - _modularPath[slidy - 1].x; - int32 deltaY = _smoothPath[smooth].y - _modularPath[slidy - 1].y; - // quarter a step minimum - int32 stepX = (scale * _modX[_smoothPath[smooth].dir]) >> 19; - int32 stepY = (scale * _modY[_smoothPath[smooth].dir]) >> 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++; - } - smooth++; - } - - // 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++; - - _modularPath[slidy].x = _smoothPath[smooth - 1].x; - _modularPath[slidy].y = _smoothPath[smooth - 1].y; - _modularPath[slidy].dir = 9; - _modularPath[slidy].num = ROUTE_END_FLAG; - slidy++; -} - -// SLOW IN - -bool Router::addSlowInFrames(WalkData *walkAnim) { - if (_walkData.usingSlowInFrames && _modularPath[1].num > 0) { - for (int slowInFrameNo = 0; slowInFrameNo < _walkData.nSlowInFrames[_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++; - } - return true; - } - - return false; -} - -void Router::earlySlowOut(byte *ob_mega, byte *ob_walkdata) { - int32 slowOutFrameNo; - int32 walk_pc; - WalkData *walkAnim; - - ObjectMega obMega(ob_mega); - - debug(5, "EARLY SLOW-OUT"); - - loadWalkData(ob_walkdata); - - debug(5, "********************************"); - debug(5, "_framesPerStep = %d", _framesPerStep); - debug(5, "_numberOfSlowOutFrames = %d", _numberOfSlowOutFrames); - debug(5, "_firstWalkingTurnLeftFrame = %d", _firstWalkingTurnLeftFrame); - debug(5, "_firstWalkingTurnRightFrame = %d", _firstWalkingTurnRightFrame); - debug(5, "_firstSlowOutFrame = %d", _firstSlowOutFrame); - debug(5, "********************************"); - - walk_pc = obMega.getWalkPc(); - - walkAnim = getRouteMem(); - - // if this mega does actually have slow-out frames - if (_walkData.usingSlowOutFrames) { - // overwrite the next step (half a cycle) of the walk - // (ie .step - 0..5) - - do { - debug(5, "STEP NUMBER: walkAnim[%d].step = %d", walk_pc, walkAnim[walk_pc].step); - debug(5, "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, then map it to a normal step - // frame first - - walkAnim[walk_pc].frame -= _firstWalkingTurnRightFrame; - debug(5, "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, then map it to a normal step - // frame first - - walkAnim[walk_pc].frame -= _firstWalkingTurnLeftFrame; - debug(5, "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; - debug(5, "SLOW-OUT FRAME: walkAnim[%d].frame = %d",walk_pc, walkAnim[walk_pc].frame); - walk_pc++; - } while (walkAnim[walk_pc].step > 0); - - // add stationary frame(s) (OPTIONAL) - - for (slowOutFrameNo = _framesPerStep; slowOutFrameNo < _numberOfSlowOutFrames; slowOutFrameNo++) { - walkAnim[walk_pc].frame = walkAnim[walk_pc - 1].frame + 1; - debug(5, "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 - // stand in current direction - - walkAnim[walk_pc].frame = _firstStandFrame + walkAnim[walk_pc - 1].dir; - 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++; - } - - // end of sequence - walkAnim[walk_pc].frame = 512; - - // so that this doesn't happen again while 'george_walking' is still - // '2' - walkAnim[walk_pc].step = 99; -} - -// SLOW OUT - -void Router::addSlowOutFrames(WalkData *walkAnim) { - int32 slowOutFrameNo; - - // if the mega did actually walk, we overwrite the last step (half a - // cycle) with slow-out frames + add any necessary stationary frames - - if (_walkData.usingSlowOutFrames && _lastCount >= _framesPerStep) { - // place stop frames here - // slowdown at the end of the last walk - - slowOutFrameNo = _lastCount - _framesPerStep; - - debug(5, "SLOW OUT: slowOutFrameNo(%d) = _lastCount(%d) - _framesPerStep(%d)", slowOutFrameNo, _lastCount, _framesPerStep); - - // overwrite the last step (half a cycle) of the walk - - do { - // 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)); - - // because no longer a normal walk-step - walkAnim[slowOutFrameNo].step = 0; - - debug(5, "walkAnim[%d].frame = %d",slowOutFrameNo,walkAnim[slowOutFrameNo].frame); - slowOutFrameNo++; - } while (slowOutFrameNo < _lastCount); - - // add stationary frame(s) (OPTIONAL) - - for (slowOutFrameNo = _framesPerStep; slowOutFrameNo < _numberOfSlowOutFrames; slowOutFrameNo++) { - walkAnim[_stepCount].frame = walkAnim[_stepCount - 1].frame + 1; - - debug(5, "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++; - } - } -} - -void Router::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; - - // START THE WALK WITH THE FIRST STANDFRAME THIS MAY CAUSE A DELAY - // BUT IT STOPS THE PLAYER MOVING FOR COLLISIONS ARE DETECTED - - debug(5, "SLIDY: 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++; - - // TURN TO START THE WALK - - debug(5, "SLIDY: 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 (_walkData.usingStandingTurnFrames) { - // new frames for turn frames 29oct95jps - if (turnDir < 0) - 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++; - } - - // rotate till were facing new dir then go back 45 degrees - while (lastDir != _currentDir) { - lastDir += turnDir; - - // new frames for turn frames 29oct95jps - if (turnDir < 0) { - 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++; - } - - // the back 45 degrees bit - // step back one because new head turn for george takes us - // past the new dir - _stepCount--; - } - - // his head is in the right direction - lastRealDir = _currentDir; - - // SLIDY: THE SLOW IN - - addSlowInFrames(walkAnim); - - // THE WALK - - debug(5, "SLIDY: THE WALK"); - - // start the walk on the left or right leg, depending on how the - // slow-in frames were drawn - - // (0 = left; 1 = right) - - if (_walkData.leadingLeg[_currentDir] == 0) { - // start the walk on the left leg (ie. at beginning of the - // first step of the walk cycle) - left = 0; - } else { - // start the walk on the right leg (ie. at beginning of the - // second step of the walk cycle) - left = _framesPerStep; - } - - _lastCount = _stepCount; - - // this ensures that we don't put in turn frames for the start - lastDir = 99; - - // this ensures that we don't put in turn frames for the start - _currentDir = 99; - - do { - assert(_stepCount < O_WALKANIM_SIZE); - while (_modularPath[p].num == 0) { - p++; - 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 += _walkData.dx[module] * scale; - module16Y += _walkData.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++; - step++; - module++; - } 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++; - walkAnim[_lastCount + frameCount - 1].x += errorX * frameCount / frames; - } while (frameCount < frames); - } - - if (errorY != 0) { - frameCount = 0; - frames = _stepCount - _lastCount; - do { - frameCount++; - 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) { - // this ensures that we don't put in - // turn frames for this walk or the - // next - _currentDir = 99; - } - - if (_currentDir != 99) - lastRealDir = _currentDir; - - // check each turn condition in turn - - // only for george - if (lastDir != 99 && _currentDir != 99 && _walkData.usingWalkingTurnFrames) { - // 1 and -7 going right -1 and 7 going - // left - lastDir = _currentDir - lastDir; - - if (lastDir == -1 || lastDir == 7 || lastDir == -2 || lastDir == 6) { - // turn at the end of the last - // walk - - _frame = _lastCount - _framesPerStep; - do { - // turning left - walkAnim[_frame].frame += _firstWalkingTurnLeftFrame; - _frame++; - } while (_frame < _lastCount); - } else if (lastDir == 1 || lastDir == -7 || lastDir == 2 || lastDir == -6) { - // turn at the end of the - // current walk - - _frame = _lastCount - _framesPerStep; - do { - // turning right - walkAnim[_frame].frame += _firstWalkingTurnRightFrame; - _frame++; - } 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 SWORD2_DEBUG - if (lastRealDir == 99) - error("slidyWalkAnimatorlast direction error"); -#endif - - // THE SLOW OUT - addSlowOutFrames(walkAnim); - - // 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++; - } - - 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++; - } - } else if (_targetDir != lastRealDir) { - // 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 (_walkData.usingStandingTurnFrames) { - // new frames for turn frames 29oct95jps - if (turnDir < 0) - 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++; - } - - // rotate if we need to - - while (lastRealDir != _targetDir) { - lastRealDir += turnDir; - - // new frames for turn frames 29oct95jps - if (turnDir < 0) { - 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++; - } - - 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++; - } - - walkAnim[_stepCount].frame = 512; - walkAnim[_stepCount].step = 99; - _stepCount++; - - walkAnim[_stepCount].frame = 512; - walkAnim[_stepCount].step = 99; - _stepCount++; - - walkAnim[_stepCount].frame = 512; - walkAnim[_stepCount].step = 99; - - // write all the frames to "debug.txt" - debug(5, "THE WALKDATA:"); - - for (_frame = 0; _frame <= _stepCount; _frame++) - debug(5, "walkAnim[%d].frame=%d", _frame, walkAnim[_frame].frame); - - debug(5, "routeFinder RouteSize is %d", _stepCount); - return; -} - -#ifndef FORCE_SLIDY - -// THE SOLID PATH ROUTINES - -int32 Router::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++; - } - - smooth++; - } 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 Router::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 left; - int32 turnDir; - int32 scale; - int32 step; - int32 errorX; - int32 errorY; - int32 moduleEnd; - bool slowStart = false; - - // start at the beginning for a change - - int32 lastDir = _modularPath[0].dir; - int32 module = _framesPerChar + lastDir; - - _currentDir = _modularPath[1].dir; - _moduleX = _startX; - _moduleY = _startY; - _stepCount = 0; - - int32 module16X = _moduleX << 16; - int32 module16Y = _moduleY << 16; - - // START THE WALK WITH THE FIRST STANDFRAME THIS MAY CAUSE A DELAY - // BUT IT STOPS THE PLAYER MOVING FOR COLLISIONS ARE DETECTED - - debug(5, "SOLID: STARTING THE WALK"); - walkAnim[_stepCount].frame = module; - walkAnim[_stepCount].step = 0; - walkAnim[_stepCount].dir = lastDir; - walkAnim[_stepCount].x = _moduleX; - walkAnim[_stepCount].y = _moduleY; - _stepCount++; - - // TURN TO START THE WALK - - debug(5, "SOLID: 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 (_walkData.usingStandingTurnFrames) { - // new frames for turn frames 29oct95jps - if (turnDir < 0) - 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++; - } - - // rotate till were facing new dir then go back 45 degrees - - while (lastDir != _currentDir) { - lastDir += turnDir; - - // new frames for turn frames - if (turnDir < 0) { - 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++; - } - - // the back 45 degrees bit - // step back one because new head turn for george takes us - // past the new dir - - _stepCount--; - } - - // THE SLOW IN - - slowStart = addSlowInFrames(walkAnim); - - // THE WALK - - debug(5, "SOLID: THE WALK"); - - // start the walk on the left or right leg, depending on how the - // slow-in frames were drawn - - // (0 = left; 1 = right) - if (_walkData.leadingLeg[_currentDir] == 0) { - // start the walk on the left leg (ie. at beginning of the - // first step of the walk cycle) - left = 0; - } else { - // start the walk on the right leg (ie. at beginning of the - // second step of the walk cycle) - left = _framesPerStep; - } - - _lastCount = _stepCount; - - // this ensures that we don't put in turn frames for the start - lastDir = 99; - - // this ensures that we don't put in turn frames for the start - _currentDir = 99; - - int32 p = 1; - - 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 += _walkData.dx[module] * scale; - module16Y += _walkData.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++; - module++; - step++; - } 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 - - // clean up if a slow in but no - // walk - - if (slowStart) { - _stepCount -= _walkData.nSlowInFrames[_currentDir]; - _lastCount -= _walkData.nSlowInFrames[_currentDir]; - slowStart = false; - } - - // this ensures that we don't - // put in turn frames for this - // walk or the next - - _currentDir = 99; - } - - // check each turn condition in turn - if (lastDir != 99 && _currentDir != 99 && _walkData.usingWalkingTurnFrames) { - // only for george - // 1 and -7 going right -1 and - // 7 going left - - lastDir = _currentDir - lastDir; - - if (lastDir == -1 || lastDir == 7 || lastDir == -2 || lastDir == 6) { - // turn at the end of - // the last walk - - _frame = _lastCount - _framesPerStep; - - do { - // turning left - walkAnim[_frame].frame += _firstWalkingTurnLeftFrame; - _frame++; - } while (_frame < _lastCount); - } else if (lastDir == 1 || lastDir == -7 || lastDir == 2 || lastDir == -6) { - // turn at the end of - // the current walk - - _frame = _lastCount - _framesPerStep; - do { - // turning right - walkAnim[_frame].frame += _firstWalkingTurnRightFrame; - _frame++; - } while (_frame < _lastCount); - } - } - - // all turns checked - _lastCount = _stepCount; - } - } - } - p++; - lastDir = _currentDir; - - // can only be valid first time round - slowStart = false; - } while (_modularPath[p].dir < NO_DIRECTIONS); - - // 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++; - - walkAnim[_stepCount].frame = 512; - walkAnim[_stepCount].step = 99; - _stepCount++; - - walkAnim[_stepCount].frame = 512; - walkAnim[_stepCount].step = 99; - _stepCount++; - - walkAnim[_stepCount].frame = 512; - walkAnim[_stepCount].step = 99; - - debug(5, "THE WALKDATA:"); - - for (_frame = 0; _frame <= _stepCount; _frame++) - debug(5, "walkAnim[%d].frame=%d", _frame, walkAnim[_frame].frame); - - // NO END TURNS - - debug(5, "routeFinder RouteSize is %d", _stepCount); - // now check the route - - int i = 0; - - do { - if (!check(_modularPath[i].x, _modularPath[i].y, _modularPath[i + 1].x, _modularPath[i + 1].y)) - p = 0; - i++; - } while (i < p - 1); - - if (p != 0) { - _targetDir = _modularPath[p - 1].dir; - if (checkTarget(_moduleX, _moduleY) == 3) { - // new target on a line - p = 0; - debug(5, "Solid walk target was on a line %d %d", _moduleX, _moduleY); - } - } - - return p; -} -#endif - -// THE SCAN ROUTINES - -bool Router::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 x1, y1, x2, y2; - int32 distance; - bool changed = false; - - // 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 (int i = 0; i < _nNodes; i++) { - if (_node[i].dist < _node[_nNodes].dist && _node[i].level == level) { - x1 = _node[i].x; - y1 = _node[i].y; - - for (int j = _nNodes; j > 0; j--) { - if (_node[j].dist > _node[i].dist) { - x2 = _node[j].x; - y2 = _node[j].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[j].dist) { - if (newCheck(0, x1, y1, x2, y2)) { - _node[j].level = level + 1; - _node[j].dist = distance + _node[i].dist; - _node[j].prev = i; - changed = true; - } - } - } - } - } - } - - return changed; -} - -int32 Router::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 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 |= 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 |= 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 |= 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 + 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 |= 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 |= 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 |= 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 |= 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 + 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 |= 8; - } - } - } - } - } - - if (status == 0) - status = steps; - else - status = options; - - return status; -} - -// CHECK ROUTINES - -bool Router::check(int32 x1, int32 y1, int32 x2, int32 y2) { - // call the fastest line check for the given line - // returns true if line didn't cross any bars - - if (x1 == x2 && y1 == y2) - return true; - - if (x1 == x2) - return vertCheck(x1, y1, y2); - - if (y1 == y2) - return horizCheck(x1, y1, x2); - - return lineCheck(x1, y1, x2, y2); -} - -bool Router::lineCheck(int32 x1, int32 y1, int32 x2, int32 y2) { - bool linesCrossed = true; - - int32 xmin = MIN(x1, x2); - int32 xmax = MAX(x1, x2); - int32 ymin = MIN(y1, y2); - int32 ymax = MAX(y1, y2); - - // Line set to go one step in chosen direction so ignore if it hits - // anything - - int32 dirx = x2 - x1; - int32 diry = y2 - y1; - - int32 co = (y1 * dirx) - (x1 * diry); // new line equation - - for (int i = 0; i < _nBars && linesCrossed; i++) { - // skip if not on module - if (xmax >= _bars[i].xmin && xmin <= _bars[i].xmax && ymax >= _bars[i].ymin && ymin <= _bars[i].ymax) { - // Okay, it's 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 - int32 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 - int32 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) { - int32 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 = false; - } - } - } - } - } - } - } - - return linesCrossed; -} - -bool Router::horizCheck(int32 x1, int32 y, int32 x2) { - bool linesCrossed = true; - - int32 xmin = MIN(x1, x2); - int32 xmax = MAX(x1, x2); - - // line set to go one step in chosen direction so ignore if it hits - // anything - - for (int i = 0; i < _nBars && linesCrossed; i++) { - // skip if not on module - if (xmax >= _bars[i].xmin && xmin <= _bars[i].xmax && y >= _bars[i].ymin && y <= _bars[i].ymax) { - // Okay, it's a valid line calculate an intercept. Wow - // but all this arithmetic we must have loads of time - - if (_bars[i].dy == 0) - linesCrossed = false; - else { - int32 ldy = y - _bars[i].y1; - int32 xc = _bars[i].x1 + (_bars[i].dx * ldy) / _bars[i].dy; - // skip if not on module - if (xc >= xmin - 1 && xc <= xmax + 1) - linesCrossed = false; - } - } - } - - return linesCrossed; -} - -bool Router::vertCheck(int32 x, int32 y1, int32 y2) { - bool linesCrossed = true; - - int32 ymin = MIN(y1, y2); - int32 ymax = MAX(y1, y2); - - // Line set to go one step in chosen direction so ignore if it hits - // anything - - for (int i = 0; i < _nBars && linesCrossed; i++) { - // skip if not on module - if (x >= _bars[i].xmin && x <= _bars[i].xmax && ymax >= _bars[i].ymin && ymin <= _bars[i].ymax) { - // Okay, it's 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 = false; - else { - int32 ldx = x - _bars[i].x1; - int32 yc = _bars[i].y1 + (_bars[i].dy * ldx) / _bars[i].dx; - // the intercept overlaps - if (yc >= ymin - 1 && yc <= ymax + 1) - linesCrossed = false; - } - } - } - - return linesCrossed; -} - -int32 Router::checkTarget(int32 x, int32 y) { - int32 onLine = 0; - - int32 xmin = x - 1; - int32 xmax = x + 1; - int32 ymin = y - 1; - int32 ymax = y + 1; - - // check if point +- 1 is on the line - // so ignore if it hits anything - - for (int i = 0; i < _nBars && onLine == 0; i++) { - // overlapping line - if (xmax >= _bars[i].xmin && xmin <= _bars[i].xmax && ymax >= _bars[i].ymin && ymin <= _bars[i].ymax) { - int32 xc, yc; - - // okay this line overlaps the target calculate - // an y intercept for x - - // vertical line so we know it overlaps y - if (_bars[i].dx == 0) - yc = 0; - else { - int ldx = x - _bars[i].x1; - yc = _bars[i].y1 + (_bars[i].dy * ldx) / _bars[i].dx; - } - - // overlapping point for y - if (yc >= ymin && yc <= ymax) { - // target on a line so drop out - onLine = 3; - debug(5, "RouteFail due to target on a line %d %d", x, y); - } else { - // vertical line so we know it overlaps y - if (_bars[i].dy == 0) - xc = 0; - else { - int32 ldy = y - _bars[i].y1; - xc = _bars[i].x1 + (_bars[i].dx * ldy) / _bars[i].dy; - } - - // skip if not on module - if (xc >= xmin && xc <= xmax) { - // target on a line so drop out - onLine = 3; - debug(5, "RouteFail due to target on a line %d %d", x, y); - } - } - } - } - - return onLine; -} - -// THE SETUP ROUTINES - -void Router::loadWalkData(byte *ob_walkdata) { - uint16 firstFrameOfDirection; - uint16 walkFrameNo; - uint32 frameCounter = 0; // starts at frame 0 of mega set - int i; - - _walkData.read(ob_walkdata); - - // 0 = not using slow out frames; non-zero = using that many frames - // for each leading leg for each direction - - _numberOfSlowOutFrames = _walkData.usingSlowOutFrames; - - for (i = 0; i < NO_DIRECTIONS; i++) { - firstFrameOfDirection = i * _walkData.nWalkFrames; - - _modX[i] = 0; - _modY[i] = 0; - - for (walkFrameNo = firstFrameOfDirection; walkFrameNo < firstFrameOfDirection + _walkData.nWalkFrames / 2; walkFrameNo++) { - // eg. _modX[0] is the sum of the x-step sizes for the - // first half of the walk cycle for direction 0 - _modX[i] += _walkData.dx[walkFrameNo]; - _modY[i] += _walkData.dy[walkFrameNo]; - } - } - - _diagonalx = _modX[3]; - _diagonaly = _modY[3]; - - // interpret the walk data - - _framesPerStep = _walkData.nWalkFrames / 2; - _framesPerChar = _walkData.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 - // stand frames come after the walk frames - // one stand frame for each direction - - _firstStandFrame = frameCounter; - frameCounter += NO_DIRECTIONS; - - // STANDING TURN FRAMES - OPTIONAL! - // standing turn-left frames come after the slow-out frames - // one for each direction - // standing turn-left frames come after the standing turn-right frames - // one for each direction - - if (_walkData.usingStandingTurnFrames) { - _firstStandingTurnLeftFrame = frameCounter; - frameCounter += NO_DIRECTIONS; - - _firstStandingTurnRightFrame = frameCounter; - frameCounter += NO_DIRECTIONS; - } else { - // refer instead to the normal stand frames - _firstStandingTurnLeftFrame = _firstStandFrame; - _firstStandingTurnRightFrame = _firstStandFrame; - } - - // WALKING TURN FRAMES - OPTIONAL! - // walking left-turn frames come after the stand frames - // walking right-turn frames come after the walking left-turn frames - - if (_walkData.usingWalkingTurnFrames) { - _firstWalkingTurnLeftFrame = frameCounter; - frameCounter += _framesPerChar; - - _firstWalkingTurnRightFrame = frameCounter; - frameCounter += _framesPerChar; - } else { - _firstWalkingTurnLeftFrame = 0; - _firstWalkingTurnRightFrame = 0; - } - - // SLOW-IN FRAMES - OPTIONAL! - // slow-in frames come after the walking right-turn frames - - if (_walkData.usingSlowInFrames) { - // Make note of frame number of first slow-in frame for each - // direction. There may be a different number of slow-in - // frames in each direction - - for (i = 0; i < NO_DIRECTIONS; i++) { - _firstSlowInFrame[i] = frameCounter; - frameCounter += _walkData.nSlowInFrames[i]; - } - } - - // SLOW-OUT FRAMES - OPTIONAL! - // slow-out frames come after the slow-in frames - - if (_walkData.usingSlowOutFrames) - _firstSlowOutFrame = frameCounter; -} - -// THE ROUTE EXTRACTOR - -void Router::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 ldx; - int32 ldy; - - // 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--; - 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++; - _routeLength++; - } while (point < O_ROUTE_SIZE); - - _routeLength--; - - // okay the route exists as a series point now put in some directions - - p = 0; - - do { - ldx = _route[p + 1].x - _route[p].x; - ldy = _route[p + 1].y - _route[p].y; - dirx = 1; - diry = 1; - - if (ldx < 0) { - ldx = -ldx; - dirx = -1; - } - - if (ldy < 0) { - ldy = -ldy; - diry = -1; - } - - if (_diagonaly * ldx > _diagonalx * ldy) { - // dir = 1,2 or 2,3 or 5,6 or 6,7 - - // 2 or 6 - dir = 4 - 2 * dirx; - _route[p].dirS = dir; - - // 1, 3, 5 or 7 - dir = dir + diry * dirx; - _route[p].dirD = dir; - } else { - // dir = 7,0 or 0,1 or 3,4 or 4,5 - - // 0 or 4 - dir = 2 + 2 * diry; - _route[p].dirS = dir; - - // 2 or 6 - dir = 4 - 2 * dirx; - - // 1, 3, 5 or 7 - dir = dir + diry * dirx; - _route[p].dirD = dir; - } - p++; - } 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 Router::setUpWalkGrid(byte *ob_mega, int32 x, int32 y, int32 dir) { - ObjectMega obMega(ob_mega); - - // get walk grid file + extra grid into 'bars' & 'node' arrays - loadWalkGrid(); - - // copy the mega structure into the local variables for use in all - // subroutines - - _startX = obMega.getFeetX(); - _startY = obMega.getFeetY(); - _startDir = obMega.getCurDir(); - _targetX = x; - _targetY = y; - _targetDir = dir; - - _scaleA = obMega.getScaleA(); - _scaleB = obMega.getScaleB(); - - // 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 (int 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 Router::plotWalkGrid() { - int32 i; - - // get walk grid file + extra grid into 'bars' & 'node' arrays - loadWalkGrid(); - - // lines - - for (i = 0; i < _nBars; i++) - _vm->_screen->drawLine(_bars[i].x1, _bars[i].y1, _bars[i].x2, _bars[i].y2, 254); - - // nodes - - // leave node 0 for start node - for (i = 1; i < _nNodes; i++) - plotCross(_node[i].x, _node[i].y, 184); -} - -void Router::plotCross(int16 x, int16 y, uint8 colour) { - _vm->_screen->drawLine(x - 1, y - 1, x + 1, y + 1, colour); - _vm->_screen->drawLine(x + 1, y - 1, x - 1, y + 1, colour); -} - -void Router::loadWalkGrid() { - WalkGridHeader floorHeader; - byte *fPolygrid; - uint16 fPolygridLen; - - _nBars = 0; // reset counts - _nNodes = 1; // leave node 0 for start-node - - // STATIC GRIDS (added/removed by object logics) - - // go through walkgrid list - for (int i = 0; i < MAX_WALKGRIDS; i++) { - if (_walkGridList[i]) { - int j; - - // open walk grid file - fPolygrid = _vm->_resman->openResource(_walkGridList[i]); - fPolygridLen = _vm->_resman->fetchLen(_walkGridList[i]); - - Common::MemoryReadStream readS(fPolygrid, fPolygridLen); - - readS.seek(ResHeader::size()); - - floorHeader.numBars = readS.readSint32LE(); - floorHeader.numNodes = readS.readSint32LE(); - - // check that we're not going to exceed the max - // allowed in the complete walkgrid arrays - - assert(_nBars + floorHeader.numBars < O_GRID_SIZE); - assert(_nNodes + floorHeader.numNodes < O_GRID_SIZE); - - // lines - - for (j = 0; j < floorHeader.numBars; j++) { - _bars[_nBars + j].x1 = readS.readSint16LE(); - _bars[_nBars + j].y1 = readS.readSint16LE(); - _bars[_nBars + j].x2 = readS.readSint16LE(); - _bars[_nBars + j].y2 = readS.readSint16LE(); - _bars[_nBars + j].xmin = readS.readSint16LE(); - _bars[_nBars + j].ymin = readS.readSint16LE(); - _bars[_nBars + j].xmax = readS.readSint16LE(); - _bars[_nBars + j].ymax = readS.readSint16LE(); - _bars[_nBars + j].dx = readS.readSint16LE(); - _bars[_nBars + j].dy = readS.readSint16LE(); - _bars[_nBars + j].co = readS.readSint32LE(); - } - - // nodes - - // leave node 0 for start node - for (j = 0; j < floorHeader.numNodes; j++) { - _node[_nNodes + j].x = readS.readSint16LE(); - _node[_nNodes + j].y = readS.readSint16LE(); - } - - // close walk grid file - _vm->_resman->closeResource(_walkGridList[i]); - - // increment counts of total bars & nodes in whole - // walkgrid - - _nBars += floorHeader.numBars; - _nNodes += floorHeader.numNodes; - } - } -} - -void Router::clearWalkGridList() { - memset(_walkGridList, 0, sizeof(_walkGridList)); -} - -// called from fnAddWalkGrid - -void Router::addWalkGrid(int32 gridResource) { - int i; - // First, scan the list to see if this grid is already included - - for (i = 0; i < MAX_WALKGRIDS; i++) { - if (_walkGridList[i] == gridResource) - return; - } - - // Scan the list for a free slot - - for (i = 0; i < MAX_WALKGRIDS; i++) { - if (_walkGridList[i] == 0) { - _walkGridList[i] = gridResource; - return; - } - } - - error("_walkGridList[] full"); -} - -// called from fnRemoveWalkGrid - -void Router::removeWalkGrid(int32 gridResource) { - for (int i = 0; i < MAX_WALKGRIDS; i++) { - if (_walkGridList[i] == gridResource) { - // If we've found it in the list, reset entry to zero. - // Otherwise just ignore the request. - _walkGridList[i] = 0; - break; - } - } -} - -} // End of namespace Sword2 |
