Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

g_target.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 //
00023 #include "g_local.h"
00024 
00025 //==========================================================
00026 
00027 /*QUAKED target_give (1 0 0) (-8 -8 -8) (8 8 8)
00028 Gives the activator all the items pointed to.
00029 */
00030 void Use_Target_Give( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
00031     gentity_t   *t;
00032     trace_t     trace;
00033 
00034     if ( !activator->client ) {
00035         return;
00036     }
00037 
00038     if ( !ent->target ) {
00039         return;
00040     }
00041 
00042     memset( &trace, 0, sizeof( trace ) );
00043     t = NULL;
00044     while ( (t = G_Find (t, FOFS(targetname), ent->target)) != NULL ) {
00045         if ( !t->item ) {
00046             continue;
00047         }
00048         Touch_Item( t, activator, &trace );
00049 
00050         // make sure it isn't going to respawn or show any events
00051         t->nextthink = 0;
00052         trap_UnlinkEntity( t );
00053     }
00054 }
00055 
00056 void SP_target_give( gentity_t *ent ) {
00057     ent->use = Use_Target_Give;
00058 }
00059 
00060 
00061 //==========================================================
00062 
00063 /*QUAKED target_remove_powerups (1 0 0) (-8 -8 -8) (8 8 8)
00064 takes away all the activators powerups.
00065 Used to drop flight powerups into death puts.
00066 */
00067 void Use_target_remove_powerups( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
00068     if( !activator->client ) {
00069         return;
00070     }
00071 
00072     if( activator->client->ps.powerups[PW_REDFLAG] ) {
00073         Team_ReturnFlag( TEAM_RED );
00074     } else if( activator->client->ps.powerups[PW_BLUEFLAG] ) {
00075         Team_ReturnFlag( TEAM_BLUE );
00076     } else if( activator->client->ps.powerups[PW_NEUTRALFLAG] ) {
00077         Team_ReturnFlag( TEAM_FREE );
00078     }
00079 
00080     memset( activator->client->ps.powerups, 0, sizeof( activator->client->ps.powerups ) );
00081 }
00082 
00083 void SP_target_remove_powerups( gentity_t *ent ) {
00084     ent->use = Use_target_remove_powerups;
00085 }
00086 
00087 
00088 //==========================================================
00089 
00090 /*QUAKED target_delay (1 0 0) (-8 -8 -8) (8 8 8)
00091 "wait" seconds to pause before firing targets.
00092 "random" delay variance, total delay = delay +/- random seconds
00093 */
00094 void Think_Target_Delay( gentity_t *ent ) {
00095     G_UseTargets( ent, ent->activator );
00096 }
00097 
00098 void Use_Target_Delay( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
00099     ent->nextthink = level.time + ( ent->wait + ent->random * crandom() ) * 1000;
00100     ent->think = Think_Target_Delay;
00101     ent->activator = activator;
00102 }
00103 
00104 void SP_target_delay( gentity_t *ent ) {
00105     // check delay for backwards compatability
00106     if ( !G_SpawnFloat( "delay", "0", &ent->wait ) ) {
00107         G_SpawnFloat( "wait", "1", &ent->wait );
00108     }
00109 
00110     if ( !ent->wait ) {
00111         ent->wait = 1;
00112     }
00113     ent->use = Use_Target_Delay;
00114 }
00115 
00116 
00117 //==========================================================
00118 
00119 /*QUAKED target_score (1 0 0) (-8 -8 -8) (8 8 8)
00120 "count" number of points to add, default 1
00121 
00122 The activator is given this many points.
00123 */
00124 void Use_Target_Score (gentity_t *ent, gentity_t *other, gentity_t *activator) {
00125     AddScore( activator, ent->r.currentOrigin, ent->count );
00126 }
00127 
00128 void SP_target_score( gentity_t *ent ) {
00129     if ( !ent->count ) {
00130         ent->count = 1;
00131     }
00132     ent->use = Use_Target_Score;
00133 }
00134 
00135 
00136 //==========================================================
00137 
00138 /*QUAKED target_print (1 0 0) (-8 -8 -8) (8 8 8) redteam blueteam private
00139 "message"   text to print
00140 If "private", only the activator gets the message.  If no checks, all clients get the message.
00141 */
00142 void Use_Target_Print (gentity_t *ent, gentity_t *other, gentity_t *activator) {
00143     if ( activator->client && ( ent->spawnflags & 4 ) ) {
00144         trap_SendServerCommand( activator-g_entities, va("cp \"%s\"", ent->message ));
00145         return;
00146     }
00147 
00148     if ( ent->spawnflags & 3 ) {
00149         if ( ent->spawnflags & 1 ) {
00150             G_TeamCommand( TEAM_RED, va("cp \"%s\"", ent->message) );
00151         }
00152         if ( ent->spawnflags & 2 ) {
00153             G_TeamCommand( TEAM_BLUE, va("cp \"%s\"", ent->message) );
00154         }
00155         return;
00156     }
00157 
00158     trap_SendServerCommand( -1, va("cp \"%s\"", ent->message ));
00159 }
00160 
00161 void SP_target_print( gentity_t *ent ) {
00162     ent->use = Use_Target_Print;
00163 }
00164 
00165 
00166 //==========================================================
00167 
00168 
00169 /*QUAKED target_speaker (1 0 0) (-8 -8 -8) (8 8 8) looped-on looped-off global activator
00170 "noise"     wav file to play
00171 
00172 A global sound will play full volume throughout the level.
00173 Activator sounds will play on the player that activated the target.
00174 Global and activator sounds can't be combined with looping.
00175 Normal sounds play each time the target is used.
00176 Looped sounds will be toggled by use functions.
00177 Multiple identical looping sounds will just increase volume without any speed cost.
00178 "wait" : Seconds between auto triggerings, 0 = don't auto trigger
00179 "random"    wait variance, default is 0
00180 */
00181 void Use_Target_Speaker (gentity_t *ent, gentity_t *other, gentity_t *activator) {
00182     if (ent->spawnflags & 3) {  // looping sound toggles
00183         if (ent->s.loopSound)
00184             ent->s.loopSound = 0;   // turn it off
00185         else
00186             ent->s.loopSound = ent->noise_index;    // start it
00187     }else { // normal sound
00188         if ( ent->spawnflags & 8 ) {
00189             G_AddEvent( activator, EV_GENERAL_SOUND, ent->noise_index );
00190         } else if (ent->spawnflags & 4) {
00191             G_AddEvent( ent, EV_GLOBAL_SOUND, ent->noise_index );
00192         } else {
00193             G_AddEvent( ent, EV_GENERAL_SOUND, ent->noise_index );
00194         }
00195     }
00196 }
00197 
00198 void SP_target_speaker( gentity_t *ent ) {
00199     char    buffer[MAX_QPATH];
00200     char    *s;
00201 
00202     G_SpawnFloat( "wait", "0", &ent->wait );
00203     G_SpawnFloat( "random", "0", &ent->random );
00204 
00205     if ( !G_SpawnString( "noise", "NOSOUND", &s ) ) {
00206         G_Error( "target_speaker without a noise key at %s", vtos( ent->s.origin ) );
00207     }
00208 
00209     // force all client reletive sounds to be "activator" speakers that
00210     // play on the entity that activates it
00211     if ( s[0] == '*' ) {
00212         ent->spawnflags |= 8;
00213     }
00214 
00215     if (!strstr( s, ".wav" )) {
00216         Com_sprintf (buffer, sizeof(buffer), "%s.wav", s );
00217     } else {
00218         Q_strncpyz( buffer, s, sizeof(buffer) );
00219     }
00220     ent->noise_index = G_SoundIndex(buffer);
00221 
00222     // a repeating speaker can be done completely client side
00223     ent->s.eType = ET_SPEAKER;
00224     ent->s.eventParm = ent->noise_index;
00225     ent->s.frame = ent->wait * 10;
00226     ent->s.clientNum = ent->random * 10;
00227 
00228 
00229     // check for prestarted looping sound
00230     if ( ent->spawnflags & 1 ) {
00231         ent->s.loopSound = ent->noise_index;
00232     }
00233 
00234     ent->use = Use_Target_Speaker;
00235 
00236     if (ent->spawnflags & 4) {
00237         ent->r.svFlags |= SVF_BROADCAST;
00238     }
00239 
00240     VectorCopy( ent->s.origin, ent->s.pos.trBase );
00241 
00242     // must link the entity so we get areas and clusters so
00243     // the server can determine who to send updates to
00244     trap_LinkEntity( ent );
00245 }
00246 
00247 
00248 
00249 //==========================================================
00250 
00251 /*QUAKED target_laser (0 .5 .8) (-8 -8 -8) (8 8 8) START_ON
00252 When triggered, fires a laser.  You can either set a target or a direction.
00253 */
00254 void target_laser_think (gentity_t *self) {
00255     vec3_t  end;
00256     trace_t tr;
00257     vec3_t  point;
00258 
00259     // if pointed at another entity, set movedir to point at it
00260     if ( self->enemy ) {
00261         VectorMA (self->enemy->s.origin, 0.5, self->enemy->r.mins, point);
00262         VectorMA (point, 0.5, self->enemy->r.maxs, point);
00263         VectorSubtract (point, self->s.origin, self->movedir);
00264         VectorNormalize (self->movedir);
00265     }
00266 
00267     // fire forward and see what we hit
00268     VectorMA (self->s.origin, 2048, self->movedir, end);
00269 
00270     trap_Trace( &tr, self->s.origin, NULL, NULL, end, self->s.number, CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_CORPSE);
00271 
00272     if ( tr.entityNum ) {
00273         // hurt it if we can
00274         G_Damage ( &g_entities[tr.entityNum], self, self->activator, self->movedir, 
00275             tr.endpos, self->damage, DAMAGE_NO_KNOCKBACK, MOD_TARGET_LASER);
00276     }
00277 
00278     VectorCopy (tr.endpos, self->s.origin2);
00279 
00280     trap_LinkEntity( self );
00281     self->nextthink = level.time + FRAMETIME;
00282 }
00283 
00284 void target_laser_on (gentity_t *self)
00285 {
00286     if (!self->activator)
00287         self->activator = self;
00288     target_laser_think (self);
00289 }
00290 
00291 void target_laser_off (gentity_t *self)
00292 {
00293     trap_UnlinkEntity( self );
00294     self->nextthink = 0;
00295 }
00296 
00297 void target_laser_use (gentity_t *self, gentity_t *other, gentity_t *activator)
00298 {
00299     self->activator = activator;
00300     if ( self->nextthink > 0 )
00301         target_laser_off (self);
00302     else
00303         target_laser_on (self);
00304 }
00305 
00306 void target_laser_start (gentity_t *self)
00307 {
00308     gentity_t *ent;
00309 
00310     self->s.eType = ET_BEAM;
00311 
00312     if (self->target) {
00313         ent = G_Find (NULL, FOFS(targetname), self->target);
00314         if (!ent) {
00315             G_Printf ("%s at %s: %s is a bad target\n", self->classname, vtos(self->s.origin), self->target);
00316         }
00317         self->enemy = ent;
00318     } else {
00319         G_SetMovedir (self->s.angles, self->movedir);
00320     }
00321 
00322     self->use = target_laser_use;
00323     self->think = target_laser_think;
00324 
00325     if ( !self->damage ) {
00326         self->damage = 1;
00327     }
00328 
00329     if (self->spawnflags & 1)
00330         target_laser_on (self);
00331     else
00332         target_laser_off (self);
00333 }
00334 
00335 void SP_target_laser (gentity_t *self)
00336 {
00337     // let everything else get spawned before we start firing
00338     self->think = target_laser_start;
00339     self->nextthink = level.time + FRAMETIME;
00340 }
00341 
00342 
00343 //==========================================================
00344 
00345 void target_teleporter_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {
00346     gentity_t   *dest;
00347 
00348     if (!activator->client)
00349         return;
00350     dest =  G_PickTarget( self->target );
00351     if (!dest) {
00352         G_Printf ("Couldn't find teleporter destination\n");
00353         return;
00354     }
00355 
00356     TeleportPlayer( activator, dest->s.origin, dest->s.angles );
00357 }
00358 
00359 /*QUAKED target_teleporter (1 0 0) (-8 -8 -8) (8 8 8)
00360 The activator will be teleported away.
00361 */
00362 void SP_target_teleporter( gentity_t *self ) {
00363     if (!self->targetname)
00364         G_Printf("untargeted %s at %s\n", self->classname, vtos(self->s.origin));
00365 
00366     self->use = target_teleporter_use;
00367 }
00368 
00369 //==========================================================
00370 
00371 
00372 /*QUAKED target_relay (.5 .5 .5) (-8 -8 -8) (8 8 8) RED_ONLY BLUE_ONLY RANDOM
00373 This doesn't perform any actions except fire its targets.
00374 The activator can be forced to be from a certain team.
00375 if RANDOM is checked, only one of the targets will be fired, not all of them
00376 */
00377 void target_relay_use (gentity_t *self, gentity_t *other, gentity_t *activator) {
00378     if ( ( self->spawnflags & 1 ) && activator->client 
00379         && activator->client->sess.sessionTeam != TEAM_RED ) {
00380         return;
00381     }
00382     if ( ( self->spawnflags & 2 ) && activator->client 
00383         && activator->client->sess.sessionTeam != TEAM_BLUE ) {
00384         return;
00385     }
00386     if ( self->spawnflags & 4 ) {
00387         gentity_t   *ent;
00388 
00389         ent = G_PickTarget( self->target );
00390         if ( ent && ent->use ) {
00391             ent->use( ent, self, activator );
00392         }
00393         return;
00394     }
00395     G_UseTargets (self, activator);
00396 }
00397 
00398 void SP_target_relay (gentity_t *self) {
00399     self->use = target_relay_use;
00400 }
00401 
00402 
00403 //==========================================================
00404 
00405 /*QUAKED target_kill (.5 .5 .5) (-8 -8 -8) (8 8 8)
00406 Kills the activator.
00407 */
00408 void target_kill_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {
00409     G_Damage ( activator, NULL, NULL, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);
00410 }
00411 
00412 void SP_target_kill( gentity_t *self ) {
00413     self->use = target_kill_use;
00414 }
00415 
00416 /*QUAKED target_position (0 0.5 0) (-4 -4 -4) (4 4 4)
00417 Used as a positional target for in-game calculation, like jumppad targets.
00418 */
00419 void SP_target_position( gentity_t *self ){
00420     G_SetOrigin( self, self->s.origin );
00421 }
00422 
00423 static void target_location_linkup(gentity_t *ent)
00424 {
00425     int i;
00426     int n;
00427 
00428     if (level.locationLinked) 
00429         return;
00430 
00431     level.locationLinked = qtrue;
00432 
00433     level.locationHead = NULL;
00434 
00435     trap_SetConfigstring( CS_LOCATIONS, "unknown" );
00436 
00437     for (i = 0, ent = g_entities, n = 1;
00438             i < level.num_entities;
00439             i++, ent++) {
00440         if (ent->classname && !Q_stricmp(ent->classname, "target_location")) {
00441             // lets overload some variables!
00442             ent->health = n; // use for location marking
00443             trap_SetConfigstring( CS_LOCATIONS + n, ent->message );
00444             n++;
00445             ent->nextTrain = level.locationHead;
00446             level.locationHead = ent;
00447         }
00448     }
00449 
00450     // All linked together now
00451 }
00452 
00453 /*QUAKED target_location (0 0.5 0) (-8 -8 -8) (8 8 8)
00454 Set "message" to the name of this location.
00455 Set "count" to 0-7 for color.
00456 0:white 1:red 2:green 3:yellow 4:blue 5:cyan 6:magenta 7:white
00457 
00458 Closest target_location in sight used for the location, if none
00459 in site, closest in distance
00460 */
00461 void SP_target_location( gentity_t *self ){
00462     self->think = target_location_linkup;
00463     self->nextthink = level.time + 200;  // Let them all spawn first
00464 
00465     G_SetOrigin( self, self->s.origin );
00466 }
00467 

Generated on Thu Aug 25 12:37:33 2005 for Quake III Arena by  doxygen 1.3.9.1