Add info_node and info_node_air support for navigation.
This commit is contained in:
@@ -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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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,6 +919,7 @@ 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();
|
||||||
|
|
||||||
@@ -817,6 +927,31 @@ int mmDispatchSpawn( edict_t *pent )
|
|||||||
|
|
||||||
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++)
|
||||||
@@ -851,6 +986,20 @@ void mmDispatchThink( edict_t *pent )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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++)
|
||||||
{
|
{
|
||||||
@@ -939,6 +1089,30 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,10 +88,83 @@ 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)
|
||||||
|
{
|
||||||
|
int mIndex;
|
||||||
|
for (mIndex = 0; monster_types[mIndex].name[0]; mIndex++)
|
||||||
|
{
|
||||||
|
if (strcmp(data[kvd_index-1].value, monster_types[mIndex].name) == 0)
|
||||||
|
{
|
||||||
|
// Now that I think about it this looks slow and bad code >.>
|
||||||
|
|
||||||
|
// A match is found. What is this?
|
||||||
|
if (strncmp(monster_types[mIndex].name, "monster", 7) == 0)
|
||||||
|
{
|
||||||
|
// It's a monster, add it to the list
|
||||||
|
if (monster_spawn_count == MAX_MONSTERS)
|
||||||
|
{
|
||||||
|
// 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++)
|
||||||
{
|
{
|
||||||
float x, y, z;
|
|
||||||
// Any unknown keyvalue is ignored.
|
// Any unknown keyvalue is ignored.
|
||||||
// Any duplicate keyvalue is overwritten.
|
// Any duplicate keyvalue is overwritten.
|
||||||
|
|
||||||
@@ -103,14 +178,25 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
LOG_MESSAGE(PLID, "ERROR: entity will spawn at 0 0 0");
|
LOG_MESSAGE(PLID, "ERROR: entity will spawn at 0 0 0");
|
||||||
x = y = z = 0;
|
x = y = z = 0;
|
||||||
}
|
}
|
||||||
|
if (monster)
|
||||||
|
{
|
||||||
monster_spawnpoint[monster_spawn_count].origin[0] = x;
|
monster_spawnpoint[monster_spawn_count].origin[0] = x;
|
||||||
monster_spawnpoint[monster_spawn_count].origin[1] = y;
|
monster_spawnpoint[monster_spawn_count].origin[1] = y;
|
||||||
monster_spawnpoint[monster_spawn_count].origin[2] = z;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (strcmp(data[i].key, "delay") == 0)
|
else if (strcmp(data[i].key, "delay") == 0)
|
||||||
{
|
{
|
||||||
// ToDo: Remove this keyvalue.
|
// ToDo: Remove this keyvalue.
|
||||||
// Monsters spawned directly should not respawn.
|
// Monsters spawned directly should not respawn.
|
||||||
|
if (monster)
|
||||||
|
{
|
||||||
if (sscanf(data[i].value, "%f", &x) != 1)
|
if (sscanf(data[i].value, "%f", &x) != 1)
|
||||||
{
|
{
|
||||||
LOG_MESSAGE(PLID, "ERROR: invalid delay: %s", input); // print conflictive line
|
LOG_MESSAGE(PLID, "ERROR: invalid delay: %s", input); // print conflictive line
|
||||||
@@ -121,7 +207,10 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
}
|
}
|
||||||
monster_spawnpoint[monster_spawn_count].delay = x;
|
monster_spawnpoint[monster_spawn_count].delay = x;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (strcmp(data[i].key, "angles") == 0)
|
else if (strcmp(data[i].key, "angles") == 0)
|
||||||
|
{
|
||||||
|
if (monster)
|
||||||
{
|
{
|
||||||
if (sscanf(data[i].value, "%f %f %f", &x, &y, &z) != 3)
|
if (sscanf(data[i].value, "%f %f %f", &x, &y, &z) != 3)
|
||||||
{
|
{
|
||||||
@@ -135,29 +224,21 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
monster_spawnpoint[monster_spawn_count].angles[1] = y;
|
monster_spawnpoint[monster_spawn_count].angles[1] = y;
|
||||||
monster_spawnpoint[monster_spawn_count].angles[2] = z;
|
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;
|
|
||||||
monster_types[mIndex].need_to_precache = 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!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (monster)
|
||||||
|
{
|
||||||
// Init monster
|
// Init monster
|
||||||
monster_spawnpoint[monster_spawn_count].respawn_time = gpGlobals->time + 0.1; // spawn (nearly) right away
|
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_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
|
// Log on? Print all the entities that were added
|
||||||
if (dllapi_log->value)
|
if (dllapi_log->value)
|
||||||
@@ -166,8 +247,8 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
// No, I'm not making this idiotproof. Classname should be the last KVD entry on an entity!
|
// 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);
|
LOG_CONSOLE(PLID, "[DEBUG] Added entity: %s", data[kvd_index-1].value);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
monster_spawn_count++;
|
|
||||||
free( data );
|
free( data );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -1453,6 +1453,7 @@ 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,14 +1530,12 @@ 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 )
|
||||||
{
|
{
|
||||||
@@ -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" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
//=========================================================
|
//=========================================================
|
||||||
|
|||||||
Reference in New Issue
Block a user