~ubuntu-branches/ubuntu/precise/openarena/precise

« back to all changes in this revision

Viewing changes to code/game/g_target.c

  • Committer: Bazaar Package Importer
  • Author(s): Bruno "Fuddl" Kleinert
  • Date: 2007-01-20 12:28:09 UTC
  • Revision ID: james.westby@ubuntu.com-20070120122809-2yza5ojt7nqiyiam
Tags: upstream-0.6.0
ImportĀ upstreamĀ versionĀ 0.6.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
===========================================================================
 
3
Copyright (C) 1999-2005 Id Software, Inc.
 
4
 
 
5
This file is part of Quake III Arena source code.
 
6
 
 
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.
 
11
 
 
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.
 
16
 
 
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
===========================================================================
 
21
*/
 
22
//
 
23
#include "g_local.h"
 
24
 
 
25
//==========================================================
 
26
 
 
27
/*QUAKED target_give (1 0 0) (-8 -8 -8) (8 8 8)
 
28
Gives the activator all the items pointed to.
 
29
*/
 
30
void Use_Target_Give( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
 
31
        gentity_t       *t;
 
32
        trace_t         trace;
 
33
 
 
34
        if ( !activator->client ) {
 
35
                return;
 
36
        }
 
37
 
 
38
        if ( !ent->target ) {
 
39
                return;
 
40
        }
 
41
 
 
42
        memset( &trace, 0, sizeof( trace ) );
 
43
        t = NULL;
 
44
        while ( (t = G_Find (t, FOFS(targetname), ent->target)) != NULL ) {
 
45
                if ( !t->item ) {
 
46
                        continue;
 
47
                }
 
48
                Touch_Item( t, activator, &trace );
 
49
 
 
50
                // make sure it isn't going to respawn or show any events
 
51
                t->nextthink = 0;
 
52
                trap_UnlinkEntity( t );
 
53
        }
 
54
}
 
55
 
 
56
void SP_target_give( gentity_t *ent ) {
 
57
        ent->use = Use_Target_Give;
 
58
}
 
59
 
 
60
 
 
61
//==========================================================
 
62
 
 
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.
 
66
*/
 
67
void Use_target_remove_powerups( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
 
68
        if( !activator->client ) {
 
69
                return;
 
70
        }
 
71
 
 
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 );
 
78
        }
 
79
 
 
80
        memset( activator->client->ps.powerups, 0, sizeof( activator->client->ps.powerups ) );
 
81
}
 
82
 
 
83
void SP_target_remove_powerups( gentity_t *ent ) {
 
84
        ent->use = Use_target_remove_powerups;
 
85
}
 
86
 
 
87
 
 
88
//==========================================================
 
89
 
 
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
 
93
*/
 
94
void Think_Target_Delay( gentity_t *ent ) {
 
95
        G_UseTargets( ent, ent->activator );
 
96
}
 
97
 
 
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;
 
102
}
 
103
 
 
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 );
 
108
        }
 
109
 
 
110
        if ( !ent->wait ) {
 
111
                ent->wait = 1;
 
112
        }
 
113
        ent->use = Use_Target_Delay;
 
114
}
 
115
 
 
116
 
 
117
//==========================================================
 
118
 
 
119
/*QUAKED target_score (1 0 0) (-8 -8 -8) (8 8 8)
 
120
"count" number of points to add, default 1
 
121
 
 
122
The activator is given this many points.
 
123
*/
 
124
void Use_Target_Score (gentity_t *ent, gentity_t *other, gentity_t *activator) {
 
125
        AddScore( activator, ent->r.currentOrigin, ent->count );
 
126
}
 
127
 
 
128
void SP_target_score( gentity_t *ent ) {
 
129
        if ( !ent->count ) {
 
130
                ent->count = 1;
 
131
        }
 
132
        ent->use = Use_Target_Score;
 
133
}
 
134
 
 
135
 
 
136
//==========================================================
 
137
 
 
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.
 
141
*/
 
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 ));
 
145
                return;
 
146
        }
 
147
 
 
148
        if ( ent->spawnflags & 3 ) {
 
149
                if ( ent->spawnflags & 1 ) {
 
150
                        G_TeamCommand( TEAM_RED, va("cp \"%s\"", ent->message) );
 
151
                }
 
152
                if ( ent->spawnflags & 2 ) {
 
153
                        G_TeamCommand( TEAM_BLUE, va("cp \"%s\"", ent->message) );
 
154
                }
 
155
                return;
 
156
        }
 
157
 
 
158
        trap_SendServerCommand( -1, va("cp \"%s\"", ent->message ));
 
159
}
 
160
 
 
161
void SP_target_print( gentity_t *ent ) {
 
162
        ent->use = Use_Target_Print;
 
163
}
 
164
 
 
165
 
 
166
//==========================================================
 
167
 
 
168
 
 
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
 
171
 
 
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
 
180
*/
 
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
 
185
                else
 
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 );
 
192
                } else {
 
193
                        G_AddEvent( ent, EV_GENERAL_SOUND, ent->noise_index );
 
194
                }
 
195
        }
 
196
}
 
197
 
 
198
void SP_target_speaker( gentity_t *ent ) {
 
199
        char    buffer[MAX_QPATH];
 
200
        char    *s;
 
201
 
 
202
        G_SpawnFloat( "wait", "0", &ent->wait );
 
203
        G_SpawnFloat( "random", "0", &ent->random );
 
204
 
 
205
        if ( !G_SpawnString( "noise", "NOSOUND", &s ) ) {
 
206
                G_Error( "target_speaker without a noise key at %s", vtos( ent->s.origin ) );
 
207
        }
 
208
 
 
209
        // force all client reletive sounds to be "activator" speakers that
 
210
        // play on the entity that activates it
 
211
        if ( s[0] == '*' ) {
 
212
                ent->spawnflags |= 8;
 
213
        }
 
214
 
 
215
        if (!strstr( s, ".wav" )) {
 
216
                Com_sprintf (buffer, sizeof(buffer), "%s.wav", s );
 
217
        } else {
 
218
                Q_strncpyz( buffer, s, sizeof(buffer) );
 
219
        }
 
220
        ent->noise_index = G_SoundIndex(buffer);
 
221
 
 
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;
 
227
 
 
228
 
 
229
        // check for prestarted looping sound
 
230
        if ( ent->spawnflags & 1 ) {
 
231
                ent->s.loopSound = ent->noise_index;
 
232
        }
 
233
 
 
234
        ent->use = Use_Target_Speaker;
 
235
 
 
236
        if (ent->spawnflags & 4) {
 
237
                ent->r.svFlags |= SVF_BROADCAST;
 
238
        }
 
239
 
 
240
        VectorCopy( ent->s.origin, ent->s.pos.trBase );
 
241
 
 
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 );
 
245
}
 
246
 
 
247
 
 
248
 
 
249
//==========================================================
 
250
 
 
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.
 
253
*/
 
254
void target_laser_think (gentity_t *self) {
 
255
        vec3_t  end;
 
256
        trace_t tr;
 
257
        vec3_t  point;
 
258
 
 
259
        // if pointed at another entity, set movedir to point at it
 
260
        if ( self->enemy ) {
 
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);
 
265
        }
 
266
 
 
267
        // fire forward and see what we hit
 
268
        VectorMA (self->s.origin, 2048, self->movedir, end);
 
269
 
 
270
        trap_Trace( &tr, self->s.origin, NULL, NULL, end, self->s.number, CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_CORPSE);
 
271
 
 
272
        if ( tr.entityNum ) {
 
273
                // hurt it if we can
 
274
                G_Damage ( &g_entities[tr.entityNum], self, self->activator, self->movedir, 
 
275
                        tr.endpos, self->damage, DAMAGE_NO_KNOCKBACK, MOD_TARGET_LASER);
 
276
        }
 
277
 
 
278
        VectorCopy (tr.endpos, self->s.origin2);
 
279
 
 
280
        trap_LinkEntity( self );
 
281
        self->nextthink = level.time + FRAMETIME;
 
282
}
 
283
 
 
284
void target_laser_on (gentity_t *self)
 
285
{
 
286
        if (!self->activator)
 
287
                self->activator = self;
 
288
        target_laser_think (self);
 
289
}
 
290
 
 
291
void target_laser_off (gentity_t *self)
 
292
{
 
293
        trap_UnlinkEntity( self );
 
294
        self->nextthink = 0;
 
295
}
 
296
 
 
297
void target_laser_use (gentity_t *self, gentity_t *other, gentity_t *activator)
 
298
{
 
299
        self->activator = activator;
 
300
        if ( self->nextthink > 0 )
 
301
                target_laser_off (self);
 
302
        else
 
303
                target_laser_on (self);
 
304
}
 
305
 
 
306
void target_laser_start (gentity_t *self)
 
307
{
 
308
        gentity_t *ent;
 
309
 
 
310
        self->s.eType = ET_BEAM;
 
311
 
 
312
        if (self->target) {
 
313
                ent = G_Find (NULL, FOFS(targetname), self->target);
 
314
                if (!ent) {
 
315
                        G_Printf ("%s at %s: %s is a bad target\n", self->classname, vtos(self->s.origin), self->target);
 
316
                }
 
317
                self->enemy = ent;
 
318
        } else {
 
319
                G_SetMovedir (self->s.angles, self->movedir);
 
320
        }
 
321
 
 
322
        self->use = target_laser_use;
 
323
        self->think = target_laser_think;
 
324
 
 
325
        if ( !self->damage ) {
 
326
                self->damage = 1;
 
327
        }
 
328
 
 
329
        if (self->spawnflags & 1)
 
330
                target_laser_on (self);
 
331
        else
 
332
                target_laser_off (self);
 
333
}
 
334
 
 
335
void SP_target_laser (gentity_t *self)
 
336
{
 
337
        // let everything else get spawned before we start firing
 
338
        self->think = target_laser_start;
 
339
        self->nextthink = level.time + FRAMETIME;
 
340
}
 
341
 
 
342
 
 
343
//==========================================================
 
344
 
 
345
void target_teleporter_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {
 
346
        gentity_t       *dest;
 
347
 
 
348
        if (!activator->client)
 
349
                return;
 
350
        dest =  G_PickTarget( self->target );
 
351
        if (!dest) {
 
352
                G_Printf ("Couldn't find teleporter destination\n");
 
353
                return;
 
354
        }
 
355
 
 
356
        TeleportPlayer( activator, dest->s.origin, dest->s.angles );
 
357
}
 
358
 
 
359
/*QUAKED target_teleporter (1 0 0) (-8 -8 -8) (8 8 8)
 
360
The activator will be teleported away.
 
361
*/
 
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));
 
365
 
 
366
        self->use = target_teleporter_use;
 
367
}
 
368
 
 
369
//==========================================================
 
370
 
 
371
 
 
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
 
376
*/
 
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 ) {
 
380
                return;
 
381
        }
 
382
        if ( ( self->spawnflags & 2 ) && activator->client 
 
383
                && activator->client->sess.sessionTeam != TEAM_BLUE ) {
 
384
                return;
 
385
        }
 
386
        if ( self->spawnflags & 4 ) {
 
387
                gentity_t       *ent;
 
388
 
 
389
                ent = G_PickTarget( self->target );
 
390
                if ( ent && ent->use ) {
 
391
                        ent->use( ent, self, activator );
 
392
                }
 
393
                return;
 
394
        }
 
395
        G_UseTargets (self, activator);
 
396
}
 
397
 
 
398
void SP_target_relay (gentity_t *self) {
 
399
        self->use = target_relay_use;
 
400
}
 
401
 
 
402
 
 
403
//==========================================================
 
404
 
 
405
/*QUAKED target_kill (.5 .5 .5) (-8 -8 -8) (8 8 8)
 
406
Kills the activator.
 
407
*/
 
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);
 
410
}
 
411
 
 
412
void SP_target_kill( gentity_t *self ) {
 
413
        self->use = target_kill_use;
 
414
}
 
415
 
 
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.
 
418
*/
 
419
void SP_target_position( gentity_t *self ){
 
420
        G_SetOrigin( self, self->s.origin );
 
421
}
 
422
 
 
423
static void target_location_linkup(gentity_t *ent)
 
424
{
 
425
        int i;
 
426
        int n;
 
427
 
 
428
        if (level.locationLinked) 
 
429
                return;
 
430
 
 
431
        level.locationLinked = qtrue;
 
432
 
 
433
        level.locationHead = NULL;
 
434
 
 
435
        trap_SetConfigstring( CS_LOCATIONS, "unknown" );
 
436
 
 
437
        for (i = 0, ent = g_entities, n = 1;
 
438
                        i < level.num_entities;
 
439
                        i++, ent++) {
 
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 );
 
444
                        n++;
 
445
                        ent->nextTrain = level.locationHead;
 
446
                        level.locationHead = ent;
 
447
                }
 
448
        }
 
449
 
 
450
        // All linked together now
 
451
}
 
452
 
 
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
 
457
 
 
458
Closest target_location in sight used for the location, if none
 
459
in site, closest in distance
 
460
*/
 
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
 
464
 
 
465
        G_SetOrigin( self, self->s.origin );
 
466
}
 
467