Remove zones and gateway routing. Also remove optimization of path steps by
line of sight raycasting. This removes two whole classes of path-finding bugs at the cost of some performance. Hopefully we can address performance later. git-svn-id: svn+ssh://svn.gna.org/svn/warzone/trunk@4637 4a71c877-e1ca-e34f-864e-861f7616d084master
parent
5de54b2936
commit
ed5ffbfa8b
|
@ -20,7 +20,7 @@ noinst_HEADERS = action.h advvis.h ai.h aiexperience.h anim_id.h \
|
|||
displaydef.h drive.h droid.h droiddef.h e3demo.h edit3d.h effects.h \
|
||||
environ.h feature.h featuredef.h formation.h formationdef.h fpath.h \
|
||||
frend.h frontend.h function.h functiondef.h game.h gateway.h \
|
||||
gatewaydef.h gatewayroute.h geometry.h group.h hci.h ingameop.h init.h intdisplay.h \
|
||||
gatewaydef.h geometry.h group.h hci.h ingameop.h init.h intdisplay.h \
|
||||
intelmap.h intfac.h intimage.h intorder.h keybind.h keyedit.h keymap.h levelint.h \
|
||||
levels.h lighting.h loadsave.h loop.h map.h mapdisplay.h mapgrid.h mechanics.h \
|
||||
message.h messagedef.h miscimd.h mission.h missiondef.h move.h movedef.h \
|
||||
|
@ -37,7 +37,7 @@ warzone2100_SOURCES = scriptvals_parser.tab.c scriptvals_lexer.lex.c \
|
|||
cheat.c cluster.c cmddroid.c combat.c component.c console.c \
|
||||
data.c design.c difficulty.c display.c droid.c e3demo.c \
|
||||
edit3d.c effects.c environ.c fpath.c feature.c formation.c frontend.c \
|
||||
gateway.c gatewayroute.c geometry.c group.c hci.c init.c \
|
||||
gateway.c geometry.c group.c hci.c init.c \
|
||||
intdisplay.c intimage.c intorder.c intelmap.c keybind.c keymap.c levels.c lighting.c \
|
||||
loop.c main.c map.c mapdisplay.c mapgrid.c mechanics.c message.c miscimd.c \
|
||||
move.c multiint.c multimenu.c multiopt.c multisync.c multibot.c multistat.c \
|
||||
|
|
|
@ -28,7 +28,6 @@ SRC=ai.c \
|
|||
formation.c \
|
||||
frontend.c \
|
||||
gateway.c \
|
||||
gatewayroute.c \
|
||||
geometry.c \
|
||||
group.c \
|
||||
hci.c \
|
||||
|
|
38
src/astar.c
38
src/astar.c
|
@ -378,41 +378,6 @@ BOOL fpathTileLOS(SDWORD x1,SDWORD y1, SDWORD x2,SDWORD y2)
|
|||
return !obstruction;
|
||||
}
|
||||
|
||||
// Optimise the route
|
||||
static void fpathOptimise(FP_NODE *psRoute)
|
||||
{
|
||||
FP_NODE *psCurr, *psSearch, *psTest;
|
||||
BOOL los;
|
||||
|
||||
ASSERT( psRoute != NULL,
|
||||
"fpathOptimise: NULL route pointer" );
|
||||
|
||||
psCurr = psRoute;
|
||||
do
|
||||
{
|
||||
// work down the route looking for a failed LOS
|
||||
los = true;
|
||||
psSearch = psCurr->psRoute;
|
||||
while (psSearch)
|
||||
{
|
||||
psTest = psSearch->psRoute;
|
||||
if (psTest)
|
||||
{
|
||||
los = fpathTileLOS(psCurr->x,psCurr->y, psTest->x,psTest->y);
|
||||
}
|
||||
if (!los)
|
||||
{
|
||||
break;
|
||||
}
|
||||
psSearch = psTest;
|
||||
}
|
||||
|
||||
// store the previous successful point
|
||||
psCurr->psRoute = psSearch;
|
||||
psCurr = psSearch;
|
||||
} while (psCurr);
|
||||
}
|
||||
|
||||
// A* findpath
|
||||
SDWORD fpathAStarRoute(SDWORD routeMode, ASTAR_ROUTE *psRoutePoints,
|
||||
SDWORD sx, SDWORD sy, SDWORD fx, SDWORD fy)
|
||||
|
@ -579,11 +544,8 @@ static FP_NODE *psNearest, *psRoute;
|
|||
retval = ASR_NEAREST;
|
||||
}
|
||||
|
||||
// optimise the route if one was found
|
||||
if (psRoute)
|
||||
{
|
||||
fpathOptimise(psRoute);
|
||||
|
||||
// get the route in the correct order
|
||||
// If as I suspect this is to reverse the list, then it's my suspicion that
|
||||
// we could route from destination to source as opposed to source to
|
||||
|
|
|
@ -70,7 +70,6 @@
|
|||
#include "target.h"
|
||||
#include "drive.h"
|
||||
#include "cmddroid.h"
|
||||
#include "gateway.h"
|
||||
#include "selection.h"
|
||||
#include "transporter.h"
|
||||
#include "intorder.h"
|
||||
|
@ -2203,9 +2202,8 @@ void dealWithLMB( void )
|
|||
if(godMode && (mouseTileX >= 0) && (mouseTileX < (SDWORD)mapWidth) &&
|
||||
(mouseTileY >= 0) && (mouseTileY < (SDWORD)mapHeight))
|
||||
{
|
||||
DBCONPRINTF(ConsoleString,(ConsoleString,"Tile Coords : %d,%d (%d,%d) Zone :%d", mouseTileX,mouseTileY,
|
||||
mouseTileX*TILE_UNITS + TILE_UNITS/2, mouseTileY*TILE_UNITS + TILE_UNITS/2,
|
||||
gwGetZone(mouseTileX, mouseTileY)));
|
||||
DBCONPRINTF(ConsoleString,(ConsoleString,"Tile Coords : %d,%d (%d,%d)", mouseTileX,mouseTileY,
|
||||
mouseTileX*TILE_UNITS + TILE_UNITS/2, mouseTileY*TILE_UNITS + TILE_UNITS/2));
|
||||
}
|
||||
|
||||
//addConsoleMessage("Droid ordered to new location",DEFAULT_JUSTIFY,SYSTEM_MESSAGE);
|
||||
|
|
|
@ -57,7 +57,6 @@
|
|||
#include "component.h"
|
||||
#include "function.h"
|
||||
#include "lighting.h"
|
||||
#include "gateway.h"
|
||||
#include "multiplay.h"
|
||||
#include "formationdef.h"
|
||||
#include "formation.h"
|
||||
|
@ -4156,7 +4155,7 @@ BOOL normalPAT(UDWORD x, UDWORD y)
|
|||
// Should stop things being placed in inaccessible areas?
|
||||
BOOL zonedPAT(UDWORD x, UDWORD y)
|
||||
{
|
||||
if(sensiblePlace(x,y) && noDroid(x,y) && gwZoneReachable(gwGetZone(x,y)))
|
||||
if (sensiblePlace(x,y) && noDroid(x,y))
|
||||
{
|
||||
return(true);
|
||||
}
|
||||
|
|
|
@ -52,7 +52,6 @@
|
|||
|
||||
#include "mapgrid.h"
|
||||
#include "display3d.h"
|
||||
#include "gateway.h"
|
||||
|
||||
|
||||
/* The statistics for the features */
|
||||
|
@ -278,13 +277,6 @@ FEATURE * buildFeature(FEATURE_STATS *psStats, UDWORD x, UDWORD y,BOOL FromSave)
|
|||
//return the average of max/min height
|
||||
height = (foundationMin + foundationMax) / 2;
|
||||
|
||||
// check you can reach an oil resource
|
||||
if ((psStats->subType == FEAT_OIL_RESOURCE) &&
|
||||
!gwZoneReachable(gwGetZone(startX,startY)))
|
||||
{
|
||||
debug( LOG_NEVER, "Oil resource at (%d,%d) is unreachable", startX, startY );
|
||||
}
|
||||
|
||||
if(FromSave == true) {
|
||||
psFeature->pos.x = (UWORD)x;
|
||||
psFeature->pos.y = (UWORD)y;
|
||||
|
|
477
src/fpath.c
477
src/fpath.c
|
@ -34,8 +34,6 @@
|
|||
#include "order.h"
|
||||
|
||||
#include "astar.h"
|
||||
#include "gateway.h"
|
||||
#include "gatewayroute.h"
|
||||
#include "action.h"
|
||||
#include "formation.h"
|
||||
|
||||
|
@ -338,7 +336,6 @@ void fpathSetDirectRoute( BASE_OBJECT *psObj, SDWORD targetX, SDWORD targetY )
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// append an astar route onto a move-control route
|
||||
static void fpathAppendRoute( MOVE_CONTROL *psMoveCntl, ASTAR_ROUTE *psAStarRoute )
|
||||
{
|
||||
|
@ -360,264 +357,6 @@ static void fpathAppendRoute( MOVE_CONTROL *psMoveCntl, ASTAR_ROUTE *psAStarRout
|
|||
psMoveCntl->DestinationY = world_coord(psAStarRoute->finalY) + TILE_UNITS/2;
|
||||
}
|
||||
|
||||
|
||||
// check whether a WORLD coordinate point is within a gateway's tiles
|
||||
static BOOL fpathPointInGateway(SDWORD x, SDWORD y, GATEWAY *psGate)
|
||||
{
|
||||
x = map_coord(x);
|
||||
y = map_coord(y);
|
||||
|
||||
if ((x >= psGate->x1) && (x <= psGate->x2) &&
|
||||
(y >= psGate->y1) && (y <= psGate->y2))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// set blocking flags for all gateways around a zone
|
||||
static void fpathSetGatewayBlock(SDWORD zone, GATEWAY *psLast, GATEWAY *psNext)
|
||||
{
|
||||
GATEWAY *psCurr;
|
||||
SDWORD pos, tx,ty, blockZone;
|
||||
MAPTILE *psTile;
|
||||
|
||||
for(psCurr=psGateways; psCurr; psCurr=psCurr->psNext)
|
||||
{
|
||||
if ((psCurr != psLast) &&
|
||||
(psCurr != psNext) &&
|
||||
!(psCurr->flags & GWR_WATERLINK) &&
|
||||
((psCurr->zone1 == zone) || (psCurr->zone2 == zone)) )
|
||||
{
|
||||
if (psCurr->x1 == psCurr->x2)
|
||||
{
|
||||
for(pos = psCurr->y1; pos <= psCurr->y2; pos += 1)
|
||||
{
|
||||
psTile = mapTile(psCurr->x1, pos);
|
||||
psTile->tileInfoBits |= BITS_FPATHBLOCK;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(pos = psCurr->x1; pos <= psCurr->x2; pos += 1)
|
||||
{
|
||||
psTile = mapTile(pos, psCurr->y1);
|
||||
psTile->tileInfoBits |= BITS_FPATHBLOCK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now set the blocking flags next to the two gateways that the route
|
||||
// is going through
|
||||
if (psLast != NULL)
|
||||
{
|
||||
blockZone = (psLast->flags & GWR_ZONE1) ? psLast->zone1 : psLast->zone2;
|
||||
debug(LOG_GATEWAY, "blocking zone 1: %d", (int)blockZone);
|
||||
for(tx = psLast->x1 - 1; tx <= psLast->x2 + 1; tx ++)
|
||||
{
|
||||
for(ty = psLast->y1 - 1; ty <= psLast->y2 + 1; ty ++)
|
||||
{
|
||||
if (!fpathPointInGateway(world_coord(tx), world_coord(ty), psLast) &&
|
||||
tileOnMap(tx,ty) && gwGetZone(tx,ty) == blockZone)
|
||||
{
|
||||
psTile = mapTile(tx, ty);
|
||||
psTile->tileInfoBits |= BITS_FPATHBLOCK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (psNext != NULL)
|
||||
{
|
||||
blockZone = (psNext->flags & GWR_ZONE1) ? psNext->zone2 : psNext->zone1;
|
||||
debug(LOG_GATEWAY, "blocking zone 2: %d", (int)blockZone);
|
||||
for(tx = psNext->x1 - 1; tx <= psNext->x2 + 1; tx ++)
|
||||
{
|
||||
for(ty = psNext->y1 - 1; ty <= psNext->y2 + 1; ty ++)
|
||||
{
|
||||
if (!fpathPointInGateway(world_coord(tx), world_coord(ty), psNext) &&
|
||||
tileOnMap(tx,ty) && gwGetZone(tx,ty) == blockZone)
|
||||
{
|
||||
psTile = mapTile(tx, ty);
|
||||
psTile->tileInfoBits |= BITS_FPATHBLOCK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// clear blocking flags for all gateways around a zone
|
||||
static void fpathClearGatewayBlock(SDWORD zone, GATEWAY *psLast, GATEWAY *psNext)
|
||||
{
|
||||
GATEWAY *psCurr;
|
||||
SDWORD pos, tx,ty, blockZone;
|
||||
MAPTILE *psTile;
|
||||
|
||||
for(psCurr=psGateways; psCurr; psCurr=psCurr->psNext)
|
||||
{
|
||||
if (!(psCurr->flags & GWR_WATERLINK) &&
|
||||
((psCurr->zone1 == zone) || (psCurr->zone2 == zone)) )
|
||||
{
|
||||
if (psCurr->x1 == psCurr->x2)
|
||||
{
|
||||
for(pos = psCurr->y1; pos <= psCurr->y2; pos += 1)
|
||||
{
|
||||
psTile = mapTile(psCurr->x1, pos);
|
||||
psTile->tileInfoBits &= ~BITS_FPATHBLOCK;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(pos = psCurr->x1; pos <= psCurr->x2; pos += 1)
|
||||
{
|
||||
psTile = mapTile(pos, psCurr->y1);
|
||||
psTile->tileInfoBits &= ~BITS_FPATHBLOCK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// clear the flags around the route gateways
|
||||
if (psLast != NULL)
|
||||
{
|
||||
blockZone = (psLast->flags & GWR_ZONE1) ? psLast->zone1 : psLast->zone2;
|
||||
for(tx = psLast->x1 - 1; tx <= psLast->x2 + 1; tx ++)
|
||||
{
|
||||
for(ty = psLast->y1 - 1; ty <= psLast->y2 + 1; ty ++)
|
||||
{
|
||||
if (!fpathPointInGateway(world_coord(tx), world_coord(ty), psLast) &&
|
||||
tileOnMap(tx,ty) && gwGetZone(tx,ty) == blockZone)
|
||||
{
|
||||
psTile = mapTile(tx, ty);
|
||||
psTile->tileInfoBits &= ~BITS_FPATHBLOCK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (psNext != NULL)
|
||||
{
|
||||
blockZone = (psNext->flags & GWR_ZONE1) ? psNext->zone2 : psNext->zone1;
|
||||
for(tx = psNext->x1 - 1; tx <= psNext->x2 + 1; tx ++)
|
||||
{
|
||||
for(ty = psNext->y1 - 1; ty <= psNext->y2 + 1; ty ++)
|
||||
{
|
||||
if (!fpathPointInGateway(world_coord(tx), world_coord(ty), psNext) &&
|
||||
tileOnMap(tx,ty) && gwGetZone(tx,ty) == blockZone)
|
||||
{
|
||||
psTile = mapTile(tx, ty);
|
||||
psTile->tileInfoBits &= ~BITS_FPATHBLOCK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// clear the routing ignore flags for the gateways
|
||||
static void fpathClearIgnore(void)
|
||||
{
|
||||
GATEWAY *psCurr;
|
||||
SDWORD link, numLinks;
|
||||
|
||||
for(psCurr=psGateways; psCurr; psCurr=psCurr->psNext)
|
||||
{
|
||||
psCurr->flags &= ~GWR_IGNORE;
|
||||
numLinks = psCurr->zone1Links + psCurr->zone2Links;
|
||||
for (link = 0; link < numLinks; link += 1)
|
||||
{
|
||||
psCurr->psLinks[link].flags &= ~ GWRL_BLOCKED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// find a clear tile on a gateway to route to
|
||||
static void fpathGatewayCoords(GATEWAY *psGate, SDWORD *px, SDWORD *py)
|
||||
{
|
||||
SDWORD x = 0, y = 0, dist, mx, my, pos;
|
||||
|
||||
// find the clear tile nearest to the middle
|
||||
mx = (psGate->x1 + psGate->x2)/2;
|
||||
my = (psGate->y1 + psGate->y2)/2;
|
||||
dist = SDWORD_MAX;
|
||||
if (psGate->x1 == psGate->x2)
|
||||
{
|
||||
for(pos=psGate->y1;pos <= psGate->y2; pos+=1)
|
||||
{
|
||||
if (!fpathBlockingTile(psGate->x1,pos) &&
|
||||
(abs(pos - my) < dist))
|
||||
{
|
||||
x = psGate->x1;
|
||||
y = pos;
|
||||
dist = abs(pos - my);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(pos=psGate->x1;pos <= psGate->x2; pos+=1)
|
||||
{
|
||||
if (!fpathBlockingTile(pos, psGate->y1) &&
|
||||
(abs(pos - mx) < dist))
|
||||
{
|
||||
x = pos;
|
||||
y = psGate->y1;
|
||||
dist = abs(pos - mx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if no clear tile is found just return the middle
|
||||
if (dist == SDWORD_MAX)
|
||||
{
|
||||
x = mx;
|
||||
y = my;
|
||||
}
|
||||
|
||||
*px = (x * TILE_UNITS) + TILE_UNITS/2;
|
||||
*py = (y * TILE_UNITS) + TILE_UNITS/2;
|
||||
}
|
||||
|
||||
static void fpathBlockGatewayLink(GATEWAY *psLast, GATEWAY *psCurr)
|
||||
{
|
||||
SDWORD link, numLinks;
|
||||
|
||||
if ((psLast == NULL) && (psCurr != NULL))
|
||||
{
|
||||
debug(LOG_GATEWAY, "fpathBlockGatewayLink: Blocking first gateway");
|
||||
psCurr->flags |= GWR_IGNORE;
|
||||
}
|
||||
else if ((psCurr == NULL) && (psLast != NULL))
|
||||
{
|
||||
debug(LOG_GATEWAY, "fpathBlockGatewayLink: Blocking last gateway");
|
||||
psLast->flags |= GWR_IGNORE;
|
||||
}
|
||||
else if ((psLast != NULL) && (psCurr != NULL))
|
||||
{
|
||||
debug(LOG_GATEWAY, "fpathBlockGatewayLink: Blocking link between gateways");
|
||||
numLinks = psLast->zone1Links + psLast->zone2Links;
|
||||
for(link = 0; link < numLinks; link += 1)
|
||||
{
|
||||
if (psLast->psLinks[link].flags & GWRL_CHILD)
|
||||
{
|
||||
debug(LOG_GATEWAY, "fpathBlockGatewayLink: last link %d", (int)link);
|
||||
psLast->psLinks[link].flags |= GWRL_BLOCKED;
|
||||
}
|
||||
}
|
||||
numLinks = psCurr->zone1Links + psCurr->zone2Links;
|
||||
for(link = 0; link < numLinks; link += 1)
|
||||
{
|
||||
if (psCurr->psLinks[link].flags & GWRL_PARENT)
|
||||
{
|
||||
debug( LOG_MOVEMENT, "fpathBlockGatewayLink: curr link %d", (int)link);
|
||||
psCurr->psLinks[link].flags |= GWRL_BLOCKED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// check if a new route is closer to the target than the one stored in
|
||||
// the droid
|
||||
static BOOL fpathRouteCloser(MOVE_CONTROL *psMoveCntl, ASTAR_ROUTE *psAStarRoute, SDWORD tx,SDWORD ty)
|
||||
|
@ -654,21 +393,18 @@ static BOOL fpathRouteCloser(MOVE_CONTROL *psMoveCntl, ASTAR_ROUTE *psAStarRoute
|
|||
}
|
||||
|
||||
// create a final route from a gateway route
|
||||
static FPATH_RETVAL fpathGatewayRoute(BASE_OBJECT *psObj, SDWORD routeMode, SDWORD GWTerrain,
|
||||
static FPATH_RETVAL fpathGatewayRoute(BASE_OBJECT *psObj, SDWORD routeMode, /*SDWORD GWTerrain,*/
|
||||
SDWORD sx, SDWORD sy, SDWORD fx, SDWORD fy,
|
||||
MOVE_CONTROL *psMoveCntl)
|
||||
{
|
||||
static SDWORD linkx, linky, gwx, gwy, asret, matchPoints;
|
||||
static ASTAR_ROUTE sAStarRoute;
|
||||
FPATH_RETVAL retval = FPR_OK;
|
||||
SDWORD gwRet, zone;
|
||||
static GATEWAY *psCurrRoute, *psGWRoute, *psLastGW;
|
||||
BOOL bRouting, bFinished;
|
||||
static BOOL bFirstRoute;
|
||||
|
||||
if (routeMode == ASR_NEWROUTE)
|
||||
{
|
||||
fpathClearIgnore();
|
||||
// initialise the move control structures
|
||||
psMoveCntl->numPoints = 0;
|
||||
sAStarRoute.numPoints = 0;
|
||||
|
@ -681,51 +417,6 @@ static FPATH_RETVAL fpathGatewayRoute(BASE_OBJECT *psObj, SDWORD routeMode, SDWO
|
|||
{
|
||||
if (routeMode == ASR_NEWROUTE)
|
||||
{
|
||||
objTrace(LOG_MOVEMENT, psObj->id, "fpathGatewayRoute: Gateway route - droid %d", (int)psObj->id);
|
||||
gwRet = gwrAStarRoute(psObj->player, GWTerrain,
|
||||
sx,sy, fx,fy, &psGWRoute);
|
||||
switch (gwRet)
|
||||
{
|
||||
case GWR_OK:
|
||||
break;
|
||||
case GWR_NEAREST:
|
||||
// need to deal with this case for retried routing - only accept this if no previous route?
|
||||
if (!bFirstRoute)
|
||||
{
|
||||
if (psMoveCntl->numPoints > 0)
|
||||
{
|
||||
objTrace(LOG_MOVEMENT, psObj->id, "fpathGatewayRoute: Gateway route nearest - Use previous route");
|
||||
retval = FPR_OK;
|
||||
goto exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
objTrace(LOG_MOVEMENT, psObj->id, "fpathGatewayRoute: Gateway route nearest - No points - failed");
|
||||
retval = FPR_FAILED;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GWR_NOZONE:
|
||||
case GWR_SAMEZONE:
|
||||
// no zone information - try a normal route
|
||||
psGWRoute = NULL;
|
||||
break;
|
||||
case GWR_FAILED:
|
||||
objTrace(LOG_MOVEMENT, psObj->id, "fpathGatewayRoute: Gateway route failed");
|
||||
if ((psObj->type == OBJ_DROID) && vtolDroid((DROID *)psObj))
|
||||
{
|
||||
// just fail for VTOLs - they can set a direct route
|
||||
retval = FPR_FAILED;
|
||||
goto exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
psGWRoute = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// reset matchPoints so that routing between gateways generated
|
||||
// by the previous gateway route can be reused
|
||||
matchPoints = 0;
|
||||
|
@ -735,16 +426,8 @@ static FPATH_RETVAL fpathGatewayRoute(BASE_OBJECT *psObj, SDWORD routeMode, SDWO
|
|||
|
||||
if (routeMode == ASR_NEWROUTE)
|
||||
{
|
||||
// if the start of the route is on the first gateway, skip it
|
||||
if ((psGWRoute != NULL) && fpathPointInGateway(sx,sy, psGWRoute))
|
||||
{
|
||||
psGWRoute = psGWRoute->psRoute;
|
||||
}
|
||||
|
||||
linkx = sx;
|
||||
linky = sy;
|
||||
psCurrRoute = psGWRoute;
|
||||
psLastGW = NULL;
|
||||
}
|
||||
|
||||
// now generate the route
|
||||
|
@ -752,94 +435,67 @@ static FPATH_RETVAL fpathGatewayRoute(BASE_OBJECT *psObj, SDWORD routeMode, SDWO
|
|||
bFinished = false;
|
||||
while (!bFinished)
|
||||
{
|
||||
if ((psCurrRoute == NULL) ||
|
||||
((psCurrRoute->psRoute == NULL) && fpathPointInGateway(fx,fy, psCurrRoute)))
|
||||
{
|
||||
// last stretch on the route is not to a gatway but to
|
||||
// the final route coordinates
|
||||
gwx = fx;
|
||||
gwy = fy;
|
||||
zone = gwGetZone(map_coord(fx), map_coord(fy));
|
||||
}
|
||||
else
|
||||
{
|
||||
fpathGatewayCoords(psCurrRoute, &gwx, &gwy);
|
||||
zone = psCurrRoute->flags & GWR_ZONE1 ? psCurrRoute->zone1 : psCurrRoute->zone2;
|
||||
}
|
||||
gwx = fx;
|
||||
gwy = fy;
|
||||
|
||||
// only route between the gateways if it wasn't done on a previous route
|
||||
objTrace(LOG_MOVEMENT, psObj->id, "fpathGatewayRoute: astar route : (%d,%d) -> (%d,%d)",
|
||||
map_coord(linkx), map_coord(linky),
|
||||
map_coord(gwx), map_coord(gwy));
|
||||
asret = fpathAStarRoute(routeMode, &sAStarRoute, linkx,linky, gwx,gwy);
|
||||
if (asret == ASR_PARTIAL)
|
||||
{
|
||||
objTrace(LOG_MOVEMENT, psObj->id, "fpathGatewayRoute: astar route : (%d,%d) -> (%d,%d) zone %d",
|
||||
map_coord(linkx), map_coord(linky),
|
||||
map_coord(gwx), map_coord(gwy), zone);
|
||||
fpathSetGatewayBlock(zone, psLastGW, psCurrRoute);
|
||||
asret = fpathAStarRoute(routeMode, &sAStarRoute, linkx,linky, gwx,gwy);
|
||||
fpathClearGatewayBlock(zone, psLastGW, psCurrRoute);
|
||||
if (asret == ASR_PARTIAL)
|
||||
{
|
||||
// routing hasn't finished yet
|
||||
objTrace(LOG_MOVEMENT, psObj->id, "fpathGatewayRoute: Reschedule");
|
||||
retval = FPR_WAIT;
|
||||
goto exit;
|
||||
}
|
||||
routeMode = ASR_NEWROUTE;
|
||||
// routing hasn't finished yet
|
||||
objTrace(LOG_MOVEMENT, psObj->id, "fpathGatewayRoute: Reschedule");
|
||||
retval = FPR_WAIT;
|
||||
goto exit;
|
||||
}
|
||||
routeMode = ASR_NEWROUTE;
|
||||
|
||||
if ((asret == ASR_NEAREST) &&
|
||||
actionRouteBlockingPos((DROID *)psObj, sAStarRoute.finalX,sAStarRoute.finalY))
|
||||
if ((asret == ASR_NEAREST) &&
|
||||
actionRouteBlockingPos((DROID *)psObj, sAStarRoute.finalX,sAStarRoute.finalY))
|
||||
{
|
||||
// found a blocking wall - route to that
|
||||
objTrace(LOG_MOVEMENT, psObj->id, "fpathGatewayRoute: Got blocking wall");
|
||||
retval = FPR_OK;
|
||||
goto exit;
|
||||
}
|
||||
else if (asret == ASR_NEAREST)
|
||||
{
|
||||
// all routing was in one zone - this is as good as it's going to be
|
||||
objTrace(LOG_MOVEMENT, psObj->id, "fpathGatewayRoute: Nearest route in same zone");
|
||||
if (fpathRouteCloser(psMoveCntl, &sAStarRoute, fx,fy))
|
||||
{
|
||||
// found a blocking wall - route to that
|
||||
objTrace(LOG_MOVEMENT, psObj->id, "fpathGatewayRoute: Got blocking wall");
|
||||
retval = FPR_OK;
|
||||
goto exit;
|
||||
psMoveCntl->numPoints = 0;
|
||||
fpathAppendRoute(psMoveCntl, &sAStarRoute);
|
||||
}
|
||||
else if ((asret == ASR_NEAREST) && (psGWRoute == NULL))
|
||||
retval = FPR_OK;
|
||||
goto exit;
|
||||
}
|
||||
else if (asret == ASR_FAILED)
|
||||
{
|
||||
// all routing was in one zone - can't retry
|
||||
objTrace(LOG_MOVEMENT, psObj->id, "fpathGatewayRoute: Failed route in same zone");
|
||||
retval = FPR_FAILED;
|
||||
goto exit;
|
||||
}
|
||||
else if ((asret == ASR_FAILED) || (asret == ASR_NEAREST))
|
||||
{
|
||||
// all routing was in one zone - this is as good as it's going to be
|
||||
objTrace(LOG_MOVEMENT, psObj->id, "fpathGatewayRoute: Nearest route in same zone");
|
||||
if (fpathRouteCloser(psMoveCntl, &sAStarRoute, fx,fy))
|
||||
{
|
||||
psMoveCntl->numPoints = 0;
|
||||
fpathAppendRoute(psMoveCntl, &sAStarRoute);
|
||||
}
|
||||
retval = FPR_OK;
|
||||
goto exit;
|
||||
}
|
||||
else if ((asret == ASR_FAILED) && (psGWRoute == NULL))
|
||||
// no route found - try ditching this gateway
|
||||
// and trying a new gateway route
|
||||
objTrace(LOG_MOVEMENT, psObj->id, "fpathGatewayRoute: Route failed");
|
||||
if (fpathRouteCloser(psMoveCntl, &sAStarRoute, fx,fy))
|
||||
{
|
||||
// all routing was in one zone - can't retry
|
||||
objTrace(LOG_MOVEMENT, psObj->id, "fpathGatewayRoute: Failed route in same zone");
|
||||
retval = FPR_FAILED;
|
||||
goto exit;
|
||||
}
|
||||
else if ((asret == ASR_FAILED) ||
|
||||
(asret == ASR_NEAREST))
|
||||
{
|
||||
// no route found - try ditching this gateway
|
||||
// and trying a new gateway route
|
||||
objTrace(LOG_MOVEMENT, psObj->id, "fpathGatewayRoute: Route failed - ignore gateway/link and reroute");
|
||||
if (fpathRouteCloser(psMoveCntl, &sAStarRoute, fx,fy))
|
||||
{
|
||||
psMoveCntl->numPoints = 0;
|
||||
fpathAppendRoute(psMoveCntl, &sAStarRoute);
|
||||
}
|
||||
fpathBlockGatewayLink(psLastGW, psCurrRoute);
|
||||
bRouting = true;
|
||||
break;
|
||||
psMoveCntl->numPoints = 0;
|
||||
fpathAppendRoute(psMoveCntl, &sAStarRoute);
|
||||
}
|
||||
//bRouting = true;
|
||||
break;
|
||||
}
|
||||
|
||||
linkx = gwx;
|
||||
linky = gwy;
|
||||
|
||||
psLastGW = psCurrRoute;
|
||||
if (psCurrRoute != NULL)
|
||||
{
|
||||
psCurrRoute = psCurrRoute->psRoute;
|
||||
}
|
||||
else
|
||||
{
|
||||
bFinished = true;
|
||||
}
|
||||
bFinished = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -850,15 +506,11 @@ static FPATH_RETVAL fpathGatewayRoute(BASE_OBJECT *psObj, SDWORD routeMode, SDWO
|
|||
}
|
||||
|
||||
exit:
|
||||
// reset the routing block flags
|
||||
if (retval != FPR_WAIT)
|
||||
{
|
||||
fpathClearIgnore();
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/* set pointer for current fpath object - GJ hack */
|
||||
void fpathSetCurrentObject( BASE_OBJECT *psObj )
|
||||
{
|
||||
|
@ -889,7 +541,6 @@ FPATH_RETVAL fpathRoute(BASE_OBJECT *psObj, MOVE_CONTROL *psMoveCntl,
|
|||
SDWORD dir, nearestDir, minDist, tileDist;
|
||||
FPATH_RETVAL retVal = FPR_OK;
|
||||
PROPULSION_STATS *psPropStats;
|
||||
UDWORD GWTerrain;
|
||||
DROID *psDroid = NULL;
|
||||
|
||||
/* set global pointer for object being routed - GJ hack */
|
||||
|
@ -930,7 +581,7 @@ FPATH_RETVAL fpathRoute(BASE_OBJECT *psObj, MOVE_CONTROL *psMoveCntl,
|
|||
return FPR_FAILED;
|
||||
}
|
||||
|
||||
// set the correct blocking tile function and gateway terrain flag
|
||||
// set the correct blocking tile function
|
||||
if (psObj->type == OBJ_DROID)
|
||||
{
|
||||
psDroid = (DROID *)psObj;
|
||||
|
@ -939,26 +590,6 @@ FPATH_RETVAL fpathRoute(BASE_OBJECT *psObj, MOVE_CONTROL *psMoveCntl,
|
|||
ASSERT(psPropStats != NULL, "fpathRoute: invalid propulsion stats pointer");
|
||||
|
||||
fpathSetBlockingTile( psPropStats->propulsionType );
|
||||
|
||||
/* set gateway terrain flag */
|
||||
switch ( psPropStats->propulsionType )
|
||||
{
|
||||
case HOVER:
|
||||
GWTerrain = GWR_TER_ALL;
|
||||
break;
|
||||
|
||||
case LIFT:
|
||||
GWTerrain = GWR_TER_ALL;
|
||||
break;
|
||||
|
||||
default:
|
||||
GWTerrain = GWR_TER_LAND;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GWTerrain = GWR_TER_LAND;
|
||||
}
|
||||
|
||||
if (psPartialRouteObj == NULL || psPartialRouteObj != psObj)
|
||||
|
@ -1094,15 +725,13 @@ FPATH_RETVAL fpathRoute(BASE_OBJECT *psObj, MOVE_CONTROL *psMoveCntl,
|
|||
// Now actually create a route
|
||||
if (psPartialRouteObj == NULL)
|
||||
{
|
||||
retVal = fpathGatewayRoute(psObj, ASR_NEWROUTE, GWTerrain,
|
||||
startX,startY, targetX,targetY, psMoveCntl);
|
||||
retVal = fpathGatewayRoute(psObj, ASR_NEWROUTE, startX,startY, targetX,targetY, psMoveCntl);
|
||||
}
|
||||
else
|
||||
{
|
||||
objTrace(LOG_MOVEMENT, psObj->id, "Partial Route");
|
||||
psPartialRouteObj = NULL;
|
||||
retVal = fpathGatewayRoute(psObj, ASR_CONTINUE, GWTerrain,
|
||||
startX,startY, targetX,targetY, psMoveCntl);
|
||||
retVal = fpathGatewayRoute(psObj, ASR_CONTINUE, startX,startY, targetX,targetY, psMoveCntl);
|
||||
}
|
||||
if (retVal == FPR_WAIT)
|
||||
{
|
||||
|
|
883
src/gateway.c
883
src/gateway.c
|
@ -37,20 +37,35 @@
|
|||
// the list of gateways on the current map
|
||||
GATEWAY *psGateways;
|
||||
|
||||
// the RLE map zones for each tile
|
||||
UBYTE **apRLEZones;
|
||||
/******************************************************************************************************/
|
||||
/* Gateway data access functions */
|
||||
|
||||
// the number of map zones
|
||||
SDWORD gwNumZones;
|
||||
// get the size of the map
|
||||
static SDWORD gwMapWidth(void)
|
||||
{
|
||||
return (SDWORD)mapWidth;
|
||||
}
|
||||
|
||||
// The zone equivalence tables - shows which land zones
|
||||
// border on a water zone
|
||||
UBYTE *aNumEquiv;
|
||||
UBYTE **apEquivZones;
|
||||
static SDWORD gwMapHeight(void)
|
||||
{
|
||||
return (SDWORD)mapHeight;
|
||||
}
|
||||
|
||||
// note which zones have a gateway to them and can therefore be reached
|
||||
UBYTE *aZoneReachable;
|
||||
// set the gateway flag on a tile
|
||||
static void gwSetGatewayFlag(SDWORD x, SDWORD y)
|
||||
{
|
||||
mapTile((UDWORD)x,(UDWORD)y)->tileInfoBits |= BITS_GATEWAY;
|
||||
}
|
||||
|
||||
// clear the gateway flag on a tile
|
||||
static void gwClearGatewayFlag(SDWORD x, SDWORD y)
|
||||
{
|
||||
mapTile((UDWORD)x,(UDWORD)y)->tileInfoBits &= ~BITS_GATEWAY;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************************************/
|
||||
/* Gateway functions */
|
||||
|
||||
// Initialise the gateway system
|
||||
BOOL gwInitialise(void)
|
||||
|
@ -74,15 +89,6 @@ void gwShutDown(void)
|
|||
gwFreeGateway(psGateways);
|
||||
psGateways = psNext;
|
||||
}
|
||||
|
||||
gwFreeZoneMap();
|
||||
gwFreeEquivTable();
|
||||
|
||||
if (aZoneReachable != NULL)
|
||||
{
|
||||
free(aZoneReachable);
|
||||
aZoneReachable = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -162,251 +168,6 @@ BOOL gwNewGateway(SDWORD x1, SDWORD y1, SDWORD x2, SDWORD y2)
|
|||
}
|
||||
|
||||
|
||||
// Add a land/water link gateway to the system
|
||||
BOOL gwNewLinkGateway(SDWORD x, SDWORD y)
|
||||
{
|
||||
GATEWAY *psNew;
|
||||
|
||||
if ((x < 0) || (x >= gwMapWidth()) ||
|
||||
(y < 0) || (y >= gwMapHeight()))
|
||||
{
|
||||
ASSERT( false,"gwNewLinkGateway: invalid coordinates" );
|
||||
return false;
|
||||
}
|
||||
|
||||
psNew = (GATEWAY*)malloc(sizeof(GATEWAY));
|
||||
if (!psNew)
|
||||
{
|
||||
debug( LOG_ERROR, "gwNewGateway: out of memory" );
|
||||
abort();
|
||||
return false;
|
||||
}
|
||||
|
||||
// initialise the gateway
|
||||
psNew->x1 = (UBYTE)x;
|
||||
psNew->y1 = (UBYTE)y;
|
||||
psNew->x2 = (UBYTE)x;
|
||||
psNew->y2 = (UBYTE)y;
|
||||
psNew->zone1 = 0;
|
||||
psNew->zone2 = 0;
|
||||
psNew->psLinks = NULL;
|
||||
psNew->flags = GWR_WATERLINK;
|
||||
|
||||
// add the gateway to the list
|
||||
psNew->psNext = psGateways;
|
||||
psGateways = psNew;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static BOOL gwBlockingTile(SDWORD x,SDWORD y)
|
||||
{
|
||||
MAPTILE *psTile;
|
||||
|
||||
if (x <1 || y < 1 || x >= (SDWORD)mapWidth-1 || y >= (SDWORD)mapHeight-1)
|
||||
{
|
||||
// coords off map - auto blocking tile
|
||||
return true;
|
||||
}
|
||||
|
||||
psTile = mapTile((UDWORD)x, (UDWORD)y);
|
||||
if (terrainType(psTile) == TER_CLIFFFACE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// scan for a particular zone on the map
|
||||
// given a start point
|
||||
static BOOL gwFindZone(SDWORD zone, SDWORD cx, SDWORD cy,
|
||||
SDWORD *px, SDWORD *py)
|
||||
{
|
||||
SDWORD x,y, dist, maxDist;
|
||||
|
||||
maxDist = gwMapWidth() > gwMapHeight() ? gwMapWidth() : gwMapHeight();
|
||||
|
||||
for(dist = 0; dist < maxDist; dist += 1)
|
||||
{
|
||||
// scan accross the top
|
||||
y = cy - dist;
|
||||
for(x = cx - dist; x <= cx + dist; x += 1)
|
||||
{
|
||||
if (x >= 0 && x < gwMapWidth() &&
|
||||
y >= 0 && y < gwMapHeight() &&
|
||||
gwGetZone(x,y) == zone)
|
||||
{
|
||||
*px = x;
|
||||
*py = y;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// scan down the left
|
||||
x = cx - dist;
|
||||
for(y = cy - dist; y <= cy + dist; y += 1)
|
||||
{
|
||||
if (x >= 0 && x < gwMapWidth() &&
|
||||
y >= 0 && y < gwMapHeight() &&
|
||||
gwGetZone(x,y) == zone)
|
||||
{
|
||||
*px = x;
|
||||
*py = y;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// scan down the right
|
||||
x = cx + dist;
|
||||
for(y = cy - dist; y <= cy + dist; y += 1)
|
||||
{
|
||||
if (x >= 0 && x < gwMapWidth() &&
|
||||
y >= 0 && y < gwMapHeight() &&
|
||||
gwGetZone(x,y) == zone)
|
||||
{
|
||||
*px = x;
|
||||
*py = y;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// scan accross the bottom
|
||||
y = cy + dist;
|
||||
for(x = cx - dist; x <= cx + dist; x += 1)
|
||||
{
|
||||
if (x >= 0 && x < gwMapWidth() &&
|
||||
y >= 0 && y < gwMapHeight() &&
|
||||
gwGetZone(x,y) == zone)
|
||||
{
|
||||
*px = x;
|
||||
*py = y;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// find a rough center position for a zone
|
||||
static void gwCalcZoneCenter(SDWORD zone, SDWORD *px, SDWORD *py)
|
||||
{
|
||||
SDWORD xsum,ysum, numtiles;
|
||||
SDWORD x,y;
|
||||
|
||||
xsum = ysum = numtiles = 0;
|
||||
for(y=0; y<gwMapHeight(); y+= 1)
|
||||
{
|
||||
for(x=0; x<gwMapWidth(); x+= 1)
|
||||
{
|
||||
if (gwGetZone(x,y) == zone)
|
||||
{
|
||||
xsum += x;
|
||||
ysum += y;
|
||||
numtiles += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT( numtiles != 0,
|
||||
"gwCalcZoneCenter: zone not found on map" );
|
||||
|
||||
x = xsum / numtiles;
|
||||
y = ysum / numtiles;
|
||||
|
||||
if (!gwFindZone(zone, x,y, px,py))
|
||||
{
|
||||
*px = x;
|
||||
*py = y;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// check all the zones are of reasonable sizes
|
||||
void gwCheckZoneSizes(void)
|
||||
{
|
||||
SDWORD zone, xsum,ysum, numtiles, inzone;
|
||||
SDWORD x,y, cx,cy;
|
||||
|
||||
for(zone=1; zone < UBYTE_MAX; zone += 1)
|
||||
{
|
||||
xsum = ysum = numtiles = inzone = 0;
|
||||
for(y=0; y<gwMapHeight(); y+= 1)
|
||||
{
|
||||
for(x=0; x<gwMapWidth(); x+= 1)
|
||||
{
|
||||
if (gwGetZone(x,y) == zone)
|
||||
{
|
||||
xsum += x;
|
||||
ysum += y;
|
||||
numtiles += 1;
|
||||
if (!gwBlockingTile(x,y))
|
||||
{
|
||||
inzone += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (numtiles > 0)
|
||||
{
|
||||
x = xsum / numtiles;
|
||||
y = ysum / numtiles;
|
||||
|
||||
if (!gwFindZone(zone, x,y, &cx,&cy))
|
||||
{
|
||||
cx = x;
|
||||
cy = y;
|
||||
}
|
||||
|
||||
if (inzone > FPATH_LOOP_LIMIT)
|
||||
{
|
||||
debug(LOG_GATEWAY, "gwCheckZoneSizes: warning zone %d at (%d,%d) is too large %d tiles (max %d)",
|
||||
zone, cx, cy, inzone, FPATH_LOOP_LIMIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// add the land/water link gateways
|
||||
BOOL gwGenerateLinkGates(void)
|
||||
{
|
||||
SDWORD zone, cx,cy;
|
||||
|
||||
ASSERT( apEquivZones != NULL,
|
||||
"gwGenerateLinkGates: no zone equivalence table" );
|
||||
|
||||
debug( LOG_NEVER, "Generating water link Gateways...." );
|
||||
|
||||
for(zone=1; zone<gwNumZones; zone += 1)
|
||||
{
|
||||
|
||||
if (aNumEquiv[zone] > 0)
|
||||
{
|
||||
LOADBARCALLBACK(); // loadingScreenCallback();
|
||||
|
||||
// got a water zone that borders on land
|
||||
// find it's center
|
||||
gwCalcZoneCenter(zone, &cx,&cy);
|
||||
if (!gwNewLinkGateway(cx,cy))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
debug(LOG_GATEWAY, "new water link gateway at (%d,%d) for zone %d", cx, cy, zone);
|
||||
}
|
||||
}
|
||||
|
||||
debug( LOG_NEVER, "Done\n" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Return the number of gateways.
|
||||
UDWORD gwNumGateways(void)
|
||||
{
|
||||
|
@ -495,597 +256,3 @@ BOOL gwLoadGateways(char *pFileBuffer, UDWORD fileSize)
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// check if a zone is in the equivalence table for a water zone
|
||||
BOOL gwZoneInEquiv(SDWORD mainZone, SDWORD checkZone)
|
||||
{
|
||||
SDWORD i;
|
||||
|
||||
if (apEquivZones == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for(i=0; i<aNumEquiv[mainZone]; i+= 1)
|
||||
{
|
||||
if (apEquivZones[mainZone][i] == checkZone)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// find a route between two gateways and return
|
||||
// its length
|
||||
static SDWORD gwRouteLength(GATEWAY *psStart, GATEWAY *psEnd)
|
||||
{
|
||||
SDWORD ret, sx,sy, ex,ey, xdiff,ydiff, i;
|
||||
ASTAR_ROUTE sRoute;
|
||||
SDWORD routeMode, dist;
|
||||
#ifdef DEBUG
|
||||
SDWORD zone;
|
||||
#endif
|
||||
|
||||
fpathBlockingTile = gwBlockingTile;
|
||||
|
||||
sx = (psStart->x1 + psStart->x2)/2;
|
||||
sy = (psStart->y1 + psStart->y2)/2;
|
||||
ex = (psEnd->x1 + psEnd->x2)/2;
|
||||
ey = (psEnd->y1 + psEnd->y2)/2;
|
||||
|
||||
// force the router to finish a route
|
||||
routeMode = ASR_NEWROUTE;
|
||||
sRoute.asPos[0].x = -1;
|
||||
sRoute.asPos[0].y = -1;
|
||||
do
|
||||
{
|
||||
astarResetCounters();
|
||||
sRoute.numPoints = 0;
|
||||
ret = fpathAStarRoute(routeMode, &sRoute,
|
||||
world_coord(sx), world_coord(sy),
|
||||
world_coord(ex), world_coord(ey));
|
||||
if (ret == ASR_PARTIAL)
|
||||
{
|
||||
routeMode = ASR_CONTINUE;
|
||||
}
|
||||
} while (ret == ASR_PARTIAL);
|
||||
|
||||
ASSERT( ret != ASR_FAILED,
|
||||
"gwRouteLength: no route between gateways at (%d,%d) and (%d,%d)",
|
||||
sx,sy, ex,ey );
|
||||
|
||||
#ifdef DEBUG
|
||||
if (ret == ASR_NEAREST)
|
||||
{
|
||||
zone = (psStart->zone1 == psEnd->zone1) || (psStart->zone1 == psEnd->zone2) ? psStart->zone1 : psStart->zone2;
|
||||
debug( LOG_ERROR, "gwRouteLength: warning only partial route between gateways at %s(%d,%d) and %s(%d,%d) zone %d\n", psStart->flags & GWR_WATERLINK ? "W" : "", sx,sy, psStart->flags & GWR_WATERLINK ? "W" : "", ex, ey, zone );
|
||||
}
|
||||
#endif
|
||||
|
||||
// calculate the length of the route
|
||||
dist = 0;
|
||||
for(i=0; i < sRoute.numPoints; i+= 1)
|
||||
{
|
||||
xdiff = sx - sRoute.asPos[i].x;
|
||||
ydiff = sy - sRoute.asPos[i].y;
|
||||
dist += (SDWORD)sqrtf(xdiff*xdiff + ydiff*ydiff);
|
||||
sx = sRoute.asPos[i].x;
|
||||
sy = sRoute.asPos[i].y;
|
||||
}
|
||||
xdiff = sx - ex;
|
||||
ydiff = sy - ey;
|
||||
dist += (SDWORD)sqrtf(xdiff*xdiff + ydiff*ydiff);
|
||||
|
||||
fpathBlockingTile = fpathGroundBlockingTile;
|
||||
|
||||
return dist;
|
||||
}
|
||||
|
||||
|
||||
// check that the initial flood fill tiles are not on a blocking tile
|
||||
static BOOL gwCheckFloodTiles(GATEWAY *psGate)
|
||||
{
|
||||
SDWORD floodX,floodY;
|
||||
|
||||
// first zone is left/above
|
||||
if (psGate->x1 == psGate->x2)
|
||||
{
|
||||
// vertical - go left
|
||||
floodX = psGate->x1 - 1;
|
||||
floodY = (psGate->y2 - psGate->y1)/2 + psGate->y1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// horizontal - go above
|
||||
floodX = (psGate->x2 - psGate->x1)/2 + psGate->x1;
|
||||
floodY = psGate->y1 - 1;
|
||||
}
|
||||
|
||||
if (gwBlockingTile(floodX,floodY))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// second zone is right/below
|
||||
if (psGate->x1 == psGate->x2)
|
||||
{
|
||||
// vertical - go right
|
||||
floodX = psGate->x1 + 1;
|
||||
floodY = (psGate->y2 - psGate->y1)/2 + psGate->y1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// horizontal - go below
|
||||
floodX = (psGate->x2 - psGate->x1)/2 + psGate->x1;
|
||||
floodY = psGate->y1 + 1;
|
||||
}
|
||||
|
||||
if (gwBlockingTile(floodX,floodY))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// link all the gateways together
|
||||
BOOL gwLinkGateways(void)
|
||||
{
|
||||
GATEWAY *psCurr, *psLink;
|
||||
SDWORD x,y, gwX,gwY, zone1Links,zone2Links, link, zone, otherZone;
|
||||
SDWORD zoneLinks;
|
||||
BOOL bZone1, bAddLink;
|
||||
|
||||
|
||||
// note which zones have a gateway
|
||||
aZoneReachable = (UBYTE*)malloc( sizeof(UBYTE) * gwNumZones );
|
||||
if (aZoneReachable == NULL)
|
||||
{
|
||||
debug( LOG_ERROR, "gwLinkGateways: out of memory" );
|
||||
abort();
|
||||
return false;
|
||||
}
|
||||
memset(aZoneReachable, 0, sizeof(UBYTE) * gwNumZones);
|
||||
|
||||
// initialise the zones for the gateways
|
||||
for(psCurr = psGateways; psCurr; psCurr = psCurr->psNext)
|
||||
{
|
||||
// a gateway is always in it's own zone1
|
||||
psCurr->zone1 = (UBYTE)gwGetZone(psCurr->x1,psCurr->y1);
|
||||
|
||||
if (psCurr->flags & GWR_WATERLINK)
|
||||
{
|
||||
// a water link gateway is only in one zone
|
||||
x = psCurr->x1;
|
||||
y = psCurr->y1;
|
||||
}
|
||||
else if (psCurr->x1 == psCurr->x2)
|
||||
{
|
||||
// vertical - go right
|
||||
x = psCurr->x1 + 1;
|
||||
y = (psCurr->y2 - psCurr->y1)/2 + psCurr->y1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// horizontal - go below
|
||||
x = (psCurr->x2 - psCurr->x1)/2 + psCurr->x1;
|
||||
y = psCurr->y1 + 1;
|
||||
}
|
||||
psCurr->zone2 = (UBYTE)gwGetZone(x,y);
|
||||
|
||||
ASSERT( (psCurr->flags & GWR_WATERLINK) || gwCheckFloodTiles(psCurr),
|
||||
"gwLinkGateways: Gateway at (%d,%d)->(%d,%d) is too close to a blocking tile. Zones %d, %d",
|
||||
psCurr->x1,psCurr->y1, psCurr->x2,psCurr->y2,
|
||||
psCurr->zone1, psCurr->zone2 );
|
||||
|
||||
aZoneReachable[psCurr->zone1] = true;
|
||||
aZoneReachable[psCurr->zone2] = true;
|
||||
}
|
||||
|
||||
// now link all the gateways together
|
||||
for(psCurr = psGateways; psCurr; psCurr = psCurr->psNext)
|
||||
{
|
||||
LOADBARCALLBACK(); // loadingScreenCallback();
|
||||
|
||||
gwX = (psCurr->x1 + psCurr->x2)/2;
|
||||
gwY = (psCurr->y1 + psCurr->y2)/2;
|
||||
|
||||
// count the number of links
|
||||
zone1Links = 0;
|
||||
zone2Links = 0;
|
||||
for(psLink=psGateways; psLink; psLink=psLink->psNext)
|
||||
{
|
||||
if (psLink == psCurr)
|
||||
{
|
||||
// don't link a gateway to itself
|
||||
continue;
|
||||
}
|
||||
if ((psLink->zone1 == psCurr->zone1) || (psLink->zone2 == psCurr->zone1) ||
|
||||
((psLink->flags & GWR_WATERLINK) &&
|
||||
gwZoneInEquiv(psLink->zone1, psCurr->zone1) &&
|
||||
!gwZoneInEquiv(psLink->zone1, psCurr->zone2) ))
|
||||
{
|
||||
zone1Links += 1;
|
||||
}
|
||||
if (psCurr->flags & GWR_WATERLINK)
|
||||
{
|
||||
// calculating links for a water link gateway
|
||||
if (gwZoneInEquiv(psCurr->zone1, psLink->zone1) ||
|
||||
gwZoneInEquiv(psCurr->zone1, psLink->zone2))
|
||||
{
|
||||
zone2Links += 1;
|
||||
}
|
||||
}
|
||||
else if ((psLink->zone1 == psCurr->zone2) || (psLink->zone2 == psCurr->zone2) ||
|
||||
((psLink->flags & GWR_WATERLINK) &&
|
||||
gwZoneInEquiv(psLink->zone1, psCurr->zone2) &&
|
||||
!gwZoneInEquiv(psLink->zone1, psCurr->zone1) ))
|
||||
{
|
||||
zone2Links += 1;
|
||||
}
|
||||
}
|
||||
if (zone1Links+zone2Links > 0)
|
||||
{
|
||||
psCurr->psLinks = (GATEWAY_LINK*)malloc(sizeof(GATEWAY_LINK) * (zone1Links+zone2Links));
|
||||
if (psCurr->psLinks == NULL)
|
||||
{
|
||||
debug( LOG_ERROR, "gwLinkGateways: out of memory" );
|
||||
abort();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
psCurr->psLinks = NULL;
|
||||
}
|
||||
psCurr->zone1Links = (UBYTE)zone1Links;
|
||||
psCurr->zone2Links = (UBYTE)zone2Links;
|
||||
|
||||
// generate the links starting with all those through zone1
|
||||
link = 0;
|
||||
zone = psCurr->zone1;
|
||||
otherZone = psCurr->zone2;
|
||||
zoneLinks = zone1Links;
|
||||
bZone1 = true;
|
||||
while (link < (zone1Links + zone2Links))
|
||||
{
|
||||
for(psLink=psGateways; psLink && (link < zoneLinks); psLink=psLink->psNext)
|
||||
{
|
||||
if (psLink == psCurr)
|
||||
{
|
||||
// don't link a gateway to itself
|
||||
continue;
|
||||
}
|
||||
bAddLink = false;
|
||||
if (!bZone1 && (psCurr->flags & GWR_WATERLINK))
|
||||
{
|
||||
// calculating links for a water link gateway
|
||||
if (gwZoneInEquiv(psCurr->zone1, psLink->zone1) ||
|
||||
gwZoneInEquiv(psCurr->zone1, psLink->zone2))
|
||||
{
|
||||
bAddLink = true;
|
||||
}
|
||||
}
|
||||
else if ((psLink->zone1 == zone) || (psLink->zone2 == zone) ||
|
||||
((psLink->flags & GWR_WATERLINK) &&
|
||||
gwZoneInEquiv(psLink->zone1, zone) &&
|
||||
!gwZoneInEquiv(psLink->zone1, otherZone) ))
|
||||
{
|
||||
bAddLink = true;
|
||||
}
|
||||
|
||||
if (bAddLink)
|
||||
{
|
||||
// debug( LOG_NEVER, "Linking %sgateway (%d,%d)->(%d,%d) through %s to gateway (%d,%d)->(%d,%d)\n", (psCurr->flags & GWR_WATERLINK) ? "water " : "", psCurr->x1,psCurr->y1, psCurr->x2, psCurr->y2, bZone1 ? "zone1" : "zone2", psLink->x1, psLink->y1, psLink->x2, psLink->y2 );
|
||||
psCurr->psLinks[link].psGateway = psLink;
|
||||
psCurr->psLinks[link].flags = 0;
|
||||
|
||||
psCurr->psLinks[link].dist = (SWORD)gwRouteLength(psCurr, psLink);
|
||||
|
||||
link += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// found all the links to zone1, now do it for zone2
|
||||
zone = psCurr->zone2;
|
||||
otherZone = psCurr->zone1;
|
||||
zoneLinks = zone1Links + zone2Links;
|
||||
bZone1 = false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************************************/
|
||||
/* RLE Zone data access functions */
|
||||
|
||||
|
||||
// Get number of zone lines.
|
||||
UDWORD gwNumZoneLines(void)
|
||||
{
|
||||
return gwMapHeight();
|
||||
}
|
||||
|
||||
|
||||
// Get the size of a zone line.
|
||||
UDWORD gwZoneLineSize(UDWORD Line)
|
||||
{
|
||||
UBYTE *pCode;
|
||||
UDWORD pos = 0;
|
||||
UDWORD x = 0;
|
||||
|
||||
ASSERT( Line < (UDWORD)gwMapHeight(),"gwNewZoneLine : Invalid line requested" );
|
||||
ASSERT( apRLEZones != NULL,"gwNewZoneLine : NULL Zone map" );
|
||||
|
||||
pCode = apRLEZones[Line];
|
||||
|
||||
while (x < (UDWORD)gwMapWidth()) {
|
||||
x += pCode[pos];
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
// Create a new empty zone map but don't allocate the actual zones yet.
|
||||
//
|
||||
BOOL gwNewZoneMap(void)
|
||||
{
|
||||
UWORD i;
|
||||
|
||||
if (apRLEZones != NULL)
|
||||
{
|
||||
gwFreeZoneMap();
|
||||
}
|
||||
|
||||
apRLEZones = (UBYTE**)malloc(sizeof(UBYTE *) * gwMapHeight());
|
||||
if (apRLEZones == NULL)
|
||||
{
|
||||
debug( LOG_ERROR, "gwNewZoneMap: Out of memory" );
|
||||
abort();
|
||||
return false;
|
||||
}
|
||||
|
||||
for(i=0; i< gwMapHeight(); i++)
|
||||
{
|
||||
apRLEZones[i] = NULL;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create a new empty zone map line in the zone map.
|
||||
//
|
||||
UBYTE * gwNewZoneLine(UDWORD Line,UDWORD Size)
|
||||
{
|
||||
ASSERT( Line < (UDWORD)gwMapHeight(),"gwNewZoneLine : Invalid line requested" );
|
||||
ASSERT( apRLEZones != NULL,"gwNewZoneLine : NULL Zone map" );
|
||||
|
||||
if(apRLEZones[Line] != NULL) {
|
||||
free(apRLEZones[Line]);
|
||||
}
|
||||
|
||||
apRLEZones[Line] = (UBYTE*)malloc(Size);
|
||||
if (apRLEZones[Line] == NULL)
|
||||
{
|
||||
debug( LOG_ERROR, "gwNewZoneLine: Out of memory" );
|
||||
abort();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return apRLEZones[Line];
|
||||
}
|
||||
|
||||
|
||||
// Create a NULL zone map for when there is no zone info loaded
|
||||
BOOL gwCreateNULLZoneMap(void)
|
||||
{
|
||||
SDWORD y;
|
||||
UBYTE *pBuf;
|
||||
|
||||
if (!gwNewZoneMap())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for(y=0; y<gwMapHeight(); y++)
|
||||
{
|
||||
pBuf = gwNewZoneLine(y, 2);
|
||||
if (!pBuf)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
pBuf[0] = (UBYTE)gwMapWidth();
|
||||
pBuf[1] = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// release the RLE Zone map
|
||||
void gwFreeZoneMap(void)
|
||||
{
|
||||
SDWORD i;
|
||||
|
||||
if (apRLEZones)
|
||||
{
|
||||
for(i=0; i<gwMapHeight(); i++)
|
||||
{
|
||||
free(apRLEZones[i]);
|
||||
}
|
||||
free(apRLEZones);
|
||||
apRLEZones = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Look up the zone for a coordinate
|
||||
SDWORD gwGetZone(SDWORD x, SDWORD y)
|
||||
{
|
||||
ASSERT( x >= 0 && x < gwMapWidth() && y >= 0 && y < gwMapHeight(), "gwGetZone: invalid coordinates" );
|
||||
|
||||
if ( x >= 0 && x < gwMapWidth() && y >= 0 && y < gwMapHeight() )
|
||||
{
|
||||
SDWORD xPos = 0, zone = 0, rlePos = 0;
|
||||
|
||||
do
|
||||
{
|
||||
xPos += apRLEZones[y][rlePos];
|
||||
zone = apRLEZones[y][rlePos + 1];
|
||||
rlePos += 2;
|
||||
} while (xPos <= x); // xPos is where the next zone starts
|
||||
|
||||
return zone;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************************************/
|
||||
/* Zone equivalence data access functions */
|
||||
|
||||
|
||||
// create an empty equivalence table
|
||||
BOOL gwNewEquivTable(SDWORD numZones)
|
||||
{
|
||||
SDWORD i;
|
||||
|
||||
ASSERT( numZones < UBYTE_MAX,
|
||||
"gwNewEquivTable: invalid number of zones" );
|
||||
|
||||
gwNumZones = numZones;
|
||||
aNumEquiv = (UBYTE*)malloc(sizeof(UBYTE) * numZones);
|
||||
if (aNumEquiv == NULL)
|
||||
{
|
||||
debug( LOG_ERROR, "gwNewEquivTable: out of memory" );
|
||||
abort();
|
||||
return false;
|
||||
}
|
||||
for(i=0; i<numZones; i+=1)
|
||||
{
|
||||
aNumEquiv[i] = 0;
|
||||
}
|
||||
|
||||
apEquivZones = (UBYTE**)malloc(sizeof(UBYTE *) * numZones);
|
||||
if (apEquivZones == NULL)
|
||||
{
|
||||
debug( LOG_ERROR, "gwNewEquivTable: out of memory" );
|
||||
abort();
|
||||
return false;
|
||||
}
|
||||
for(i=0; i<numZones; i+=1)
|
||||
{
|
||||
apEquivZones[i] = NULL;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// release the equivalence table
|
||||
void gwFreeEquivTable(void)
|
||||
{
|
||||
SDWORD i;
|
||||
|
||||
if (aNumEquiv)
|
||||
{
|
||||
free(aNumEquiv);
|
||||
aNumEquiv = NULL;
|
||||
}
|
||||
|
||||
if (apEquivZones)
|
||||
{
|
||||
for(i=0; i<gwNumZones; i+=1)
|
||||
{
|
||||
if (apEquivZones[i])
|
||||
{
|
||||
free(apEquivZones[i]);
|
||||
}
|
||||
}
|
||||
free(apEquivZones);
|
||||
apEquivZones = NULL;
|
||||
}
|
||||
gwNumZones = 0;
|
||||
}
|
||||
|
||||
|
||||
// set the zone equivalence for a zone
|
||||
BOOL gwSetZoneEquiv(SDWORD zone, SDWORD numEquiv, UBYTE *pEquiv)
|
||||
{
|
||||
SDWORD i;
|
||||
|
||||
ASSERT( aNumEquiv != NULL && apEquivZones != NULL,
|
||||
"gwSetZoneEquiv: equivalence arrays not initialised" );
|
||||
ASSERT( zone < gwNumZones,
|
||||
"gwSetZoneEquiv: invalid zone" );
|
||||
ASSERT( numEquiv <= gwNumZones,
|
||||
"gwSetZoneEquiv: invalid number of zone equivalents" );
|
||||
|
||||
apEquivZones[zone] = (UBYTE*)malloc(sizeof(UBYTE) * numEquiv);
|
||||
if (apEquivZones[zone] == NULL)
|
||||
{
|
||||
debug( LOG_ERROR, "gwSetZoneEquiv: out of memory" );
|
||||
abort();
|
||||
return false;
|
||||
}
|
||||
|
||||
aNumEquiv[zone] = (UBYTE)numEquiv;
|
||||
for(i=0; i<numEquiv; i+=1)
|
||||
{
|
||||
apEquivZones[zone][i] = pEquiv[i];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************************************/
|
||||
/* Gateway data access functions */
|
||||
|
||||
// get the size of the map
|
||||
SDWORD gwMapWidth(void)
|
||||
{
|
||||
return (SDWORD)mapWidth;
|
||||
}
|
||||
|
||||
SDWORD gwMapHeight(void)
|
||||
{
|
||||
return (SDWORD)mapHeight;
|
||||
}
|
||||
|
||||
// set the gateway flag on a tile
|
||||
void gwSetGatewayFlag(SDWORD x, SDWORD y)
|
||||
{
|
||||
mapTile((UDWORD)x,(UDWORD)y)->tileInfoBits |= BITS_GATEWAY;
|
||||
}
|
||||
|
||||
// clear the gateway flag on a tile
|
||||
void gwClearGatewayFlag(SDWORD x, SDWORD y)
|
||||
{
|
||||
mapTile((UDWORD)x,(UDWORD)y)->tileInfoBits &= ~BITS_GATEWAY;
|
||||
}
|
||||
|
||||
// check whether a tile is water
|
||||
BOOL gwTileIsWater(UDWORD x, UDWORD y)
|
||||
{
|
||||
return terrainType(mapTile(x ,y)) == TER_WATER;
|
||||
}
|
||||
|
||||
// see if a zone is reachable
|
||||
BOOL gwZoneReachable(SDWORD zone)
|
||||
{
|
||||
ASSERT( zone >= 0 && zone < gwNumZones,
|
||||
"gwZoneReachable: invalid zone" );
|
||||
|
||||
return aZoneReachable[zone];
|
||||
}
|
||||
|
|
|
@ -28,17 +28,6 @@
|
|||
|
||||
// the list of gateways on the current map
|
||||
extern GATEWAY *psGateways;
|
||||
// the RLE map zones for each tile
|
||||
extern UBYTE **apRLEZones;
|
||||
|
||||
// the number of map zones
|
||||
extern SDWORD gwNumZones;
|
||||
|
||||
// The zone equivalence tables
|
||||
extern UBYTE *aNumEquiv;
|
||||
extern UBYTE **apEquivZones;
|
||||
|
||||
extern UBYTE *aZoneReachable;
|
||||
|
||||
// Initialise the gateway system
|
||||
BOOL gwInitialise(void);
|
||||
|
@ -49,76 +38,16 @@ void gwShutDown(void);
|
|||
// Add a gateway to the system
|
||||
BOOL gwNewGateway(SDWORD x1, SDWORD y1, SDWORD x2, SDWORD y2);
|
||||
|
||||
// Add a land/water link gateway to the system
|
||||
BOOL gwNewLinkGateway(SDWORD x, SDWORD y);
|
||||
|
||||
// add the land/water link gateways
|
||||
BOOL gwGenerateLinkGates(void);
|
||||
|
||||
// Release a gateway
|
||||
void gwFreeGateway(GATEWAY *psDel);
|
||||
|
||||
// load a gateway list
|
||||
BOOL gwLoadGateways(char *pFileBuffer, UDWORD fileSize);
|
||||
|
||||
// link all the gateways together
|
||||
BOOL gwLinkGateways(void);
|
||||
|
||||
// check all the zones are of reasonable sizes
|
||||
void gwCheckZoneSizes(void);
|
||||
|
||||
// check if a zone is in the equivalence table for a water zone
|
||||
BOOL gwZoneInEquiv(SDWORD mainZone, SDWORD checkZone);
|
||||
|
||||
// Look up the zone for a coordinate
|
||||
SDWORD gwGetZone(SDWORD x, SDWORD y);
|
||||
|
||||
// Create a new empty zone map but don't allocate the actual zones yet.
|
||||
BOOL gwNewZoneMap(void);
|
||||
|
||||
// Create a new empty zone map line in the zone map.
|
||||
UBYTE * gwNewZoneLine(UDWORD Line,UDWORD Size);
|
||||
|
||||
// Create a NULL zone map for when there is no zone info loaded
|
||||
BOOL gwCreateNULLZoneMap(void);
|
||||
|
||||
// release the RLE Zone map
|
||||
void gwFreeZoneMap(void);
|
||||
|
||||
// get the size of the map
|
||||
SDWORD gwMapWidth(void);
|
||||
SDWORD gwMapHeight(void);
|
||||
|
||||
// set the gateway flag on a tile
|
||||
void gwSetGatewayFlag(SDWORD x, SDWORD y);
|
||||
// clear the gateway flag on a tile
|
||||
void gwClearGatewayFlag(SDWORD x, SDWORD y);
|
||||
|
||||
// check whether a tile is water
|
||||
BOOL gwTileIsWater(UDWORD x, UDWORD y);
|
||||
|
||||
// Get number of gateways.
|
||||
UDWORD gwNumGateways(void);
|
||||
|
||||
// Get the gateway list.
|
||||
GATEWAY *gwGetGateways(void);
|
||||
|
||||
// Get number of zone lines.
|
||||
UDWORD gwNumZoneLines(void);
|
||||
|
||||
// Get size of a zone line in bytes.
|
||||
UDWORD gwZoneLineSize(UDWORD Line);
|
||||
|
||||
// create an empty equivalence table
|
||||
BOOL gwNewEquivTable(SDWORD numZones);
|
||||
|
||||
// release the equivalence table
|
||||
void gwFreeEquivTable(void);
|
||||
|
||||
// set the zone equivalence for a zone
|
||||
BOOL gwSetZoneEquiv(SDWORD zone, SDWORD numEquiv, UBYTE *pEquiv);
|
||||
|
||||
// see if a zone is reachable
|
||||
BOOL gwZoneReachable(SDWORD zone);
|
||||
|
||||
#endif // __INCLUDED_SRC_GATEWAY_H__
|
||||
|
|
|
@ -1,407 +0,0 @@
|
|||
/*
|
||||
This file is part of Warzone 2100.
|
||||
Copyright (C) 1999-2004 Eidos Interactive
|
||||
Copyright (C) 2005-2007 Warzone Resurrection Project
|
||||
|
||||
Warzone 2100 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.
|
||||
|
||||
Warzone 2100 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 Warzone 2100; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
/*
|
||||
* Generate a 'meta' route through the gateways to guide the normal routing
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lib/framework/frame.h"
|
||||
|
||||
#include "map.h"
|
||||
#include "gateway.h"
|
||||
#include "gatewayroute.h"
|
||||
#include "fpath.h"
|
||||
|
||||
// the open list
|
||||
static GATEWAY *psOpenList;
|
||||
|
||||
// estimate the distance to the target from a gateway
|
||||
static SDWORD gwrEstimate(GATEWAY *psGate, SDWORD x, SDWORD y)
|
||||
{
|
||||
SDWORD gwx,gwy, dx,dy;
|
||||
|
||||
gwx = (psGate->x1 + psGate->x2)/2;
|
||||
gwy = (psGate->y1 + psGate->y2)/2;
|
||||
|
||||
dx = gwx - x;
|
||||
dy = gwy - y;
|
||||
|
||||
dx = abs( dx );
|
||||
dy = abs( dy );
|
||||
|
||||
return dx > dy ? dx + dy/2 : dx/2 + dy;
|
||||
}
|
||||
|
||||
|
||||
// add a gateway to the open list
|
||||
static void gwrOpenAdd(GATEWAY *psGate)
|
||||
{
|
||||
psGate->flags &= ~GWR_CLOSED;
|
||||
psGate->flags |= GWR_OPEN;
|
||||
psGate->psOpen = psOpenList;
|
||||
psOpenList = psGate;
|
||||
}
|
||||
|
||||
|
||||
// get the next gateway from the open list
|
||||
static GATEWAY *gwrOpenGet(void)
|
||||
{
|
||||
SDWORD minDist, dist;
|
||||
GATEWAY *psCurr, *psPrev, *psParent = NULL, *psFound = NULL;
|
||||
|
||||
if (psOpenList == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
psPrev = NULL;
|
||||
minDist = SDWORD_MAX;
|
||||
for (psCurr = psOpenList; psCurr; psCurr=psCurr->psOpen)
|
||||
{
|
||||
dist = psCurr->dist + psCurr->est;
|
||||
if (dist < minDist)
|
||||
{
|
||||
minDist = dist;
|
||||
psParent = psPrev;
|
||||
psFound = psCurr;
|
||||
}
|
||||
psPrev = psCurr;
|
||||
}
|
||||
|
||||
// remove the found gateway from the list
|
||||
if (psParent == NULL)
|
||||
{
|
||||
psOpenList = psOpenList->psOpen;
|
||||
}
|
||||
else
|
||||
{
|
||||
psParent->psOpen = psFound->psOpen;
|
||||
}
|
||||
psFound->psOpen = NULL;
|
||||
psFound->flags &= ~(GWR_OPEN|GWR_CLOSED);
|
||||
|
||||
return psFound;
|
||||
}
|
||||
|
||||
|
||||
// check whether a gateway should be considered for routing
|
||||
// (i.e. whether it is inside the current scroll limits)
|
||||
static BOOL gwrConsiderGateway(GATEWAY *psGate)
|
||||
{
|
||||
return (psGate->x1 >= scrollMinX) && (psGate->x1 <= scrollMaxX) &&
|
||||
(psGate->x2 >= scrollMinX) && (psGate->x2 <= scrollMaxX) &&
|
||||
(psGate->y1 >= scrollMinY) && (psGate->y1 <= scrollMaxY) &&
|
||||
(psGate->y2 >= scrollMinY) && (psGate->y2 <= scrollMaxY) &&
|
||||
!(psGate->flags & GWR_BLOCKED);
|
||||
}
|
||||
|
||||
|
||||
// check whether all the tiles on a gateway are blocked
|
||||
static BOOL gwrBlockedGateway(GATEWAY *psGate, SDWORD player, UDWORD terrain)
|
||||
{
|
||||
// SDWORD pos;
|
||||
BOOL blocked;
|
||||
MAPTILE *psTile;
|
||||
|
||||
blocked = false;
|
||||
|
||||
psTile = mapTile( (psGate->x1+psGate->x2)/2,
|
||||
(psGate->y1+psGate->y2)/2);
|
||||
if ( (terrainType(psTile) == TER_WATER) &&
|
||||
!(terrain & GWR_TER_WATER))
|
||||
{
|
||||
blocked = true;
|
||||
}
|
||||
if ( (terrainType(psTile) != TER_WATER) &&
|
||||
!(terrain & GWR_TER_LAND))
|
||||
{
|
||||
blocked = true;
|
||||
}
|
||||
if (psGate->flags & GWR_IGNORE)
|
||||
{
|
||||
blocked = true;
|
||||
}
|
||||
|
||||
/* blocked = true;
|
||||
if (psGate->x1 == psGate->x2)
|
||||
{
|
||||
for(pos = psGate->y1; pos <= psGate->y2; pos += 1)
|
||||
{
|
||||
psTile = mapTile(psGate->x1, pos);
|
||||
if (!fpathBlockingTile(psGate->x1, pos) &&
|
||||
TEST_TILE_VISIBLE(player, psTile))
|
||||
{
|
||||
blocked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(pos = psGate->x1; pos <= psGate->x2; pos += 1)
|
||||
{
|
||||
psTile = mapTile(pos, psGate->y1);
|
||||
if (!fpathBlockingTile(pos, psGate->y1) &&
|
||||
TEST_TILE_VISIBLE(player, psTile))
|
||||
{
|
||||
blocked = false;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
return blocked;
|
||||
}
|
||||
|
||||
|
||||
// A* findpath for the gateway system
|
||||
SDWORD gwrAStarRoute(SDWORD player, UDWORD terrain,
|
||||
SDWORD sx, SDWORD sy, SDWORD fx, SDWORD fy,
|
||||
GATEWAY **ppsRoute)
|
||||
{
|
||||
SDWORD tileSX,tileSY,tileFX,tileFY;
|
||||
SDWORD currDist, retval;
|
||||
GATEWAY *psCurr, *psNew, *psRoute, *psParent, *psNext, *psNearest, *psPrev;
|
||||
SDWORD zone, finalZone, link, finalLink;
|
||||
BOOL add;
|
||||
|
||||
*ppsRoute = NULL;
|
||||
tileSX = map_coord(sx);
|
||||
tileSY = map_coord(sy);
|
||||
|
||||
tileFX = map_coord(fx);
|
||||
tileFY = map_coord(fy);
|
||||
|
||||
// reset the flags on the gateways
|
||||
for(psCurr = psGateways; psCurr; psCurr=psCurr->psNext)
|
||||
{
|
||||
psCurr->flags &= ~GWR_RESET_MASK;
|
||||
psCurr->dist = SWORD_MAX;
|
||||
for(link = 0; link < (psCurr->zone1Links + psCurr->zone2Links); link++)
|
||||
{
|
||||
psCurr->psLinks[link].flags &= ~GWRL_RESET_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
// add all the gateways next to the start point
|
||||
zone = gwGetZone(tileSX, tileSY);
|
||||
finalZone = gwGetZone(tileFX, tileFY);
|
||||
if (zone == finalZone)
|
||||
{
|
||||
debug( LOG_GATEWAY, "Route same zone\n");
|
||||
return GWR_SAMEZONE;
|
||||
}
|
||||
if (zone == 0 || finalZone == 0)
|
||||
{
|
||||
debug( LOG_GATEWAY, "Route no zone info\n");
|
||||
return GWR_NOZONE;
|
||||
}
|
||||
psOpenList = NULL;
|
||||
for(psNew = psGateways; psNew; psNew=psNew->psNext)
|
||||
{
|
||||
add = false;
|
||||
if (psNew->zone1 == zone)
|
||||
{
|
||||
psNew->flags |= GWR_ZONE1;
|
||||
add = true;
|
||||
}
|
||||
else if (psNew->zone2 == zone)
|
||||
{
|
||||
psNew->flags |= GWR_ZONE2;
|
||||
add = true;
|
||||
}
|
||||
else if ((psNew->flags & GWR_WATERLINK) &&
|
||||
gwZoneInEquiv(psNew->zone1, zone))
|
||||
{
|
||||
psNew->flags |= GWR_ZONE2;
|
||||
add = true;
|
||||
}
|
||||
|
||||
if (gwrBlockedGateway(psNew, player, terrain))
|
||||
{
|
||||
psNew->flags |= GWR_BLOCKED;
|
||||
add = false;
|
||||
}
|
||||
|
||||
if (add && gwrConsiderGateway(psNew))
|
||||
{
|
||||
psNew->dist = (SWORD)gwrEstimate(psNew, tileSX,tileSY);
|
||||
psNew->est = (SWORD)gwrEstimate(psNew, tileFX,tileFY);
|
||||
psNew->psRoute = NULL;
|
||||
gwrOpenAdd(psNew);
|
||||
}
|
||||
}
|
||||
|
||||
// search for a route
|
||||
psRoute = NULL;
|
||||
psNearest = NULL;
|
||||
while (psOpenList != NULL)
|
||||
{
|
||||
psCurr = gwrOpenGet();
|
||||
// debug( LOG_NEVER, "processing gateway (%d,%d)->(%d,%d)\n", psCurr->x1, psCurr->y1, psCurr->x2, psCurr->y2 );
|
||||
|
||||
if (psCurr->zone1 == finalZone || psCurr->zone2 == finalZone ||
|
||||
((psCurr->flags & GWR_WATERLINK) && gwZoneInEquiv(psCurr->zone1, finalZone)))
|
||||
{
|
||||
// reached the target
|
||||
psRoute = psCurr;
|
||||
// debug( LOG_NEVER, "Found route\n" );
|
||||
break;
|
||||
}
|
||||
|
||||
if (psNearest == NULL || psCurr->est < psNearest->est)
|
||||
{
|
||||
psNearest = psCurr;
|
||||
}
|
||||
|
||||
if (psCurr->flags & GWR_WATERLINK)
|
||||
{
|
||||
// water link gatway - route can continue to any other
|
||||
// gateway apart from the one it came from
|
||||
zone = psCurr->zone1;
|
||||
link = 0;
|
||||
finalLink = psCurr->zone1Links + psCurr->zone2Links;
|
||||
}
|
||||
else if (psCurr->flags & GWR_ZONE1)
|
||||
{
|
||||
// route came from zone1 continue with zone2
|
||||
zone = psCurr->zone2;
|
||||
link = psCurr->zone1Links;
|
||||
finalLink = psCurr->zone1Links + psCurr->zone2Links;
|
||||
}
|
||||
else
|
||||
{
|
||||
zone = psCurr->zone1;
|
||||
link = 0;
|
||||
finalLink = psCurr->zone1Links;
|
||||
}
|
||||
|
||||
for (; link < finalLink; link += 1)
|
||||
{
|
||||
// skip any link that is known to be blocked
|
||||
if (psCurr->psLinks[link].flags & GWRL_BLOCKED)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
psNew = psCurr->psLinks[link].psGateway;
|
||||
currDist = psCurr->dist + psCurr->psLinks[link].dist;
|
||||
|
||||
// don't loop back on the route
|
||||
if ((psNew == psCurr->psRoute) ||
|
||||
// skip any gates outside the current scroll limits
|
||||
!gwrConsiderGateway(psNew) ||
|
||||
// skip any gate already visited node by a shorter route
|
||||
(psNew->dist <= currDist))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Now insert the gateway into the appropriate list
|
||||
if ((psNew->flags & GWR_RESET_MASK) == 0)
|
||||
{
|
||||
// Not in open or closed lists - add to the open list
|
||||
psNew->dist = (SWORD)currDist;
|
||||
psNew->est = (SWORD)gwrEstimate(psNew, tileFX,tileFY);
|
||||
psNew->psRoute = psCurr;
|
||||
psNew->flags |= (psNew->zone1 == zone) ? GWR_ZONE1 : GWR_ZONE2;
|
||||
gwrOpenAdd(psNew);
|
||||
// debug( LOG_NEVER, "new gateway (%d,%d)->(%d,%d) dist %d est %d\n", psNew->x1, psNew->y1, psNew->x2, psNew->y2, psNew->dist, psNew->est );
|
||||
}
|
||||
else if (psNew->flags & GWR_OPEN)
|
||||
{
|
||||
// already in the open list but this is shorter
|
||||
// debug( LOG_NEVER, "new route to open gateway (%d,%d)->(%d,%d) dist %d->%d est %d\n", psNew->x1, psNew->y1, psNew->x2, psNew->y2, currDist, psNew->dist, psNew->est );
|
||||
psNew->dist = (SWORD)currDist;
|
||||
psNew->psRoute = psCurr;
|
||||
}
|
||||
else if (psNew->flags & GWR_CLOSED)
|
||||
{
|
||||
// already in the closed list but this is shorter
|
||||
// debug( LOG_NEVER, "new route to closed gateway (%d,%d)->(%d,%d) dist %d->%d est %d\n", psNew->x1, psNew->y1, psNew->x2, psNew->y2, currDist, psNew->dist, psNew->est );
|
||||
psNew->dist = (SWORD)currDist;
|
||||
psNew->psRoute = psCurr;
|
||||
gwrOpenAdd(psNew);
|
||||
}
|
||||
|
||||
psNew->flags &= ~(GWR_ZONE1 | GWR_ZONE2);
|
||||
psNew->flags |= (psNew->zone1 == zone) ? GWR_ZONE1 : GWR_ZONE2;
|
||||
}
|
||||
|
||||
psCurr->flags &= ~(GWR_CLOSED|GWR_OPEN);
|
||||
psCurr->flags |= GWR_CLOSED;
|
||||
}
|
||||
|
||||
retval = GWR_OK;
|
||||
if (psRoute == NULL)
|
||||
{
|
||||
// debug( LOG_NEVER, "Partial route\n" );
|
||||
psRoute = psNearest;
|
||||
retval = GWR_NEAREST;
|
||||
}
|
||||
|
||||
// get the route in the correct order if one was found
|
||||
// (it is currently in reverse order).
|
||||
if (psRoute)
|
||||
{
|
||||
psParent = NULL;
|
||||
psPrev = NULL;
|
||||
for(psCurr=psRoute; psCurr; psCurr=psNext)
|
||||
{
|
||||
psNext = psCurr->psRoute;
|
||||
if (!(psCurr->flags & GWR_WATERLINK))
|
||||
{
|
||||
psCurr->flags |= GWR_INROUTE;
|
||||
for(link = 0; link < (psCurr->zone1Links + psCurr->zone2Links); link++)
|
||||
{
|
||||
// NB link flags are reversed because the route order is being reversed
|
||||
if (psCurr->psLinks[link].psGateway == psPrev)
|
||||
{
|
||||
psCurr->psLinks[link].flags |= GWRL_CHILD;
|
||||
}
|
||||
else if (psCurr->psLinks[link].psGateway == psNext)
|
||||
{
|
||||
psCurr->psLinks[link].flags |= GWRL_PARENT;
|
||||
}
|
||||
}
|
||||
psCurr->psRoute = psParent;
|
||||
psParent = psCurr;
|
||||
}
|
||||
|
||||
// NB psPrev is not quite the same as psParent as it includes water link gateways
|
||||
psPrev = psCurr;
|
||||
}
|
||||
psRoute = psParent;
|
||||
|
||||
debug( LOG_GATEWAY, "Final route:\n");
|
||||
for(psCurr=psRoute; psCurr; psCurr=psCurr->psRoute)
|
||||
{
|
||||
debug( LOG_GATEWAY, " (%d,%d)->(%d,%d) dist %d est %d\n",
|
||||
psCurr->x1, psCurr->y1, psCurr->x2, psCurr->y2, psCurr->dist, psCurr->est);
|
||||
}
|
||||
|
||||
*ppsRoute = psRoute;
|
||||
}
|
||||
|
||||
if (psRoute == NULL)
|
||||
{
|
||||
retval = GWR_FAILED;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
This file is part of Warzone 2100.
|
||||
Copyright (C) 1999-2004 Eidos Interactive
|
||||
Copyright (C) 2005-2007 Warzone Resurrection Project
|
||||
|
||||
Warzone 2100 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.
|
||||
|
||||
Warzone 2100 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 Warzone 2100; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
/** @file
|
||||
* Interface to the gateway routing code
|
||||
*/
|
||||
|
||||
#ifndef __INCLUDED_SRC_GATEWAYROUTE_H__
|
||||
#define __INCLUDED_SRC_GATEWAYROUTE_H__
|
||||
|
||||
#include "gateway.h"
|
||||
|
||||
// what type of terrain the unit can move over
|
||||
enum _gwr_terrain_types
|
||||
{
|
||||
GWR_TER_LAND = 0x01,
|
||||
GWR_TER_WATER = 0x02,
|
||||
|
||||
GWR_TER_ALL = 0xff,
|
||||
};
|
||||
|
||||
// return codes for the router
|
||||
enum _gwr_return_codes
|
||||
{
|
||||
GWR_OK, // found a route
|
||||
GWR_NEAREST, // chose the nearest gateway to the target
|
||||
GWR_FAILED, // couldn't find a route
|
||||
GWR_SAMEZONE, // start and end points in the same zone
|
||||
GWR_NOZONE, // the route did not start on a valid zone
|
||||
};
|
||||
|
||||
// A* findpath for the gateway system
|
||||
extern SDWORD gwrAStarRoute(SDWORD player, UDWORD terrain,
|
||||
SDWORD sx, SDWORD sy, SDWORD fx, SDWORD fy,
|
||||
GATEWAY **ppsRoute);
|
||||
|
||||
#endif // __INCLUDED_SRC_GATEWAYROUTE_H__
|
172
src/map.c
172
src/map.c
|
@ -191,10 +191,6 @@ static BOOL mapLoadV3(char *pFileData, UDWORD fileSize)
|
|||
MAP_SAVETILEV2 *psTileData;
|
||||
GATEWAY_SAVEHEADER *psGateHeader;
|
||||
GATEWAY_SAVE *psGate;
|
||||
ZONEMAP_SAVEHEADER *psZoneHeader;
|
||||
UWORD ZoneSize;
|
||||
UBYTE *pZone;
|
||||
UBYTE *pDestZone;
|
||||
|
||||
/* Load in the map data */
|
||||
psTileData = (MAP_SAVETILEV2 *)(pFileData + SAVE_HEADER_SIZE);
|
||||
|
@ -230,100 +226,8 @@ static BOOL mapLoadV3(char *pFileData, UDWORD fileSize)
|
|||
psGate++;
|
||||
}
|
||||
|
||||
psZoneHeader = (ZONEMAP_SAVEHEADER*)psGate;
|
||||
|
||||
/* ZONEMAP_SAVEHEADER */
|
||||
endian_uword(&psZoneHeader->version);
|
||||
endian_uword(&psZoneHeader->numZones);
|
||||
endian_uword(&psZoneHeader->numEquivZones);
|
||||
endian_uword(&psZoneHeader->pad);
|
||||
|
||||
ASSERT( (psZoneHeader->version == 1) || (psZoneHeader->version == 2),
|
||||
"Invalid zone map version" );
|
||||
|
||||
if(!gwNewZoneMap()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This is a bit nasty but should work fine.
|
||||
if(psZoneHeader->version == 1) {
|
||||
// version 1 so add the size of a version 1 header.
|
||||
pZone = ((UBYTE*)psZoneHeader) + sizeof(ZONEMAP_SAVEHEADER_V1);
|
||||
} else {
|
||||
// version 2 so add the size of a version 2 header.
|
||||
pZone = ((UBYTE*)psZoneHeader) + sizeof(ZONEMAP_SAVEHEADER);
|
||||
}
|
||||
|
||||
for(i=0; i<psZoneHeader->numZones; i++) {
|
||||
ZoneSize = *((UWORD*)(pZone));
|
||||
endian_uword(&ZoneSize);
|
||||
|
||||
pDestZone = gwNewZoneLine(i,ZoneSize);
|
||||
|
||||
if(pDestZone == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for(j=0; j<ZoneSize; j++) {
|
||||
pDestZone[j] = pZone[2+j];
|
||||
}
|
||||
|
||||
pZone += ZoneSize+2;
|
||||
}
|
||||
|
||||
// Version 2 has the zone equivelancy lists tacked on the end.
|
||||
if(psZoneHeader->version == 2) {
|
||||
|
||||
if(psZoneHeader->numEquivZones > 0) {
|
||||
// Load in the zone equivelance lists.
|
||||
if(!gwNewEquivTable(psZoneHeader->numEquivZones)) {
|
||||
debug( LOG_ERROR, "gwNewEquivTable failed" );
|
||||
abort();
|
||||
return false;
|
||||
}
|
||||
|
||||
for(i=0; i<psZoneHeader->numEquivZones; i++) {
|
||||
if(*pZone != 0) {
|
||||
if(!gwSetZoneEquiv(i, (SDWORD)*pZone, pZone+1)) {
|
||||
debug( LOG_ERROR, "gwSetZoneEquiv failed" );
|
||||
abort();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
pZone += ((UDWORD)*pZone)+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((char *)pZone - pFileData > fileSize)
|
||||
{
|
||||
debug( LOG_ERROR, "mapLoadV3: unexpected end of file" );
|
||||
abort();
|
||||
return false;
|
||||
}
|
||||
|
||||
LOADBARCALLBACK(); // loadingScreenCallback();
|
||||
|
||||
if ((apEquivZones != NULL) &&
|
||||
!gwGenerateLinkGates())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
LOADBARCALLBACK(); // loadingScreenCallback();
|
||||
|
||||
//add new map initialise
|
||||
if (!gwLinkGateways())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
LOADBARCALLBACK(); // loadingScreenCallback();
|
||||
|
||||
#if defined(DEBUG)
|
||||
gwCheckZoneSizes();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1072,29 +976,6 @@ BOOL mapSaveTagged(char *pFileName)
|
|||
}
|
||||
tagWriteLeave(0x0f);
|
||||
|
||||
tagWriteEnter(0x10, gwNumZoneLines()); // gateway zone lines
|
||||
for (i = 0; i < gwNumZoneLines(); i++)
|
||||
{
|
||||
// binary blob for now... ugh, this is ugly, but no worse than it was
|
||||
tagWrite(0x01, gwZoneLineSize(i));
|
||||
tagWrite8v(0x02, gwZoneLineSize(i), apRLEZones[i]);
|
||||
tagWriteNext();
|
||||
}
|
||||
tagWriteLeave(0x10);
|
||||
|
||||
tagWriteEnter(0x11, gwNumZones); // gateway equivalency zones
|
||||
for (i = 0; i < gwNumZones; i++)
|
||||
{
|
||||
tagWrite(0x01, aNumEquiv[i]);
|
||||
if (aNumEquiv[i])
|
||||
{
|
||||
// another ugly blob job
|
||||
tagWrite8v(0x02, aNumEquiv[i], apEquivZones[i]);
|
||||
}
|
||||
tagWriteNext();
|
||||
}
|
||||
tagWriteLeave(0x11);
|
||||
|
||||
tagClose();
|
||||
return true;
|
||||
}
|
||||
|
@ -1174,34 +1055,12 @@ BOOL mapSave(char **ppFileData, UDWORD *pFileSize)
|
|||
GATEWAY_SAVEHEADER *psGateHeader = NULL;
|
||||
GATEWAY_SAVE *psGate = NULL;
|
||||
ZONEMAP_SAVEHEADER *psZoneHeader = NULL;
|
||||
UBYTE *psZone = NULL;
|
||||
UBYTE *psLastZone = NULL;
|
||||
SDWORD numGateways = 0;
|
||||
|
||||
// find the number of non water gateways
|
||||
for(psCurrGate = gwGetGateways(); psCurrGate; psCurrGate = psCurrGate->psNext)
|
||||
{
|
||||
if (!(psCurrGate->flags & GWR_WATERLINK))
|
||||
{
|
||||
numGateways += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Allocate the data buffer */
|
||||
*pFileSize = SAVE_HEADER_SIZE + mapWidth*mapHeight * SAVE_TILE_SIZE;
|
||||
// Add on the size of the gateway data.
|
||||
*pFileSize += sizeof(GATEWAY_SAVEHEADER) + sizeof(GATEWAY_SAVE)*numGateways;
|
||||
// Add on the size of the zone data header.
|
||||
*pFileSize += sizeof(ZONEMAP_SAVEHEADER);
|
||||
// Add on the size of the zone data.
|
||||
for(i=0; i<gwNumZoneLines(); i++) {
|
||||
*pFileSize += 2+gwZoneLineSize(i);
|
||||
}
|
||||
// Add on the size of the equivalency lists.
|
||||
for(i=0; i<(UDWORD)gwNumZones; i++) {
|
||||
*pFileSize += 1+aNumEquiv[i];
|
||||
}
|
||||
|
||||
*ppFileData = (char*)malloc(*pFileSize);
|
||||
if (*ppFileData == NULL)
|
||||
|
@ -1273,8 +1132,8 @@ BOOL mapSave(char **ppFileData, UDWORD *pFileSize)
|
|||
// Put the zone header.
|
||||
psZoneHeader = (ZONEMAP_SAVEHEADER*)psGate;
|
||||
psZoneHeader->version = 2;
|
||||
psZoneHeader->numZones =(UWORD)gwNumZoneLines();
|
||||
psZoneHeader->numEquivZones =(UWORD)gwNumZones;
|
||||
psZoneHeader->numZones = 0;
|
||||
psZoneHeader->numEquivZones = 0;
|
||||
|
||||
/* ZONEMAP_SAVEHEADER */
|
||||
endian_uword(&psZoneHeader->version);
|
||||
|
@ -1282,33 +1141,6 @@ BOOL mapSave(char **ppFileData, UDWORD *pFileSize)
|
|||
endian_uword(&psZoneHeader->numEquivZones);
|
||||
endian_uword(&psZoneHeader->pad);
|
||||
|
||||
// Put the zone data.
|
||||
psZone = (UBYTE*)(psZoneHeader+1);
|
||||
for(i=0; i<gwNumZoneLines(); i++) {
|
||||
psLastZone = psZone;
|
||||
*((UWORD*)psZone) = (UWORD)gwZoneLineSize(i);
|
||||
endian_uword(((UWORD *) psZone));
|
||||
|
||||
psZone += sizeof(UWORD);
|
||||
memcpy(psZone,apRLEZones[i],gwZoneLineSize(i));
|
||||
psZone += gwZoneLineSize(i);
|
||||
}
|
||||
|
||||
// Put the equivalency lists.
|
||||
if(gwNumZones > 0) {
|
||||
for(i=0; i<(UDWORD)gwNumZones; i++) {
|
||||
psLastZone = psZone;
|
||||
*psZone = aNumEquiv[i];
|
||||
psZone ++;
|
||||
if(aNumEquiv[i]) {
|
||||
memcpy(psZone,apEquivZones[i],aNumEquiv[i]);
|
||||
psZone += aNumEquiv[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT( (intptr_t)psLastZone - (intptr_t)*ppFileData < (intptr_t)*pFileSize, "Buffer overflow saving map" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -261,13 +261,8 @@ void initMission(void)
|
|||
mission.ETA = -1;
|
||||
mission.startTime = 0;
|
||||
mission.psGateways = NULL;
|
||||
mission.apRLEZones = NULL;
|
||||
mission.gwNumZones = 0;
|
||||
mission.mapHeight = 0;
|
||||
mission.mapWidth = 0;
|
||||
mission.aNumEquiv = NULL;
|
||||
mission.apEquivZones = NULL;
|
||||
mission.aZoneReachable = NULL;
|
||||
|
||||
//init all the landing zones
|
||||
for (inc = 0; inc < MAX_NOGO_AREAS; inc++)
|
||||
|
@ -336,11 +331,6 @@ BOOL missionShutDown(void)
|
|||
mapWidth = mission.mapWidth;
|
||||
mapHeight = mission.mapHeight;
|
||||
psGateways = mission.psGateways;
|
||||
apRLEZones = mission.apRLEZones;
|
||||
gwNumZones = mission.gwNumZones;
|
||||
aNumEquiv = mission.aNumEquiv;
|
||||
apEquivZones = mission.apEquivZones;
|
||||
aZoneReachable = mission.aZoneReachable;
|
||||
}
|
||||
|
||||
// sorry if this breaks something - but it looks like it's what should happen - John
|
||||
|
@ -746,16 +736,6 @@ void saveMissionData(void)
|
|||
mission.scrollMaxY = scrollMaxY;
|
||||
mission.psGateways = psGateways;
|
||||
psGateways = NULL;
|
||||
mission.apRLEZones = apRLEZones;
|
||||
apRLEZones = NULL;
|
||||
mission.gwNumZones = gwNumZones;
|
||||
gwNumZones = 0;
|
||||
mission.aNumEquiv = aNumEquiv;
|
||||
aNumEquiv = NULL;
|
||||
mission.apEquivZones = apEquivZones;
|
||||
apEquivZones = NULL;
|
||||
mission.aZoneReachable = aZoneReachable;
|
||||
aZoneReachable = NULL;
|
||||
// save the selectedPlayer's LZ
|
||||
mission.homeLZ_X = getLandingX(selectedPlayer);
|
||||
mission.homeLZ_Y = getLandingY(selectedPlayer);
|
||||
|
@ -928,11 +908,6 @@ void restoreMissionData(void)
|
|||
scrollMaxX = mission.scrollMaxX;
|
||||
scrollMaxY = mission.scrollMaxY;
|
||||
psGateways = mission.psGateways;
|
||||
apRLEZones = mission.apRLEZones;
|
||||
gwNumZones = mission.gwNumZones;
|
||||
aNumEquiv = mission.aNumEquiv;
|
||||
apEquivZones = mission.apEquivZones;
|
||||
aZoneReachable = mission.aZoneReachable;
|
||||
//and clear the mission pointers
|
||||
mission.psMapTiles = NULL;
|
||||
mission.aMapLinePoints = NULL;
|
||||
|
@ -943,11 +918,6 @@ void restoreMissionData(void)
|
|||
mission.scrollMaxX = 0;
|
||||
mission.scrollMaxY = 0;
|
||||
mission.psGateways = NULL;
|
||||
mission.apRLEZones = NULL;
|
||||
mission.gwNumZones = 0;
|
||||
mission.aNumEquiv = NULL;
|
||||
mission.apEquivZones = NULL;
|
||||
mission.aZoneReachable = NULL;
|
||||
|
||||
//reset the current structure lists
|
||||
setCurrentStructQuantity(false);
|
||||
|
@ -1467,7 +1437,6 @@ void processMissionLimbo(void)
|
|||
void swapMissionPointers(void)
|
||||
{
|
||||
void *pVoid;
|
||||
void **ppVoid;
|
||||
UDWORD udwTemp, inc;
|
||||
|
||||
debug(LOG_SAVEGAME, "swapMissionPointers: called");
|
||||
|
@ -1487,21 +1456,6 @@ void swapMissionPointers(void)
|
|||
pVoid = (void*)psGateways;
|
||||
psGateways = mission.psGateways;
|
||||
mission.psGateways = (struct _gateway *)pVoid;
|
||||
ppVoid = (void**)apRLEZones;
|
||||
apRLEZones = mission.apRLEZones;
|
||||
mission.apRLEZones = (UBYTE **)ppVoid;
|
||||
udwTemp = (UDWORD)gwNumZones;
|
||||
gwNumZones = mission.gwNumZones;
|
||||
mission.gwNumZones = (SDWORD)udwTemp;
|
||||
pVoid = (void*)aNumEquiv;
|
||||
aNumEquiv = mission.aNumEquiv;
|
||||
mission.aNumEquiv = (UBYTE *)pVoid;
|
||||
ppVoid = (void**)apEquivZones;
|
||||
apEquivZones = mission.apEquivZones;
|
||||
mission.apEquivZones = (UBYTE **)ppVoid;
|
||||
pVoid = (void*)aZoneReachable;
|
||||
aZoneReachable = mission.aZoneReachable;
|
||||
mission.aZoneReachable = (UBYTE *)pVoid;
|
||||
// Swap scroll limits
|
||||
udwTemp = scrollMinX;
|
||||
scrollMinX = mission.scrollMinX;
|
||||
|
|
|
@ -4092,21 +4092,6 @@ BOOL validLocation(BASE_STATS *psStats, UDWORD x, UDWORD y, UDWORD player,
|
|||
goto failed;
|
||||
}
|
||||
|
||||
#ifdef NDEBUG
|
||||
/*God Awful HACK!! - AB 30/04/99 - gets round a problem with
|
||||
UrbanDuel map where an oil derrick cannot be built - when the
|
||||
map has been edited this hack can be removed*/
|
||||
if (psBuilding->type != REF_RESOURCE_EXTRACTOR)
|
||||
{
|
||||
if( gwZoneReachable(gwGetZone(i,j)) == false)
|
||||
{
|
||||
// Can't ever drive there
|
||||
valid = false;
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//don't check tile is visible for placement of a delivery point
|
||||
if (psStats->ref >= REF_STRUCTURE_START &&
|
||||
psStats->ref < (REF_STRUCTURE_START + REF_RANGE))
|
||||
|
|
Loading…
Reference in New Issue