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

g_misc.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 // g_misc.c
00024 
00025 #include "g_local.h"
00026 
00027 
00028 /*QUAKED func_group (0 0 0) ?
00029 Used to group brushes together just for editor convenience.  They are turned into normal brushes by the utilities.
00030 */
00031 
00032 
00033 /*QUAKED info_camp (0 0.5 0) (-4 -4 -4) (4 4 4)
00034 Used as a positional target for calculations in the utilities (spotlights, etc), but removed during gameplay.
00035 */
00036 void SP_info_camp( gentity_t *self ) {
00037     G_SetOrigin( self, self->s.origin );
00038 }
00039 
00040 
00041 /*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4)
00042 Used as a positional target for calculations in the utilities (spotlights, etc), but removed during gameplay.
00043 */
00044 void SP_info_null( gentity_t *self ) {
00045     G_FreeEntity( self );
00046 }
00047 
00048 
00049 /*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4)
00050 Used as a positional target for in-game calculation, like jumppad targets.
00051 target_position does the same thing
00052 */
00053 void SP_info_notnull( gentity_t *self ){
00054     G_SetOrigin( self, self->s.origin );
00055 }
00056 
00057 
00058 /*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) linear
00059 Non-displayed light.
00060 "light" overrides the default 300 intensity.
00061 Linear checbox gives linear falloff instead of inverse square
00062 Lights pointed at a target will be spotlights.
00063 "radius" overrides the default 64 unit radius of a spotlight at the target point.
00064 */
00065 void SP_light( gentity_t *self ) {
00066     G_FreeEntity( self );
00067 }
00068 
00069 
00070 
00071 /*
00072 =================================================================================
00073 
00074 TELEPORTERS
00075 
00076 =================================================================================
00077 */
00078 
00079 void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles ) {
00080     gentity_t   *tent;
00081 
00082     // use temp events at source and destination to prevent the effect
00083     // from getting dropped by a second player event
00084     if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) {
00085         tent = G_TempEntity( player->client->ps.origin, EV_PLAYER_TELEPORT_OUT );
00086         tent->s.clientNum = player->s.clientNum;
00087 
00088         tent = G_TempEntity( origin, EV_PLAYER_TELEPORT_IN );
00089         tent->s.clientNum = player->s.clientNum;
00090     }
00091 
00092     // unlink to make sure it can't possibly interfere with G_KillBox
00093     trap_UnlinkEntity (player);
00094 
00095     VectorCopy ( origin, player->client->ps.origin );
00096     player->client->ps.origin[2] += 1;
00097 
00098     // spit the player out
00099     AngleVectors( angles, player->client->ps.velocity, NULL, NULL );
00100     VectorScale( player->client->ps.velocity, 400, player->client->ps.velocity );
00101     player->client->ps.pm_time = 160;       // hold time
00102     player->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
00103 
00104     // toggle the teleport bit so the client knows to not lerp
00105     player->client->ps.eFlags ^= EF_TELEPORT_BIT;
00106 
00107     // set angles
00108     SetClientViewAngle( player, angles );
00109 
00110     // kill anything at the destination
00111     if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) {
00112         G_KillBox (player);
00113     }
00114 
00115     // save results of pmove
00116     BG_PlayerStateToEntityState( &player->client->ps, &player->s, qtrue );
00117 
00118     // use the precise origin for linking
00119     VectorCopy( player->client->ps.origin, player->r.currentOrigin );
00120 
00121     if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) {
00122         trap_LinkEntity (player);
00123     }
00124 }
00125 
00126 
00127 /*QUAKED misc_teleporter_dest (1 0 0) (-32 -32 -24) (32 32 -16)
00128 Point teleporters at these.
00129 Now that we don't have teleport destination pads, this is just
00130 an info_notnull
00131 */
00132 void SP_misc_teleporter_dest( gentity_t *ent ) {
00133 }
00134 
00135 
00136 //===========================================================
00137 
00138 /*QUAKED misc_model (1 0 0) (-16 -16 -16) (16 16 16)
00139 "model"     arbitrary .md3 file to display
00140 */
00141 void SP_misc_model( gentity_t *ent ) {
00142 
00143 #if 0
00144     ent->s.modelindex = G_ModelIndex( ent->model );
00145     VectorSet (ent->mins, -16, -16, -16);
00146     VectorSet (ent->maxs, 16, 16, 16);
00147     trap_LinkEntity (ent);
00148 
00149     G_SetOrigin( ent, ent->s.origin );
00150     VectorCopy( ent->s.angles, ent->s.apos.trBase );
00151 #else
00152     G_FreeEntity( ent );
00153 #endif
00154 }
00155 
00156 //===========================================================
00157 
00158 void locateCamera( gentity_t *ent ) {
00159     vec3_t      dir;
00160     gentity_t   *target;
00161     gentity_t   *owner;
00162 
00163     owner = G_PickTarget( ent->target );
00164     if ( !owner ) {
00165         G_Printf( "Couldn't find target for misc_partal_surface\n" );
00166         G_FreeEntity( ent );
00167         return;
00168     }
00169     ent->r.ownerNum = owner->s.number;
00170 
00171     // frame holds the rotate speed
00172     if ( owner->spawnflags & 1 ) {
00173         ent->s.frame = 25;
00174     } else if ( owner->spawnflags & 2 ) {
00175         ent->s.frame = 75;
00176     }
00177 
00178     // swing camera ?
00179     if ( owner->spawnflags & 4 ) {
00180         // set to 0 for no rotation at all
00181         ent->s.powerups = 0;
00182     }
00183     else {
00184         ent->s.powerups = 1;
00185     }
00186 
00187     // clientNum holds the rotate offset
00188     ent->s.clientNum = owner->s.clientNum;
00189 
00190     VectorCopy( owner->s.origin, ent->s.origin2 );
00191 
00192     // see if the portal_camera has a target
00193     target = G_PickTarget( owner->target );
00194     if ( target ) {
00195         VectorSubtract( target->s.origin, owner->s.origin, dir );
00196         VectorNormalize( dir );
00197     } else {
00198         G_SetMovedir( owner->s.angles, dir );
00199     }
00200 
00201     ent->s.eventParm = DirToByte( dir );
00202 }
00203 
00204 /*QUAKED misc_portal_surface (0 0 1) (-8 -8 -8) (8 8 8)
00205 The portal surface nearest this entity will show a view from the targeted misc_portal_camera, or a mirror view if untargeted.
00206 This must be within 64 world units of the surface!
00207 */
00208 void SP_misc_portal_surface(gentity_t *ent) {
00209     VectorClear( ent->r.mins );
00210     VectorClear( ent->r.maxs );
00211     trap_LinkEntity (ent);
00212 
00213     ent->r.svFlags = SVF_PORTAL;
00214     ent->s.eType = ET_PORTAL;
00215 
00216     if ( !ent->target ) {
00217         VectorCopy( ent->s.origin, ent->s.origin2 );
00218     } else {
00219         ent->think = locateCamera;
00220         ent->nextthink = level.time + 100;
00221     }
00222 }
00223 
00224 /*QUAKED misc_portal_camera (0 0 1) (-8 -8 -8) (8 8 8) slowrotate fastrotate noswing
00225 The target for a misc_portal_director.  You can set either angles or target another entity to determine the direction of view.
00226 "roll" an angle modifier to orient the camera around the target vector;
00227 */
00228 void SP_misc_portal_camera(gentity_t *ent) {
00229     float   roll;
00230 
00231     VectorClear( ent->r.mins );
00232     VectorClear( ent->r.maxs );
00233     trap_LinkEntity (ent);
00234 
00235     G_SpawnFloat( "roll", "0", &roll );
00236 
00237     ent->s.clientNum = roll/360.0 * 256;
00238 }
00239 
00240 /*
00241 ======================================================================
00242 
00243   SHOOTERS
00244 
00245 ======================================================================
00246 */
00247 
00248 void Use_Shooter( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
00249     vec3_t      dir;
00250     float       deg;
00251     vec3_t      up, right;
00252 
00253     // see if we have a target
00254     if ( ent->enemy ) {
00255         VectorSubtract( ent->enemy->r.currentOrigin, ent->s.origin, dir );
00256         VectorNormalize( dir );
00257     } else {
00258         VectorCopy( ent->movedir, dir );
00259     }
00260 
00261     // randomize a bit
00262     PerpendicularVector( up, dir );
00263     CrossProduct( up, dir, right );
00264 
00265     deg = crandom() * ent->random;
00266     VectorMA( dir, deg, up, dir );
00267 
00268     deg = crandom() * ent->random;
00269     VectorMA( dir, deg, right, dir );
00270 
00271     VectorNormalize( dir );
00272 
00273     switch ( ent->s.weapon ) {
00274     case WP_GRENADE_LAUNCHER:
00275         fire_grenade( ent, ent->s.origin, dir );
00276         break;
00277     case WP_ROCKET_LAUNCHER:
00278         fire_rocket( ent, ent->s.origin, dir );
00279         break;
00280     case WP_PLASMAGUN:
00281         fire_plasma( ent, ent->s.origin, dir );
00282         break;
00283     }
00284 
00285     G_AddEvent( ent, EV_FIRE_WEAPON, 0 );
00286 }
00287 
00288 
00289 static void InitShooter_Finish( gentity_t *ent ) {
00290     ent->enemy = G_PickTarget( ent->target );
00291     ent->think = 0;
00292     ent->nextthink = 0;
00293 }
00294 
00295 void InitShooter( gentity_t *ent, int weapon ) {
00296     ent->use = Use_Shooter;
00297     ent->s.weapon = weapon;
00298 
00299     RegisterItem( BG_FindItemForWeapon( weapon ) );
00300 
00301     G_SetMovedir( ent->s.angles, ent->movedir );
00302 
00303     if ( !ent->random ) {
00304         ent->random = 1.0;
00305     }
00306     ent->random = sin( M_PI * ent->random / 180 );
00307     // target might be a moving object, so we can't set movedir for it
00308     if ( ent->target ) {
00309         ent->think = InitShooter_Finish;
00310         ent->nextthink = level.time + 500;
00311     }
00312     trap_LinkEntity( ent );
00313 }
00314 
00315 /*QUAKED shooter_rocket (1 0 0) (-16 -16 -16) (16 16 16)
00316 Fires at either the target or the current direction.
00317 "random" the number of degrees of deviance from the taget. (1.0 default)
00318 */
00319 void SP_shooter_rocket( gentity_t *ent ) {
00320     InitShooter( ent, WP_ROCKET_LAUNCHER );
00321 }
00322 
00323 /*QUAKED shooter_plasma (1 0 0) (-16 -16 -16) (16 16 16)
00324 Fires at either the target or the current direction.
00325 "random" is the number of degrees of deviance from the taget. (1.0 default)
00326 */
00327 void SP_shooter_plasma( gentity_t *ent ) {
00328     InitShooter( ent, WP_PLASMAGUN);
00329 }
00330 
00331 /*QUAKED shooter_grenade (1 0 0) (-16 -16 -16) (16 16 16)
00332 Fires at either the target or the current direction.
00333 "random" is the number of degrees of deviance from the taget. (1.0 default)
00334 */
00335 void SP_shooter_grenade( gentity_t *ent ) {
00336     InitShooter( ent, WP_GRENADE_LAUNCHER);
00337 }
00338 
00339 
00340 #ifdef MISSIONPACK
00341 static void PortalDie (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod) {
00342     G_FreeEntity( self );
00343     //FIXME do something more interesting
00344 }
00345 
00346 
00347 void DropPortalDestination( gentity_t *player ) {
00348     gentity_t   *ent;
00349     vec3_t      snapped;
00350 
00351     // create the portal destination
00352     ent = G_Spawn();
00353     ent->s.modelindex = G_ModelIndex( "models/powerups/teleporter/tele_exit.md3" );
00354 
00355     VectorCopy( player->s.pos.trBase, snapped );
00356     SnapVector( snapped );
00357     G_SetOrigin( ent, snapped );
00358     VectorCopy( player->r.mins, ent->r.mins );
00359     VectorCopy( player->r.maxs, ent->r.maxs );
00360 
00361     ent->classname = "hi_portal destination";
00362     ent->s.pos.trType = TR_STATIONARY;
00363 
00364     ent->r.contents = CONTENTS_CORPSE;
00365     ent->takedamage = qtrue;
00366     ent->health = 200;
00367     ent->die = PortalDie;
00368 
00369     VectorCopy( player->s.apos.trBase, ent->s.angles );
00370 
00371     ent->think = G_FreeEntity;
00372     ent->nextthink = level.time + 2 * 60 * 1000;
00373 
00374     trap_LinkEntity( ent );
00375 
00376     player->client->portalID = ++level.portalSequence;
00377     ent->count = player->client->portalID;
00378 
00379     // give the item back so they can drop the source now
00380     player->client->ps.stats[STAT_HOLDABLE_ITEM] = BG_FindItem( "Portal" ) - bg_itemlist;
00381 }
00382 
00383 
00384 static void PortalTouch( gentity_t *self, gentity_t *other, trace_t *trace) {
00385     gentity_t   *destination;
00386 
00387     // see if we will even let other try to use it
00388     if( other->health <= 0 ) {
00389         return;
00390     }
00391     if( !other->client ) {
00392         return;
00393     }
00394 //  if( other->client->ps.persistant[PERS_TEAM] != self->spawnflags ) {
00395 //      return;
00396 //  }
00397 
00398     if ( other->client->ps.powerups[PW_NEUTRALFLAG] ) {     // only happens in One Flag CTF
00399         Drop_Item( other, BG_FindItemForPowerup( PW_NEUTRALFLAG ), 0 );
00400         other->client->ps.powerups[PW_NEUTRALFLAG] = 0;
00401     }
00402     else if ( other->client->ps.powerups[PW_REDFLAG] ) {        // only happens in standard CTF
00403         Drop_Item( other, BG_FindItemForPowerup( PW_REDFLAG ), 0 );
00404         other->client->ps.powerups[PW_REDFLAG] = 0;
00405     }
00406     else if ( other->client->ps.powerups[PW_BLUEFLAG] ) {   // only happens in standard CTF
00407         Drop_Item( other, BG_FindItemForPowerup( PW_BLUEFLAG ), 0 );
00408         other->client->ps.powerups[PW_BLUEFLAG] = 0;
00409     }
00410 
00411     // find the destination
00412     destination = NULL;
00413     while( (destination = G_Find(destination, FOFS(classname), "hi_portal destination")) != NULL ) {
00414         if( destination->count == self->count ) {
00415             break;
00416         }
00417     }
00418 
00419     // if there is not one, die!
00420     if( !destination ) {
00421         if( self->pos1[0] || self->pos1[1] || self->pos1[2] ) {
00422             TeleportPlayer( other, self->pos1, self->s.angles );
00423         }
00424         G_Damage( other, other, other, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_TELEFRAG );
00425         return;
00426     }
00427 
00428     TeleportPlayer( other, destination->s.pos.trBase, destination->s.angles );
00429 }
00430 
00431 
00432 static void PortalEnable( gentity_t *self ) {
00433     self->touch = PortalTouch;
00434     self->think = G_FreeEntity;
00435     self->nextthink = level.time + 2 * 60 * 1000;
00436 }
00437 
00438 
00439 void DropPortalSource( gentity_t *player ) {
00440     gentity_t   *ent;
00441     gentity_t   *destination;
00442     vec3_t      snapped;
00443 
00444     // create the portal source
00445     ent = G_Spawn();
00446     ent->s.modelindex = G_ModelIndex( "models/powerups/teleporter/tele_enter.md3" );
00447 
00448     VectorCopy( player->s.pos.trBase, snapped );
00449     SnapVector( snapped );
00450     G_SetOrigin( ent, snapped );
00451     VectorCopy( player->r.mins, ent->r.mins );
00452     VectorCopy( player->r.maxs, ent->r.maxs );
00453 
00454     ent->classname = "hi_portal source";
00455     ent->s.pos.trType = TR_STATIONARY;
00456 
00457     ent->r.contents = CONTENTS_CORPSE | CONTENTS_TRIGGER;
00458     ent->takedamage = qtrue;
00459     ent->health = 200;
00460     ent->die = PortalDie;
00461 
00462     trap_LinkEntity( ent );
00463 
00464     ent->count = player->client->portalID;
00465     player->client->portalID = 0;
00466 
00467 //  ent->spawnflags = player->client->ps.persistant[PERS_TEAM];
00468 
00469     ent->nextthink = level.time + 1000;
00470     ent->think = PortalEnable;
00471 
00472     // find the destination
00473     destination = NULL;
00474     while( (destination = G_Find(destination, FOFS(classname), "hi_portal destination")) != NULL ) {
00475         if( destination->count == ent->count ) {
00476             VectorCopy( destination->s.pos.trBase, ent->pos1 );
00477             break;
00478         }
00479     }
00480 
00481 }
00482 #endif

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