mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-20 16:59:06 +00:00
1619 lines
44 KiB
C++
1619 lines
44 KiB
C++
|
/* 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
|