jedi-academy/codemp/game/g_target.c

1003 lines
25 KiB
C
Raw Normal View History

2013-04-04 22:35:38 +00:00
// Copyright (C) 1999-2000 Id Software, Inc.
//
#include "g_local.h"
//==========================================================
/*QUAKED target_give (1 0 0) (-8 -8 -8) (8 8 8)
Gives the activator all the items pointed to.
*/
void Use_Target_Give( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
gentity_t *t;
trace_t trace;
if ( !activator->client ) {
return;
}
if ( !ent->target ) {
return;
}
memset( &trace, 0, sizeof( trace ) );
t = NULL;
while ( (t = G_Find (t, FOFS(targetname), ent->target)) != NULL ) {
if ( !t->item ) {
continue;
}
Touch_Item( t, activator, &trace );
// make sure it isn't going to respawn or show any events
t->nextthink = 0;
trap_UnlinkEntity( t );
}
}
void SP_target_give( gentity_t *ent ) {
ent->use = Use_Target_Give;
}
//==========================================================
/*QUAKED target_remove_powerups (1 0 0) (-8 -8 -8) (8 8 8)
takes away all the activators powerups.
Used to drop flight powerups into death puts.
*/
void Use_target_remove_powerups( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
if( !activator->client ) {
return;
}
if( activator->client->ps.powerups[PW_REDFLAG] ) {
Team_ReturnFlag( TEAM_RED );
} else if( activator->client->ps.powerups[PW_BLUEFLAG] ) {
Team_ReturnFlag( TEAM_BLUE );
} else if( activator->client->ps.powerups[PW_NEUTRALFLAG] ) {
Team_ReturnFlag( TEAM_FREE );
}
memset( activator->client->ps.powerups, 0, sizeof( activator->client->ps.powerups ) );
}
void SP_target_remove_powerups( gentity_t *ent ) {
ent->use = Use_target_remove_powerups;
}
//==========================================================
/*QUAKED target_delay (1 0 0) (-8 -8 -8) (8 8 8) NO_RETRIGGER
NO_RETRIGGER - Keeps the delay from resetting the time if it is
activated again while it is counting down to an event.
"wait" seconds to pause before firing targets.
"random" delay variance, total delay = delay +/- random seconds
*/
void Think_Target_Delay( gentity_t *ent ) {
G_UseTargets( ent, ent->activator );
}
void Use_Target_Delay( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
if (ent->nextthink > level.time && (ent->spawnflags & 1))
{ //Leave me alone, I am thinking.
return;
}
G_ActivateBehavior(ent,BSET_USE);
ent->nextthink = level.time + ( ent->wait + ent->random * crandom() ) * 1000;
ent->think = Think_Target_Delay;
ent->activator = activator;
}
void SP_target_delay( gentity_t *ent ) {
// check delay for backwards compatability
if ( !G_SpawnFloat( "delay", "0", &ent->wait ) ) {
G_SpawnFloat( "wait", "1", &ent->wait );
}
if ( !ent->wait ) {
ent->wait = 1;
}
ent->use = Use_Target_Delay;
}
//==========================================================
/*QUAKED target_score (1 0 0) (-8 -8 -8) (8 8 8)
"count" number of points to add, default 1
The activator is given this many points.
*/
void Use_Target_Score (gentity_t *ent, gentity_t *other, gentity_t *activator) {
AddScore( activator, ent->r.currentOrigin, ent->count );
}
void SP_target_score( gentity_t *ent ) {
if ( !ent->count ) {
ent->count = 1;
}
ent->use = Use_Target_Score;
}
//==========================================================
/*QUAKED target_print (1 0 0) (-8 -8 -8) (8 8 8) redteam blueteam private
"message" text to print
"wait" don't fire off again if triggered within this many milliseconds ago
If "private", only the activator gets the message. If no checks, all clients get the message.
*/
void Use_Target_Print (gentity_t *ent, gentity_t *other, gentity_t *activator)
{
if (!ent || !ent->inuse)
{
2013-04-04 23:21:13 +00:00
Com_Printf("ERROR: Bad ent in Use_Target_Print");
return;
2013-04-04 22:35:38 +00:00
}
if (ent->wait)
{
if (ent->genericValue14 >= level.time)
{
return;
}
ent->genericValue14 = level.time + ent->wait;
}
#ifndef FINAL_BUILD
2013-04-04 23:21:13 +00:00
if (!ent || !ent->inuse)
{
Com_Error(ERR_DROP, "Bad ent in Use_Target_Print");
}
else if (!activator || !activator->inuse)
{
Com_Error(ERR_DROP, "Bad activator in Use_Target_Print");
}
2013-04-04 22:35:38 +00:00
if (ent->genericValue15 > level.time)
{
Com_Printf("TARGET PRINT ERRORS:\n");
if (activator && activator->classname && activator->classname[0])
{
Com_Printf("activator classname: %s\n", activator->classname);
}
if (activator && activator->target && activator->target[0])
{
Com_Printf("activator target: %s\n", activator->target);
}
if (activator && activator->targetname && activator->targetname[0])
{
Com_Printf("activator targetname: %s\n", activator->targetname);
}
if (ent->targetname && ent->targetname[0])
{
Com_Printf("print targetname: %s\n", ent->targetname);
}
Com_Error(ERR_DROP, "target_print used in quick succession, fix it! See the console for details.");
}
ent->genericValue15 = level.time + 5000;
#endif
G_ActivateBehavior(ent,BSET_USE);
2013-04-04 23:21:13 +00:00
if ( ( ent->spawnflags & 4 ) )
{//private, to one client only
if (!activator || !activator->inuse)
2013-04-04 22:35:38 +00:00
{
2013-04-04 23:21:13 +00:00
Com_Printf("ERROR: Bad activator in Use_Target_Print");
2013-04-04 22:35:38 +00:00
}
2013-04-04 23:21:13 +00:00
if ( activator && activator->client )
{//make sure there's a valid client ent to send it to
if (ent->message[0] == '@' && ent->message[1] != '@')
{
trap_SendServerCommand( activator-g_entities, va("cps \"%s\"", ent->message ));
}
else
{
trap_SendServerCommand( activator-g_entities, va("cp \"%s\"", ent->message ));
}
2013-04-04 22:35:38 +00:00
}
2013-04-04 23:21:13 +00:00
//NOTE: change in functionality - if there *is* no valid client ent, it won't send it to anyone at all
2013-04-04 22:35:38 +00:00
return;
}
if ( ent->spawnflags & 3 ) {
if ( ent->spawnflags & 1 ) {
if (ent->message[0] == '@' && ent->message[1] != '@')
{
G_TeamCommand( TEAM_RED, va("cps \"%s\"", ent->message) );
}
else
{
G_TeamCommand( TEAM_RED, va("cp \"%s\"", ent->message) );
}
}
if ( ent->spawnflags & 2 ) {
if (ent->message[0] == '@' && ent->message[1] != '@')
{
G_TeamCommand( TEAM_BLUE, va("cps \"%s\"", ent->message) );
}
else
{
G_TeamCommand( TEAM_BLUE, va("cp \"%s\"", ent->message) );
}
}
return;
}
if (ent->message[0] == '@' && ent->message[1] != '@')
{
trap_SendServerCommand( -1, va("cps \"%s\"", ent->message ));
}
else
{
trap_SendServerCommand( -1, va("cp \"%s\"", ent->message ));
}
}
void SP_target_print( gentity_t *ent ) {
ent->use = Use_Target_Print;
}
//==========================================================
/*QUAKED target_speaker (1 0 0) (-8 -8 -8) (8 8 8) looped-on looped-off global activator
"noise" wav file to play
A global sound will play full volume throughout the level.
Activator sounds will play on the player that activated the target.
Global and activator sounds can't be combined with looping.
Normal sounds play each time the target is used.
Looped sounds will be toggled by use functions.
Multiple identical looping sounds will just increase volume without any speed cost.
"wait" : Seconds between auto triggerings, 0 = don't auto trigger
"random" wait variance, default is 0
*/
void Use_Target_Speaker (gentity_t *ent, gentity_t *other, gentity_t *activator) {
G_ActivateBehavior(ent,BSET_USE);
if (ent->spawnflags & 3) { // looping sound toggles
if (ent->s.loopSound)
{
ent->s.loopSound = 0; // turn it off
ent->s.loopIsSoundset = qfalse;
ent->s.trickedentindex = 1;
}
else
{
ent->s.loopSound = ent->noise_index; // start it
ent->s.loopIsSoundset = qfalse;
ent->s.trickedentindex = 0;
}
}else { // normal sound
if ( ent->spawnflags & 8 ) {
G_AddEvent( activator, EV_GENERAL_SOUND, ent->noise_index );
} else if (ent->spawnflags & 4) {
G_AddEvent( ent, EV_GLOBAL_SOUND, ent->noise_index );
} else {
G_AddEvent( ent, EV_GENERAL_SOUND, ent->noise_index );
}
}
}
void SP_target_speaker( gentity_t *ent ) {
char buffer[MAX_QPATH];
char *s;
G_SpawnFloat( "wait", "0", &ent->wait );
G_SpawnFloat( "random", "0", &ent->random );
if ( G_SpawnString ( "soundSet", "", &s ) )
{ // this is a sound set
ent->s.soundSetIndex = G_SoundSetIndex(s);
ent->s.eFlags = EF_PERMANENT;
VectorCopy( ent->s.origin, ent->s.pos.trBase );
trap_LinkEntity (ent);
return;
}
if ( !G_SpawnString( "noise", "NOSOUND", &s ) ) {
G_Error( "target_speaker without a noise key at %s", vtos( ent->s.origin ) );
}
// force all client reletive sounds to be "activator" speakers that
// play on the entity that activates it
if ( s[0] == '*' ) {
ent->spawnflags |= 8;
}
Q_strncpyz( buffer, s, sizeof(buffer) );
ent->noise_index = G_SoundIndex(buffer);
// a repeating speaker can be done completely client side
ent->s.eType = ET_SPEAKER;
ent->s.eventParm = ent->noise_index;
ent->s.frame = ent->wait * 10;
ent->s.clientNum = ent->random * 10;
// check for prestarted looping sound
if ( ent->spawnflags & 1 ) {
ent->s.loopSound = ent->noise_index;
ent->s.loopIsSoundset = qfalse;
}
ent->use = Use_Target_Speaker;
if (ent->spawnflags & 4) {
ent->r.svFlags |= SVF_BROADCAST;
}
VectorCopy( ent->s.origin, ent->s.pos.trBase );
// must link the entity so we get areas and clusters so
// the server can determine who to send updates to
trap_LinkEntity( ent );
}
//==========================================================
/*QUAKED target_laser (0 .5 .8) (-8 -8 -8) (8 8 8) START_ON
When triggered, fires a laser. You can either set a target or a direction.
*/
void target_laser_think (gentity_t *self) {
vec3_t end;
trace_t tr;
vec3_t point;
// if pointed at another entity, set movedir to point at it
if ( self->enemy ) {
VectorMA (self->enemy->s.origin, 0.5, self->enemy->r.mins, point);
VectorMA (point, 0.5, self->enemy->r.maxs, point);
VectorSubtract (point, self->s.origin, self->movedir);
VectorNormalize (self->movedir);
}
// fire forward and see what we hit
VectorMA (self->s.origin, 2048, self->movedir, end);
trap_Trace( &tr, self->s.origin, NULL, NULL, end, self->s.number, CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_CORPSE);
if ( tr.entityNum ) {
// hurt it if we can
G_Damage ( &g_entities[tr.entityNum], self, self->activator, self->movedir,
tr.endpos, self->damage, DAMAGE_NO_KNOCKBACK, MOD_TARGET_LASER);
}
VectorCopy (tr.endpos, self->s.origin2);
trap_LinkEntity( self );
self->nextthink = level.time + FRAMETIME;
}
void target_laser_on (gentity_t *self)
{
if (!self->activator)
self->activator = self;
target_laser_think (self);
}
void target_laser_off (gentity_t *self)
{
trap_UnlinkEntity( self );
self->nextthink = 0;
}
void target_laser_use (gentity_t *self, gentity_t *other, gentity_t *activator)
{
self->activator = activator;
if ( self->nextthink > 0 )
target_laser_off (self);
else
target_laser_on (self);
}
void target_laser_start (gentity_t *self)
{
gentity_t *ent;
self->s.eType = ET_BEAM;
if (self->target) {
ent = G_Find (NULL, FOFS(targetname), self->target);
if (!ent) {
G_Printf ("%s at %s: %s is a bad target\n", self->classname, vtos(self->s.origin), self->target);
}
self->enemy = ent;
} else {
G_SetMovedir (self->s.angles, self->movedir);
}
self->use = target_laser_use;
self->think = target_laser_think;
if ( !self->damage ) {
self->damage = 1;
}
if (self->spawnflags & 1)
target_laser_on (self);
else
target_laser_off (self);
}
void SP_target_laser (gentity_t *self)
{
// let everything else get spawned before we start firing
self->think = target_laser_start;
self->nextthink = level.time + FRAMETIME;
}
//==========================================================
void target_teleporter_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {
gentity_t *dest;
if (!activator->client)
return;
G_ActivateBehavior(self,BSET_USE);
dest = G_PickTarget( self->target );
if (!dest) {
G_Printf ("Couldn't find teleporter destination\n");
return;
}
TeleportPlayer( activator, dest->s.origin, dest->s.angles );
}
/*QUAKED target_teleporter (1 0 0) (-8 -8 -8) (8 8 8)
The activator will be teleported away.
*/
void SP_target_teleporter( gentity_t *self ) {
if (!self->targetname)
G_Printf("untargeted %s at %s\n", self->classname, vtos(self->s.origin));
self->use = target_teleporter_use;
}
//==========================================================
/*QUAKED target_relay (.5 .5 .5) (-8 -8 -8) (8 8 8) RED_ONLY BLUE_ONLY RANDOM x x x x INACTIVE
This doesn't perform any actions except fire its targets.
The activator can be forced to be from a certain team.
if RANDOM is checked, only one of the targets will be fired, not all of them
INACTIVE Can't be used until activated
wait - set to -1 to use it only once
*/
void target_relay_use (gentity_t *self, gentity_t *other, gentity_t *activator) {
qboolean ranscript = qfalse;
if ( ( self->spawnflags & 1 ) && activator->client
&& activator->client->sess.sessionTeam != TEAM_RED ) {
return;
}
if ( ( self->spawnflags & 2 ) && activator->client
&& activator->client->sess.sessionTeam != TEAM_BLUE ) {
return;
}
if ( self->flags & FL_INACTIVE )
{//set by target_deactivate
return;
}
ranscript = G_ActivateBehavior( self, BSET_USE );
if ( self->wait == -1 )
{//never use again
if ( ranscript )
{//crap, can't remove!
self->use = NULL;
}
else
{//remove
self->think = G_FreeEntity;
self->nextthink = level.time + FRAMETIME;
}
}
if ( self->spawnflags & 4 ) {
gentity_t *ent;
ent = G_PickTarget( self->target );
if ( ent && ent->use ) {
GlobalUse( ent, self, activator );
}
return;
}
G_UseTargets (self, activator);
}
void SP_target_relay (gentity_t *self) {
self->use = target_relay_use;
if ( self->spawnflags&128 )
{
self->flags |= FL_INACTIVE;
}
}
//==========================================================
/*QUAKED target_kill (.5 .5 .5) (-8 -8 -8) (8 8 8)
Kills the activator.
*/
void target_kill_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {
G_ActivateBehavior(self,BSET_USE);
G_Damage ( activator, NULL, NULL, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);
}
void SP_target_kill( gentity_t *self ) {
self->use = target_kill_use;
}
/*QUAKED target_position (0 0.5 0) (-4 -4 -4) (4 4 4)
Used as a positional target for in-game calculation, like jumppad targets.
*/
void SP_target_position( gentity_t *self ){
G_SetOrigin( self, self->s.origin );
/*
G_SetAngles( self, self->s.angles );
self->s.eType = ET_INVISIBLE;
*/
}
static void target_location_linkup(gentity_t *ent)
{
int i;
int n;
if (level.locationLinked)
return;
level.locationLinked = qtrue;
level.locationHead = NULL;
trap_SetConfigstring( CS_LOCATIONS, "unknown" );
for (i = 0, ent = g_entities, n = 1;
i < level.num_entities;
i++, ent++) {
if (ent->classname && !Q_stricmp(ent->classname, "target_location")) {
// lets overload some variables!
ent->health = n; // use for location marking
trap_SetConfigstring( CS_LOCATIONS + n, ent->message );
n++;
ent->nextTrain = level.locationHead;
level.locationHead = ent;
}
}
// All linked together now
}
/*QUAKED target_location (0 0.5 0) (-8 -8 -8) (8 8 8)
Set "message" to the name of this location.
Set "count" to 0-7 for color.
0:white 1:red 2:green 3:yellow 4:blue 5:cyan 6:magenta 7:white
Closest target_location in sight used for the location, if none
in site, closest in distance
*/
void SP_target_location( gentity_t *self ){
self->think = target_location_linkup;
self->nextthink = level.time + 200; // Let them all spawn first
G_SetOrigin( self, self->s.origin );
}
/*QUAKED target_counter (1.0 0 0) (-4 -4 -4) (4 4 4) x x x x x x x INACTIVE
Acts as an intermediary for an action that takes multiple inputs.
INACTIVE cannot be used until used by a target_activate
target2 - what the counter should fire each time it's incremented and does NOT reach it's count
After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself.
bounceCount - number of times the counter should reset to it's full count when it's done
*/
extern void G_DebugPrint( int level, const char *format, ... );
void target_counter_use( gentity_t *self, gentity_t *other, gentity_t *activator )
{
if ( self->count == 0 )
{
return;
}
//gi.Printf("target_counter %s used by %s, entnum %d\n", self->targetname, activator->targetname, activator->s.number );
self->count--;
if ( activator )
{
G_DebugPrint( WL_VERBOSE, "target_counter %s used by %s (%d/%d)\n", self->targetname, activator->targetname, (self->genericValue1-self->count), self->genericValue1 );
}
if ( self->count )
{
if ( self->target2 )
{
//gi.Printf("target_counter %s firing target2 from %s, entnum %d\n", self->targetname, activator->targetname, activator->s.number );
G_UseTargets2( self, activator, self->target2 );
}
return;
}
G_ActivateBehavior( self,BSET_USE );
if ( self->spawnflags & 128 )
{
self->flags |= FL_INACTIVE;
}
self->activator = activator;
G_UseTargets( self, activator );
if ( self->count == 0 )
{
if ( self->bounceCount == 0 )
{
return;
}
self->count = self->genericValue1;
if ( self->bounceCount > 0 )
{//-1 means bounce back forever
self->bounceCount--;
}
}
}
void SP_target_counter (gentity_t *self)
{
self->wait = -1;
if (!self->count)
{
self->count = 2;
}
//if ( self->bounceCount > 0 )//let's always set this anyway
{//we will reset when we use up our count, remember our initial count
self->genericValue1 = self->count;
}
self->use = target_counter_use;
}
/*QUAKED target_random (.5 .5 .5) (-4 -4 -4) (4 4 4) USEONCE
Randomly fires off only one of it's targets each time used
USEONCE set to never fire again
*/
void target_random_use(gentity_t *self, gentity_t *other, gentity_t *activator)
{
int t_count = 0, pick;
gentity_t *t = NULL;
//gi.Printf("target_random %s used by %s (entnum %d)\n", self->targetname, activator->targetname, activator->s.number );
G_ActivateBehavior(self,BSET_USE);
if(self->spawnflags & 1)
{
self->use = 0;
}
while ( (t = G_Find (t, FOFS(targetname), self->target)) != NULL )
{
if (t != self)
{
t_count++;
}
}
if(!t_count)
{
return;
}
if(t_count == 1)
{
G_UseTargets (self, activator);
return;
}
//FIXME: need a seed
pick = Q_irand(1, t_count);
t_count = 0;
while ( (t = G_Find (t, FOFS(targetname), self->target)) != NULL )
{
if (t != self)
{
t_count++;
}
else
{
continue;
}
if (t == self)
{
// gi.Printf ("WARNING: Entity used itself.\n");
}
else if(t_count == pick)
{
if (t->use != NULL) // check can be omitted
{
GlobalUse(t, self, activator);
return;
}
}
if (!self->inuse)
{
Com_Printf("entity was removed while using targets\n");
return;
}
}
}
void SP_target_random (gentity_t *self)
{
self->use = target_random_use;
}
int numNewICARUSEnts = 0;
void scriptrunner_run (gentity_t *self)
{
/*
if (self->behaviorSet[BSET_USE])
{
char newname[MAX_FILENAME_LENGTH];
sprintf((char *) &newname, "%s/%s", Q3_SCRIPT_DIR, self->behaviorSet[BSET_USE] );
ICARUS_RunScript( self, newname );
}
*/
if ( self->count != -1 )
{
if ( self->count <= 0 )
{
self->use = 0;
self->behaviorSet[BSET_USE] = NULL;
return;
}
else
{
--self->count;
}
}
if (self->behaviorSet[BSET_USE])
{
if ( self->spawnflags & 1 )
{
if ( !self->activator )
{
if (g_developer.integer)
{
Com_Printf("target_scriptrunner tried to run on invalid entity!\n");
}
return;
}
//if ( !self->activator->sequencer || !self->activator->taskManager )
if (!trap_ICARUS_IsInitialized(self->s.number))
{//Need to be initialized through ICARUS
if ( !self->activator->script_targetname || !self->activator->script_targetname[0] )
{
//We don't have a script_targetname, so create a new one
self->activator->script_targetname = va( "newICARUSEnt%d", numNewICARUSEnts++ );
}
if ( trap_ICARUS_ValidEnt( self->activator ) )
{
trap_ICARUS_InitEnt( self->activator );
}
else
{
if (g_developer.integer)
{
Com_Printf("target_scriptrunner tried to run on invalid ICARUS activator!\n");
}
return;
}
}
if (g_developer.integer)
{
Com_Printf( "target_scriptrunner running %s on activator %s\n", self->behaviorSet[BSET_USE], self->activator->targetname );
}
trap_ICARUS_RunScript( self->activator, va( "%s/%s", Q3_SCRIPT_DIR, self->behaviorSet[BSET_USE] ) );
}
else
{
if ( g_developer.integer && self->activator )
{
Com_Printf( "target_scriptrunner %s used by %s\n", self->targetname, self->activator->targetname );
}
G_ActivateBehavior( self, BSET_USE );
}
}
if ( self->wait )
{
self->nextthink = level.time + self->wait;
}
}
void target_scriptrunner_use(gentity_t *self, gentity_t *other, gentity_t *activator)
{
if ( self->nextthink > level.time )
{
return;
}
self->activator = activator;
self->enemy = other;
if ( self->delay )
{//delay before firing scriptrunner
self->think = scriptrunner_run;
self->nextthink = level.time + self->delay;
}
else
{
scriptrunner_run (self);
}
}
/*QUAKED target_scriptrunner (1 0 0) (-4 -4 -4) (4 4 4) runonactivator x x x x x x INACTIVE
--- SPAWNFLAGS ---
runonactivator - Will run the script on the entity that used this or tripped the trigger that used this
INACTIVE - start off
----- KEYS ------
Usescript - Script to run when used
count - how many times to run, -1 = infinite. Default is once
wait - can't be used again in this amount of seconds (Default is 1 second if it's multiple-use)
delay - how long to wait after use to run script
*/
void SP_target_scriptrunner( gentity_t *self )
{
float v;
if ( self->spawnflags & 128 )
{
self->flags |= FL_INACTIVE;
}
if ( !self->count )
{
self->count = 1;//default 1 use only
}
/*
else if ( !self->wait )
{
self->wait = 1;//default wait of 1 sec
}
*/
// FIXME: this is a hack... because delay is read in as an int, so I'm bypassing that because it's too late in the project to change it and I want to be able to set less than a second delays
// no one should be setting a radius on a scriptrunner, if they are this would be bad, take this out for the next project
v = 0.0f;
G_SpawnFloat( "delay", "0", &v );
self->delay = v * 1000;//sec to ms
self->wait *= 1000;//sec to ms
G_SetOrigin( self, self->s.origin );
self->use = target_scriptrunner_use;
}
void G_SetActiveState(char *targetstring, qboolean actState)
{
gentity_t *target = NULL;
while( NULL != (target = G_Find(target, FOFS(targetname), targetstring)) )
{
target->flags = actState ? (target->flags&~FL_INACTIVE) : (target->flags|FL_INACTIVE);
}
}
#define ACT_ACTIVE qtrue
#define ACT_INACTIVE qfalse
void target_activate_use(gentity_t *self, gentity_t *other, gentity_t *activator)
{
G_ActivateBehavior(self,BSET_USE);
G_SetActiveState(self->target, ACT_ACTIVE);
}
void target_deactivate_use(gentity_t *self, gentity_t *other, gentity_t *activator)
{
G_ActivateBehavior(self,BSET_USE);
G_SetActiveState(self->target, ACT_INACTIVE);
}
//FIXME: make these apply to doors, etc too?
/*QUAKED target_activate (1 0 0) (-4 -4 -4) (4 4 4)
Will set the target(s) to be usable/triggerable
*/
void SP_target_activate( gentity_t *self )
{
G_SetOrigin( self, self->s.origin );
self->use = target_activate_use;
}
/*QUAKED target_deactivate (1 0 0) (-4 -4 -4) (4 4 4)
Will set the target(s) to be non-usable/triggerable
*/
void SP_target_deactivate( gentity_t *self )
{
G_SetOrigin( self, self->s.origin );
self->use = target_deactivate_use;
}
void target_level_change_use(gentity_t *self, gentity_t *other, gentity_t *activator)
{
G_ActivateBehavior(self,BSET_USE);
trap_SendConsoleCommand(EXEC_NOW, va("map %s", self->message));
}
/*QUAKED target_level_change (1 0 0) (-4 -4 -4) (4 4 4)
"mapname" - Name of map to change to
*/
void SP_target_level_change( gentity_t *self )
{
char *s;
G_SpawnString( "mapname", "", &s );
self->message = G_NewString(s);
if ( !self->message || !self->message[0] )
{
G_Error( "target_level_change with no mapname!\n");
return;
}
G_SetOrigin( self, self->s.origin );
self->use = target_level_change_use;
}
void target_play_music_use(gentity_t *self, gentity_t *other, gentity_t *activator)
{
G_ActivateBehavior(self,BSET_USE);
trap_SetConfigstring( CS_MUSIC, self->message );
}
/*QUAKED target_play_music (1 0 0) (-4 -4 -4) (4 4 4)
target_play_music
Plays the requested music files when this target is used.
"targetname"
"music" music WAV or MP3 file ( music/introfile.mp3 [optional] music/loopfile.mp3 )
If an intro file and loop file are specified, the intro plays first, then the looping
portion will start and loop indefinetly. If no introfile is entered, only the loopfile
will play.
*/
void SP_target_play_music( gentity_t *self )
{
char *s;
G_SetOrigin( self, self->s.origin );
if (!G_SpawnString( "music", "", &s ))
{
G_Error( "target_play_music without a music key at %s", vtos( self->s.origin ) );
}
self->message = G_NewString(s);
self->use = target_play_music_use;
}