2
===========================================================================
3
Copyright (C) 1999-2005 Id Software, Inc.
5
This file is part of Quake III Arena source code.
7
Quake III Arena source code is free software; you can redistribute it
8
and/or modify it under the terms of the GNU General Public License as
9
published by the Free Software Foundation; either version 2 of the License,
10
or (at your option) any later version.
12
Quake III Arena source code is distributed in the hope that it will be
13
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with Quake III Arena source code; if not, write to the Free Software
19
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
===========================================================================
25
//==========================================================
27
/*QUAKED target_give (1 0 0) (-8 -8 -8) (8 8 8)
28
Gives the activator all the items pointed to.
30
void Use_Target_Give( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
34
if ( !activator->client ) {
42
memset( &trace, 0, sizeof( trace ) );
44
while ( (t = G_Find (t, FOFS(targetname), ent->target)) != NULL ) {
48
Touch_Item( t, activator, &trace );
50
// make sure it isn't going to respawn or show any events
52
trap_UnlinkEntity( t );
56
void SP_target_give( gentity_t *ent ) {
57
ent->use = Use_Target_Give;
61
//==========================================================
63
/*QUAKED target_remove_powerups (1 0 0) (-8 -8 -8) (8 8 8)
64
takes away all the activators powerups.
65
Used to drop flight powerups into death puts.
67
void Use_target_remove_powerups( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
68
if( !activator->client ) {
72
if( activator->client->ps.powerups[PW_REDFLAG] ) {
73
Team_ReturnFlag( TEAM_RED );
74
} else if( activator->client->ps.powerups[PW_BLUEFLAG] ) {
75
Team_ReturnFlag( TEAM_BLUE );
76
} else if( activator->client->ps.powerups[PW_NEUTRALFLAG] ) {
77
Team_ReturnFlag( TEAM_FREE );
80
memset( activator->client->ps.powerups, 0, sizeof( activator->client->ps.powerups ) );
83
void SP_target_remove_powerups( gentity_t *ent ) {
84
ent->use = Use_target_remove_powerups;
88
//==========================================================
90
/*QUAKED target_delay (1 0 0) (-8 -8 -8) (8 8 8)
91
"wait" seconds to pause before firing targets.
92
"random" delay variance, total delay = delay +/- random seconds
94
void Think_Target_Delay( gentity_t *ent ) {
95
G_UseTargets( ent, ent->activator );
98
void Use_Target_Delay( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
99
ent->nextthink = level.time + ( ent->wait + ent->random * crandom() ) * 1000;
100
ent->think = Think_Target_Delay;
101
ent->activator = activator;
104
void SP_target_delay( gentity_t *ent ) {
105
// check delay for backwards compatability
106
if ( !G_SpawnFloat( "delay", "0", &ent->wait ) ) {
107
G_SpawnFloat( "wait", "1", &ent->wait );
113
ent->use = Use_Target_Delay;
117
//==========================================================
119
/*QUAKED target_score (1 0 0) (-8 -8 -8) (8 8 8)
120
"count" number of points to add, default 1
122
The activator is given this many points.
124
void Use_Target_Score (gentity_t *ent, gentity_t *other, gentity_t *activator) {
125
AddScore( activator, ent->r.currentOrigin, ent->count );
128
void SP_target_score( gentity_t *ent ) {
132
ent->use = Use_Target_Score;
136
//==========================================================
138
/*QUAKED target_print (1 0 0) (-8 -8 -8) (8 8 8) redteam blueteam private
139
"message" text to print
140
If "private", only the activator gets the message. If no checks, all clients get the message.
142
void Use_Target_Print (gentity_t *ent, gentity_t *other, gentity_t *activator) {
143
if ( activator->client && ( ent->spawnflags & 4 ) ) {
144
trap_SendServerCommand( activator-g_entities, va("cp \"%s\"", ent->message ));
148
if ( ent->spawnflags & 3 ) {
149
if ( ent->spawnflags & 1 ) {
150
G_TeamCommand( TEAM_RED, va("cp \"%s\"", ent->message) );
152
if ( ent->spawnflags & 2 ) {
153
G_TeamCommand( TEAM_BLUE, va("cp \"%s\"", ent->message) );
158
trap_SendServerCommand( -1, va("cp \"%s\"", ent->message ));
161
void SP_target_print( gentity_t *ent ) {
162
ent->use = Use_Target_Print;
166
//==========================================================
169
/*QUAKED target_speaker (1 0 0) (-8 -8 -8) (8 8 8) looped-on looped-off global activator
170
"noise" wav file to play
172
A global sound will play full volume throughout the level.
173
Activator sounds will play on the player that activated the target.
174
Global and activator sounds can't be combined with looping.
175
Normal sounds play each time the target is used.
176
Looped sounds will be toggled by use functions.
177
Multiple identical looping sounds will just increase volume without any speed cost.
178
"wait" : Seconds between auto triggerings, 0 = don't auto trigger
179
"random" wait variance, default is 0
181
void Use_Target_Speaker (gentity_t *ent, gentity_t *other, gentity_t *activator) {
182
if (ent->spawnflags & 3) { // looping sound toggles
183
if (ent->s.loopSound)
184
ent->s.loopSound = 0; // turn it off
186
ent->s.loopSound = ent->noise_index; // start it
187
}else { // normal sound
188
if ( ent->spawnflags & 8 ) {
189
G_AddEvent( activator, EV_GENERAL_SOUND, ent->noise_index );
190
} else if (ent->spawnflags & 4) {
191
G_AddEvent( ent, EV_GLOBAL_SOUND, ent->noise_index );
193
G_AddEvent( ent, EV_GENERAL_SOUND, ent->noise_index );
198
void SP_target_speaker( gentity_t *ent ) {
199
char buffer[MAX_QPATH];
202
G_SpawnFloat( "wait", "0", &ent->wait );
203
G_SpawnFloat( "random", "0", &ent->random );
205
if ( !G_SpawnString( "noise", "NOSOUND", &s ) ) {
206
G_Error( "target_speaker without a noise key at %s", vtos( ent->s.origin ) );
209
// force all client reletive sounds to be "activator" speakers that
210
// play on the entity that activates it
212
ent->spawnflags |= 8;
215
if (!strstr( s, ".wav" )) {
216
Com_sprintf (buffer, sizeof(buffer), "%s.wav", s );
218
Q_strncpyz( buffer, s, sizeof(buffer) );
220
ent->noise_index = G_SoundIndex(buffer);
222
// a repeating speaker can be done completely client side
223
ent->s.eType = ET_SPEAKER;
224
ent->s.eventParm = ent->noise_index;
225
ent->s.frame = ent->wait * 10;
226
ent->s.clientNum = ent->random * 10;
229
// check for prestarted looping sound
230
if ( ent->spawnflags & 1 ) {
231
ent->s.loopSound = ent->noise_index;
234
ent->use = Use_Target_Speaker;
236
if (ent->spawnflags & 4) {
237
ent->r.svFlags |= SVF_BROADCAST;
240
VectorCopy( ent->s.origin, ent->s.pos.trBase );
242
// must link the entity so we get areas and clusters so
243
// the server can determine who to send updates to
244
trap_LinkEntity( ent );
249
//==========================================================
251
/*QUAKED target_laser (0 .5 .8) (-8 -8 -8) (8 8 8) START_ON
252
When triggered, fires a laser. You can either set a target or a direction.
254
void target_laser_think (gentity_t *self) {
259
// if pointed at another entity, set movedir to point at it
261
VectorMA (self->enemy->s.origin, 0.5, self->enemy->r.mins, point);
262
VectorMA (point, 0.5, self->enemy->r.maxs, point);
263
VectorSubtract (point, self->s.origin, self->movedir);
264
VectorNormalize (self->movedir);
267
// fire forward and see what we hit
268
VectorMA (self->s.origin, 2048, self->movedir, end);
270
trap_Trace( &tr, self->s.origin, NULL, NULL, end, self->s.number, CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_CORPSE);
272
if ( tr.entityNum ) {
274
G_Damage ( &g_entities[tr.entityNum], self, self->activator, self->movedir,
275
tr.endpos, self->damage, DAMAGE_NO_KNOCKBACK, MOD_TARGET_LASER);
278
VectorCopy (tr.endpos, self->s.origin2);
280
trap_LinkEntity( self );
281
self->nextthink = level.time + FRAMETIME;
284
void target_laser_on (gentity_t *self)
286
if (!self->activator)
287
self->activator = self;
288
target_laser_think (self);
291
void target_laser_off (gentity_t *self)
293
trap_UnlinkEntity( self );
297
void target_laser_use (gentity_t *self, gentity_t *other, gentity_t *activator)
299
self->activator = activator;
300
if ( self->nextthink > 0 )
301
target_laser_off (self);
303
target_laser_on (self);
306
void target_laser_start (gentity_t *self)
310
self->s.eType = ET_BEAM;
313
ent = G_Find (NULL, FOFS(targetname), self->target);
315
G_Printf ("%s at %s: %s is a bad target\n", self->classname, vtos(self->s.origin), self->target);
319
G_SetMovedir (self->s.angles, self->movedir);
322
self->use = target_laser_use;
323
self->think = target_laser_think;
325
if ( !self->damage ) {
329
if (self->spawnflags & 1)
330
target_laser_on (self);
332
target_laser_off (self);
335
void SP_target_laser (gentity_t *self)
337
// let everything else get spawned before we start firing
338
self->think = target_laser_start;
339
self->nextthink = level.time + FRAMETIME;
343
//==========================================================
345
void target_teleporter_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {
348
if (!activator->client)
350
dest = G_PickTarget( self->target );
352
G_Printf ("Couldn't find teleporter destination\n");
356
TeleportPlayer( activator, dest->s.origin, dest->s.angles );
359
/*QUAKED target_teleporter (1 0 0) (-8 -8 -8) (8 8 8)
360
The activator will be teleported away.
362
void SP_target_teleporter( gentity_t *self ) {
363
if (!self->targetname)
364
G_Printf("untargeted %s at %s\n", self->classname, vtos(self->s.origin));
366
self->use = target_teleporter_use;
369
//==========================================================
372
/*QUAKED target_relay (.5 .5 .5) (-8 -8 -8) (8 8 8) RED_ONLY BLUE_ONLY RANDOM
373
This doesn't perform any actions except fire its targets.
374
The activator can be forced to be from a certain team.
375
if RANDOM is checked, only one of the targets will be fired, not all of them
377
void target_relay_use (gentity_t *self, gentity_t *other, gentity_t *activator) {
378
if ( ( self->spawnflags & 1 ) && activator->client
379
&& activator->client->sess.sessionTeam != TEAM_RED ) {
382
if ( ( self->spawnflags & 2 ) && activator->client
383
&& activator->client->sess.sessionTeam != TEAM_BLUE ) {
386
if ( self->spawnflags & 4 ) {
389
ent = G_PickTarget( self->target );
390
if ( ent && ent->use ) {
391
ent->use( ent, self, activator );
395
G_UseTargets (self, activator);
398
void SP_target_relay (gentity_t *self) {
399
self->use = target_relay_use;
403
//==========================================================
405
/*QUAKED target_kill (.5 .5 .5) (-8 -8 -8) (8 8 8)
408
void target_kill_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {
409
G_Damage ( activator, NULL, NULL, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);
412
void SP_target_kill( gentity_t *self ) {
413
self->use = target_kill_use;
416
/*QUAKED target_position (0 0.5 0) (-4 -4 -4) (4 4 4)
417
Used as a positional target for in-game calculation, like jumppad targets.
419
void SP_target_position( gentity_t *self ){
420
G_SetOrigin( self, self->s.origin );
423
static void target_location_linkup(gentity_t *ent)
428
if (level.locationLinked)
431
level.locationLinked = qtrue;
433
level.locationHead = NULL;
435
trap_SetConfigstring( CS_LOCATIONS, "unknown" );
437
for (i = 0, ent = g_entities, n = 1;
438
i < level.num_entities;
440
if (ent->classname && !Q_stricmp(ent->classname, "target_location")) {
441
// lets overload some variables!
442
ent->health = n; // use for location marking
443
trap_SetConfigstring( CS_LOCATIONS + n, ent->message );
445
ent->nextTrain = level.locationHead;
446
level.locationHead = ent;
450
// All linked together now
453
/*QUAKED target_location (0 0.5 0) (-8 -8 -8) (8 8 8)
454
Set "message" to the name of this location.
455
Set "count" to 0-7 for color.
456
0:white 1:red 2:green 3:yellow 4:blue 5:cyan 6:magenta 7:white
458
Closest target_location in sight used for the location, if none
459
in site, closest in distance
461
void SP_target_location( gentity_t *self ){
462
self->think = target_location_linkup;
463
self->nextthink = level.time + 200; // Let them all spawn first
465
G_SetOrigin( self, self->s.origin );