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-861f7616d084
master
Per Inge Mathisen 2008-04-15 20:52:53 +00:00
parent 5de54b2936
commit ed5ffbfa8b
14 changed files with 85 additions and 2099 deletions

View File

@ -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 \

View File

@ -28,7 +28,6 @@ SRC=ai.c \
formation.c \
frontend.c \
gateway.c \
gatewayroute.c \
geometry.c \
group.c \
hci.c \

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -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)
{

View File

@ -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];
}

View File

@ -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__

View File

@ -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;
}

View File

@ -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
View File

@ -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;
}

View File

@ -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;

View File

@ -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))