aboutsummaryrefslogtreecommitdiffstats
path: root/code/game/g_misc.c
diff options
context:
space:
mode:
authorzakk <zakk@edf5b092-35ff-0310-97b2-ce42778d08ea>2005-08-26 17:39:27 +0000
committerzakk <zakk@edf5b092-35ff-0310-97b2-ce42778d08ea>2005-08-26 17:39:27 +0000
commit6bf20c78f5b69d40bcc4931df93d29198435ab67 (patch)
treee3eda937a05d7db42de725b7013bd0344b987f34 /code/game/g_misc.c
parent872d4d7f55af706737ffb361bb76ad13e7496770 (diff)
downloadioquake3-aero-6bf20c78f5b69d40bcc4931df93d29198435ab67.tar.gz
ioquake3-aero-6bf20c78f5b69d40bcc4931df93d29198435ab67.zip
newlines fixed
git-svn-id: svn://svn.icculus.org/quake3/trunk@6 edf5b092-35ff-0310-97b2-ce42778d08ea
Diffstat (limited to 'code/game/g_misc.c')
-rwxr-xr-xcode/game/g_misc.c964
1 files changed, 482 insertions, 482 deletions
diff --git a/code/game/g_misc.c b/code/game/g_misc.c
index 2328461..ee75cde 100755
--- a/code/game/g_misc.c
+++ b/code/game/g_misc.c
@@ -1,482 +1,482 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// g_misc.c
-
-#include "g_local.h"
-
-
-/*QUAKED func_group (0 0 0) ?
-Used to group brushes together just for editor convenience. They are turned into normal brushes by the utilities.
-*/
-
-
-/*QUAKED info_camp (0 0.5 0) (-4 -4 -4) (4 4 4)
-Used as a positional target for calculations in the utilities (spotlights, etc), but removed during gameplay.
-*/
-void SP_info_camp( gentity_t *self ) {
- G_SetOrigin( self, self->s.origin );
-}
-
-
-/*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4)
-Used as a positional target for calculations in the utilities (spotlights, etc), but removed during gameplay.
-*/
-void SP_info_null( gentity_t *self ) {
- G_FreeEntity( self );
-}
-
-
-/*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4)
-Used as a positional target for in-game calculation, like jumppad targets.
-target_position does the same thing
-*/
-void SP_info_notnull( gentity_t *self ){
- G_SetOrigin( self, self->s.origin );
-}
-
-
-/*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) linear
-Non-displayed light.
-"light" overrides the default 300 intensity.
-Linear checbox gives linear falloff instead of inverse square
-Lights pointed at a target will be spotlights.
-"radius" overrides the default 64 unit radius of a spotlight at the target point.
-*/
-void SP_light( gentity_t *self ) {
- G_FreeEntity( self );
-}
-
-
-
-/*
-=================================================================================
-
-TELEPORTERS
-
-=================================================================================
-*/
-
-void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles ) {
- gentity_t *tent;
-
- // use temp events at source and destination to prevent the effect
- // from getting dropped by a second player event
- if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) {
- tent = G_TempEntity( player->client->ps.origin, EV_PLAYER_TELEPORT_OUT );
- tent->s.clientNum = player->s.clientNum;
-
- tent = G_TempEntity( origin, EV_PLAYER_TELEPORT_IN );
- tent->s.clientNum = player->s.clientNum;
- }
-
- // unlink to make sure it can't possibly interfere with G_KillBox
- trap_UnlinkEntity (player);
-
- VectorCopy ( origin, player->client->ps.origin );
- player->client->ps.origin[2] += 1;
-
- // spit the player out
- AngleVectors( angles, player->client->ps.velocity, NULL, NULL );
- VectorScale( player->client->ps.velocity, 400, player->client->ps.velocity );
- player->client->ps.pm_time = 160; // hold time
- player->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
-
- // toggle the teleport bit so the client knows to not lerp
- player->client->ps.eFlags ^= EF_TELEPORT_BIT;
-
- // set angles
- SetClientViewAngle( player, angles );
-
- // kill anything at the destination
- if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) {
- G_KillBox (player);
- }
-
- // save results of pmove
- BG_PlayerStateToEntityState( &player->client->ps, &player->s, qtrue );
-
- // use the precise origin for linking
- VectorCopy( player->client->ps.origin, player->r.currentOrigin );
-
- if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) {
- trap_LinkEntity (player);
- }
-}
-
-
-/*QUAKED misc_teleporter_dest (1 0 0) (-32 -32 -24) (32 32 -16)
-Point teleporters at these.
-Now that we don't have teleport destination pads, this is just
-an info_notnull
-*/
-void SP_misc_teleporter_dest( gentity_t *ent ) {
-}
-
-
-//===========================================================
-
-/*QUAKED misc_model (1 0 0) (-16 -16 -16) (16 16 16)
-"model" arbitrary .md3 file to display
-*/
-void SP_misc_model( gentity_t *ent ) {
-
-#if 0
- ent->s.modelindex = G_ModelIndex( ent->model );
- VectorSet (ent->mins, -16, -16, -16);
- VectorSet (ent->maxs, 16, 16, 16);
- trap_LinkEntity (ent);
-
- G_SetOrigin( ent, ent->s.origin );
- VectorCopy( ent->s.angles, ent->s.apos.trBase );
-#else
- G_FreeEntity( ent );
-#endif
-}
-
-//===========================================================
-
-void locateCamera( gentity_t *ent ) {
- vec3_t dir;
- gentity_t *target;
- gentity_t *owner;
-
- owner = G_PickTarget( ent->target );
- if ( !owner ) {
- G_Printf( "Couldn't find target for misc_partal_surface\n" );
- G_FreeEntity( ent );
- return;
- }
- ent->r.ownerNum = owner->s.number;
-
- // frame holds the rotate speed
- if ( owner->spawnflags & 1 ) {
- ent->s.frame = 25;
- } else if ( owner->spawnflags & 2 ) {
- ent->s.frame = 75;
- }
-
- // swing camera ?
- if ( owner->spawnflags & 4 ) {
- // set to 0 for no rotation at all
- ent->s.powerups = 0;
- }
- else {
- ent->s.powerups = 1;
- }
-
- // clientNum holds the rotate offset
- ent->s.clientNum = owner->s.clientNum;
-
- VectorCopy( owner->s.origin, ent->s.origin2 );
-
- // see if the portal_camera has a target
- target = G_PickTarget( owner->target );
- if ( target ) {
- VectorSubtract( target->s.origin, owner->s.origin, dir );
- VectorNormalize( dir );
- } else {
- G_SetMovedir( owner->s.angles, dir );
- }
-
- ent->s.eventParm = DirToByte( dir );
-}
-
-/*QUAKED misc_portal_surface (0 0 1) (-8 -8 -8) (8 8 8)
-The portal surface nearest this entity will show a view from the targeted misc_portal_camera, or a mirror view if untargeted.
-This must be within 64 world units of the surface!
-*/
-void SP_misc_portal_surface(gentity_t *ent) {
- VectorClear( ent->r.mins );
- VectorClear( ent->r.maxs );
- trap_LinkEntity (ent);
-
- ent->r.svFlags = SVF_PORTAL;
- ent->s.eType = ET_PORTAL;
-
- if ( !ent->target ) {
- VectorCopy( ent->s.origin, ent->s.origin2 );
- } else {
- ent->think = locateCamera;
- ent->nextthink = level.time + 100;
- }
-}
-
-/*QUAKED misc_portal_camera (0 0 1) (-8 -8 -8) (8 8 8) slowrotate fastrotate noswing
-The target for a misc_portal_director. You can set either angles or target another entity to determine the direction of view.
-"roll" an angle modifier to orient the camera around the target vector;
-*/
-void SP_misc_portal_camera(gentity_t *ent) {
- float roll;
-
- VectorClear( ent->r.mins );
- VectorClear( ent->r.maxs );
- trap_LinkEntity (ent);
-
- G_SpawnFloat( "roll", "0", &roll );
-
- ent->s.clientNum = roll/360.0 * 256;
-}
-
-/*
-======================================================================
-
- SHOOTERS
-
-======================================================================
-*/
-
-void Use_Shooter( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
- vec3_t dir;
- float deg;
- vec3_t up, right;
-
- // see if we have a target
- if ( ent->enemy ) {
- VectorSubtract( ent->enemy->r.currentOrigin, ent->s.origin, dir );
- VectorNormalize( dir );
- } else {
- VectorCopy( ent->movedir, dir );
- }
-
- // randomize a bit
- PerpendicularVector( up, dir );
- CrossProduct( up, dir, right );
-
- deg = crandom() * ent->random;
- VectorMA( dir, deg, up, dir );
-
- deg = crandom() * ent->random;
- VectorMA( dir, deg, right, dir );
-
- VectorNormalize( dir );
-
- switch ( ent->s.weapon ) {
- case WP_GRENADE_LAUNCHER:
- fire_grenade( ent, ent->s.origin, dir );
- break;
- case WP_ROCKET_LAUNCHER:
- fire_rocket( ent, ent->s.origin, dir );
- break;
- case WP_PLASMAGUN:
- fire_plasma( ent, ent->s.origin, dir );
- break;
- }
-
- G_AddEvent( ent, EV_FIRE_WEAPON, 0 );
-}
-
-
-static void InitShooter_Finish( gentity_t *ent ) {
- ent->enemy = G_PickTarget( ent->target );
- ent->think = 0;
- ent->nextthink = 0;
-}
-
-void InitShooter( gentity_t *ent, int weapon ) {
- ent->use = Use_Shooter;
- ent->s.weapon = weapon;
-
- RegisterItem( BG_FindItemForWeapon( weapon ) );
-
- G_SetMovedir( ent->s.angles, ent->movedir );
-
- if ( !ent->random ) {
- ent->random = 1.0;
- }
- ent->random = sin( M_PI * ent->random / 180 );
- // target might be a moving object, so we can't set movedir for it
- if ( ent->target ) {
- ent->think = InitShooter_Finish;
- ent->nextthink = level.time + 500;
- }
- trap_LinkEntity( ent );
-}
-
-/*QUAKED shooter_rocket (1 0 0) (-16 -16 -16) (16 16 16)
-Fires at either the target or the current direction.
-"random" the number of degrees of deviance from the taget. (1.0 default)
-*/
-void SP_shooter_rocket( gentity_t *ent ) {
- InitShooter( ent, WP_ROCKET_LAUNCHER );
-}
-
-/*QUAKED shooter_plasma (1 0 0) (-16 -16 -16) (16 16 16)
-Fires at either the target or the current direction.
-"random" is the number of degrees of deviance from the taget. (1.0 default)
-*/
-void SP_shooter_plasma( gentity_t *ent ) {
- InitShooter( ent, WP_PLASMAGUN);
-}
-
-/*QUAKED shooter_grenade (1 0 0) (-16 -16 -16) (16 16 16)
-Fires at either the target or the current direction.
-"random" is the number of degrees of deviance from the taget. (1.0 default)
-*/
-void SP_shooter_grenade( gentity_t *ent ) {
- InitShooter( ent, WP_GRENADE_LAUNCHER);
-}
-
-
-#ifdef MISSIONPACK
-static void PortalDie (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod) {
- G_FreeEntity( self );
- //FIXME do something more interesting
-}
-
-
-void DropPortalDestination( gentity_t *player ) {
- gentity_t *ent;
- vec3_t snapped;
-
- // create the portal destination
- ent = G_Spawn();
- ent->s.modelindex = G_ModelIndex( "models/powerups/teleporter/tele_exit.md3" );
-
- VectorCopy( player->s.pos.trBase, snapped );
- SnapVector( snapped );
- G_SetOrigin( ent, snapped );
- VectorCopy( player->r.mins, ent->r.mins );
- VectorCopy( player->r.maxs, ent->r.maxs );
-
- ent->classname = "hi_portal destination";
- ent->s.pos.trType = TR_STATIONARY;
-
- ent->r.contents = CONTENTS_CORPSE;
- ent->takedamage = qtrue;
- ent->health = 200;
- ent->die = PortalDie;
-
- VectorCopy( player->s.apos.trBase, ent->s.angles );
-
- ent->think = G_FreeEntity;
- ent->nextthink = level.time + 2 * 60 * 1000;
-
- trap_LinkEntity( ent );
-
- player->client->portalID = ++level.portalSequence;
- ent->count = player->client->portalID;
-
- // give the item back so they can drop the source now
- player->client->ps.stats[STAT_HOLDABLE_ITEM] = BG_FindItem( "Portal" ) - bg_itemlist;
-}
-
-
-static void PortalTouch( gentity_t *self, gentity_t *other, trace_t *trace) {
- gentity_t *destination;
-
- // see if we will even let other try to use it
- if( other->health <= 0 ) {
- return;
- }
- if( !other->client ) {
- return;
- }
-// if( other->client->ps.persistant[PERS_TEAM] != self->spawnflags ) {
-// return;
-// }
-
- if ( other->client->ps.powerups[PW_NEUTRALFLAG] ) { // only happens in One Flag CTF
- Drop_Item( other, BG_FindItemForPowerup( PW_NEUTRALFLAG ), 0 );
- other->client->ps.powerups[PW_NEUTRALFLAG] = 0;
- }
- else if ( other->client->ps.powerups[PW_REDFLAG] ) { // only happens in standard CTF
- Drop_Item( other, BG_FindItemForPowerup( PW_REDFLAG ), 0 );
- other->client->ps.powerups[PW_REDFLAG] = 0;
- }
- else if ( other->client->ps.powerups[PW_BLUEFLAG] ) { // only happens in standard CTF
- Drop_Item( other, BG_FindItemForPowerup( PW_BLUEFLAG ), 0 );
- other->client->ps.powerups[PW_BLUEFLAG] = 0;
- }
-
- // find the destination
- destination = NULL;
- while( (destination = G_Find(destination, FOFS(classname), "hi_portal destination")) != NULL ) {
- if( destination->count == self->count ) {
- break;
- }
- }
-
- // if there is not one, die!
- if( !destination ) {
- if( self->pos1[0] || self->pos1[1] || self->pos1[2] ) {
- TeleportPlayer( other, self->pos1, self->s.angles );
- }
- G_Damage( other, other, other, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_TELEFRAG );
- return;
- }
-
- TeleportPlayer( other, destination->s.pos.trBase, destination->s.angles );
-}
-
-
-static void PortalEnable( gentity_t *self ) {
- self->touch = PortalTouch;
- self->think = G_FreeEntity;
- self->nextthink = level.time + 2 * 60 * 1000;
-}
-
-
-void DropPortalSource( gentity_t *player ) {
- gentity_t *ent;
- gentity_t *destination;
- vec3_t snapped;
-
- // create the portal source
- ent = G_Spawn();
- ent->s.modelindex = G_ModelIndex( "models/powerups/teleporter/tele_enter.md3" );
-
- VectorCopy( player->s.pos.trBase, snapped );
- SnapVector( snapped );
- G_SetOrigin( ent, snapped );
- VectorCopy( player->r.mins, ent->r.mins );
- VectorCopy( player->r.maxs, ent->r.maxs );
-
- ent->classname = "hi_portal source";
- ent->s.pos.trType = TR_STATIONARY;
-
- ent->r.contents = CONTENTS_CORPSE | CONTENTS_TRIGGER;
- ent->takedamage = qtrue;
- ent->health = 200;
- ent->die = PortalDie;
-
- trap_LinkEntity( ent );
-
- ent->count = player->client->portalID;
- player->client->portalID = 0;
-
-// ent->spawnflags = player->client->ps.persistant[PERS_TEAM];
-
- ent->nextthink = level.time + 1000;
- ent->think = PortalEnable;
-
- // find the destination
- destination = NULL;
- while( (destination = G_Find(destination, FOFS(classname), "hi_portal destination")) != NULL ) {
- if( destination->count == ent->count ) {
- VectorCopy( destination->s.pos.trBase, ent->pos1 );
- break;
- }
- }
-
-}
-#endif
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// g_misc.c
+
+#include "g_local.h"
+
+
+/*QUAKED func_group (0 0 0) ?
+Used to group brushes together just for editor convenience. They are turned into normal brushes by the utilities.
+*/
+
+
+/*QUAKED info_camp (0 0.5 0) (-4 -4 -4) (4 4 4)
+Used as a positional target for calculations in the utilities (spotlights, etc), but removed during gameplay.
+*/
+void SP_info_camp( gentity_t *self ) {
+ G_SetOrigin( self, self->s.origin );
+}
+
+
+/*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4)
+Used as a positional target for calculations in the utilities (spotlights, etc), but removed during gameplay.
+*/
+void SP_info_null( gentity_t *self ) {
+ G_FreeEntity( self );
+}
+
+
+/*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4)
+Used as a positional target for in-game calculation, like jumppad targets.
+target_position does the same thing
+*/
+void SP_info_notnull( gentity_t *self ){
+ G_SetOrigin( self, self->s.origin );
+}
+
+
+/*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) linear
+Non-displayed light.
+"light" overrides the default 300 intensity.
+Linear checbox gives linear falloff instead of inverse square
+Lights pointed at a target will be spotlights.
+"radius" overrides the default 64 unit radius of a spotlight at the target point.
+*/
+void SP_light( gentity_t *self ) {
+ G_FreeEntity( self );
+}
+
+
+
+/*
+=================================================================================
+
+TELEPORTERS
+
+=================================================================================
+*/
+
+void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles ) {
+ gentity_t *tent;
+
+ // use temp events at source and destination to prevent the effect
+ // from getting dropped by a second player event
+ if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) {
+ tent = G_TempEntity( player->client->ps.origin, EV_PLAYER_TELEPORT_OUT );
+ tent->s.clientNum = player->s.clientNum;
+
+ tent = G_TempEntity( origin, EV_PLAYER_TELEPORT_IN );
+ tent->s.clientNum = player->s.clientNum;
+ }
+
+ // unlink to make sure it can't possibly interfere with G_KillBox
+ trap_UnlinkEntity (player);
+
+ VectorCopy ( origin, player->client->ps.origin );
+ player->client->ps.origin[2] += 1;
+
+ // spit the player out
+ AngleVectors( angles, player->client->ps.velocity, NULL, NULL );
+ VectorScale( player->client->ps.velocity, 400, player->client->ps.velocity );
+ player->client->ps.pm_time = 160; // hold time
+ player->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
+
+ // toggle the teleport bit so the client knows to not lerp
+ player->client->ps.eFlags ^= EF_TELEPORT_BIT;
+
+ // set angles
+ SetClientViewAngle( player, angles );
+
+ // kill anything at the destination
+ if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) {
+ G_KillBox (player);
+ }
+
+ // save results of pmove
+ BG_PlayerStateToEntityState( &player->client->ps, &player->s, qtrue );
+
+ // use the precise origin for linking
+ VectorCopy( player->client->ps.origin, player->r.currentOrigin );
+
+ if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) {
+ trap_LinkEntity (player);
+ }
+}
+
+
+/*QUAKED misc_teleporter_dest (1 0 0) (-32 -32 -24) (32 32 -16)
+Point teleporters at these.
+Now that we don't have teleport destination pads, this is just
+an info_notnull
+*/
+void SP_misc_teleporter_dest( gentity_t *ent ) {
+}
+
+
+//===========================================================
+
+/*QUAKED misc_model (1 0 0) (-16 -16 -16) (16 16 16)
+"model" arbitrary .md3 file to display
+*/
+void SP_misc_model( gentity_t *ent ) {
+
+#if 0
+ ent->s.modelindex = G_ModelIndex( ent->model );
+ VectorSet (ent->mins, -16, -16, -16);
+ VectorSet (ent->maxs, 16, 16, 16);
+ trap_LinkEntity (ent);
+
+ G_SetOrigin( ent, ent->s.origin );
+ VectorCopy( ent->s.angles, ent->s.apos.trBase );
+#else
+ G_FreeEntity( ent );
+#endif
+}
+
+//===========================================================
+
+void locateCamera( gentity_t *ent ) {
+ vec3_t dir;
+ gentity_t *target;
+ gentity_t *owner;
+
+ owner = G_PickTarget( ent->target );
+ if ( !owner ) {
+ G_Printf( "Couldn't find target for misc_partal_surface\n" );
+ G_FreeEntity( ent );
+ return;
+ }
+ ent->r.ownerNum = owner->s.number;
+
+ // frame holds the rotate speed
+ if ( owner->spawnflags & 1 ) {
+ ent->s.frame = 25;
+ } else if ( owner->spawnflags & 2 ) {
+ ent->s.frame = 75;
+ }
+
+ // swing camera ?
+ if ( owner->spawnflags & 4 ) {
+ // set to 0 for no rotation at all
+ ent->s.powerups = 0;
+ }
+ else {
+ ent->s.powerups = 1;
+ }
+
+ // clientNum holds the rotate offset
+ ent->s.clientNum = owner->s.clientNum;
+
+ VectorCopy( owner->s.origin, ent->s.origin2 );
+
+ // see if the portal_camera has a target
+ target = G_PickTarget( owner->target );
+ if ( target ) {
+ VectorSubtract( target->s.origin, owner->s.origin, dir );
+ VectorNormalize( dir );
+ } else {
+ G_SetMovedir( owner->s.angles, dir );
+ }
+
+ ent->s.eventParm = DirToByte( dir );
+}
+
+/*QUAKED misc_portal_surface (0 0 1) (-8 -8 -8) (8 8 8)
+The portal surface nearest this entity will show a view from the targeted misc_portal_camera, or a mirror view if untargeted.
+This must be within 64 world units of the surface!
+*/
+void SP_misc_portal_surface(gentity_t *ent) {
+ VectorClear( ent->r.mins );
+ VectorClear( ent->r.maxs );
+ trap_LinkEntity (ent);
+
+ ent->r.svFlags = SVF_PORTAL;
+ ent->s.eType = ET_PORTAL;
+
+ if ( !ent->target ) {
+ VectorCopy( ent->s.origin, ent->s.origin2 );
+ } else {
+ ent->think = locateCamera;
+ ent->nextthink = level.time + 100;
+ }
+}
+
+/*QUAKED misc_portal_camera (0 0 1) (-8 -8 -8) (8 8 8) slowrotate fastrotate noswing
+The target for a misc_portal_director. You can set either angles or target another entity to determine the direction of view.
+"roll" an angle modifier to orient the camera around the target vector;
+*/
+void SP_misc_portal_camera(gentity_t *ent) {
+ float roll;
+
+ VectorClear( ent->r.mins );
+ VectorClear( ent->r.maxs );
+ trap_LinkEntity (ent);
+
+ G_SpawnFloat( "roll", "0", &roll );
+
+ ent->s.clientNum = roll/360.0 * 256;
+}
+
+/*
+======================================================================
+
+ SHOOTERS
+
+======================================================================
+*/
+
+void Use_Shooter( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
+ vec3_t dir;
+ float deg;
+ vec3_t up, right;
+
+ // see if we have a target
+ if ( ent->enemy ) {
+ VectorSubtract( ent->enemy->r.currentOrigin, ent->s.origin, dir );
+ VectorNormalize( dir );
+ } else {
+ VectorCopy( ent->movedir, dir );
+ }
+
+ // randomize a bit
+ PerpendicularVector( up, dir );
+ CrossProduct( up, dir, right );
+
+ deg = crandom() * ent->random;
+ VectorMA( dir, deg, up, dir );
+
+ deg = crandom() * ent->random;
+ VectorMA( dir, deg, right, dir );
+
+ VectorNormalize( dir );
+
+ switch ( ent->s.weapon ) {
+ case WP_GRENADE_LAUNCHER:
+ fire_grenade( ent, ent->s.origin, dir );
+ break;
+ case WP_ROCKET_LAUNCHER:
+ fire_rocket( ent, ent->s.origin, dir );
+ break;
+ case WP_PLASMAGUN:
+ fire_plasma( ent, ent->s.origin, dir );
+ break;
+ }
+
+ G_AddEvent( ent, EV_FIRE_WEAPON, 0 );
+}
+
+
+static void InitShooter_Finish( gentity_t *ent ) {
+ ent->enemy = G_PickTarget( ent->target );
+ ent->think = 0;
+ ent->nextthink = 0;
+}
+
+void InitShooter( gentity_t *ent, int weapon ) {
+ ent->use = Use_Shooter;
+ ent->s.weapon = weapon;
+
+ RegisterItem( BG_FindItemForWeapon( weapon ) );
+
+ G_SetMovedir( ent->s.angles, ent->movedir );
+
+ if ( !ent->random ) {
+ ent->random = 1.0;
+ }
+ ent->random = sin( M_PI * ent->random / 180 );
+ // target might be a moving object, so we can't set movedir for it
+ if ( ent->target ) {
+ ent->think = InitShooter_Finish;
+ ent->nextthink = level.time + 500;
+ }
+ trap_LinkEntity( ent );
+}
+
+/*QUAKED shooter_rocket (1 0 0) (-16 -16 -16) (16 16 16)
+Fires at either the target or the current direction.
+"random" the number of degrees of deviance from the taget. (1.0 default)
+*/
+void SP_shooter_rocket( gentity_t *ent ) {
+ InitShooter( ent, WP_ROCKET_LAUNCHER );
+}
+
+/*QUAKED shooter_plasma (1 0 0) (-16 -16 -16) (16 16 16)
+Fires at either the target or the current direction.
+"random" is the number of degrees of deviance from the taget. (1.0 default)
+*/
+void SP_shooter_plasma( gentity_t *ent ) {
+ InitShooter( ent, WP_PLASMAGUN);
+}
+
+/*QUAKED shooter_grenade (1 0 0) (-16 -16 -16) (16 16 16)
+Fires at either the target or the current direction.
+"random" is the number of degrees of deviance from the taget. (1.0 default)
+*/
+void SP_shooter_grenade( gentity_t *ent ) {
+ InitShooter( ent, WP_GRENADE_LAUNCHER);
+}
+
+
+#ifdef MISSIONPACK
+static void PortalDie (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod) {
+ G_FreeEntity( self );
+ //FIXME do something more interesting
+}
+
+
+void DropPortalDestination( gentity_t *player ) {
+ gentity_t *ent;
+ vec3_t snapped;
+
+ // create the portal destination
+ ent = G_Spawn();
+ ent->s.modelindex = G_ModelIndex( "models/powerups/teleporter/tele_exit.md3" );
+
+ VectorCopy( player->s.pos.trBase, snapped );
+ SnapVector( snapped );
+ G_SetOrigin( ent, snapped );
+ VectorCopy( player->r.mins, ent->r.mins );
+ VectorCopy( player->r.maxs, ent->r.maxs );
+
+ ent->classname = "hi_portal destination";
+ ent->s.pos.trType = TR_STATIONARY;
+
+ ent->r.contents = CONTENTS_CORPSE;
+ ent->takedamage = qtrue;
+ ent->health = 200;
+ ent->die = PortalDie;
+
+ VectorCopy( player->s.apos.trBase, ent->s.angles );
+
+ ent->think = G_FreeEntity;
+ ent->nextthink = level.time + 2 * 60 * 1000;
+
+ trap_LinkEntity( ent );
+
+ player->client->portalID = ++level.portalSequence;
+ ent->count = player->client->portalID;
+
+ // give the item back so they can drop the source now
+ player->client->ps.stats[STAT_HOLDABLE_ITEM] = BG_FindItem( "Portal" ) - bg_itemlist;
+}
+
+
+static void PortalTouch( gentity_t *self, gentity_t *other, trace_t *trace) {
+ gentity_t *destination;
+
+ // see if we will even let other try to use it
+ if( other->health <= 0 ) {
+ return;
+ }
+ if( !other->client ) {
+ return;
+ }
+// if( other->client->ps.persistant[PERS_TEAM] != self->spawnflags ) {
+// return;
+// }
+
+ if ( other->client->ps.powerups[PW_NEUTRALFLAG] ) { // only happens in One Flag CTF
+ Drop_Item( other, BG_FindItemForPowerup( PW_NEUTRALFLAG ), 0 );
+ other->client->ps.powerups[PW_NEUTRALFLAG] = 0;
+ }
+ else if ( other->client->ps.powerups[PW_REDFLAG] ) { // only happens in standard CTF
+ Drop_Item( other, BG_FindItemForPowerup( PW_REDFLAG ), 0 );
+ other->client->ps.powerups[PW_REDFLAG] = 0;
+ }
+ else if ( other->client->ps.powerups[PW_BLUEFLAG] ) { // only happens in standard CTF
+ Drop_Item( other, BG_FindItemForPowerup( PW_BLUEFLAG ), 0 );
+ other->client->ps.powerups[PW_BLUEFLAG] = 0;
+ }
+
+ // find the destination
+ destination = NULL;
+ while( (destination = G_Find(destination, FOFS(classname), "hi_portal destination")) != NULL ) {
+ if( destination->count == self->count ) {
+ break;
+ }
+ }
+
+ // if there is not one, die!
+ if( !destination ) {
+ if( self->pos1[0] || self->pos1[1] || self->pos1[2] ) {
+ TeleportPlayer( other, self->pos1, self->s.angles );
+ }
+ G_Damage( other, other, other, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_TELEFRAG );
+ return;
+ }
+
+ TeleportPlayer( other, destination->s.pos.trBase, destination->s.angles );
+}
+
+
+static void PortalEnable( gentity_t *self ) {
+ self->touch = PortalTouch;
+ self->think = G_FreeEntity;
+ self->nextthink = level.time + 2 * 60 * 1000;
+}
+
+
+void DropPortalSource( gentity_t *player ) {
+ gentity_t *ent;
+ gentity_t *destination;
+ vec3_t snapped;
+
+ // create the portal source
+ ent = G_Spawn();
+ ent->s.modelindex = G_ModelIndex( "models/powerups/teleporter/tele_enter.md3" );
+
+ VectorCopy( player->s.pos.trBase, snapped );
+ SnapVector( snapped );
+ G_SetOrigin( ent, snapped );
+ VectorCopy( player->r.mins, ent->r.mins );
+ VectorCopy( player->r.maxs, ent->r.maxs );
+
+ ent->classname = "hi_portal source";
+ ent->s.pos.trType = TR_STATIONARY;
+
+ ent->r.contents = CONTENTS_CORPSE | CONTENTS_TRIGGER;
+ ent->takedamage = qtrue;
+ ent->health = 200;
+ ent->die = PortalDie;
+
+ trap_LinkEntity( ent );
+
+ ent->count = player->client->portalID;
+ player->client->portalID = 0;
+
+// ent->spawnflags = player->client->ps.persistant[PERS_TEAM];
+
+ ent->nextthink = level.time + 1000;
+ ent->think = PortalEnable;
+
+ // find the destination
+ destination = NULL;
+ while( (destination = G_Find(destination, FOFS(classname), "hi_portal destination")) != NULL ) {
+ if( destination->count == ent->count ) {
+ VectorCopy( destination->s.pos.trBase, ent->pos1 );
+ break;
+ }
+ }
+
+}
+#endif