diff options
Diffstat (limited to 'engines/tinsel/move.cpp')
-rw-r--r-- | engines/tinsel/move.cpp | 1618 |
1 files changed, 1618 insertions, 0 deletions
diff --git a/engines/tinsel/move.cpp b/engines/tinsel/move.cpp new file mode 100644 index 0000000000..803bc5fd7b --- /dev/null +++ b/engines/tinsel/move.cpp @@ -0,0 +1,1618 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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$ + * + * Handles walking and use of the path system. + * + * Contains the dodgiest code in the whole system. + */ + +#include "tinsel/actors.h" +#include "tinsel/anim.h" +#include "tinsel/background.h" +#include "tinsel/cursor.h" +#include "tinsel/dw.h" +#include "tinsel/graphics.h" +#include "tinsel/move.h" +#include "tinsel/multiobj.h" // multi-part object defintions etc. +#include "tinsel/object.h" +#include "tinsel/polygons.h" +#include "tinsel/rince.h" +#include "tinsel/scroll.h" +#include "tinsel/tinlib.h" // For stand() + +namespace Tinsel { + +//----------------- DEVELOPMENT OPTIONS -------------------- + +#define SLOW_RINCE_DOWN 0 + +//----------------- EXTERNAL FUNCTIONS --------------------- + +// in BG.C +extern int BackgroundWidth(void); +extern int BackgroundHeight(void); + + +// in POLYGONS.C +// Deliberatley defined here, and not in polygons.h +HPOLYGON InitExtraBlock(PMACTOR ca, PMACTOR ta); + +//----------------- LOCAL DEFINES -------------------- + +#define XMDIST 4 +#define XHMDIST 2 +#define YMDIST 2 +#define YHMDIST 2 + +#define XTHERE 1 +#define XRESTRICT 2 +#define YTHERE 4 +#define YRESTRICT 8 +#define STUCK 16 + +#define LEAVING_PATH 0x100 +#define ENTERING_BLOCK 0x200 +#define ENTERING_MBLOCK 0x400 + +#define ALL_SORTED 1 +#define NOT_SORTED 0 + + +//----------------- LOCAL GLOBAL DATA -------------------- + +#if SLOW_RINCE_DOWN +static int Interlude = 0; // For slowing down walking, for testing +static int BogusVar = 0; // For slowing down walking, for testing +#endif + +static int32 DefaultRefer = 0; +static int hSlowVar = 0; // used by MoveActor() + + +//----------------- FORWARD REFERENCES -------------------- + +static void NewCoOrdinates(int fromx, int fromy, int *targetX, int *targetY, + int *newx, int *newy, int *s1, int *s2, HPOLYGON *hS2p, + bool bOver, bool bBodge, + PMACTOR pActor, PMACTOR *collisionActor = 0); + + +#if SLOW_RINCE_DOWN +/** + * AddInterlude + */ + +void AddInterlude(int n) { + Interlude += n; + if (Interlude < 0) + Interlude = 0; +} +#endif + +/** + * Given (x, y) of a click within a path polygon, checks that the + * co-ordinates are not within a blocking polygon. If it is not, the + * destination is the click point, otherwise tries to find a legal point + * below or above the click point. + * Returns: + * NOT_SORTED - if a destination is worked out (movement required) + * ALL_SORTED - no destination found (so no movement required) + */ +static int ClickedOnPath(int clickX, int clickY, int *ptgtX, int *ptgtY) { + int Loffset, Toffset; + int i; + + /*-------------------------------------- + Clicked within a path, + go to where requested unless blocked. + --------------------------------------*/ + if (InPolygon(clickX, clickY, BLOCKING) == NOPOLY) { + // Not in a blocking polygon - go to where requested. + *ptgtX = clickX; + *ptgtY = clickY; + } else { + /*------------------------------------------------------ + In a Blocking polygon - try searching down and up. + If still nowhere (for now) give up! + ------------------------------------------------------*/ + PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset); + + for (i = clickY+1; i < SCREEN_HEIGHT + Toffset; i++) { + // Don't leave the path system + if (InPolygon(clickX, i, PATH) == NOPOLY) { + i = SCREEN_HEIGHT; + break; + } + if (InPolygon(clickX, i, BLOCKING) == NOPOLY) { + *ptgtX = clickX; + *ptgtY = i; + break; + } + } + if (i == SCREEN_HEIGHT) { + for (i = clickY-1; i >= Toffset; i--) { + // Don't leave the path system + if (InPolygon(clickX, i, PATH) == NOPOLY) { + i = -1; + break; + } + if (InPolygon(clickX, i, BLOCKING) == NOPOLY) { + *ptgtX = clickX; + *ptgtY = i; + break; + } + } + } + if (i < 0) { + return ALL_SORTED; + } + } + return NOT_SORTED; +} + +/** + * Given (x, y) of a click within a referral polygon, works out the + * destination according to the referral type. + * Returns: + * NOT_SORTED - if a destination is worked out (movement required) + * ALL_SORTED - no destination found (so no movement required) + */ +static int ClickedOnRefer(HPOLYGON hRefpoly, int clickX, int clickY, int *ptgtX, int *ptgtY) { + int i; + int end; // Extreme of the scene + int Loffset, Toffset; + + PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset); + *ptgtX = *ptgtY = -1; + + switch (PolySubtype(hRefpoly)) { + case REF_POINT: // Go to specified node + getPolyNode(hRefpoly, ptgtX, ptgtY); + assert(InPolygon(*ptgtX, *ptgtY, PATH) != NOPOLY); // POINT Referral to illegal point + break; + + case REF_DOWN: // Search downwards + end = BackgroundHeight(); + for (i = clickY+1; i < end; i++) + if (InPolygon(clickX, i, PATH) != NOPOLY + && InPolygon(clickX, i, BLOCKING) == NOPOLY) { + *ptgtX = clickX; + *ptgtY = i; + break; + } + break; + + case REF_UP: // Search upwards + for (i = clickY-1; i >= 0; i--) + if (InPolygon(clickX, i, PATH) != NOPOLY + && InPolygon(clickX, i, BLOCKING) == NOPOLY) { + *ptgtX = clickX; + *ptgtY = i; + break; + } + break; + + case REF_RIGHT: // Search to the right + end = BackgroundWidth(); + for (i = clickX+1; i < end; i++) + if (InPolygon(i, clickY, PATH) != NOPOLY + && InPolygon(i, clickY, BLOCKING) == NOPOLY) { + *ptgtX = i; + *ptgtY = clickY; + break; + } + break; + + case REF_LEFT: // Search to the left + for (i = clickX-1; i >= 0; i--) + if (InPolygon(i, clickY, PATH) != NOPOLY + && InPolygon(i, clickY, BLOCKING) == NOPOLY) { + *ptgtX = i; + *ptgtY = clickY; + break; + } + break; + } + if (*ptgtX != -1 && *ptgtY != -1) { + return NOT_SORTED; + } else + return ALL_SORTED; +} + +/** + * Given (x, y) of a click, works out the destination according to the + * default referral type. + * Returns: + * NOT_SORTED - if a destination is worked out (movement required) + * ALL_SORTED - no destination found (so no movement required) + */ +static int ClickedOnNothing(int clickX, int clickY, int *ptgtX, int *ptgtY) { + int i; + int end; // Extreme of the scene + int Loffset, Toffset; + + PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset); + + switch (DefaultRefer) { + case REF_DEFAULT: + // Try searching down and up (onscreen). + for (i = clickY+1; i < SCREEN_HEIGHT+Toffset; i++) + if (InPolygon(clickX, i, PATH) != NOPOLY) { + return ClickedOnPath(clickX, i, ptgtX, ptgtY); + } + for (i = clickY-1; i >= Toffset; i--) + if (InPolygon(clickX, i, PATH) != NOPOLY) { + return ClickedOnPath(clickX, i, ptgtX, ptgtY); + } + // Try searching down and up (offscreen). + end = BackgroundHeight(); + for (i = clickY+1; i < end; i++) + if (InPolygon(clickX, i, PATH) != NOPOLY) { + return ClickedOnPath(clickX, i, ptgtX, ptgtY); + } + for (i = clickY-1; i >= 0; i--) + if (InPolygon(clickX, i, PATH) != NOPOLY) { + return ClickedOnPath(clickX, i, ptgtX, ptgtY); + } + break; + + case REF_UP: + for (i = clickY-1; i >= 0; i--) + if (InPolygon(clickX, i, PATH) != NOPOLY) { + return ClickedOnPath(clickX, i, ptgtX, ptgtY); + } + break; + + case REF_DOWN: + end = BackgroundHeight(); + for (i = clickY+1; i < end; i++) + if (InPolygon(clickX, i, PATH) != NOPOLY) { + return ClickedOnPath(clickX, i, ptgtX, ptgtY); + } + break; + + case REF_LEFT: + for (i = clickX-1; i >= 0; i--) + if (InPolygon(i, clickY, PATH) != NOPOLY) { + return ClickedOnPath(i, clickY, ptgtX, ptgtY); + } + break; + + case REF_RIGHT: + end = BackgroundWidth(); + for (i = clickX + 1; i < end; i++) + if (InPolygon(i, clickY, PATH) != NOPOLY) { + return ClickedOnPath(i, clickY, ptgtX, ptgtY); + } + break; + } + + // Going nowhere! + return ALL_SORTED; +} + +/** + * Given (x, y) of the click, ascertains whether the click is within a + * path, within a referral poly, or niether. The appropriate function + * then gets called to give us a revised destination. + * Returns: + * NOT_SORTED - if a destination is worked out (movement required) + * ALL_SORTED - no destination found (so no movement required) + */ +static int WorkOutDestination(int clickX, int clickY, int *ptgtX, int *ptgtY) { + HPOLYGON hPoly; + + /*-------------------------------------- + Clicked within a path? + if not, within a referral poly? + if not, try and sort something out. + ---------------------------------------*/ + if (InPolygon(clickX, clickY, PATH) != NOPOLY) { + return ClickedOnPath(clickX, clickY, ptgtX, ptgtY); + } else if ((hPoly = InPolygon(clickX, clickY, REFER)) != NOPOLY) { + return ClickedOnRefer(hPoly, clickX, clickY, ptgtX, ptgtY); + } else { + return ClickedOnNothing(clickX, clickY, ptgtX, ptgtY); + } +} + +/** + * Work out which reel to adopt for a section of movement. + */ +static DIRREEL GetDirectionReel(int fromx, int fromy, int tox, int toy, DIRREEL lastreel, HPOLYGON hPath) { + int xchange = 0, ychange = 0; + enum {X_NONE, X_LEFT, X_RIGHT, X_NO} xdir; + enum {Y_NONE, Y_UP, Y_DOWN, Y_NO} ydir; + + DIRREEL reel = lastreel; // Leave alone if can't decide + + /* + * Determine size and direction of X movement. + * i.e. left, right, none or not allowed. + */ + if (getPolyReelType(hPath) == REEL_VERT) + xdir = X_NO; + else if (tox == -1) + xdir = X_NONE; + else { + xchange = tox - fromx; + if (xchange > 0) + xdir = X_RIGHT; + else if (xchange < 0) { + xchange = -xchange; + xdir = X_LEFT; + } else + xdir = X_NONE; + } + + /* + * Determine size and direction of Y movement. + * i.e. up, down, none or not allowed. + */ + if (getPolyReelType(hPath) == REEL_HORIZ) + ydir = Y_NO; + else if (toy == -1) + ydir = Y_NONE; + else { + ychange = toy - fromy; + if (ychange > 0) + ydir = Y_DOWN; + else if (ychange < 0) { + ychange = -ychange; + ydir = Y_UP; + } else + ydir = Y_NONE; + } + + /* + * Some adjustment to allow for different x and y pixell sizes. + */ + ychange += ychange; // Double y distance to cover + + /* + * Determine which reel to use. + */ + if (xdir == X_NO) { + // Forced to be FORWARD or AWAY + switch (ydir) { + case Y_DOWN: + reel = FORWARD; + break; + case Y_UP: + reel = AWAY; + break; + default: + if (reel != AWAY) // No gratuitous turn + reel = FORWARD; + break; + } + } else if (ydir == Y_NO) { + // Forced to be LEFTREEL or RIGHTREEL + switch (xdir) { + case X_LEFT: + reel = LEFTREEL; + break; + case X_RIGHT: + reel = RIGHTREEL; + break; + default: + if (reel != LEFTREEL) // No gratuitous turn + reel = RIGHTREEL; + break; + } + } else if (xdir != X_NONE || ydir != Y_NONE) { + if (xdir == X_NONE) + reel = (ydir == Y_DOWN) ? FORWARD : AWAY; + else if (ydir == Y_NONE) + reel = (xdir == X_LEFT) ? LEFTREEL : RIGHTREEL; + else { + bool DontBother = false; + + if (xchange <= 4 && ychange <= 4) { + switch (reel) { + case LEFTREEL: + if (xdir == X_LEFT) + DontBother = true; + break; + case RIGHTREEL: + if (xdir == X_RIGHT) + DontBother = true; + break; + case FORWARD: + if (ydir == Y_DOWN) + DontBother = true; + break; + case AWAY: + if (ydir == Y_UP) + DontBother = true; + break; + } + } + if (!DontBother) { + if (xchange > ychange) + reel = (xdir == X_LEFT) ? LEFTREEL : RIGHTREEL; + else + reel = (ydir == Y_DOWN) ? FORWARD : AWAY; + } + } + } + return reel; +} + +/** + * Haven't moved, look towards the cursor. + */ +static void GotThereWithoutMoving(PMACTOR pActor) { + int curX, curY; + DIRREEL reel; + + if (!pActor->TagReelRunning) { + GetCursorXYNoWait(&curX, &curY, true); + + reel = GetDirectionReel(pActor->objx, pActor->objy, curX, curY, pActor->dirn, pActor->hCpath); + + if (reel != pActor->dirn) + SetMActorWalkReel(pActor, reel, pActor->scale, false); + } +} + +/** + * Arrived at final destination. + */ +static void GotThere(PMACTOR pActor) { + pActor->targetX = pActor->targetY = -1; // 4/1/95 + pActor->ItargetX = pActor->ItargetY = -1; + pActor->UtargetX = pActor->UtargetY = -1; + + // Perhaps we have'nt moved. + if (pActor->objx == (int)pActor->fromx && pActor->objy == (int)pActor->fromy) + GotThereWithoutMoving(pActor); + + ReTagActor(pActor->actorID); // Tag allowed while stationary + + SetMActorStanding(pActor); + + pActor->bMoving = false; +} + +enum cgt { GT_NOTL, GT_NOTB, GT_NOT2, GT_OK, GT_MAY }; + +/** + * Can we get straight there? + */ +static cgt CanGetThere(PMACTOR pActor, int tx, int ty) { + int s1, s2; // s2 not used here! + HPOLYGON hS2p; // nor is s2p! + int nextx, nexty; + + int targetX = tx; + int targetY = ty; // Ultimate destination + int x = pActor->objx; + int y = pActor->objy; // Present position + + while (targetX != -1 || targetY != -1) { + NewCoOrdinates(x, y, &targetX, &targetY, &nextx, &nexty, + &s1, &s2, &hS2p, pActor->over, false, pActor); + + if (s1 == (XTHERE | YTHERE)) { + return GT_OK; // Can get there directly. + } else if (s1 == (XTHERE | YRESTRICT) || s1 == (YTHERE | XRESTRICT)) { + return GT_MAY; // Can't get there directly. + } else if (s1 & STUCK) { + if (s2 == LEAVING_PATH) + return GT_NOTL; // Can't get there. + else + return GT_NOTB; // Can't get there. + } else if (x == nextx && y == nexty) { + return GT_NOT2; // Can't get there. + } + x = nextx; + y = nexty; + } + return GT_MAY; +} + + +/** + * Set final destination. + */ +static void SetMoverUltDest(PMACTOR pActor, int x, int y) { + pActor->UtargetX = x; + pActor->UtargetY = y; + pActor->hUpath = InPolygon(x, y, PATH); + + assert(pActor->hUpath != NOPOLY || pActor->bIgPath); // Invalid ultimate destination +} + +/** + * Set intermediate destination. + * + * If in final destination path, go straight to target. + * If in a neighbouring path to the final destination, if the target path + * is a follow nodes path, head for the end node, otherwise head straight + * for the target. + * Otherwise, head towards the pseudo-centre or end node of the first + * en-route path. + */ +static void SetMoverIntDest(PMACTOR pActor, int x, int y) { + HPOLYGON hIpath, hTpath; + int node; + + hTpath = InPolygon(x, y, PATH); // Target path +#ifdef DEBUG + if (!pActor->bIgPath) + assert(hTpath != NOPOLY); // SetMoverIntDest() - target not in path +#endif + + if (pActor->hCpath == hTpath || pActor->bIgPath + || IsInPolygon(pActor->objx, pActor->objy, hTpath)) { + // In destination path - head straight for the target. + pActor->ItargetX = x; + pActor->ItargetY = y; + pActor->hIpath = hTpath; + } else if (IsAdjacentPath(pActor->hCpath, hTpath)) { + // In path adjacent to target + if (PolySubtype(hTpath) != NODE) { + // Target path is normal - head for target. + // Added 26/01/95, innroom + if (CanGetThere(pActor, x, y) == GT_NOTL) { + NearestCorner(&x, &y, pActor->hCpath, hTpath); + } + pActor->ItargetX = x; + pActor->ItargetY = y; + } else { + // Target path is node - head for end node. + node = NearestEndNode(hTpath, pActor->objx, pActor->objy); + getNpathNode(hTpath, node, &pActor->ItargetX, &pActor->ItargetY); + + } + pActor->hIpath = hTpath; + } else { + assert(hTpath != NOPOLY); // Error 701 + hIpath = getPathOnTheWay(pActor->hCpath, hTpath); + + if (hIpath != NOPOLY) { + /* Head for an en-route path */ + if (PolySubtype(hIpath) != NODE) { + /* En-route path is normal - head for pseudo centre. */ + if (CanGetThere(pActor, x, y) == GT_OK) { + pActor->ItargetX = x; + pActor->ItargetY = y; + } else { + pActor->ItargetX = PolyCentreX(hIpath); + pActor->ItargetY = PolyCentreY(hIpath); + } + } else { + /* En-route path is node - head for end node. */ + node = NearestEndNode(hIpath, pActor->objx, pActor->objy); + getNpathNode(hIpath, node, &pActor->ItargetX, &pActor->ItargetY); + } + pActor->hIpath = hIpath; + } + } + + pActor->InDifficulty = NO_PROB; +} + +/** + * Set short-term destination and adopt the appropriate reel. + */ +static void SetMoverDest(PMACTOR pActor, int x, int y) { + int scale; + DIRREEL reel; + + // Set the co-ordinates requested. + pActor->targetX = x; + pActor->targetY = y; + pActor->InDifficulty = NO_PROB; + + reel = GetDirectionReel(pActor->objx, pActor->objy, x, y, pActor->dirn, pActor->hCpath); + scale = GetScale(pActor->hCpath, pActor->objy); + if (scale != pActor->scale || reel != pActor->dirn) { + SetMActorWalkReel(pActor, reel, scale, false); + } +} + +/** + * SetNextDest + */ +static void SetNextDest(PMACTOR pActor) { + int targetX, targetY; // Ultimate destination + int x, y; // Present position + int nextx, nexty; + int s1, lstatus = 0; + int s2; + HPOLYGON hS2p; + int i; + HPOLYGON hNpoly; + HPOLYGON hPath; + int znode; + int nx, ny; + int sx, sy; + HPOLYGON hEb; + + int ss1, ss2; + HPOLYGON shS2p; + PMACTOR collisionActor; +#if 1 + int sTargetX, sTargetY; +#endif + + /* + * Desired destination (Itarget) is already set + */ + x = pActor->objx; // Current position + y = pActor->objy; + targetX = pActor->ItargetX; // Desired position + targetY = pActor->ItargetY; + + /* + * If we're where we're headed, end it all (the moving). + */ +// if (x == targetX && y == targetY) + if (ABS(x - targetX) < XMDIST && ABS(y - targetY) < YMDIST) { + if (targetX == pActor->UtargetX && targetY == pActor->UtargetY) { + // Desired position + GotThere(pActor); + return; + } else { + assert(pActor->bIgPath || InPolygon(pActor->UtargetX, pActor->UtargetY, PATH) != NOPOLY); // Error 5001 + SetMoverIntDest(pActor, pActor->UtargetX, pActor->UtargetY); + } + } + + if (pActor->bNoPath || pActor->bIgPath) { + /* Can get there directly. */ + SetMoverDest(pActor, targetX, targetY); + pActor->over = false; + return; + } + + /*---------------------------------------------------------------------- + | Some work to do here if we're in a follow nodes polygon - basically + | head for the next node. + ----------------------------------------------------------------------*/ + hNpoly = pActor->hFnpath; // The node path we're in (if any) + switch (pActor->npstatus) { + case NOT_IN: + break; + + case ENTERING: + znode = NearestEndNode(hNpoly, x, y); + /* Hang on, we're probably here already! */ + if (znode) { + pActor->npstatus = GOING_DOWN; + pActor->line = znode-1; + getNpathNode(hNpoly, znode - 1, &nx, &ny); + } else { + pActor->npstatus = GOING_UP; + pActor->line = znode; + getNpathNode(hNpoly, 1, &nx, &ny); + } + SetMoverDest(pActor, nx, ny); + + // Test for pseudo-one-node npaths + if (numNodes(hNpoly) == 2 && + ABS(pActor->objx - pActor->targetX) < XMDIST && + ABS(pActor->objy - pActor->targetY) < YMDIST) { + // That's enough, we're leaving + pActor->npstatus = LEAVING; + } else { + // Normal situation + pActor->over = true; + return; + } + // Fall through for LEAVING + + case LEAVING: + assert(pActor->bIgPath || InPolygon(pActor->UtargetX, pActor->UtargetY, PATH) != NOPOLY); // Error 5002 + SetMoverIntDest(pActor, pActor->UtargetX, pActor->UtargetY); + targetX = pActor->ItargetX; // Desired position + targetY = pActor->ItargetY; + break; + + case GOING_UP: + i = pActor->line; // The line we're on + + // Is this the final target line? + if (i+1 == pActor->Tline && hNpoly == pActor->hUpath) { + // The final leg of the journey + pActor->line = i+1; + SetMoverDest(pActor, pActor->UtargetX, pActor->UtargetY); + pActor->over = false; + return; + } else { + // Go to the next node unless we're at the last one + i++; // The node we're at + if (++i < numNodes(hNpoly)) { + getNpathNode(hNpoly, i, &nx, &ny); + SetMoverDest(pActor, nx, ny); + pActor->line = i-1; + if (ABS(pActor->UtargetX - pActor->targetX) < XMDIST && + ABS(pActor->UtargetY - pActor->targetY) < YMDIST) + pActor->over = false; + else + pActor->over = true; + return; + } else { + // Last node - we're off + pActor->npstatus = LEAVING; + assert(pActor->bIgPath || InPolygon(pActor->UtargetX, pActor->UtargetY, PATH) != NOPOLY); // Error 5003 + SetMoverIntDest(pActor, pActor->UtargetX, pActor->UtargetY); + targetX = pActor->ItargetX; // Desired position + targetY = pActor->ItargetY; + break; + } + } + + case GOING_DOWN: + i = pActor->line; // The line we're on and the node we're at + + // Is this the final target line? + if (i - 1 == pActor->Tline && hNpoly == pActor->hUpath) { + // The final leg of the journey + SetMoverDest(pActor, pActor->UtargetX, pActor->UtargetY); + pActor->line = i-1; + pActor->over = false; + return; + } else { + // Go to the next node unless we're at the last one + if (--i >= 0) { + getNpathNode(hNpoly, i, &nx, &ny); + SetMoverDest(pActor, nx, ny); + pActor->line--; /* The next node to head for */ + if (ABS(pActor->UtargetX - pActor->targetX) < XMDIST && + ABS(pActor->UtargetY - pActor->targetY) < YMDIST) + pActor->over = false; + else + pActor->over = true; + return; + } else { + // Last node - we're off + pActor->npstatus = LEAVING; + assert(pActor->bIgPath || InPolygon(pActor->UtargetX, pActor->UtargetY, PATH) != NOPOLY); // Error 5004 + SetMoverIntDest(pActor, pActor->UtargetX, pActor->UtargetY); + targetX = pActor->ItargetX; // Desired position + targetY = pActor->ItargetY; + break; + } + } + } + + + + + /*------------------------------------------------------ + | See if it can get there directly. There may be an + | intermediate destination to head for. + ------------------------------------------------------*/ + + while (targetX != -1 || targetY != -1) { +#if 1 + // 'push' the target + sTargetX = targetX; + sTargetY = targetY; +#endif + NewCoOrdinates(x, y, &targetX, &targetY, &nextx, &nexty, + &s1, &s2, &hS2p, pActor->over, false, pActor, &collisionActor); + + if (s1 != (XTHERE | YTHERE) && x == nextx && y == nexty) { + ss1 = s1; + ss2 = s2; + shS2p = hS2p; +#if 1 + // 'pop' the target + targetX = sTargetX; + targetY = sTargetY; +#endif + // Note: this aint right - targetX/Y (may) have been + // nobbled by that last call to NewCoOrdinates() + // Re-instating them (can) leads to oscillation + NewCoOrdinates(x, y, &targetX, &targetY, &nextx, &nexty, + &s1, &s2, &hS2p, pActor->over, true, pActor, &collisionActor); + + if (x == nextx && y == nexty) { + s1 = ss1; + s2 = ss2; + hS2p = shS2p; + } + } + + if (s1 == (XTHERE | YTHERE)) { + /* Can get there directly. */ + SetMoverDest(pActor, nextx, nexty); + pActor->over = false; + break; + } else if ((s1 & STUCK) || s1 == (XRESTRICT + YRESTRICT) + || s1 == (XTHERE | YRESTRICT) || s1 == (YTHERE | XRESTRICT)) { + /*------------------------------------------------- + Can't go any further in this direction. | + If it's because of a blocking polygon, try to do | + something about it. | + -------------------------------------------------*/ + if (s2 & ENTERING_BLOCK) { + x = pActor->objx; // Current position + y = pActor->objy; + // Go to the nearest corner of the blocking polygon concerned + BlockingCorner(hS2p, &x, &y, pActor->ItargetX, pActor->ItargetY); + SetMoverDest(pActor, x, y); + pActor->over = false; + } else if (s2 & ENTERING_MBLOCK) { + if (InMActorBlock(pActor, pActor->UtargetX, pActor->UtargetY)) { + // The best we're going to achieve + SetMoverUltDest(pActor, x, y); + SetMoverDest(pActor, x, y); + } else { + sx = pActor->objx; + sy = pActor->objy; +// pActor->objx = x; +// pActor->objy = y; + + hEb = InitExtraBlock(pActor, collisionActor); + x = pActor->objx; + y = pActor->objy; + BlockingCorner(hEb, &x, &y, pActor->ItargetX, pActor->ItargetY); + + pActor->objx = sx; + pActor->objy = sy; + SetMoverDest(pActor, x, y); + pActor->over = false; + } + } else { + /*---------------------------------------- + Currently, this is as far as we can go. | + Definitely room for improvement here! | + ----------------------------------------*/ + hPath = InPolygon(pActor->ItargetX, pActor->ItargetY, PATH); + if (hPath != pActor->hIpath) { + if (IsInPolygon(pActor->ItargetX, pActor->ItargetY, pActor->hIpath)) + hPath = pActor->hIpath; + } + assert(hPath == pActor->hIpath); + + if (pActor->InDifficulty == NO_PROB) { + x = PolyCentreX(hPath); + y = PolyCentreY(hPath); + SetMoverDest(pActor, x, y); + pActor->InDifficulty = TRY_CENTRE; + pActor->over = false; + } else if (pActor->InDifficulty == TRY_CENTRE) { + NearestCorner(&x, &y, pActor->hCpath, pActor->hIpath); + SetMoverDest(pActor, x, y); + pActor->InDifficulty = TRY_CORNER; + pActor->over = false; + } else if (pActor->InDifficulty == TRY_CORNER) { + NearestCorner(&x, &y, pActor->hCpath, pActor->hIpath); + SetMoverDest(pActor, x, y); + pActor->InDifficulty = TRY_NEXTCORNER; + pActor->over = false; + } + } + break; + } + else if (((lstatus & YRESTRICT) && !(s1 & YRESTRICT)) + || ((lstatus & XRESTRICT) && !(s1 & XRESTRICT))) { + /*----------------------------------------------- + A restriction in a direction has been removed. | + Use this as an intermediate destination. | + -----------------------------------------------*/ + SetMoverDest(pActor, nextx, nexty); + pActor->over = false; + break; + } + + x = nextx; + y = nexty; + + /*------------------------- + Change of path polygon? | + -------------------------*/ + hPath = InPolygon(x, y, PATH); + if (pActor->hCpath != hPath && + !IsInPolygon(x, y, pActor->hCpath) && + !IsAdjacentPath(pActor->hCpath, pActor->hIpath)) { + /*---------------------------------------------------------- + If just entering a follow nodes polygon, go to first node.| + Else if just going to pass through, go to pseudo-centre. | + ----------------------------------------------------------*/ + if (PolySubtype(hPath) == NODE && pActor->hFnpath != hPath && pActor->npstatus != LEAVING) { + int node = NearestEndNode(hPath, x, y); + getNpathNode(hPath, node, &nx, &ny); + SetMoverDest(pActor, nx, ny); + pActor->over = true; + } else if (!IsInPolygon(pActor->ItargetX, pActor->ItargetY, hPath) && + !IsInPolygon(pActor->ItargetX, pActor->ItargetY, pActor->hCpath)) { + SetMoverDest(pActor, PolyCentreX(hPath), PolyCentreY(hPath)); + pActor->over = true; + } else { + SetMoverDest(pActor, pActor->ItargetX, pActor->ItargetY); + } + break; + } + + lstatus = s1; + } +} + +/** + * Work out where the next position should be. + * Check that it's in a path and not in a blocking polygon. + */ +static void NewCoOrdinates(int fromx, int fromy, int *targetX, int *targetY, + int *newx, int *newy, int *s1, int *s2, + HPOLYGON *hS2p, bool bOver, bool bBodge, + PMACTOR pActor, PMACTOR *collisionActor) { + HPOLYGON hPoly; + int sidem, depthm; + int sidesteps, depthsteps; + PMACTOR ma; + + *s1 = *s2 = 0; + + /*------------------------------------------------ + Don't overrun if this is the final destination. | + ------------------------------------------------*/ + if (*targetX == pActor->UtargetX && (*targetY == -1 || *targetY == pActor->UtargetY) || + *targetY == pActor->UtargetY && (*targetX == -1 || *targetX == pActor->UtargetX)) + bOver = false; + + /*---------------------------------------------------- + Decide how big a step to attempt in each direction. | + ----------------------------------------------------*/ + sidesteps = *targetX == -1 ? 0 : *targetX - fromx; + sidesteps = ABS(sidesteps); + + depthsteps = *targetY == -1 ? 0 : *targetY - fromy; + depthsteps = ABS(depthsteps); + + if (sidesteps && depthsteps > sidesteps) { + depthm = YMDIST; + sidem = depthm * sidesteps/depthsteps; + + if (!sidem) + sidem = 1; + } else if (depthsteps && sidesteps > depthsteps) { + sidem = XMDIST; + depthm = sidem * depthsteps/sidesteps; + + if (!depthm) { + if (bBodge) + depthm = 1; + } else if (depthm > YMDIST) + depthm = YMDIST; + } else { + sidem = sidesteps ? XMDIST : 0; + depthm = depthsteps ? YMDIST : 0; + } + + *newx = fromx; + *newy = fromy; + + /*------------------------------------------------------------ + If Left-Right movement is required - then make the move, | + but don't overshoot, and do notice when we're already there | + ------------------------------------------------------------*/ + if (*targetX == -1) + *s1 |= XTHERE; + else { + if (*targetX > fromx) { /* To the right? */ + *newx += sidem; // Move to the right... + if (*newx == *targetX) + *s1 |= XTHERE; + else if (*newx > *targetX) { // ...but don't overshoot + if (!bOver) + *newx = *targetX; + else + *targetX = *newx; + *s1 |= XTHERE; + } + } else if (*targetX < fromx) { /* To the left? */ + *newx -= sidem; // Move to the left... + if (*newx == *targetX) + *s1 |= XTHERE; + else if (*newx < *targetX) { // ...but don't overshoot + if (!bOver) + *newx = *targetX; + else + *targetX = *newx; + *s1 |= XTHERE; + } + } else { + *targetX = -1; // We're already there! + *s1 |= XTHERE; + } + } + + /*-------------------------------------------------------------- + If Up-Down movement is required - then make the move, + but don't overshoot, and do notice when we're already there + --------------------------------------------------------------*/ + if (*targetY == -1) + *s1 |= YTHERE; + else { + if (*targetY > fromy) { /* Downwards? */ + *newy += depthm; // Move down... + if (*newy == *targetY) // ...but don't overshoot + *s1 |= YTHERE; + else if (*newy > *targetY) { // ...but don't overshoot + if (!bOver) + *newy = *targetY; + else + *targetY = *newy; + *s1 |= YTHERE; + } + } else if (*targetY < fromy) { /* Upwards? */ + *newy -= depthm; // Move up... + if (*newy == *targetY) // ...but don't overshoot + *s1 |= YTHERE; + else if (*newy < *targetY) { // ...but don't overshoot + if (!bOver) + *newy = *targetY; + else + *targetY = *newy; + *s1 |= YTHERE; + } + } else { + *targetY = -1; // We're already there! + *s1 |= YTHERE; + } + } + + /* Give over if this is it */ + if (*s1 == (XTHERE | YTHERE)) + return; + + /*------------------------------------------------------ + Have worked out where an optimum step would take us. + Must now check if it's in a legal spot. + ------------------------------------------------------*/ + + if (!pActor->bNoPath && !pActor->bIgPath) { + /*------------------------------ + Must stay in a path polygon. + -------------------------------*/ + hPoly = InPolygon(*newx, *newy, PATH); + if (hPoly == NOPOLY) { + *s2 = LEAVING_PATH; // Trying to leave the path polygons + + if (*newx != fromx && InPolygon(*newx, fromy, PATH) != NOPOLY && InPolygon(*newx, fromy, BLOCKING) == NOPOLY) { + *newy = fromy; + *s1 |= YRESTRICT; + } else if (*newy != fromy && InPolygon(fromx, *newy, PATH) != NOPOLY && InPolygon(fromx, *newy, BLOCKING) == NOPOLY) { + *newx = fromx; + *s1 |= XRESTRICT; + } else { + *newx = fromx; + *newy = fromy; +#if 1 + *targetX = *targetY = -1; +#endif + *s1 |= STUCK; + return; + } + } + + /*-------------------------------------- + Must stay out of blocking polygons. + --------------------------------------*/ + hPoly = InPolygon(*newx, *newy, BLOCKING); + if (hPoly != NOPOLY) { + *s2 = ENTERING_BLOCK; // Trying to enter a blocking poly + *hS2p = hPoly; + + if (*newx != fromx && InPolygon(*newx, fromy, BLOCKING) == NOPOLY && InPolygon(*newx, fromy, PATH) != NOPOLY) { + *newy = fromy; + *s1 |= YRESTRICT; + } else if (*newy != fromy && InPolygon(fromx, *newy, BLOCKING) == NOPOLY && InPolygon(fromx, *newy, PATH) != NOPOLY) { + *newx = fromx; + *s1 |= XRESTRICT; + } else { + *newx = fromx; + *newy = fromy; +#if 1 + *targetX = *targetY = -1; +#endif + *s1 |= STUCK; + } + } + /*------------------------------------------------------ + Must stay out of moving actors' blocking polygons. + ------------------------------------------------------*/ + ma = InMActorBlock(pActor, *newx, *newy); + if (ma != NULL) { + // Ignore if already in it (it may have just appeared) + if (!InMActorBlock(pActor, pActor->objx, pActor->objy)) { + *s2 = ENTERING_MBLOCK; // Trying to walk through an actor + + *hS2p = -1; + if (collisionActor) + *collisionActor = ma; + + if (*newx != fromx && InMActorBlock(pActor, *newx, fromy) == NULL + && InPolygon(*newx, fromy, BLOCKING) == NOPOLY && InPolygon(*newx, fromy, PATH) != NOPOLY) { + *newy = fromy; + *s1 |= YRESTRICT; + } else if (*newy != fromy && InMActorBlock(pActor, fromx, *newy) == NULL + && InPolygon(fromx, *newy, BLOCKING) == NOPOLY && InPolygon(fromx, *newy, PATH) != NOPOLY) { + *newx = fromx; + *s1 |= XRESTRICT; + } else { + *newx = fromx; + *newy = fromy; +#if 1 + *targetX = *targetY = -1; +#endif + *s1 |= STUCK; + } + } + } + } +} + +/** + * SetOffWithinNodePath + */ +static void SetOffWithinNodePath(PMACTOR pActor, HPOLYGON StartPath, HPOLYGON DestPath, + int targetX, int targetY) { + int endnode; + HPOLYGON hIpath; + int nx, ny; + int x, y; + + if (StartPath == DestPath) { + if (pActor->line == pActor->Tline) { + SetMoverDest(pActor, pActor->UtargetX, pActor->UtargetY); + pActor->over = false; + } else if (pActor->line < pActor->Tline) { + getNpathNode(StartPath, pActor->line+1, &nx, &ny); + SetMoverDest(pActor, nx, ny); + pActor->npstatus = GOING_UP; + } else if (pActor->line > pActor->Tline) { + getNpathNode(StartPath, pActor->line, &nx, &ny); + SetMoverDest(pActor, nx, ny); + pActor->npstatus = GOING_DOWN; + } + } else { + /* + * Leaving this path - work out + * which end of this path to head for. + */ + assert(DestPath != NOPOLY); // Error 702 + if ((hIpath = getPathOnTheWay(StartPath, DestPath)) == NOPOLY) { + // This should never happen! + // It's the old code that didn't always work. + endnode = NearestEndNode(StartPath, targetX, targetY); + } else { + if (PolySubtype(hIpath) != NODE) { + x = PolyCentreX(hIpath); + y = PolyCentreY(hIpath); + endnode = NearestEndNode(StartPath, x, y); + } else { + endnode = NearEndNode(StartPath, hIpath); + } + } + +#if 1 + if ((pActor->npstatus == LEAVING) && + endnode == NearestEndNode(StartPath, pActor->objx, pActor->objy)) { + // Leave it be + } else +#endif + { + if (endnode) { + getNpathNode(StartPath, pActor->line+1, &nx, &ny); + SetMoverDest(pActor, nx, ny); + pActor->npstatus = GOING_UP; + } else { + getNpathNode(StartPath, pActor->line, &nx, &ny); + SetMoverDest(pActor, nx, ny); + pActor->npstatus = GOING_DOWN; + } + } + } +} + +/** + * Restore a movement, called from restoreMovement() in ACTORS.CPP + */ +void SSetActorDest(PMACTOR pActor) { + if (pActor->UtargetX != -1 && pActor->UtargetY != -1) { + stand(pActor->actorID, pActor->objx, pActor->objy, 0); + + if (pActor->UtargetX != -1 && pActor->UtargetY != -1) { + SetActorDest(pActor, pActor->UtargetX, pActor->UtargetY, + pActor->bIgPath, 0); + } + } else { + stand(pActor->actorID, pActor->objx, pActor->objy, 0); + } +} + +/** + * Initiate a movement, called from WalkTo_Event() + */ +void SetActorDest(PMACTOR pActor, int clickX, int clickY, bool igPath, SCNHANDLE film) { + HPOLYGON StartPath, DestPath = 0; + int targetX, targetY; + + if (pActor->actorID == LeadId()) // Now only for lead actor + UnTagActor(pActor->actorID); // Tag not allowed while moving + pActor->ticket++; + pActor->stop = false; + pActor->over = false; + pActor->fromx = pActor->objx; + pActor->fromy = pActor->objy; + pActor->bMoving = true; + pActor->bIgPath = igPath; + + // Use the supplied reel or restore the normal actor. + if (film != 0) + AlterMActor(pActor, film, AR_WALKREEL); + else + AlterMActor(pActor, 0, AR_NORMAL); + + if (igPath) { + targetX = clickX; + targetY = clickY; + } else { + if (WorkOutDestination(clickX, clickY, &targetX, &targetY) == ALL_SORTED) { + GotThere(pActor); + return; + } + assert(InPolygon(targetX, targetY, PATH) != NOPOLY); // illegal destination! + assert(InPolygon(targetX, targetY, BLOCKING) == NOPOLY); // illegal destination! + } + + + /***** Now have a destination to aim for. *****/ + + /*---------------------------------- + | Don't move if it's not worth it. + ----------------------------------*/ + if (ABS(targetX - pActor->objx) < XMDIST && ABS(targetY - pActor->objy) < YMDIST) { + GotThere(pActor); + return; + } + + /*------------------------------------------------------ + | If the destiation is within a follow nodes polygon, + | set destination as the nearest node. + ------------------------------------------------------*/ + if (!igPath) { + DestPath = InPolygon(targetX, targetY, PATH); + if (PolySubtype(DestPath) == NODE) { + // Find the nearest point on a line, or nearest node + FindBestPoint(DestPath, &targetX, &targetY, &pActor->Tline); + } + } + + assert(pActor->bIgPath || InPolygon(targetX, targetY, PATH) != NOPOLY); // Error 5005 + SetMoverUltDest(pActor, targetX, targetY); + SetMoverIntDest(pActor, targetX, targetY); + + /*------------------------------------------------------------------- + | If in a follow nodes path, need to set off in the right direction! | + -------------------------------------------------------------------*/ + if ((StartPath = pActor->hFnpath) != NOPOLY && !igPath) { + SetOffWithinNodePath(pActor, StartPath, DestPath, targetX, targetY); + } else { + // Set off! + SetNextDest(pActor); + } +} + +/** + * Change scale if appropriate. + */ +static void CheckScale(PMACTOR pActor, HPOLYGON hPath, int ypos) { + int scale; + + scale = GetScale(hPath, ypos); + if (scale != pActor->scale) { + SetMActorWalkReel(pActor, pActor->dirn, scale, false); + } +} + +/** + * Not going anywhere - Kick off again if not at final destination. + */ +static void NotMoving(PMACTOR pActor, int x, int y) { + pActor->targetX = pActor->targetY = -1; + +// if (x == pActor->UtargetX && y == pActor->UtargetY) + if (ABS(x - pActor->UtargetX) < XMDIST && ABS(y - pActor->UtargetY) < YMDIST) { + GotThere(pActor); + return; + } + + if (pActor->ItargetX != -1 || pActor->ItargetY != -1) { + SetNextDest(pActor); + } else if (pActor->UtargetX != -1 || pActor->UtargetY != -1) { + assert(pActor->bIgPath || InPolygon(pActor->UtargetX, pActor->UtargetY, PATH) != NOPOLY); // Error 5006 + SetMoverIntDest(pActor, pActor->UtargetX, pActor->UtargetY); + SetNextDest(pActor); + } +} + +/** + * Does the necessary business when entering a different path polygon. + */ +static void EnteringNewPath(PMACTOR pActor, HPOLYGON hPath, int x, int y) { + int firstnode; // First node to go to + int lastnode; // Last node to go to + HPOLYGON hIpath; + int nx, ny; + int nxl, nyl; + + pActor->hCpath = hPath; // current path + + if (hPath == NOPOLY) { + // Not proved this ever happens, but just in case + pActor->hFnpath = NOPOLY; + pActor->npstatus = NOT_IN; + return; + } + + // Is new path a node path? + if (PolySubtype(hPath) == NODE) { + // Node path - usually go to nearest end node + firstnode = NearestEndNode(hPath, x, y); + lastnode = -1; + + // If this is not the destination path, + // find which end nodfe we wish to leave via + if (hPath != pActor->hUpath) { + if (pActor->bIgPath) { + lastnode = NearestEndNode(hPath, pActor->UtargetX, pActor->UtargetY); + } else { + assert(pActor->hUpath != NOPOLY); // Error 703 + hIpath = getPathOnTheWay(hPath, pActor->hUpath); + assert(hIpath != NOPOLY); // No path on the way + + if (PolySubtype(hIpath) != NODE) { + lastnode = NearestEndNode(hPath, PolyCentreX(hIpath), PolyCentreY(hIpath)); + } else { + lastnode = NearEndNode(hPath, hIpath); + } + } + } + // Test for pseudo-one-node npaths + if (lastnode != -1 && numNodes(hPath) == 2) { + getNpathNode(hPath, firstnode, &nx, &ny); + getNpathNode(hPath, lastnode, &nxl, &nyl); + if (nxl == nx && nyl == ny) + firstnode = lastnode; + } + + // If leaving by same node as entering, don't bother. + if (lastnode == firstnode) { + pActor->hFnpath = NOPOLY; + pActor->npstatus = NOT_IN; + assert(pActor->bIgPath || InPolygon(pActor->UtargetX, pActor->UtargetY, PATH) != NOPOLY); // Error 5007 + SetMoverIntDest(pActor, pActor->UtargetX, pActor->UtargetY); + SetNextDest(pActor); + } else { + // Head for first node + pActor->over = true; + pActor->npstatus = ENTERING; + pActor->hFnpath = hPath; + pActor->line = firstnode ? firstnode - 1 : firstnode; + if (pActor->line == pActor->Tline && hPath == pActor->hUpath) { + assert(pActor->bIgPath || InPolygon(pActor->UtargetX, pActor->UtargetY, PATH) != NOPOLY); // Error 5008 + SetMoverIntDest(pActor, pActor->UtargetX, pActor->UtargetY); + SetMoverDest(pActor, pActor->UtargetX, pActor->UtargetY); + } else { + // This doesn't seem right + getNpathNode(hPath, firstnode, &nx, &ny); + if (ABS(pActor->objx - nx) < XMDIST + && ABS(pActor->objy - ny) < YMDIST) { + pActor->npstatus = ENTERING; + pActor->hFnpath = hPath; + SetNextDest(pActor); + } else { + getNpathNode(hPath, firstnode, &nx, &ny); + SetMoverDest(pActor, nx, ny); + } + } + } + return; + } else { + pActor->hFnpath = NOPOLY; + pActor->npstatus = NOT_IN; + assert(pActor->bIgPath || InPolygon(pActor->UtargetX, pActor->UtargetY, PATH) != NOPOLY); // Error 5009 +// Added 26/01/95 + if (IsPolyCorner(hPath, pActor->ItargetX, pActor->ItargetY)) + return; + + SetMoverIntDest(pActor, pActor->UtargetX, pActor->UtargetY); + SetNextDest(pActor); + } +} + +/** + * Move + */ +void Move(PMACTOR pActor, int newx, int newy, HPOLYGON hPath) { + MultiSetAniXY(pActor->actorObj, newx, newy); + MAsetZPos(pActor, newy, getPolyZfactor(hPath)); + if (StepAnimScript(&pActor->actorAnim) == ScriptFinished) { + // The end of a scale-change reel + // Revert to normal walking reel + pActor->walkReel = false; + pActor->scount = 0; + SetMActorWalkReel(pActor, pActor->dirn, pActor->scale, true); + } + pActor->objx = newx; + pActor->objy = newy; + + // Synchronised walking reels + if (++pActor->scount >= 6) + pActor->scount = 0; +} + +/** + * Called from MActorProcess() on every tick. + * + * Moves the actor as appropriate. + */ +void MoveActor(PMACTOR pActor) { + int newx, newy; + HPOLYGON hPath; + int status, s2; // s2 not used here! + HPOLYGON hS2p; // nor is s2p! + HPOLYGON hEb; + PMACTOR ma; + int sTargetX, sTargetY; + bool bNewPath = false; + + // Only do anything if the actor needs to move! + if (pActor->targetX == -1 && pActor->targetY == -1) + return; + + if (pActor->stop) { + GotThere(pActor); + pActor->stop = false; + SetMActorStanding(pActor); + return; + } + +#if SLOW_RINCE_DOWN +/**/ if (BogusVar++ < Interlude) // Temporary slow-down-the-action code +/**/ return; // +/**/ BogusVar = 0; // +#endif + + // During swalk()s, movement while hidden may be slowed down. + if (pActor->aHidden) { + if (++hSlowVar < pActor->SlowFactor) + return; + hSlowVar = 0; + } + + // 'push' the target + sTargetX = pActor->targetX; + sTargetY = pActor->targetY; + + NewCoOrdinates(pActor->objx, pActor->objy, &pActor->targetX, &pActor->targetY, + &newx, &newy, &status, &s2, &hS2p, pActor->over, false, pActor); + + if (newx == pActor->objx && newy == pActor->objy) { + // 'pop' the target + pActor->targetX = sTargetX; + pActor->targetY = sTargetY; + + NewCoOrdinates(pActor->objx, pActor->objy, &pActor->targetX, &pActor->targetY, &newx, &newy, + &status, &s2, &hS2p, pActor->over, true, pActor); + if (newx == pActor->objx && newy == pActor->objy) { + NotMoving(pActor, newx, newy); + return; + } + } + + // Find out which path we're in now + hPath = InPolygon(newx, newy, PATH); + if (hPath == NOPOLY) { + if (pActor->bNoPath) { + Move(pActor, newx, newy, pActor->hCpath); + return; + } else { + // May be marginally outside! + // OR bIgPath may be set. + hPath = pActor->hCpath; + } + } else if (pActor->bNoPath) { + pActor->bNoPath = false; + bNewPath = true; + } else if (hPath != pActor->hCpath) { + if (IsInPolygon(newx, newy, pActor->hCpath)) + hPath = pActor->hCpath; + } + + CheckScale(pActor, hPath, newy); + + /* + * Must stay out of moving actors' blocking polygons. + */ + ma = InMActorBlock(pActor, newx, newy); + if (ma != NULL) { + // Stop if there's no chance of arriving + if (InMActorBlock(pActor, pActor->UtargetX, pActor->UtargetY)) { + GotThere(pActor); + return; + } + + if (InMActorBlock(pActor, pActor->objx, pActor->objy)) + ; + else { + hEb = InitExtraBlock(pActor, ma); + newx = pActor->objx; + newy = pActor->objy; + BlockingCorner(hEb, &newx, &newy, pActor->ItargetX, pActor->ItargetY); + SetMoverDest(pActor, newx, newy); + return; + } + } + + /*-------------------------------------- + This is where it actually gets moved. + --------------------------------------*/ + Move(pActor, newx, newy, hPath); + + // Entering a new path polygon? + if (hPath != pActor->hCpath || bNewPath) + EnteringNewPath(pActor, hPath, newx, newy); +} + +/** + * Store the default refer type for the current scene. + */ +void SetDefaultRefer(int32 defRefer) { + DefaultRefer = defRefer; +} + +/** + * DoMoveActor + */ +void DoMoveActor(PMACTOR pActor) { + int wasx, wasy; + int i; + +#define NUMBER 1 + + wasx = pActor->objx; + wasy = pActor->objy; + + MoveActor(pActor); + + if ((pActor->targetX != -1 || pActor->targetY != -1) + && (wasx == pActor->objx && wasy == pActor->objy)) { + for (i=0; i < NUMBER; i++) { + MoveActor(pActor); + if (wasx != pActor->objx || wasy != pActor->objy) + break; + } +// assert(i<NUMBER); + } +} + +} // end of namespace Tinsel |