2012-08-04 10:54:37 +00:00
// Copyright (C) 1999-2000 Id Software, Inc.
2012-01-22 21:34:33 +00:00
//
// g_misc.c
# include "g_local.h"
/*QUAKED func_group (0 0 0) ?
2012-11-27 02:04:09 +00:00
- - - - - DESCRIPTION - - - - -
2012-01-22 21:34:33 +00:00
Used to group brushes together just for editor convenience . They are turned into normal brushes by the utilities .
2012-11-27 02:04:09 +00:00
- - - - - SPAWNFLAGS - - - - -
none
- - - - - KEYS - - - - -
q3map2 :
" _lightmapscale " - set a diffrent lightmapscale for this func group only
2012-01-22 21:34:33 +00:00
*/
/*QUAKED info_camp (0 0.5 0) (-4 -4 -4) (4 4 4)
2012-11-27 02:04:09 +00:00
- - - - - DESCRIPTION - - - - -
Used as a positional target for calculations in the compiler / utilities ( spotlights , etc ) , but removed during gameplay .
- - - - - SAPWNFLAGS - - - - -
none
- - - - - KEYS - - - - -
" targetname " - have whatever is required point at this .
2012-01-22 21:34:33 +00:00
*/
2012-11-27 02:04:09 +00:00
// Lol, this is contradictory, should free but instead sets origin... Description sais removed so maybe merge with info_null.
2012-01-22 21:34:33 +00:00
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)
2012-11-27 02:04:09 +00:00
- - - - - DESCRIPTION - - - - -
Used as a positional target for calculations in the compiler / utilities ( spotlights , etc ) , but removed during gameplay .
- - - - - SAPWNFLAGS - - - - -
none
- - - - - KEYS - - - - -
" targetname " - have whatever is required point at this .
2012-01-22 21:34:33 +00:00
*/
void SP_info_null ( gentity_t * self ) {
G_FreeEntity ( self ) ;
}
/*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4)
2012-11-27 02:04:09 +00:00
- - - - - DESCRIPTION - - - - -
2012-01-22 21:34:33 +00:00
Used as a positional target for in - game calculation , like jumppad targets .
target_position does the same thing
2012-11-27 02:04:09 +00:00
- - - - - SPAWNFLAGS - - - - -
none
- - - - - KEYS - - - - -
" targetname " - have whatever is required point at this .
*/
//these share the spawnfunction with info_notnull
/*QUAKED misc_teleporter_dest (1 0 0) (-32 -32 -24) (32 32 -16)
- - - - - DESCRIPTION - - - - -
Merely a fancy name for info_notnull .
was originally used for teleporters but became redundant .
- - - - - SPAWNFLAGS - - - - -
none
2012-11-27 21:57:55 +00:00
- - - - - KEYS - - - - -
" targetname " - have whatever is required point at this .
*/
/*QUAKED target_position (0 0.5 0) (-4 -4 -4) (4 4 4)
- - - - - DESCRIPTION - - - - -
Merely a fancy name for info_notnull .
- - - - - SPAWNFLAGS - - - - -
none
2012-11-27 02:04:09 +00:00
- - - - - KEYS - - - - -
" targetname " - have whatever is required point at this .
2012-01-22 21:34:33 +00:00
*/
void SP_info_notnull ( gentity_t * self ) {
2012-08-04 10:54:37 +00:00
if ( ! Q_stricmp ( self - > classname , " ref_tag " ) & & ! rpg_allowspmaps . integer )
G_FreeEntity ( self ) ;
2012-11-27 02:04:09 +00:00
if ( strcmp ( self - > classname , " info_notnull " ) ) {
self - > classname = G_NewString ( " info_notnull " ) ;
}
2012-01-22 21:34:33 +00:00
G_SetOrigin ( self , self - > s . origin ) ;
}
2012-11-27 02:04:09 +00:00
/*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) LINEAR NO_INCIDENCE X X NO_GRID NORMALIZED_COLOR FORCE_DISTANCE_ATTENUATION
- - - - - DESCRIPTION - - - - -
Light source for the compiler . Will be removed ingame .
Lights pointed at a target ( info_null ) will be spotlights .
- - - - - SPAWNFLAGS - - - - -
1 : LINEAR - checkbox gives linear falloff instead of inverse square
2 : NO_INCIDENCE - checkbox makes lighting smoother
4 : X - Unknown . Usage not recomended .
8 : X - Unknown . Usage not recomended .
q3map2 :
16 : NO_GRID - light does not affect the grid
32 : NORMALIZED_COLOR - light color gets normalized by the compiler
64 : FORCE_DISTANCE_ATTENUATION - distance attenuation is enforced
- - - - - KEYS - - - - -
" light " - overrides the default 300 intensity .
" radius " - overrides the default 64 unit radius of a spotlight at the target point .
" _color " - light color
q3map2 :
" _style " - light style number
" fade " - Fade factor of light attenuation of linear lights . ( Linear lights vanish at light / ( fade * 8000 ) .
" _anglescale " - scales angle attenuation
" scale " - intensity multiplier
" _samples " - number of samples to use to get soft shadows from a light
" _deviance " - position deviance of the samples of a regular light
" _filterradius " - filter radius for this light
" _sun " - if 1 , this light is an infinite sun light
" _flareshader " - shader for a flare surface generated by this light
" _flare " - when set , this light is a flare without a specified shader
2012-01-22 21:34:33 +00:00
*/
void SP_light ( gentity_t * self ) {
G_FreeEntity ( self ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
TELEPORTERS
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-08-04 10:54:37 +00:00
void TransportPlayer ( gentity_t * player , vec3_t origin , vec3_t angles , int speed )
{
gentity_t * tent = NULL ;
playerState_t * ps = & player - > client - > ps ;
clientSession_t * sess = & player - > client - > sess ;
2012-01-22 21:34:33 +00:00
// use temp events at source and destination to prevent the effect
// from getting dropped by a second player event
2012-08-04 10:54:37 +00:00
if ( sess - > sessionTeam ! = TEAM_SPECTATOR /*&& !(ps->eFlags&EF_ELIMINATED)*/ ) {
vec3_t org ;
VectorCopy ( ps - > origin , org ) ;
org [ 2 ] + = ( ps - > viewheight > > 1 ) ;
tent = G_TempEntity ( ps - > origin , EV_PLAYER_TELEPORT_OUT ) ;
2012-01-22 21:34:33 +00:00
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 ) ;
2012-08-04 10:54:37 +00:00
VectorCopy ( origin , ps - > origin ) ;
ps - > origin [ 2 ] + = 1 ;
2012-01-22 21:34:33 +00:00
// spit the player out
2012-08-04 10:54:37 +00:00
AngleVectors ( angles , ps - > velocity , NULL , NULL ) ;
VectorScale ( ps - > velocity , speed , ps - > velocity ) ;
ps - > pm_time = 160 ; // hold time
ps - > pm_flags | = PMF_TIME_KNOCKBACK ;
// toggle the teleport bit so the client knows to not lerp
ps - > eFlags ^ = EF_TELEPORT_BIT ;
2012-01-22 21:34:33 +00:00
// set angles
2012-11-15 23:58:56 +00:00
G_Client_SetViewAngle ( player , angles ) ;
2012-08-04 10:54:37 +00:00
// kill anything at the destination
if ( sess - > sessionTeam ! = TEAM_SPECTATOR /*&& !(ps->eFlags&EF_ELIMINATED)*/ ) {
G_KillBox ( player ) ;
}
// save results of pmove
BG_PlayerStateToEntityState ( & player - > client - > ps , & player - > s , qtrue ) ;
// use the precise origin for linking
VectorCopy ( ps - > origin , player - > r . currentOrigin ) ;
if ( sess - > sessionTeam ! = TEAM_SPECTATOR /*&& !(ps->eFlags&EF_ELIMINATED)*/ ) {
trap_LinkEntity ( player ) ;
}
}
void TeleportPlayer ( gentity_t * player , vec3_t origin , vec3_t angles , tpType_t tpType ) {
gentity_t * tent ;
playerState_t * ps = & player - > client - > ps ;
clientSession_t * sess = & player - > client - > sess ;
// unlink to make sure it can't possibly interfere with G_KillBox
trap_UnlinkEntity ( player ) ;
VectorCopy ( origin , ps - > origin ) ;
// use temp events at source and destination to prevent the effect
// from getting dropped by a second player event
2012-11-12 11:42:22 +00:00
if ( sess - > sessionTeam ! = TEAM_SPECTATOR )
2012-08-04 10:54:37 +00:00
{
if ( tpType = = TP_BORG )
{
// ...we are borg...prepare to be...
tent = G_TempEntity ( origin , EV_BORG_TELEPORT ) ;
tent - > s . clientNum = player - > s . clientNum ;
}
//RPG-X: J2J Added to get fed trans effect without any traveling after beam in
//TiM: Since the SP teleporter has been coded to only work with Jay's modification,
//we'll add the second half of the client-side effects (ie materialization) here
else if ( tpType = = TP_TRI_TP )
{
// probably isn't necessary, but just in case, end the beam out powerup
ps - > powerups [ PW_BEAM_OUT ] = 0 ;
//and add the beam in one
ps - > powerups [ PW_QUAD ] = level . time + 4000 ;
tent = G_TempEntity ( ps - > origin , EV_PLAYER_TRANSPORT_IN ) ;
2012-11-12 11:42:22 +00:00
tent - > s . clientNum = player - > s . clientNum ;
2012-08-04 10:54:37 +00:00
}
}
// spit the player out
//TiM - If in a turbolift and moving, get their velocity, perform the rotation
//calc on it, and then reset it to their velocity.
2012-11-12 11:42:22 +00:00
if ( tpType = = TP_TURBO )
2012-08-04 10:54:37 +00:00
{
vec3_t dir ;
vec3_t velAngles ;
float length ;
VectorCopy ( ps - > velocity , dir ) ;
length = VectorLength ( dir ) ;
VectorNormalize ( dir ) ;
vectoangles ( dir , velAngles ) ;
velAngles [ YAW ] = AngleNormalize360 ( velAngles [ YAW ] + ( angles [ YAW ] - ps - > viewangles [ YAW ] ) ) ;
AngleVectors ( velAngles , dir , NULL , NULL ) ;
VectorScale ( dir , length , ps - > velocity ) ;
}
else {
//TiM: Set the velocity to 0. So if they were moving b4 the transport, they'll be stopped when they come out.
//It's a little something called the Heisenberg compensators. ;)
//bug-fix. if the velocity is killed in a spectator door teleporter, the player
//gets wedged in the door. >_<
if ( sess - > sessionTeam ! = TEAM_SPECTATOR )
VectorScale ( ps - > velocity , 0 , ps - > velocity ) ;
else
{
AngleVectors ( angles , ps - > velocity , NULL , NULL ) ;
VectorScale ( ps - > velocity , 400 , ps - > velocity ) ;
ps - > pm_time = 160 ; // hold time
ps - > pm_flags | = PMF_TIME_KNOCKBACK ;
}
{ //see if we can move the player up one
vec3_t newOrg ;
trace_t tr ;
VectorCopy ( origin , newOrg ) ;
newOrg [ 2 ] + = 1 ;
trap_Trace ( & tr , ps - > origin , player - > r . mins , player - > r . maxs , newOrg , ps - > clientNum , player - > clipmask ) ;
if ( ! tr . allsolid & & ! tr . startsolid & & tr . fraction = = 1.0 )
{
ps - > origin [ 2 ] + = 1 ;
}
}
2012-01-22 21:34:33 +00:00
}
2012-08-04 10:54:37 +00:00
2012-01-22 21:34:33 +00:00
// toggle the teleport bit so the client knows to not lerp
2012-08-04 10:54:37 +00:00
ps - > eFlags ^ = EF_TELEPORT_BIT ;
// set angles
2012-11-15 23:58:56 +00:00
G_Client_SetViewAngle ( player , angles ) ;
2012-08-04 10:54:37 +00:00
2012-01-22 21:34:33 +00:00
// kill anything at the destination
2012-11-12 11:42:22 +00:00
if ( sess - > sessionTeam ! = TEAM_SPECTATOR ) {
2012-08-04 10:54:37 +00:00
if ( G_MoveBox ( player ) )
player - > r . contents = CONTENTS_NONE ;
2012-01-22 21:34:33 +00:00
}
// save results of pmove
BG_PlayerStateToEntityState ( & player - > client - > ps , & player - > s , qtrue ) ;
// use the precise origin for linking
2012-08-04 10:54:37 +00:00
VectorCopy ( ps - > origin , player - > r . currentOrigin ) ;
2012-01-22 21:34:33 +00:00
2012-08-04 10:54:37 +00:00
if ( sess - > sessionTeam ! = TEAM_SPECTATOR /*&& !(ps->eFlags&EF_ELIMINATED)*/ ) {
2012-01-22 21:34:33 +00:00
trap_LinkEntity ( player ) ;
}
}
//===========================================================
2012-08-04 10:54:37 +00:00
/*QUAKED misc_model (1 0 0) (-16 -16 -16) (16 16 16) CAST_SHADOWS CLIP_MODEL FORCE_META
2012-11-27 02:04:09 +00:00
- - - - - DESCRIPTION - - - - -
Will just spawn and display it ' s model .
Can be hooked up with a brushmodel - entity to move relative to .
- - - - - SPAWNFLAGS - - - - -
q3map2 :
1 : CAST_SHADOWS - Model will cast shadows .
2 : CLIP_MODEL - Model will be clipped so noone can pass trough .
4 : FORCE_META - will enforce a meta - compile for . bsp - build even if the compiler wasn ' t told to do so .
- - - - - KEYS - - - - -
" model " - arbitrary . md3 file to display
" target " - brushmodel - entity to attach to
q3map2 :
" _castShadows " OR " _cs " sets whether the entity casts shadows
" _receiveShadows " OR " _rs " sets whether the entity receives shadows
" modelscale " scaling factor for the model to include
" modelscale_vec " non - uniform scaling vector for the model to include
" model2 " path name of second model to load
" _frame " frame of model to load
" _frame2 " frame of second model to load
2012-01-22 21:34:33 +00:00
*/
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
}
2012-08-04 10:54:37 +00:00
//===========================================================
2012-11-12 11:42:22 +00:00
static void setCamera ( gentity_t * ent , int ownernum )
2012-08-04 10:54:37 +00:00
{
2012-01-22 21:34:33 +00:00
vec3_t dir ;
2012-08-04 10:54:37 +00:00
gentity_t * target = NULL ;
gentity_t * owner = NULL ;
2012-01-22 21:34:33 +00:00
2012-08-04 10:54:37 +00:00
ent - > r . ownerNum = ownernum ;
2012-01-22 21:34:33 +00:00
2012-08-04 10:54:37 +00:00
owner = & g_entities [ ownernum ] ;
2012-01-22 21:34:33 +00:00
2012-08-04 10:54:37 +00:00
//frame holds the rotate speed
ent - > s . frame = 0 ; //TiM: 0
2012-01-22 21:34:33 +00:00
// 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 ) ;
}
2012-08-04 10:54:37 +00:00
void cycleCamera ( gentity_t * self )
{
gentity_t * orgOwner = NULL ;
gentity_t * owner = NULL ;
if ( self - > r . ownerNum > = 0 & & self - > r . ownerNum < ENTITYNUM_WORLD )
{
orgOwner = & g_entities [ self - > r . ownerNum ] ;
}
owner = G_Find ( orgOwner , FOFS ( targetname ) , self - > target ) ;
if ( owner = = NULL )
{
//Uh oh! Not targeted at any ents! Or reached end of list? Which is it?
//for now assume reached end of list and are cycling
owner = G_Find ( owner , FOFS ( targetname ) , self - > target ) ;
}
setCamera ( self , owner - > s . number ) ;
if ( self - > think = = cycleCamera )
{
if ( owner - > wait > 0 )
self - > nextthink = level . time + owner - > wait ;
2012-11-27 02:04:09 +00:00
else if ( self - > wait > 0 )
2012-08-04 10:54:37 +00:00
self - > nextthink = level . time + self - > wait ;
2012-11-27 02:04:09 +00:00
else
self - > nextthink = - 1 ; //no auto cycle
2012-08-04 10:54:37 +00:00
}
}
void misc_portal_use ( gentity_t * self , gentity_t * other , gentity_t * activator )
{
2012-11-27 02:04:09 +00:00
if ( ! Q_stricmp ( self - > swapname , activator - > target ) & & self - > wait > 0 ) { //failsafe in case something slipped up, I'm too tired to be sure ^^
if ( self - > nextthink )
self - > nextthink = - 1 ;
else
self - > nextthink = level . time + self - > wait ;
} else {
cycleCamera ( self ) ;
}
2012-08-04 10:54:37 +00:00
}
void locateCamera ( gentity_t * ent ) {
gentity_t * owner = NULL ;
owner = G_Find ( NULL , FOFS ( targetname ) , ent - > target ) ;
2012-11-27 02:04:09 +00:00
if ( ! owner ) {
DEVELOPER ( G_Printf ( S_COLOR_YELLOW " [Entity-Error] Couldn't find target for misc_partal_surface, removing surface so you'll note. \n " ) ; ) ;
2012-08-04 10:54:37 +00:00
G_FreeEntity ( ent ) ;
return ;
}
2012-11-27 02:04:09 +00:00
//let's see if we need cyceling of some sort. Basic requirement: Do we have another camera connected?
if ( G_Find ( owner , FOFS ( targetname ) , ent - > target ) ) {
//we do, so do we need to set up for manual cycle or pause?
if ( ent - > targetname | | ( ent - > swapname & & ent - > wait > 0 ) )
ent - > use = misc_portal_use ; //there's one of either. Which one will be determined in usefunction.
//to set up the autocycle we need wait set on either surface or camera.
if ( ent - > wait > 0 | | owner - > wait > 0 ) {
if ( ent - > wait = = - 1 & & owner - > wait > 0 ) { //we need to make sure every camera has an individual wait
while ( ( owner = G_Find ( owner , FOFS ( targetname ) , ent - > target ) ) ! = NULL ) {
if ( owner - > wait = = - 1 ) {
DEVELOPER ( G_Printf ( S_COLOR_YELLOW " [Entity-Error] One of the tragetet misc_portal_cameras does not have an individual wait. Adapting wait of the first camera found as a default. \n " ) ; ) ;
owner = G_Find ( NULL , FOFS ( targetname ) , ent - > target ) ;
ent - > wait = owner - > wait ; //a camera failed so make sure to have the wait of the first camera ported over to the surface as failsafe
break ;
}
}
}
//make sure we got the right camera at this point
owner = G_Find ( NULL , FOFS ( targetname ) , ent - > target ) ;
ent - > think = cycleCamera ;
if ( owner - > wait > 0 )
ent - > nextthink = level . time + owner - > wait ;
else if ( ent - > wait > 0 )
ent - > nextthink = level . time + ent - > wait ;
else
ent - > nextthink = - 1 ; //no auto cycle
2012-08-04 10:54:37 +00:00
}
}
2012-11-27 02:04:09 +00:00
setCamera ( ent , owner - > s . number ) ;
2012-08-04 10:54:37 +00:00
}
2012-01-22 21:34:33 +00:00
/*QUAKED misc_portal_surface (0 0 1) (-8 -8 -8) (8 8 8)
2012-11-27 02:04:09 +00:00
- - - - - DESCRIPTION - - - - -
2012-01-22 21:34:33 +00:00
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 !
2012-08-04 10:54:37 +00:00
2012-11-27 02:04:09 +00:00
- - - - - SPAWNFLAGS - - - - -
none
- - - - - KEYS - - - - -
" target " - misc_portal_camera ' s to target
" targetname " - When used , cycles to the next misc_portal_camera it ' s targeted
" wait " - makes it auto - cycle between all cameras it ' s pointed at at intevervals of specified number of seconds . Default = - 1 = don ' t autocycle
cameras will be cycled through in the order they were created on the map .
if this and the first camera are - 1 there will be no autocycle .
if this is - 1 but the first camera is positive the wait will be adapted as a faulsafe measure should one of the later cameras lack an individual wait .
" swapname " - will pause / unpause the autocycle . The next cycle will happen aufer " wait " seconds , so wait is required for this .
requires SELF / NO_ACRIVATOR
- - - - - USAGE - - - - -
Autocycle or manual Cycle usually only makes sence for a survaliance - station or security .
For a viewscreen or a communications channel make the brush having the portal - texture a func_usable and treat is as described on that entity for VFX - Entities .
2012-01-22 21:34:33 +00:00
*/
void SP_misc_portal_surface ( gentity_t * ent ) {
2012-11-27 02:04:09 +00:00
2012-01-22 21:34:33 +00:00
VectorClear ( ent - > r . mins ) ;
VectorClear ( ent - > r . maxs ) ;
trap_LinkEntity ( ent ) ;
ent - > r . svFlags = SVF_PORTAL ;
ent - > s . eType = ET_PORTAL ;
2012-11-27 02:04:09 +00:00
if ( ent - > wait > 0 )
ent - > wait * = 1000 ;
else
ent - > wait = - 1 ;
2012-01-22 21:34:33 +00:00
if ( ! ent - > target ) {
2012-11-27 02:04:09 +00:00
VectorCopy ( ent - > s . origin , ent - > s . origin2 ) ; //mirror
2012-01-22 21:34:33 +00:00
} else {
ent - > think = locateCamera ;
2012-11-27 02:04:09 +00:00
ent - > nextthink = level . time + 500 ; //give cameras time to spawn
if ( ent - > targetname & & ent - > swapname & & ent - > wait = = - 1 ) {
DEVELOPER ( G_Printf ( S_COLOR_YELLOW " [Entity-Error] Both swapname and wait need to be present on a misc_model_surface to potentionally turn it's autocycle off. NULLing swapname. \n " ) ; ) ;
ent - > swapname = G_NewString ( " NULL " ) ; //Failsafe: We'll have the usefunction, however we can not use it for pausing as we did not have wait on ent. Set swapname to NULL so we can use wait as a potential failsafe should one of the cameras lack an individual wait.
2012-08-04 10:54:37 +00:00
}
2012-01-22 21:34:33 +00:00
}
}
2012-11-27 02:04:09 +00:00
/*QUAKED misc_portal_camera (0 0 1) (-8 -8 -8) (8 8 8) SLOWROTATE FASTROTATE
- - - - - DESCRIPTION - - - - -
The target for a misc_portal_surface .
You can set either angles or target another entity ( NOT an info_null or similar ) to determine the direction of view .
- - - - - SPAWNFLAGS - - - - -
1 : SLOWROTATE - slowly rotates around it ' s axis of view
2 : FASTROTATE - quickly rotates around it ' s axis of view
- - - - - KEYS - - - - -
" targetname " - have misc_portal_surface target this
" roll " - an angle modifier to orient the camera around the target vector . Default is 0.
" wait " - delay for autocycle misc_portal_surface . Will overwrite theirs . Default is - 1 = use surface - value .
2012-01-22 21:34:33 +00:00
*/
void SP_misc_portal_camera ( gentity_t * ent ) {
float roll ;
VectorClear ( ent - > r . mins ) ;
VectorClear ( ent - > r . maxs ) ;
2012-08-04 10:54:37 +00:00
trap_LinkEntity ( ent ) ;
2012-01-22 21:34:33 +00:00
G_SpawnFloat ( " roll " , " 0 " , & roll ) ;
ent - > s . clientNum = roll / 360.0 * 256 ;
2012-11-27 02:04:09 +00:00
if ( ent - > wait > 0 )
ent - > wait * = 1000 ;
else
ent - > wait = - 1 ;
2012-01-22 21:34:33 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
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 ) {
2012-08-04 10:54:37 +00:00
case WP_8 :
2012-01-22 21:34:33 +00:00
fire_grenade ( ent , ent - > s . origin , dir ) ;
break ;
2012-08-04 10:54:37 +00:00
case WP_10 :
2012-01-22 21:34:33 +00:00
fire_rocket ( ent , ent - > s . origin , dir ) ;
break ;
2012-08-04 10:54:37 +00:00
case WP_4 :
2012-01-22 21:34:33 +00:00
fire_plasma ( ent , ent - > s . origin , dir ) ;
break ;
2012-08-04 10:54:37 +00:00
case WP_9 :
fire_quantum ( ent , ent - > s . origin , dir ) ;
break ;
case WP_6 :
fire_comprifle ( ent , ent - > s . origin , dir ) ;
break ;
2012-01-22 21:34:33 +00:00
}
}
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 ;
2012-11-12 11:42:22 +00:00
RegisterItem ( BG_FindItemForWeapon ( ( weapon_t ) weapon ) ) ;
2012-01-22 21:34:33 +00:00
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)
2012-11-27 09:37:48 +00:00
- - - - - DESCRIPTION - - - - -
When used fires a rocket at either the target or the current direction .
- - - - - SPAWNFLAGS - - - - -
none
- - - - - KEYS - - - - -
" target " - direction to fire to
" random " - the number of degrees of deviance from the taget . ( 1.0 default )
2012-01-22 21:34:33 +00:00
*/
void SP_shooter_rocket ( gentity_t * ent ) {
2012-08-04 10:54:37 +00:00
InitShooter ( ent , WP_10 ) ;
2012-01-22 21:34:33 +00:00
}
/*QUAKED shooter_plasma (1 0 0) (-16 -16 -16) (16 16 16)
2012-11-27 09:37:48 +00:00
- - - - - DESCRIPTION - - - - -
When used fires a plasma - burst at either the target or the current direction .
- - - - - SPAWNFLAGS - - - - -
none
- - - - - KEYS - - - - -
" target " - direction to fire to
" random " - the number of degrees of deviance from the taget . ( 1.0 default )
2012-01-22 21:34:33 +00:00
*/
void SP_shooter_plasma ( gentity_t * ent ) {
2012-08-04 10:54:37 +00:00
InitShooter ( ent , WP_6 ) ; //TiM : WP_4
2012-01-22 21:34:33 +00:00
}
/*QUAKED shooter_grenade (1 0 0) (-16 -16 -16) (16 16 16)
2012-11-27 09:37:48 +00:00
- - - - - DESCRIPTION - - - - -
When used fires a grenade at either the target or the current direction .
- - - - - SPAWNFLAGS - - - - -
none
- - - - - KEYS - - - - -
" target " - direction to fire to
" random " - the number of degrees of deviance from the taget . ( 1.0 default )
2012-01-22 21:34:33 +00:00
*/
void SP_shooter_grenade ( gentity_t * ent ) {
2012-08-04 10:54:37 +00:00
InitShooter ( ent , WP_8 ) ;
2012-01-22 21:34:33 +00:00
}
2012-08-04 10:54:37 +00:00
/*QUAKED shooter_torpedo (1 0 0) (-16 -16 -16) (16 16 16)
2012-11-27 09:37:48 +00:00
- - - - - DESCRIPTION - - - - -
When used fires a torpedo at either the target or the current direction .
- - - - - SPAWNFLAGS - - - - -
none
- - - - - KEYS - - - - -
" target " - direction to fire to
" random " - the number of degrees of deviance from the taget . ( 1.0 default )
2012-08-04 10:54:37 +00:00
*/
void SP_shooter_torpedo ( gentity_t * ent ) {
InitShooter ( ent , WP_9 ) ;
2012-01-22 21:34:33 +00:00
}