Add info_node and info_node_air support for navigation.

This commit is contained in:
Julian
2020-02-29 22:23:44 -03:00
parent b22f0d1e89
commit f7865ef24e
6 changed files with 422 additions and 108 deletions

View File

@@ -609,3 +609,42 @@ template <class T> T * CreateClassPtr( T *a )
return a; return a;
} }
//
// Converts a entvars_t * to a class pointer
// It will allocate the class and entity
// Use this for non-monsters entities
//
// WARNING: This does not check for free edicts!
//
template <class T> T * CreateNormalClassPtr( T *a )
{
entvars_t *pev = (entvars_t *)a;
if (pev != NULL)
return NULL; // don't allocate if pointer already provided
// allocate entity...
edict_t *temp_edict;
int edict_index;
// allocate private data
a = new T;
if ((temp_edict = a->CreateEntity("info_target")) == NULL)
{
(*g_engfuncs.pfnServerPrint)("[MONSTER] ERROR: NULL Ent in CreateNormalClassPtr!\n" );
delete a;
return NULL;
}
edict_index = (*g_engfuncs.pfnIndexOfEdict)(temp_edict);
// store the class pointer to the edict pev...
pev = VARS(temp_edict);
a->pev = pev;
// get the private data
a = (T *)pev->euser4;
return a;
}

View File

@@ -48,6 +48,9 @@
#include "decals.h" #include "decals.h"
#include "shake.h" #include "shake.h"
#include "skill.h" #include "skill.h"
#include "nodes.h"
extern CGraph WorldGraph;
extern globalvars_t *gpGlobals; extern globalvars_t *gpGlobals;
extern enginefuncs_t g_engfuncs; extern enginefuncs_t g_engfuncs;
@@ -108,7 +111,12 @@ monster_type_t monster_types[]=
// These are just names. But to keep it consistent // These are just names. But to keep it consistent
// with the new KVD format, ensure these are exactly // with the new KVD format, ensure these are exactly
// like an actual, entity classname. // like an actual, entity classname.
"monster_alien_grunt", FALSE,
// We are going to use this as a list of what entities
// can be spawned. Monsters should go first.
// DO NOT ALTER THE ORDER OF ELEMENTS!
"monster_alien_grunt", FALSE, // Monsters
"monster_apache", FALSE, "monster_apache", FALSE,
"monster_barney", FALSE, "monster_barney", FALSE,
"monster_bigmomma", FALSE, "monster_bigmomma", FALSE,
@@ -122,6 +130,8 @@ monster_type_t monster_types[]=
"monster_scientist", FALSE, "monster_scientist", FALSE,
"monster_snark", FALSE, "monster_snark", FALSE,
"monster_zombie", FALSE, "monster_zombie", FALSE,
"info_node", FALSE, // Nodes
"info_node_air", FALSE,
"", FALSE "", FALSE
}; };
@@ -131,6 +141,9 @@ int monster_ents_used = 0;
monster_spawnpoint_t monster_spawnpoint[MAX_MONSTERS]; monster_spawnpoint_t monster_spawnpoint[MAX_MONSTERS];
int monster_spawn_count = 0; int monster_spawn_count = 0;
node_spawnpoint_t node_spawnpoint[MAX_NODES];
int node_spawn_count = 0;
float check_respawn_time; float check_respawn_time;
bool process_monster_cfg(void); bool process_monster_cfg(void);
@@ -779,6 +792,102 @@ void MonsterCommand(void)
} }
} }
void SpawnViewerCommand(void)
{
int index;
// debug command to spawn a node_viewer at a player's location
if (CMD_ARGC() >= 2)
{
// check for a valid player name or index...
const char *parg2 = CMD_ARGV(1);
int player_index = -1;
edict_t *pPlayer;
const char *player_name;
if (*parg2 == '#') // player index
{
if (sscanf(&parg2[1], "%d", &player_index) != 1)
player_index = -1;
if ((player_index < 1) || (player_index > gpGlobals->maxClients))
{
//META_CONS("[MONSTER] invalid player index! (%d to %d allowed)", 1, gpGlobals->maxClients);
LOG_MESSAGE(PLID, "invalid player index! (%d to %d allowed)", 1, gpGlobals->maxClients);
player_index = -1;
return;
}
}
else
{
for (index = 1; index <= gpGlobals->maxClients; index++)
{
pPlayer = INDEXENT(index);
if (pPlayer && !pPlayer->free)
{
if (stricmp(STRING(pPlayer->v.netname), parg2) == 0)
{
player_index = index; // found the matching player name
break;
}
}
}
if (player_index == -1)
{
//META_CONS("[MONSTER] can't find player named \"%s\"!", parg2);
LOG_MESSAGE(PLID, "can't find player named \"%s\"!", parg2);
return;
}
}
if (player_index != -1)
{
pPlayer = INDEXENT(player_index);
if ((pPlayer == NULL) || (pPlayer->free))
{
//META_CONS("[MONSTER] player index %d is not a valid player!", player_index);
LOG_MESSAGE(PLID, "player index %d is not a valid player!", player_index);
return;
}
player_name = STRING(pPlayer->v.netname);
if (player_name[0] == 0)
{
//META_CONS("[MONSTER] player index %d is not a valid player!", player_index);
LOG_MESSAGE(PLID, "player index %d is not a valid player!", player_index);
return;
}
if (!UTIL_IsAlive(pPlayer))
{
//META_CONS("[MONSTER] player \"%s\" is not alive or is an observer!", player_name);
LOG_MESSAGE(PLID, "player \"%s\" is not alive or is an observer!", player_name);
return;
}
Vector origin = pPlayer->v.origin;
CMBaseEntity *pViewer = CreateClassPtr((CNodeViewer *)NULL);
if (pViewer == NULL)
{
//META_CONS("[MONSTER] ERROR: Error Creating Node!" );
LOG_MESSAGE(PLID, "ERROR: Error Creating Viewer!");
return;
}
pViewer->pev->origin = origin;
pViewer->Spawn();
return;
}
}
LOG_MESSAGE(PLID, "usage: node_viewer player_name | #player_index");
LOG_MESSAGE(PLID, "spawns a node viewer at the player's location");
}
void mmGameDLLInit( void ) void mmGameDLLInit( void )
{ {
@@ -810,13 +919,39 @@ int mmDispatchSpawn( edict_t *pent )
world_precache(); world_precache();
monster_spawn_count = 0; monster_spawn_count = 0;
node_spawn_count = 0;
monster_skill_init(); monster_skill_init();
process_monster_precache_cfg(); process_monster_precache_cfg();
process_monster_cfg(); process_monster_cfg();
// node support. -Giegue
// init the WorldGraph.
WorldGraph.InitGraph();
// make sure the .NOD file is newer than the .BSP file.
if ( !WorldGraph.CheckNODFile ( ( char * )STRING( gpGlobals->mapname ) ) )
{
// NOD file is not present, or is older than the BSP file.
WorldGraph.AllocNodes();
}
else
{
// Load the node graph for this level
if ( !WorldGraph.FLoadGraph ( (char *)STRING( gpGlobals->mapname ) ) )
{
// couldn't load, so alloc and prepare to build a graph.
ALERT ( at_console, "*Error opening .NOD file\n" );
WorldGraph.AllocNodes();
}
else
{
ALERT ( at_console, "\n*Graph Loaded!\n" );
}
}
check_respawn_time = 0.0; check_respawn_time = 0.0;
for (index = 0; index < MAX_MONSTER_ENTS; index++) for (index = 0; index < MAX_MONSTER_ENTS; index++)
@@ -850,7 +985,21 @@ void mmDispatchThink( edict_t *pent )
RETURN_META(MRES_SUPERCEDE); RETURN_META(MRES_SUPERCEDE);
} }
} }
// Manually call think on these other entities
if (FClassnameIs( pent, "testhull" ))
{
// Ensure you do think...
CMBaseEntity::Instance(pent)->Think();
RETURN_META(MRES_SUPERCEDE);
}
if (FClassnameIs( pent, "node_viewer" ))
{
CMBaseEntity::Instance(pent)->Think();
RETURN_META(MRES_SUPERCEDE);
}
RETURN_META(MRES_IGNORED); RETURN_META(MRES_IGNORED);
} }
// HACKHACK -- this is a hack to keep the node graph entity from "touching" things (like triggers) // HACKHACK -- this is a hack to keep the node graph entity from "touching" things (like triggers)
@@ -899,6 +1048,7 @@ void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
g_psv_gravity = CVAR_GET_POINTER( "sv_gravity" ); g_psv_gravity = CVAR_GET_POINTER( "sv_gravity" );
(g_engfuncs.pfnAddServerCommand)("monster", MonsterCommand); (g_engfuncs.pfnAddServerCommand)("monster", MonsterCommand);
(g_engfuncs.pfnAddServerCommand)("node_viewer", SpawnViewerCommand);
for (index = 0; monster_types[index].name[0]; index++) for (index = 0; monster_types[index].name[0]; index++)
{ {
@@ -938,7 +1088,31 @@ void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
} }
monster_ents_used = 0; monster_ents_used = 0;
// spawn nodes
for (index = 0; index < node_spawn_count; index++)
{
CMBaseEntity *pNode;
pNode = CreateNormalClassPtr((CNodeEnt *)NULL);
if (pNode == NULL)
{
//META_CONS("[MONSTER] ERROR: Error Creating Node!" );
LOG_MESSAGE(PLID, "ERROR: Error Creating Node!");
}
else
{
pNode->pev->origin = node_spawnpoint[index].origin;
if (node_spawnpoint[index].is_air_node)
pNode->pev->classname = MAKE_STRING("info_node_air");
else
pNode->pev->classname = MAKE_STRING("info_node");
pNode->Spawn();
}
}
RETURN_META(MRES_IGNORED); RETURN_META(MRES_IGNORED);
} }

View File

@@ -18,7 +18,7 @@ extern cvar_t *dllapi_log;
extern monster_type_t monster_types[]; extern monster_type_t monster_types[];
extern int monster_spawn_count; extern int monster_spawn_count;
extern int node_spawn_count;
bool get_input(FILE *fp, char *input) bool get_input(FILE *fp, char *input)
{ {
@@ -72,9 +72,11 @@ void scan_monster_cfg(FILE *fp)
// Let's make a full rework of this. -Giegue // Let's make a full rework of this. -Giegue
char input[1024]; char input[1024];
float x, y, z; float x, y, z;
bool badent, monster, node;
while (get_input(fp, input)) while (get_input(fp, input))
{ {
badent = monster = node = FALSE;
if (input[0] == '{') if (input[0] == '{')
{ {
// Proper start, initialize entity creation // Proper start, initialize entity creation
@@ -86,88 +88,167 @@ void scan_monster_cfg(FILE *fp)
// It's the end of the entity structure? // It's the end of the entity structure?
if (input[0] == '}') if (input[0] == '}')
{ {
// Done. Let's process the keyvalues. // Check if the classname of whatever we want to spawn is valid.
for (int i = 0; i < kvd_index; i++) if (strcmp(data[kvd_index-1].key, "classname") == 0)
{ {
float x, y, z; int mIndex;
// Any unknown keyvalue is ignored. for (mIndex = 0; monster_types[mIndex].name[0]; mIndex++)
// Any duplicate keyvalue is overwritten.
if (strcmp(data[i].key, "origin") == 0)
{ {
if (sscanf(data[i].value, "%f %f %f", &x, &y, &z) != 3) if (strcmp(data[kvd_index-1].value, monster_types[mIndex].name) == 0)
{ {
LOG_MESSAGE(PLID, "ERROR: invalid origin: %s", input); // print conflictive line // Now that I think about it this looks slow and bad code >.>
// reset origin to g_vecZero // A match is found. What is this?
LOG_MESSAGE(PLID, "ERROR: entity will spawn at 0 0 0"); if (strncmp(monster_types[mIndex].name, "monster", 7) == 0)
x = y = z = 0;
}
monster_spawnpoint[monster_spawn_count].origin[0] = x;
monster_spawnpoint[monster_spawn_count].origin[1] = y;
monster_spawnpoint[monster_spawn_count].origin[2] = z;
}
else if (strcmp(data[i].key, "delay") == 0)
{
// ToDo: Remove this keyvalue.
// Monsters spawned directly should not respawn.
if (sscanf(data[i].value, "%f", &x) != 1)
{
LOG_MESSAGE(PLID, "ERROR: invalid delay: %s", input); // print conflictive line
// default to 30 seconds
LOG_MESSAGE(PLID, "ERROR: entity respawn frequency will be set to 30 seconds");
x = 30;
}
monster_spawnpoint[monster_spawn_count].delay = x;
}
else if (strcmp(data[i].key, "angles") == 0)
{
if (sscanf(data[i].value, "%f %f %f", &x, &y, &z) != 3)
{
LOG_MESSAGE(PLID, "ERROR: invalid angles: %s", input); // print conflictive line
// reset angles to g_vecZero
LOG_MESSAGE(PLID, "ERROR: entity angles will be set to 0 0 0");
x = y = z = 0;
}
monster_spawnpoint[monster_spawn_count].angles[0] = x;
monster_spawnpoint[monster_spawn_count].angles[1] = y;
monster_spawnpoint[monster_spawn_count].angles[2] = z;
}
else if (strcmp(data[i].key, "classname") == 0)
{
int mIndex;
for (mIndex = 0; monster_types[mIndex].name[0]; mIndex++)
{
if (strcmp(data[i].value, monster_types[mIndex].name) == 0)
{ {
monster_spawnpoint[monster_spawn_count].monster = mIndex; // It's a monster, add it to the list
monster_types[mIndex].need_to_precache = TRUE; if (monster_spawn_count == MAX_MONSTERS)
break; {
// Ouch! Not enough room.
LOG_MESSAGE(PLID, "ERROR: can't add monster, reached MAX_MONSTERS!"); // It will get spammy, sadly.
badent = TRUE;
}
else
{
monster_spawnpoint[monster_spawn_count].monster = mIndex;
monster_types[mIndex].need_to_precache = TRUE;
monster = TRUE;
}
}
else if (strcmp(monster_types[mIndex].name, "info_node") == 0)
{
// Normal node
if (node_spawn_count == MAX_NODES)
{
// The map can't be THAT big can it?
LOG_MESSAGE(PLID, "ERROR: can't add node, reached MAX_NODES!"); // zee spam bOi
badent = TRUE;
}
else
node = TRUE;
}
else if (strcmp(monster_types[mIndex].name, "info_node_air") == 0)
{
// Aerial node
if (node_spawn_count == MAX_NODES)
{
// Ctrl+C --> Ctrl+V
LOG_MESSAGE(PLID, "ERROR: can't add node, reached MAX_NODES!"); // poppo was here.
badent = TRUE;
}
else
{
node_spawnpoint[node_spawn_count].is_air_node = TRUE;
node = TRUE;
}
}
break;
}
}
if (monster_types[mIndex].name[0] == 0)
{
LOG_MESSAGE(PLID, "ERROR: unknown classname: %s", input); // print conflictive line
LOG_MESSAGE(PLID, "ERROR: nothing will spawn here!");
badent = TRUE;
}
}
else
{
// What are you doing?!
LOG_MESSAGE(PLID, "ERROR: BAD ENTITY STRUCTURE! Last line was %s", input); // print conflictive line
LOG_MESSAGE(PLID, "ERROR: nothing will spawn here!");
badent = TRUE;
}
if (!badent)
{
// Done. Let's process the keyvalues.
for (int i = 0; i < (kvd_index-1); i++)
{
// Any unknown keyvalue is ignored.
// Any duplicate keyvalue is overwritten.
if (strcmp(data[i].key, "origin") == 0)
{
if (sscanf(data[i].value, "%f %f %f", &x, &y, &z) != 3)
{
LOG_MESSAGE(PLID, "ERROR: invalid origin: %s", input); // print conflictive line
// reset origin to g_vecZero
LOG_MESSAGE(PLID, "ERROR: entity will spawn at 0 0 0");
x = y = z = 0;
}
if (monster)
{
monster_spawnpoint[monster_spawn_count].origin[0] = x;
monster_spawnpoint[monster_spawn_count].origin[1] = y;
monster_spawnpoint[monster_spawn_count].origin[2] = z;
}
else if (node)
{
node_spawnpoint[node_spawn_count].origin[0] = x;
node_spawnpoint[node_spawn_count].origin[1] = y;
node_spawnpoint[node_spawn_count].origin[2] = z;
} }
} }
if (monster_types[mIndex].name[0] == 0) else if (strcmp(data[i].key, "delay") == 0)
{ {
LOG_MESSAGE(PLID, "ERROR: unknown classname: %s", input); // print conflictive line // ToDo: Remove this keyvalue.
LOG_MESSAGE(PLID, "ERROR: nothing will spawn here!"); // Monsters spawned directly should not respawn.
if (monster)
{
if (sscanf(data[i].value, "%f", &x) != 1)
{
LOG_MESSAGE(PLID, "ERROR: invalid delay: %s", input); // print conflictive line
// default to 30 seconds
LOG_MESSAGE(PLID, "ERROR: entity respawn frequency will be set to 30 seconds");
x = 30;
}
monster_spawnpoint[monster_spawn_count].delay = x;
}
} }
else if (strcmp(data[i].key, "angles") == 0)
{
if (monster)
{
if (sscanf(data[i].value, "%f %f %f", &x, &y, &z) != 3)
{
LOG_MESSAGE(PLID, "ERROR: invalid angles: %s", input); // print conflictive line
// reset angles to g_vecZero
LOG_MESSAGE(PLID, "ERROR: entity angles will be set to 0 0 0");
x = y = z = 0;
}
monster_spawnpoint[monster_spawn_count].angles[0] = x;
monster_spawnpoint[monster_spawn_count].angles[1] = y;
monster_spawnpoint[monster_spawn_count].angles[2] = z;
}
}
}
if (monster)
{
// Init monster
monster_spawnpoint[monster_spawn_count].respawn_time = gpGlobals->time + 0.1; // spawn (nearly) right away
monster_spawnpoint[monster_spawn_count].need_to_respawn = TRUE;
monster_spawn_count++;
}
else if (node)
{
// Increase node count
node_spawn_count++;
}
// Log on? Print all the entities that were added
if (dllapi_log->value)
{
// Classname only, or we will flood the server!
// No, I'm not making this idiotproof. Classname should be the last KVD entry on an entity!
LOG_CONSOLE(PLID, "[DEBUG] Added entity: %s", data[kvd_index-1].value);
} }
} }
// Init monster
monster_spawnpoint[monster_spawn_count].respawn_time = gpGlobals->time + 0.1; // spawn (nearly) right away
monster_spawnpoint[monster_spawn_count].need_to_respawn = TRUE;
// Log on? Print all the entities that were added
if (dllapi_log->value)
{
// Classname only, or we will flood the server!
// No, I'm not making this idiotproof. Classname should be the last KVD entry on an entity!
LOG_CONSOLE(PLID, "[DEBUG] Added entity: %s", data[kvd_index-1].value);
}
monster_spawn_count++;
free( data ); free( data );
break; break;
} }

View File

@@ -40,6 +40,18 @@ typedef struct {
#define MAX_MONSTERS 100 #define MAX_MONSTERS 100
extern monster_spawnpoint_t monster_spawnpoint[MAX_MONSTERS]; extern monster_spawnpoint_t monster_spawnpoint[MAX_MONSTERS];
// this is here to store if a node we want to spawn is an ordinary one, or a flying one
typedef struct
{
Vector origin;
bool is_air_node;
} node_spawnpoint_t;
// nodes.cpp defines 1024 max nodes, but that amount is likely to trigger a
// no free edicts crash if the server num_edicts is low. Increase if needed.
#define MAX_NODES 256
extern node_spawnpoint_t node_spawnpoint[MAX_NODES];
extern DLL_GLOBAL short g_sModelIndexFireball;// holds the index for the fireball extern DLL_GLOBAL short g_sModelIndexFireball;// holds the index for the fireball
extern DLL_GLOBAL short g_sModelIndexSmoke;// holds the index for the smoke cloud extern DLL_GLOBAL short g_sModelIndexSmoke;// holds the index for the smoke cloud
extern DLL_GLOBAL short g_sModelIndexWExplosion;// holds the index for the underwater explosion extern DLL_GLOBAL short g_sModelIndexWExplosion;// holds the index for the underwater explosion

View File

@@ -1452,7 +1452,8 @@ void CTestHull :: Spawn( entvars_t *pevMasterNode )
{ {
SET_MODEL(ENT(pev), "models/player.mdl"); SET_MODEL(ENT(pev), "models/player.mdl");
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
pev->solid = SOLID_SLIDEBOX; pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP; pev->movetype = MOVETYPE_STEP;
pev->effects = 0; pev->effects = 0;
@@ -1474,6 +1475,8 @@ void CTestHull :: Spawn( entvars_t *pevMasterNode )
// UNDONE: Shouldn't we just use EF_NODRAW? This doesn't need to go to the client. // UNDONE: Shouldn't we just use EF_NODRAW? This doesn't need to go to the client.
pev->rendermode = kRenderTransTexture; pev->rendermode = kRenderTransTexture;
pev->renderamt = 0; pev->renderamt = 0;
pev->classname = MAKE_STRING("testhull");
} }
//========================================================= //=========================================================
@@ -1482,13 +1485,15 @@ void CTestHull :: Spawn( entvars_t *pevMasterNode )
//========================================================= //=========================================================
void CTestHull::DropDelay ( void ) void CTestHull::DropDelay ( void )
{ {
UTIL_CenterPrintAll( "Node Graph out of Date. Rebuilding..." ); // Do NOT uncomment or you'll get a "Tried to create a message with a bogus message type ( 0 )" crash!
// Left here only because it's on the original HLSDK, and for comedy purposes. -Giegue
//UTIL_CenterPrintAll( "Node Graph out of Date. Rebuilding..." );
UTIL_SetOrigin ( VARS(pev), WorldGraph.m_pNodes[ 0 ].m_vecOrigin ); UTIL_SetOrigin ( VARS(pev), WorldGraph.m_pNodes[ 0 ].m_vecOrigin );
SetThink ( &CTestHull::CallBuildNodeGraph ); SetThink ( &CTestHull::CallBuildNodeGraph );
pev->nextthink = gpGlobals->time + 1; pev->nextthink = gpGlobals->time + 2; // think called earlier, so add extra second. -Giegue
} }
//========================================================= //=========================================================
@@ -1525,15 +1530,13 @@ void CNodeEnt :: Spawn( void )
return; return;
} }
// Give time to the nodes to spawn and get added to the worldgraph, if ( WorldGraph.m_cNodes == 0 )
// TestHull is spawned after map start, not before. -Giegue
/*if ( WorldGraph.m_cNodes == 0 )
{ {
// this is the first node to spawn, spawn the test hull entity that builds and walks the node tree // this is the first node to spawn, spawn the test hull entity that builds and walks the node tree
CTestHull *pHull = CreateClassPtr((CTestHull *)NULL); CTestHull *pHull = CreateNormalClassPtr((CTestHull *)NULL);
pHull->Spawn( pev ); pHull->Spawn( pev );
}*/ }
if ( WorldGraph.m_cNodes >= MAX_NODES ) if ( WorldGraph.m_cNodes >= MAX_NODES )
{ {
ALERT ( at_aiconsole, "cNodes > MAX_NODES\n" ); ALERT ( at_aiconsole, "cNodes > MAX_NODES\n" );
@@ -1552,7 +1555,7 @@ void CNodeEnt :: Spawn( void )
WorldGraph.m_pNodes[ WorldGraph.m_cNodes ].m_afNodeInfo = 0; WorldGraph.m_pNodes[ WorldGraph.m_cNodes ].m_afNodeInfo = 0;
WorldGraph.m_cNodes++; WorldGraph.m_cNodes++;
REMOVE_ENTITY( edict() ); REMOVE_ENTITY( edict() );
} }
@@ -1665,7 +1668,7 @@ void CTestHull :: BuildNodeGraph( void )
if ( !file ) if ( !file )
{// file error {// file error
ALERT ( at_aiconsole, "Couldn't create %s!\n", szNrpFilename ); ALERT ( at_aiconsole, "Couldn't create %s!\n", szNrpFilename );
if ( pTempPool ) if ( pTempPool )
{ {
free ( pTempPool ); free ( pTempPool );
@@ -2464,7 +2467,7 @@ int CGraph :: FLoadGraph ( char *szMapName )
// Set the graph present flag, clear the pointers set flag // Set the graph present flag, clear the pointers set flag
// //
m_fGraphPresent = TRUE; m_fGraphPresent = TRUE;
m_fGraphPointersSet = FALSE; m_fGraphPointersSet = TRUE; // what if...?
FREE_FILE(aMemFile); FREE_FILE(aMemFile);
@@ -3472,26 +3475,6 @@ EnoughSaid:
// to current location (typically the player). It then draws // to current location (typically the player). It then draws
// as many connects as it can per frame, trying not to overflow the buffer // as many connects as it can per frame, trying not to overflow the buffer
//========================================================= //=========================================================
class CNodeViewer : public CMBaseEntity
{
public:
void Spawn( void );
int m_iBaseNode;
int m_iDraw;
int m_nVisited;
int m_aFrom[128];
int m_aTo[128];
int m_iHull;
int m_afNodeType;
Vector m_vecColor;
void FindNodeConnections( int iNode );
void AddNode( int iFrom, int iTo );
void EXPORT DrawThink( void );
};
void CNodeViewer::Spawn( ) void CNodeViewer::Spawn( )
{ {
/*CNodeViewer *pViewer = CreateClassPtr((CNodeViewer *)NULL); /*CNodeViewer *pViewer = CreateClassPtr((CNodeViewer *)NULL);
@@ -3567,6 +3550,8 @@ void CNodeViewer::Spawn( )
m_iDraw = 0; m_iDraw = 0;
SetThink( &CNodeViewer::DrawThink ); SetThink( &CNodeViewer::DrawThink );
pev->nextthink = gpGlobals->time; pev->nextthink = gpGlobals->time;
pev->classname = MAKE_STRING( "node_viewer" );
} }

View File

@@ -270,6 +270,29 @@ class CNodeEnt : public CMBaseEntity
}; };
//=========================================================
// Node viewer
//=========================================================
class CNodeViewer : public CMBaseEntity
{
public:
void Spawn( void );
int m_iBaseNode;
int m_iDraw;
int m_nVisited;
int m_aFrom[128];
int m_aTo[128];
int m_iHull;
int m_afNodeType;
Vector m_vecColor;
void FindNodeConnections( int iNode );
void AddNode( int iFrom, int iTo );
void EXPORT DrawThink( void );
};
//========================================================= //=========================================================
// CStack - last in, first out. // CStack - last in, first out.
//========================================================= //=========================================================