mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-05-10 20:46:39 +03:00
633 lines
14 KiB
C++
633 lines
14 KiB
C++
![]() |
|
||
|
//
|
||
|
// b_nav.c
|
||
|
//
|
||
|
|
||
|
//FIXME make botInfo, etc visible here too and get rid of all the mutliple dereferences like bot->bot->
|
||
|
|
||
|
#include "b_local.h"
|
||
|
|
||
|
|
||
|
#define NAVF_EDGEZONE 0x00000001
|
||
|
|
||
|
#define INFINITE 1000000
|
||
|
|
||
|
#define BOTAI_PUSHED (1<<0)
|
||
|
|
||
|
cvar_t *nav_showsectors;
|
||
|
|
||
|
char *navFileData;
|
||
|
|
||
|
int surfaceCount;
|
||
|
nsurface_t *surface;
|
||
|
int neighborCount;
|
||
|
nneighbor_t *neighbor;
|
||
|
byte *route;
|
||
|
|
||
|
//#if 0
|
||
|
|
||
|
static int spawnpadModelIndex;
|
||
|
|
||
|
|
||
|
int Nav_SurfaceUnderPlayer( gentity_t *player ) {
|
||
|
vec3_t start;
|
||
|
vec3_t end;
|
||
|
vec3_t p;
|
||
|
trace_t tr;
|
||
|
float bestDist;
|
||
|
int bestSurf;
|
||
|
vec3_t v;
|
||
|
int n;
|
||
|
float dist;
|
||
|
|
||
|
VectorCopy( player->s.origin, start );
|
||
|
VectorCopy( player->s.origin, end );
|
||
|
end[2] -= 4096;
|
||
|
|
||
|
gi.trace ( &tr, start, player->mins, player->maxs, end, player->s.number, MASK_DEADSOLID, true );
|
||
|
|
||
|
// p[0] = ((int)tr.endpos[0] + 8) & (~16);
|
||
|
// p[1] = ((int)tr.endpos[1] + 8) & (~16);
|
||
|
p[0] = tr.endpos[0];
|
||
|
p[1] = tr.endpos[1];
|
||
|
p[2] = floor(tr.endpos[2]+player->mins[2]);
|
||
|
|
||
|
bestDist = INFINITE;
|
||
|
bestSurf = -1;
|
||
|
|
||
|
for ( n = 0; n < surfaceCount; n++ ) {
|
||
|
if ( Q_fabs( surface[n].origin[2] - p[2] ) > 24 ) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
VectorSubtract( p, surface[n].origin, v );
|
||
|
dist = VectorLength( v );
|
||
|
if ( dist < bestDist ) {
|
||
|
bestDist = dist;
|
||
|
bestSurf = n;
|
||
|
}
|
||
|
|
||
|
if ( surface[n].origin[2] != p[2] ) {
|
||
|
continue;
|
||
|
}
|
||
|
if ( surface[n].absmin[0] > p[0] ) {
|
||
|
continue;
|
||
|
}
|
||
|
if ( surface[n].absmax[0] < p[0] ) {
|
||
|
continue;
|
||
|
}
|
||
|
if ( surface[n].absmin[1] > p[1] ) {
|
||
|
continue;
|
||
|
}
|
||
|
if ( surface[n].absmax[1] < p[1] ) {
|
||
|
continue;
|
||
|
}
|
||
|
return n;
|
||
|
}
|
||
|
|
||
|
// gi.Printf( "guess for %s at %s\n", ent->classname, vtos( p ) );
|
||
|
return bestSurf;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
=============
|
||
|
Nav_GroundSurfaceNumber
|
||
|
|
||
|
Returns the surface number for where an entity is currently located.
|
||
|
If the entity is not on the ground, it returns -1.
|
||
|
|
||
|
FIXME we can make this more efficient
|
||
|
right now surfaces are in Z sorted order
|
||
|
we could make a Z index and binary search it to get to right z group fast
|
||
|
=============
|
||
|
*/
|
||
|
int Nav_GroundSurfaceNumber( gentity_t *ent ) {
|
||
|
vec3_t p;
|
||
|
vec3_t v;
|
||
|
int n;
|
||
|
float dist;
|
||
|
float bestDist;
|
||
|
int bestSurf;
|
||
|
gentity_t *groundEntity;
|
||
|
|
||
|
// if ent is not on the ground it is not on a surface
|
||
|
if ( ent->s.groundEntityNum == -1 ) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
// p[0] = ((int)ent->s.origin[0] + 8) & (~16);
|
||
|
// p[1] = ((int)ent->s.origin[1] + 8) & (~16);
|
||
|
p[0] = ent->s.origin[0];
|
||
|
p[1] = ent->s.origin[1];
|
||
|
p[2] = floor(ent->s.origin[2]+ent->mins[2]);
|
||
|
|
||
|
// if ground is not the world we need to handle it differently.
|
||
|
if ( ent->s.groundEntityNum != ENTITYNUM_WORLD ) {
|
||
|
groundEntity = &g_entities[ent->s.groundEntityNum];
|
||
|
|
||
|
// check for sitting on a spawn pad
|
||
|
if ( !groundEntity->bmodel && groundEntity->s.modelindex == spawnpadModelIndex ) {
|
||
|
p[2] -= 8.0;
|
||
|
}
|
||
|
// check for plats
|
||
|
/* else if ( groundEntity->bmodel && Q_stricmp( groundEntity->classname, "func_plat" ) == 0 ) {
|
||
|
// if at the top the return PLATHIGH surface number, otherwise return PLATLOW surface number
|
||
|
if ( VectorCompare( groundEntity->currentOrigin, groundEntity->pos2 ) ) {
|
||
|
return surface[groundEntity->navSurfaceNum].parm;
|
||
|
}
|
||
|
return groundEntity->navSurfaceNum;
|
||
|
} */
|
||
|
}
|
||
|
|
||
|
bestDist = INFINITE;
|
||
|
bestSurf = -1;
|
||
|
|
||
|
for ( n = 0; n < surfaceCount; n++ ) {
|
||
|
if ( Q_fabs( surface[n].origin[2] - p[2] ) > 24 ) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
VectorSubtract( p, surface[n].origin, v );
|
||
|
dist = VectorLength( v );
|
||
|
if ( dist < bestDist ) {
|
||
|
bestDist = dist;
|
||
|
bestSurf = n;
|
||
|
}
|
||
|
|
||
|
if ( surface[n].origin[2] != p[2] ) {
|
||
|
continue;
|
||
|
}
|
||
|
if ( surface[n].absmin[0] > p[0] ) {
|
||
|
continue;
|
||
|
}
|
||
|
if ( surface[n].absmax[0] < p[0] ) {
|
||
|
continue;
|
||
|
}
|
||
|
if ( surface[n].absmin[1] > p[1] ) {
|
||
|
continue;
|
||
|
}
|
||
|
if ( surface[n].absmax[1] < p[1] ) {
|
||
|
continue;
|
||
|
}
|
||
|
return n;
|
||
|
}
|
||
|
|
||
|
// gi.Printf( "guess for %s at %s\n", ent->classname, vtos( p ) );
|
||
|
return bestSurf;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
=============
|
||
|
Nav_ItemSurfaceNumber
|
||
|
|
||
|
Returns the surface number for where an item entity is currently located.
|
||
|
If the entity is not on the ground, it returns -1. This is a specialized
|
||
|
copy of Nav_GroundSurfaceNumber for items that caches the result.
|
||
|
=============
|
||
|
*/
|
||
|
int Nav_ItemSurfaceNumber( gentity_t *ent ) {
|
||
|
if ( !VectorCompare( ent->s.origin, ent->navOrigin ) && level.time > ent->navTime ) {
|
||
|
VectorCopy( ent->s.origin, ent->navOrigin );
|
||
|
ent->navTime = level.time;
|
||
|
ent->navSurfaceNum = Nav_GroundSurfaceNumber( ent );
|
||
|
}
|
||
|
return ent->navSurfaceNum;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
=============
|
||
|
Nav_EntitySurfaceNumber
|
||
|
=============
|
||
|
*/
|
||
|
int Nav_EntitySurfaceNumber( gentity_t *ent ) {
|
||
|
if ( ent->s.eType == ET_ITEM ) {
|
||
|
return Nav_ItemSurfaceNumber( ent );
|
||
|
}
|
||
|
|
||
|
/*if ( ent->classname&& strcmp( ent->classname, "bot_goal" ) == 0 ) {
|
||
|
return Nav_SurfaceUnderPlayer( ent );
|
||
|
}*/
|
||
|
|
||
|
return Nav_GroundSurfaceNumber( ent );
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
=============
|
||
|
PathEdge
|
||
|
=============
|
||
|
*/
|
||
|
|
||
|
static nneighbor_t *PathEdge( int sourceSurfNum, int destSurfNum ) {
|
||
|
int base;
|
||
|
int n;
|
||
|
|
||
|
base = surface[sourceSurfNum].neighborIndex;
|
||
|
for ( n = 0; n < surface[sourceSurfNum].neighborCount; n++ ) {
|
||
|
if ( neighbor[base+n].surfaceNum == destSurfNum ) {
|
||
|
return &neighbor[base+n];
|
||
|
}
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
=============
|
||
|
PointIsInEdgeRegion
|
||
|
=============
|
||
|
*/
|
||
|
|
||
|
static qboolean PointIsInEdgeRegion( vec3_t p, nneighbor_t *n ) {
|
||
|
if ( p[0] < n->absmin[0] ) {
|
||
|
return qfalse;
|
||
|
}
|
||
|
if ( p[0] > n->absmax[0] ) {
|
||
|
return qfalse;
|
||
|
}
|
||
|
if ( p[1] < n->absmin[1] ) {
|
||
|
return qfalse;
|
||
|
}
|
||
|
if ( p[1] > n->absmax[1] ) {
|
||
|
return qfalse;
|
||
|
}
|
||
|
return qtrue;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
=============
|
||
|
Nav_MoveToGoal
|
||
|
=============
|
||
|
*/
|
||
|
|
||
|
int Nav_MoveToGoal( gentity_t *bot, vec3_t dir, int *flags ) {
|
||
|
int currentSurf;
|
||
|
int nextSurf;
|
||
|
int thirdSurf;
|
||
|
int goalSurf;
|
||
|
int routeIndex;
|
||
|
nneighbor_t *edge;
|
||
|
nneighbor_t *nextEdge;
|
||
|
//gentity_t *ent;
|
||
|
//float dist;
|
||
|
|
||
|
*flags = 0;
|
||
|
VectorCopy( bot->navDir, dir );
|
||
|
|
||
|
currentSurf = bot->currentSurface;
|
||
|
|
||
|
// if bot is airborne, just keep heading the same
|
||
|
if ( currentSurf == -1 ) {
|
||
|
if ( bot->aiFlags & BOTAI_PUSHED ) {
|
||
|
//gi.Printf( "bot was bounced\n" );
|
||
|
*flags |= NAVF_HOLD;
|
||
|
}
|
||
|
//gi.Printf( "not on ground\n" );
|
||
|
return 0;
|
||
|
}
|
||
|
if ( bot->pushedTime < level.time ) {
|
||
|
bot->aiFlags &= ~BOTAI_PUSHED;
|
||
|
}
|
||
|
|
||
|
if ( !bot->goalEntity ) {
|
||
|
// gi.Printf( ERROR "Nav_MoveToGoal called with no goalEntity set\n" );
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
goalSurf = Nav_EntitySurfaceNumber( bot->goalEntity );
|
||
|
if ( goalSurf == -1 ) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
// if we've changed surfaces, the surface to surface navigation flags and timer need to be cleared
|
||
|
if ( currentSurf != bot->lastSurface ) {
|
||
|
bot->navFlags = 0;
|
||
|
bot->navTime = 0;
|
||
|
//gi.Printf( "surface changed from %i to %i\n", bot->bot->lastSurface, bot->bot->currentSurface );
|
||
|
}
|
||
|
|
||
|
if ( currentSurf == goalSurf ) {
|
||
|
//gi.Printf( "On target surface\n" );
|
||
|
VectorSubtract( bot->goalEntity->s.origin, bot->s.origin, dir );
|
||
|
//VectorCopy( dir, bot->bot->navDir );
|
||
|
VectorCopy( dir, bot->navDir );
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
routeIndex = route[currentSurf * surfaceCount + goalSurf];
|
||
|
if ( routeIndex == 255 ) {
|
||
|
//gi.Printf( "Nav_MoveToGoal - no known route from %i to %i\n", currentSurf, goalSurf );
|
||
|
return -1;
|
||
|
}
|
||
|
if ( routeIndex >= surface[currentSurf].neighborCount ) {
|
||
|
gi.Printf( ERROR "Nav_MoveToGoal - bad routeIndex\n" );
|
||
|
return -1;
|
||
|
}
|
||
|
nextSurf = neighbor[surface[currentSurf].neighborIndex + routeIndex].surfaceNum;
|
||
|
|
||
|
edge = PathEdge( currentSurf, nextSurf );
|
||
|
if ( !edge ) {
|
||
|
gi.Printf( ERROR "Nav_MoveToGoal - %i does not have %i as a neighbor\n", currentSurf, nextSurf );
|
||
|
VectorClear( dir );
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if ( ! ( bot->navFlags & NAVF_EDGEZONE ) ) {
|
||
|
if ( PointIsInEdgeRegion( bot->s.origin, edge ) ) {
|
||
|
//gi.Printf( "hit edge\n" );
|
||
|
bot->navFlags |= NAVF_EDGEZONE;
|
||
|
bot->navTime = level.time;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// if we are in the edge zone
|
||
|
if ( bot->navFlags & NAVF_EDGEZONE ) {
|
||
|
// if we're trying to get onto a plat, we must make sure it's there
|
||
|
/*if ( surface[nextSurf].flags & SF_PLATLOW ) {
|
||
|
ent = &g_entities[surface[surface[nextSurf].parm].parm]; //FIXME this works for now, but I don't like it
|
||
|
if ( VectorCompare( ent->currentOrigin, ent->pos1 ) == 0 ) {
|
||
|
*flags |= NAVF_HOLD;
|
||
|
//gi.Printf(" wait for plat2\n" );
|
||
|
}
|
||
|
}*/
|
||
|
|
||
|
// if we're riding up on a plat, we don't need to move
|
||
|
if ( surface[nextSurf].flags & SF_PLATHIGH ) {
|
||
|
*flags |= NAVF_HOLD;
|
||
|
//gi.Printf(" hold on plat\n" );
|
||
|
}
|
||
|
|
||
|
// if the next surface contains the goalEntity, head towards it
|
||
|
if ( nextSurf == goalSurf ) {
|
||
|
//gi.Printf( "next surf has goal - targeting directly\n" );
|
||
|
VectorSubtract( bot->goalEntity->s.origin, bot->s.origin, dir );
|
||
|
//VectorCopy( dir, bot->bot->navDir );
|
||
|
VectorCopy( dir, bot->navDir );
|
||
|
}
|
||
|
// start heading towards the next edge
|
||
|
else {
|
||
|
routeIndex = route[nextSurf * surfaceCount + goalSurf];
|
||
|
if ( routeIndex == 255 ) {
|
||
|
gi.Printf( ERROR "Nav_MoveToGoal - no known route from %i to %i\n", nextSurf, goalSurf );
|
||
|
return -1;
|
||
|
}
|
||
|
if ( routeIndex >= surface[nextSurf].neighborCount ) {
|
||
|
gi.Printf( ERROR "Nav_MoveToGoal - bad routeIndex\n" );
|
||
|
return -1;
|
||
|
}
|
||
|
thirdSurf = neighbor[surface[nextSurf].neighborIndex + routeIndex].surfaceNum;
|
||
|
nextEdge = PathEdge( nextSurf, thirdSurf );
|
||
|
if ( !nextEdge ) {
|
||
|
gi.Printf( ERROR "Nav_MoveToGoal - %i does not have %i as a neighbor\n", nextSurf, thirdSurf );
|
||
|
VectorClear( dir );
|
||
|
return -1;
|
||
|
}
|
||
|
//gi.Printf( "targeting next edge\n" );
|
||
|
if ( surface[nextSurf].flags & SF_PLATHIGH ) {
|
||
|
VectorSubtract( nextEdge->origin, surface[nextSurf].origin, dir );
|
||
|
}
|
||
|
else {
|
||
|
VectorSubtract( nextEdge->origin, bot->s.origin, dir );
|
||
|
}
|
||
|
//VectorCopy( dir, bot->bot->navDir );
|
||
|
VectorCopy( dir, bot->navDir );
|
||
|
}
|
||
|
|
||
|
if ( edge->flags & NF_DUCK ) {
|
||
|
*flags |= NAVF_DUCK;
|
||
|
}
|
||
|
if ( edge->flags & NF_JUMP ) {
|
||
|
*flags |= NAVF_JUMP;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
VectorSubtract( edge->origin, bot->s.origin, dir );
|
||
|
//VectorCopy( dir, bot->bot->navDir );
|
||
|
VectorCopy( dir, bot->navDir );
|
||
|
|
||
|
/*if ( surface[nextSurf].flags & SF_PLATLOW ) {
|
||
|
ent = &g_entities[surface[surface[nextSurf].parm].parm]; //FIXME this works for now, but I don't like it
|
||
|
if ( VectorCompare( ent->currentOrigin, ent->pos1 ) == 0 ) {
|
||
|
dist = VectorLength( dir );
|
||
|
if ( dist > 64 ) {
|
||
|
*flags |= NAVF_SLOW;
|
||
|
//gi.Printf(" slow for plat\n" );
|
||
|
}
|
||
|
else {
|
||
|
*flags |= NAVF_HOLD;
|
||
|
//gi.Printf(" wait for plat\n" );
|
||
|
}
|
||
|
}
|
||
|
}*/
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
void Nav_ShowPath( gentity_t *bot ) {
|
||
|
#if 0
|
||
|
gentity_t *tent;
|
||
|
int m, n;
|
||
|
|
||
|
if ( !bot->bot->goalEntity ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
tent = G_TempEntity( bot->s.origin, EV_DEBUG_LINE );
|
||
|
VectorCopy( bot->bot->currentWaypoint->s.origin, tent->s.origin2 );
|
||
|
|
||
|
m = bot->bot->currentWaypoint->count;
|
||
|
for (;;) {
|
||
|
if ( m == bot->bot->finalWaypoint->count ) {
|
||
|
break;
|
||
|
}
|
||
|
n = route[m*maxwaypoints+bot->bot->finalWaypoint->count];
|
||
|
if ( n == -1 ) {
|
||
|
break;
|
||
|
}
|
||
|
tent = G_TempEntity( rents[m]->s.origin, EV_DEBUG_LINE );
|
||
|
VectorCopy( rents[n]->s.origin, tent->s.origin2 );
|
||
|
m = n;
|
||
|
}
|
||
|
|
||
|
if ( bot->bot->finalWaypoint != bot->bot->goalEntity ) {
|
||
|
tent = G_TempEntity( bot->bot->finalWaypoint->s.origin, EV_DEBUG_LINE );
|
||
|
VectorCopy( bot->bot->goalEntity->s.origin, tent->s.origin2 );
|
||
|
}
|
||
|
#endif
|
||
|
/* gentity_t *tent;
|
||
|
int m, n;
|
||
|
gentity_t *player;
|
||
|
int pSurf;
|
||
|
|
||
|
player = &g_entities[1];
|
||
|
pSurf = Nav_GroundSurfaceNumber( player );
|
||
|
|
||
|
tent = G_TempEntity( player->s.origin, EV_DEBUG_LINE );
|
||
|
VectorCopy( surface[pSurf].origin, tent->s.origin2 ); */
|
||
|
}
|
||
|
//#endif
|
||
|
|
||
|
|
||
|
/*
|
||
|
// Init and Shutdown
|
||
|
//
|
||
|
//
|
||
|
*/
|
||
|
|
||
|
static void Nav_Cleanup( void ) {
|
||
|
if ( navFileData ) {
|
||
|
gi.FS_FreeFile ( navFileData );
|
||
|
navFileData = NULL;
|
||
|
}
|
||
|
surfaceCount = 0;
|
||
|
neighborCount = 0;
|
||
|
}
|
||
|
|
||
|
void Nav_InitPreSpawn( void ) {
|
||
|
nav_showsectors = gi.cvar( "nav_showsectors", "0", 0 );
|
||
|
Nav_Cleanup();
|
||
|
Nav_LoadRoutes();
|
||
|
}
|
||
|
|
||
|
void Nav_InitPostSpawn( void ) {
|
||
|
#if 0
|
||
|
int n;
|
||
|
nsurface_t *s;
|
||
|
gentity_t *ent;
|
||
|
|
||
|
// FIXME resolve targetnames here (like button needed to open a door)
|
||
|
|
||
|
// get the modelindex for the spawnpad model so we can use it for surface determination
|
||
|
spawnpadModelIndex = G_ModelIndex( "models/objects/dmspot.md3" );
|
||
|
|
||
|
// set the navSurface for plats
|
||
|
for ( n = 0; n < surfaceCount; n++ ) {
|
||
|
s = &surface[n];
|
||
|
if ( s->flags & SF_PLATLOW ) {
|
||
|
ent = &g_entities[surface[s->parm].parm]; //FIXME this works for now, but I don't like it
|
||
|
ent->navSurfaceNum = n;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
void Nav_Shutdown ( void ) {
|
||
|
Nav_Cleanup();
|
||
|
}
|
||
|
|
||
|
void Nav_Test_f( void ) {
|
||
|
#if 0
|
||
|
gentity_t *player;
|
||
|
gentity_t *goal;
|
||
|
char *goalname;
|
||
|
int pSurf;
|
||
|
int gSurf;
|
||
|
int cSurf;
|
||
|
int n;
|
||
|
gentity_t *tent;
|
||
|
|
||
|
player = &g_entities[0];
|
||
|
pSurf = Nav_GroundSurfaceNumber( player );
|
||
|
|
||
|
goalname = gi.argv(2);
|
||
|
if ( !goalname[0] ) {
|
||
|
gi.Printf( "Player1 is at (%f, %f, %f) on surface %i\n", player->s.origin[0], player->s.origin[1], player->s.origin[2] + player->mins[2], pSurf );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
goal = NULL;
|
||
|
goal = G_Find( goal, FOFS( classname ), goalname );
|
||
|
if ( !goal ) {
|
||
|
gi.Printf( "no %s on level\n", goalname );
|
||
|
return;
|
||
|
}
|
||
|
gSurf = Nav_EntitySurfaceNumber( goal );
|
||
|
|
||
|
|
||
|
cSurf = pSurf;
|
||
|
while ( cSurf != gSurf ) {
|
||
|
n = route[cSurf * surfaceCount + gSurf];
|
||
|
if ( n == 255 ) {
|
||
|
//gi.Printf( "no known route from %i to %i\n", cSurf, gSurf );
|
||
|
return;
|
||
|
}
|
||
|
if ( n >= surface[cSurf].neighborCount ) {
|
||
|
gi.Printf( ERROR "bad routeIndex\n" );
|
||
|
return;
|
||
|
}
|
||
|
n = neighbor[surface[cSurf].neighborIndex + n].surfaceNum;
|
||
|
|
||
|
if ( cSurf == pSurf ) {
|
||
|
tent = G_TempEntity( player->s.origin, EV_DEBUG_LINE );
|
||
|
}
|
||
|
else {
|
||
|
tent = G_TempEntity( surface[cSurf].origin, EV_DEBUG_LINE );
|
||
|
}
|
||
|
if ( n == gSurf ) {
|
||
|
VectorCopy( goal->s.origin, tent->s.origin2 );
|
||
|
}
|
||
|
else {
|
||
|
VectorCopy( surface[n].origin, tent->s.origin2 );
|
||
|
}
|
||
|
|
||
|
cSurf = n;
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void Nav_Gen_f( void );
|
||
|
|
||
|
void Cmd_Nav_f( void )
|
||
|
{
|
||
|
char *cmd;
|
||
|
|
||
|
cmd = gi.argv(1);
|
||
|
|
||
|
if ( Q_stricmp ( cmd, "gen" ) == 0 ) {
|
||
|
Nav_Gen_f();
|
||
|
Nav_InitPreSpawn();
|
||
|
}
|
||
|
else if ( Q_stricmp ( cmd, "test" ) == 0 ) {
|
||
|
Nav_Test_f();
|
||
|
}
|
||
|
else {
|
||
|
gi.Printf("Unknown nav command '%s'\n", cmd);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Nav_ShowStuff
|
||
|
(
|
||
|
void
|
||
|
)
|
||
|
|
||
|
{
|
||
|
int i;
|
||
|
nsurface_t *surf;
|
||
|
|
||
|
if ( !nav_showsectors->integer )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
G_Color4f( 1, 1, 0, 1 );
|
||
|
for( i = 0; i < surfaceCount; i++ )
|
||
|
{
|
||
|
surf = &surface[ i ];
|
||
|
|
||
|
G_BeginLine();
|
||
|
G_Vertex( Vector( surf->absmin[ 0 ], surf->absmin[ 1 ], surf->origin[ 2 ] ) );
|
||
|
G_Vertex( Vector( surf->absmin[ 0 ], surf->absmax[ 1 ], surf->origin[ 2 ] ) );
|
||
|
G_Vertex( Vector( surf->absmax[ 0 ], surf->absmax[ 1 ], surf->origin[ 2 ] ) );
|
||
|
G_Vertex( Vector( surf->absmax[ 0 ], surf->absmin[ 1 ], surf->origin[ 2 ] ) );
|
||
|
G_Vertex( Vector( surf->absmin[ 0 ], surf->absmin[ 1 ], surf->origin[ 2 ] ) );
|
||
|
G_EndLine();
|
||
|
}
|
||
|
}
|