stvoy-sp-sdk/game/g_ref.cpp

388 lines
8.4 KiB
C++

// Reference tag utility functions
#include "g_local.h"
#include "g_functions.h"
#include "g_nav.h"
#define TAG_GENERIC_NAME "__WORLD__" //If a designer chooses this name, cut a finger off as an example to the others
typedef vector < reference_tag_t * > refTag_v;
typedef map < string, reference_tag_t * > refTag_m;
typedef struct tagOwner_s
{
refTag_v tags;
refTag_m tagMap;
} tagOwner_t;
typedef map < string, tagOwner_t * > refTagOwner_m;
refTagOwner_m refTagOwnerMap;
/*
-------------------------
TAG_ShowTags
-------------------------
*/
void TAG_ShowTags( int flags )
{
refTagOwner_m::iterator rtoi;
STL_ITERATE( rtoi, refTagOwnerMap )
{
refTag_v::iterator rti;
STL_ITERATE( rti, (((*rtoi).second)->tags) )
{
if ( (*rti)->flags & RTF_NAVGOAL )
{
if ( gi.inPVS( g_entities[0].currentOrigin, (*rti)->origin ) )
CG_DrawNode( (*rti)->origin, NODE_NAVGOAL );
}
}
}
}
/*
-------------------------
TAG_Init
-------------------------
*/
void TAG_Init( void )
{
refTagOwner_m::iterator rtoi;
//Delete all owners
for ( rtoi = refTagOwnerMap.begin(); rtoi != refTagOwnerMap.end(); rtoi++ )
{
if ( (*rtoi).second == NULL )
{
assert( 0 ); //FIXME: This is not good
continue;
}
refTag_v::iterator rti;
//Delete all tags within the owner's scope
for ( rti = ((*rtoi).second)->tags.begin(); rti != ((*rtoi).second)->tags.end(); rti++ )
{
if ( (*rti) == NULL )
{
assert( 0 ); //FIXME: Bad bad
continue;
}
//Free it
delete (*rti);
}
//Clear the containers
((*rtoi).second)->tags.clear();
((*rtoi).second)->tagMap.clear();
//Delete the owner
delete ((*rtoi).second);
}
//Clear the container
refTagOwnerMap.clear();
}
/*
-------------------------
TAG_FindOwner
-------------------------
*/
tagOwner_t *TAG_FindOwner( const char *owner )
{
refTagOwner_m::iterator rtoi;
rtoi = refTagOwnerMap.find( owner );
if ( rtoi == refTagOwnerMap.end() )
return NULL;
return (*rtoi).second;
}
/*
-------------------------
TAG_Find
-------------------------
*/
reference_tag_t *TAG_Find( const char *owner, const char *name )
{
tagOwner_t *tagOwner;
tagOwner = VALIDSTRING( owner ) ? TAG_FindOwner( owner ) : TAG_FindOwner( TAG_GENERIC_NAME );
//Not found...
if ( tagOwner == NULL )
{
tagOwner = TAG_FindOwner( TAG_GENERIC_NAME );
if ( tagOwner == NULL )
return NULL;
}
refTag_m::iterator rti;
rti = tagOwner->tagMap.find( name );
if ( rti == tagOwner->tagMap.end() )
{
//Try the generic owner instead
tagOwner = TAG_FindOwner( TAG_GENERIC_NAME );
if ( tagOwner == NULL )
return NULL;
char tempName[ MAX_REFNAME ];
Q_strncpyz( (char *) tempName, name, MAX_REFNAME );
strlwr( (char *) tempName ); //NOTENOTE: For case insensitive searches on a map
rti = tagOwner->tagMap.find( tempName );
if ( rti == tagOwner->tagMap.end() )
return NULL;
}
return (*rti).second;
}
/*
-------------------------
TAG_Add
-------------------------
*/
reference_tag_t *TAG_Add( const char *name, const char *owner, vec3_t origin, vec3_t angles, int radius, int flags )
{
reference_tag_t *tag = new reference_tag_t;
VALIDATEP( tag );
//Copy the information
VectorCopy( origin, tag->origin );
VectorCopy( angles, tag->angles );
tag->radius = radius;
tag->flags = flags;
if ( VALIDSTRING( name ) == false )
{
//gi.Error("Nameless ref_tag found at (%i %i %i)", (int)origin[0], (int)origin[1], (int)origin[2]);
gi.Printf(S_COLOR_RED"ERROR: Nameless ref_tag found at (%i %i %i)\n", (int)origin[0], (int)origin[1], (int)origin[2]);
return NULL;
}
//Copy the name
Q_strncpyz( (char *) tag->name, name, MAX_REFNAME );
strlwr( (char *) tag->name ); //NOTENOTE: For case insensitive searches on a map
//Make sure this tag's name isn't alread in use
if ( TAG_Find( owner, name ) )
{
gi.Printf(S_COLOR_RED"Duplicate tag name \"%s\"\n", name );
return NULL;
}
//Attempt to add this to the owner's list
if ( VALIDSTRING( owner ) == false )
{
//If the owner isn't found, use the generic world name
owner = TAG_GENERIC_NAME;
}
tagOwner_t *tagOwner = TAG_FindOwner( owner );
//If the owner is valid, add this tag to it
if VALID( tagOwner )
{
tagOwner->tags.insert( tagOwner->tags.end(), tag );
tagOwner->tagMap[ (char*) &tag->name ] = tag;
}
else
{
//Create a new owner list
tagOwner_t *tagOwner = new tagOwner_t;
VALIDATEP( tagOwner );
//Insert the information
tagOwner->tags.insert( tagOwner->tags.end(), tag );
tagOwner->tagMap[ (char *) tag->name ] = tag;
//Map it
refTagOwnerMap[ owner ] = tagOwner;
}
return tag;
}
/*
-------------------------
TAG_GetOrigin
-------------------------
*/
int TAG_GetOrigin( const char *owner, const char *name, vec3_t origin )
{
reference_tag_t *tag = TAG_Find( owner, name );
VALIDATEB( tag );
VectorCopy( tag->origin, origin );
return true;
}
/*
-------------------------
TAG_GetOrigin2
Had to get rid of that damn assert for dev
-------------------------
*/
int TAG_GetOrigin2( const char *owner, const char *name, vec3_t origin )
{
reference_tag_t *tag = TAG_Find( owner, name );
if( tag == NULL )
{
return qfalse;
}
VectorCopy( tag->origin, origin );
return qtrue;
}
/*
-------------------------
TAG_GetAngles
-------------------------
*/
int TAG_GetAngles( const char *owner, const char *name, vec3_t angles )
{
reference_tag_t *tag = TAG_Find( owner, name );
VALIDATEB( tag );
VectorCopy( tag->angles, angles );
return true;
}
/*
-------------------------
TAG_GetRadius
-------------------------
*/
int TAG_GetRadius( const char *owner, const char *name )
{
reference_tag_t *tag = TAG_Find( owner, name );
VALIDATEB( tag );
return tag->radius;
}
/*
-------------------------
TAG_GetFlags
-------------------------
*/
int TAG_GetFlags( const char *owner, const char *name )
{
reference_tag_t *tag = TAG_Find( owner, name );
VALIDATEB( tag );
return tag->flags;
}
/*
==============================================================================
Spawn functions
==============================================================================
*/
/*QUAKED ref_tag (0.5 0.5 1) (-8 -8 -8) (8 8 8)
Reference tags which can be positioned throughout the level.
These tags can later be refered to by the scripting system
so that their origins and angles can be referred to.
If you set angles on the tag, these will be retained.
If you target a ref_tag at an entity, that will set the ref_tag's
angles toward that entity.
If you set the ref_tag's ownername to the ownername of an entity,
it makes that entity is the owner of the ref_tag. This means
that the owner, and only the owner, may refer to that tag.
Tags may not have the same name as another tag with the same
owner. However, tags with different owners may have the same
name as one another. In this way, scripts can generically
refer to tags by name, and their owners will automatically
specifiy which tag is being referred to.
targetname - the name of this tag
ownername - the owner of this tag
target - use to point the tag at something for angles
*/
void ref_link ( gentity_t *ent )
{
reference_tag_t *tag;
if ( ent->target )
{
//TODO: Find the target and set our angles to that direction
gentity_t *target = G_Find( NULL, FOFS(targetname), ent->target );
vec3_t dir;
if ( target )
{
//Find the direction to the target
VectorSubtract( target->s.origin, ent->s.origin, dir );
VectorNormalize( dir );
vectoangles( dir, ent->s.angles );
//FIXME: Does pitch get flipped?
}
else
{
gi.Printf( S_COLOR_RED"ERROR: ref_tag (%s) has invalid target (%s)", ent->targetname, ent->target );
}
}
//Add the tag
tag = TAG_Add( ent->targetname, ent->ownername, ent->s.origin, ent->s.angles, 16, 0 );
//Delete immediately, cannot be refered to as an entity again
//NOTE: this means if you wanted to link them in a chain for, say, a path, you can't
G_FreeEntity( ent );
}
void SP_reference_tag ( gentity_t *ent )
{
if ( ent->target )
{
//Init cannot occur until all entities have been spawned
ent->e_ThinkFunc = thinkF_ref_link;
ent->nextthink = level.time + 0.1;
}
else
{
ref_link( ent );
}
}