2013-04-19 02:52:48 +00:00
// leave this line at the top for all g_xxxx.cpp files...
# include "g_headers.h"
# include "g_local.h"
# include "g_functions.h"
extern int G_FindConfigstringIndex ( const char * name , int start , int max , qboolean create ) ;
# define FX_ENT_RADIUS 32
extern int BMS_START ;
extern int BMS_MID ;
extern int BMS_END ;
//----------------------------------------------------------
/*QUAKED fx_runner (0 0 1) (-8 -8 -8) (8 8 8) STARTOFF ONESHOT DAMAGE
Runs the specified effect , can also be targeted at an info_notnull to orient the effect
STARTOFF - effect starts off , toggles on / off when used
ONESHOT - effect fires only when used
DAMAGE - does radius damage around effect every " delay " milliseonds
" fxFile " - name of the effect file to play
" target " - direction to aim the effect in , otherwise defaults to up
" target2 " - uses its target2 when the fx gets triggered
" delay " - how often to call the effect , don ' t over - do this ( default 200 )
" random " - random amount of time to add to delay , ( default 0 , 200 = 0 ms to 200 ms )
" splashRadius " - only works when damage is checked ( default 16 )
" splashDamage " - only works when damage is checked ( default 5 )
" soundset " - bmodel set to use , plays start sound when toggled on , loop sound while on ( doesn ' t play on a oneshot ) , and a stop sound when turned off
*/
# define FX_RUNNER_RESERVED 0x800000
//----------------------------------------------------------
void fx_runner_think ( gentity_t * ent )
{
vec3_t temp ;
EvaluateTrajectory ( & ent - > s . pos , level . time , ent - > currentOrigin ) ;
EvaluateTrajectory ( & ent - > s . apos , level . time , ent - > currentAngles ) ;
// call the effect with the desired position and orientation
G_AddEvent ( ent , EV_PLAY_EFFECT , ent - > fxID ) ;
// Assume angles, we'll do a cross product on the other end to finish up
AngleVectors ( ent - > currentAngles , ent - > pos3 , NULL , NULL ) ;
MakeNormalVectors ( ent - > pos3 , ent - > pos4 , temp ) ; // there IS a reason this is done...it's so that it doesn't break every effect in the game...
ent - > nextthink = level . time + ent - > delay + random ( ) * ent - > random ;
if ( ent - > spawnflags & 4 ) // damage
{
G_RadiusDamage ( ent - > currentOrigin , ent , ent - > splashDamage , ent - > splashRadius , ent , MOD_UNKNOWN ) ;
}
if ( ent - > target2 )
{
// let our target know that we have spawned an effect
G_UseTargets2 ( ent , ent , ent - > target2 ) ;
}
if ( ! ( ent - > spawnflags & 2 ) & & ! ent - > s . loopSound ) // NOT ONESHOT...this is an assy thing to do
{
if ( VALIDSTRING ( ent - > soundSet ) = = true )
{
ent - > s . loopSound = CAS_GetBModelSound ( ent - > soundSet , BMS_MID ) ;
if ( ent - > s . loopSound < 0 )
{
ent - > s . loopSound = 0 ;
}
}
}
}
//----------------------------------------------------------
void fx_runner_use ( gentity_t * self , gentity_t * other , gentity_t * activator )
{
if ( self - > s . isPortalEnt )
{ //rww - mark it as broadcast upon first use if it's within the area of a skyportal
self - > svFlags | = SVF_BROADCAST ;
}
if ( self - > spawnflags & 2 ) // ONESHOT
{
// call the effect with the desired position and orientation, as a safety thing,
// make sure we aren't thinking at all.
fx_runner_think ( self ) ;
self - > nextthink = - 1 ;
if ( self - > target2 )
{
// let our target know that we have spawned an effect
G_UseTargets2 ( self , self , self - > target2 ) ;
}
if ( VALIDSTRING ( self - > soundSet ) = = true )
{
G_AddEvent ( self , EV_BMODEL_SOUND , CAS_GetBModelSound ( self - > soundSet , BMS_START ) ) ;
}
}
else
{
// ensure we are working with the right think function
self - > e_ThinkFunc = thinkF_fx_runner_think ;
// toggle our state
if ( self - > nextthink = = - 1 )
{
// NOTE: we fire the effect immediately on use, the fx_runner_think func will set
// up the nextthink time.
fx_runner_think ( self ) ;
if ( VALIDSTRING ( self - > soundSet ) = = true )
{
G_AddEvent ( self , EV_BMODEL_SOUND , CAS_GetBModelSound ( self - > soundSet , BMS_START ) ) ;
self - > s . loopSound = CAS_GetBModelSound ( self - > soundSet , BMS_MID ) ;
if ( self - > s . loopSound < 0 )
{
self - > s . loopSound = 0 ;
}
}
}
else
{
// turn off for now
self - > nextthink = - 1 ;
if ( VALIDSTRING ( self - > soundSet ) = = true )
{
G_AddEvent ( self , EV_BMODEL_SOUND , CAS_GetBModelSound ( self - > soundSet , BMS_END ) ) ;
self - > s . loopSound = 0 ;
}
}
}
}
//----------------------------------------------------------
void fx_runner_link ( gentity_t * ent )
{
vec3_t dir ;
if ( ent - > target )
{
// try to use the target to override the orientation
gentity_t * target = NULL ;
target = G_Find ( target , FOFS ( targetname ) , ent - > target ) ;
if ( ! target )
{
// Bah, no good, dump a warning, but continue on and use the UP vector
Com_Printf ( " fx_runner_link: target specified but not found: %s \n " , ent - > target ) ;
Com_Printf ( " -assuming UP orientation. \n " ) ;
}
else
{
// Our target is valid so let's override the default UP vector
VectorSubtract ( target - > s . origin , ent - > s . origin , dir ) ;
VectorNormalize ( dir ) ;
vectoangles ( dir , ent - > s . angles ) ;
}
}
// don't really do anything with this right now other than do a check to warn the designers if the target2 is bogus
if ( ent - > target2 )
{
gentity_t * target = NULL ;
target = G_Find ( target , FOFS ( targetname ) , ent - > target2 ) ;
if ( ! target )
{
// Target2 is bogus, but we can still continue
Com_Printf ( " fx_runner_link: target2 was specified but is not valid: %s \n " , ent - > target2 ) ;
}
}
G_SetAngles ( ent , ent - > s . angles ) ;
if ( ent - > spawnflags & 1 | | ent - > spawnflags & 2 ) // STARTOFF || ONESHOT
{
// We won't even consider thinking until we are used
ent - > nextthink = - 1 ;
}
else
{
if ( VALIDSTRING ( ent - > soundSet ) = = true )
{
ent - > s . loopSound = CAS_GetBModelSound ( ent - > soundSet , BMS_MID ) ;
if ( ent - > s . loopSound < 0 )
{
ent - > s . loopSound = 0 ;
}
}
// Let's get to work right now!
ent - > e_ThinkFunc = thinkF_fx_runner_think ;
ent - > nextthink = level . time + 200 ; // wait a small bit, then start working
}
// make us useable if we can be targeted
if ( ent - > targetname )
{
ent - > e_UseFunc = useF_fx_runner_use ;
}
}
//----------------------------------------------------------
void SP_fx_runner ( gentity_t * ent )
{
// Get our defaults
G_SpawnInt ( " delay " , " 200 " , & ent - > delay ) ;
G_SpawnFloat ( " random " , " 0 " , & ent - > random ) ;
G_SpawnInt ( " splashRadius " , " 16 " , & ent - > splashRadius ) ;
G_SpawnInt ( " splashDamage " , " 5 " , & ent - > splashDamage ) ;
if ( ! G_SpawnAngleHack ( " angle " , " 0 " , ent - > s . angles ) )
{
// didn't have angles, so give us the default of up
VectorSet ( ent - > s . angles , - 90 , 0 , 0 ) ;
}
if ( ! ent - > fxFile )
{
gi . Printf ( S_COLOR_RED " ERROR: fx_runner %s at %s has no fxFile specified \n " , ent - > targetname , vtos ( ent - > s . origin ) ) ;
G_FreeEntity ( ent ) ;
return ;
}
// Try and associate an effect file, unfortunately we won't know if this worked or not
// until the CGAME trys to register it...
ent - > fxID = G_EffectIndex ( ent - > fxFile ) ;
ent - > s . eType = ET_MOVER ;
// Give us a bit of time to spawn in the other entities, since we may have to target one of 'em
ent - > e_ThinkFunc = thinkF_fx_runner_link ;
ent - > nextthink = level . time + 400 ;
// Save our position and link us up!
G_SetOrigin ( ent , ent - > s . origin ) ;
VectorSet ( ent - > maxs , FX_ENT_RADIUS , FX_ENT_RADIUS , FX_ENT_RADIUS ) ;
VectorScale ( ent - > maxs , - 1 , ent - > mins ) ;
gi . linkentity ( ent ) ;
}
/*QUAKED fx_snow (1 0 0) (-16 -16 -16) (16 16 16) LIGHT MEDIUM HEAVY MISTY_FOG
This world effect will spawn snow globally into the level .
*/
void SP_CreateSnow ( gentity_t * ent )
{
cvar_t * r_weatherScale = gi . cvar ( " r_weatherScale " , " 1 " , CVAR_ARCHIVE ) ;
if ( r_weatherScale - > value = = 0.0f )
{
return ;
}
// Different Types Of Rain
//-------------------------
if ( ent - > spawnflags & 1 )
{
G_FindConfigstringIndex ( " lightsnow " , CS_WORLD_FX , MAX_WORLD_FX , qtrue ) ;
}
else if ( ent - > spawnflags & 2 )
{
G_FindConfigstringIndex ( " snow " , CS_WORLD_FX , MAX_WORLD_FX , qtrue ) ;
}
else if ( ent - > spawnflags & 4 )
{
G_FindConfigstringIndex ( " heavysnow " , CS_WORLD_FX , MAX_WORLD_FX , qtrue ) ;
}
else
{
G_FindConfigstringIndex ( " snow " , CS_WORLD_FX , MAX_WORLD_FX , qtrue ) ;
G_FindConfigstringIndex ( " fog " , CS_WORLD_FX , MAX_WORLD_FX , qtrue ) ;
}
// MISTY FOG
//===========
if ( ent - > spawnflags & 8 )
{
G_FindConfigstringIndex ( " fog " , CS_WORLD_FX , MAX_WORLD_FX , qtrue ) ;
}
}
/*QUAKED fx_wind (0 .5 .8) (-16 -16 -16) (16 16 16) NORMAL CONSTANT GUSTING SWIRLING x FOG LIGHT_FOG
Generates global wind forces
NORMAL creates a random light global wind
CONSTANT forces all wind to go in a specified direction
GUSTING causes random gusts of wind
SWIRLING causes random swirls of wind
" angles " the direction for constant wind
" speed " the speed for constant wind
*/
void SP_CreateWind ( gentity_t * ent )
{
cvar_t * r_weatherScale = gi . cvar ( " r_weatherScale " , " 1 " , CVAR_ARCHIVE ) ;
if ( r_weatherScale - > value < = 0.0f )
{
return ;
}
char temp [ 256 ] ;
// Normal Wind
//-------------
if ( ent - > spawnflags & 1 )
{
G_FindConfigstringIndex ( " wind " , CS_WORLD_FX , MAX_WORLD_FX , qtrue ) ;
}
// Constant Wind
//---------------
if ( ent - > spawnflags & 2 )
{
vec3_t windDir ;
AngleVectors ( ent - > s . angles , windDir , 0 , 0 ) ;
G_SpawnFloat ( " speed " , " 500 " , & ent - > speed ) ;
VectorScale ( windDir , ent - > speed , windDir ) ;
sprintf ( temp , " constantwind ( %f %f %f ) " , windDir [ 0 ] , windDir [ 1 ] , windDir [ 2 ] ) ;
G_FindConfigstringIndex ( temp , CS_WORLD_FX , MAX_WORLD_FX , qtrue ) ;
}
// Gusting Wind
//--------------
if ( ent - > spawnflags & 4 )
{
G_FindConfigstringIndex ( " gustingwind " , CS_WORLD_FX , MAX_WORLD_FX , qtrue ) ;
}
// Swirling Wind
//---------------
if ( ent - > spawnflags & 8 )
{
G_FindConfigstringIndex ( " swirlingwind " , CS_WORLD_FX , MAX_WORLD_FX , qtrue ) ;
}
// MISTY FOG
//===========
if ( ent - > spawnflags & 32 )
{
G_FindConfigstringIndex ( " fog " , CS_WORLD_FX , MAX_WORLD_FX , qtrue ) ;
}
// MISTY FOG
//===========
if ( ent - > spawnflags & 64 )
{
G_FindConfigstringIndex ( " light_fog " , CS_WORLD_FX , MAX_WORLD_FX , qtrue ) ;
}
}
/*QUAKED fx_wind_zone (0 .5 .8) ? Creates a constant wind in a local area
Generates local wind forces
" angles " the direction for constant wind
" speed " the speed for constant wind
*/
void SP_CreateWindZone ( gentity_t * ent )
{
cvar_t * r_weatherScale = gi . cvar ( " r_weatherScale " , " 1 " , CVAR_ARCHIVE ) ;
if ( r_weatherScale - > value < = 0.0f )
{
return ;
}
gi . SetBrushModel ( ent , ent - > model ) ;
vec3_t windDir ;
AngleVectors ( ent - > s . angles , windDir , 0 , 0 ) ;
G_SpawnFloat ( " speed " , " 500 " , & ent - > speed ) ;
VectorScale ( windDir , ent - > speed , windDir ) ;
char temp [ 256 ] ;
sprintf ( temp , " windzone ( %f %f %f ) ( %f %f %f ) ( %f %f %f ) " ,
ent - > mins [ 0 ] , ent - > mins [ 1 ] , ent - > mins [ 2 ] ,
ent - > maxs [ 0 ] , ent - > maxs [ 1 ] , ent - > maxs [ 2 ] ,
windDir [ 0 ] , windDir [ 1 ] , windDir [ 2 ]
) ;
G_FindConfigstringIndex ( temp , CS_WORLD_FX , MAX_WORLD_FX , qtrue ) ;
}
/*QUAKED fx_rain (1 0 0) (-16 -16 -16) (16 16 16) LIGHT MEDIUM HEAVY ACID OUTSIDE_SHAKE MISTY_FOG
This world effect will spawn rain globally into the level .
LIGHT create light drizzle
MEDIUM create average medium rain
HEAVY create heavy downpour ( with fog and lightning automatically )
ACID create acid rain
OUTSIDE_SHAKE will cause the camera to shake slightly whenever outside
MISTY_FOG causes clouds of misty fog to float through the level
LIGHTNING causes random bursts of lightning and thunder in the level
The following fields are for lightning :
" flashcolor " " 200 200 200 " ( r g b ) ( values 0.0 - 255.0 )
" flashdelay " " 12000 " maximum time delay between lightning strikes
" chanceflicker " " 2 " 1 in 2 chance of flickering fog
" chancesound " " 3 " 1 in 3 chance of playing a sound
" chanceeffect " " 4 " 1 in 4 chance of playing the effect
*/
//----------------------------------------------------------
//----------------------------------------------------------
extern void G_SoundAtSpot ( vec3_t org , int soundIndex , qboolean broadcast ) ;
void fx_rain_think ( gentity_t * ent )
{
if ( player )
{
if ( ent - > count ! = 0 )
{
ent - > count - - ;
if ( ent - > count = = 0 | | ( ent - > count % 2 ) = = 0 )
{
gi . WE_SetTempGlobalFogColor ( ent - > pos2 ) ; // Turn Off
if ( ent - > count = = 0 )
{
ent - > nextthink = level . time + Q_irand ( 1000 , 12000 ) ;
}
else if ( ent - > count = = 2 )
{
ent - > nextthink = level . time + Q_irand ( 150 , 450 ) ;
}
else
{
ent - > nextthink = level . time + Q_irand ( 50 , 150 ) ;
}
}
else
{
gi . WE_SetTempGlobalFogColor ( ent - > pos3 ) ; // Turn On
ent - > nextthink = level . time + 50 ;
}
}
else if ( gi . WE_IsOutside ( player - > currentOrigin ) )
{
vec3_t effectPos ;
vec3_t effectDir ;
VectorClear ( effectDir ) ;
effectDir [ 0 ] + = Q_flrand ( - 1.0f , 1.0f ) ;
effectDir [ 1 ] + = Q_flrand ( - 1.0f , 1.0f ) ;
bool PlayEffect = Q_irand ( 1 , ent - > aimDebounceTime ) = = 1 ;
bool PlayFlicker = Q_irand ( 1 , ent - > attackDebounceTime ) = = 1 ;
bool PlaySound = ( PlayEffect | | PlayFlicker | | Q_irand ( 1 , ent - > pushDebounceTime ) = = 1 ) ;
// Play The Sound
//----------------
if ( PlaySound & & ! PlayEffect )
{
VectorMA ( player - > currentOrigin , 250.0f , effectDir , effectPos ) ;
G_SoundAtSpot ( effectPos , G_SoundIndex ( va ( " sound/ambience/thunder%d " , Q_irand ( 1 , 4 ) ) ) , qtrue ) ;
}
// Play The Effect
//-----------------
if ( PlayEffect )
{
VectorMA ( player - > currentOrigin , 400.0f , effectDir , effectPos ) ;
if ( PlaySound )
{
G_Sound ( player , G_SoundIndex ( va ( " sound/ambience/thunder_close%d " , Q_irand ( 1 , 2 ) ) ) ) ;
}
// Raise It Up Into The Sky
//--------------------------
effectPos [ 2 ] + = Q_flrand ( 600.0f , 1000.0f ) ;
VectorClear ( effectDir ) ;
effectDir [ 2 ] = - 1.0f ;
G_PlayEffect ( " env/huge_lightning " , effectPos , effectDir ) ;
ent - > nextthink = level . time + Q_irand ( 100 , 200 ) ;
}
// Change The Fog Color
//----------------------
if ( PlayFlicker )
{
ent - > count = ( Q_irand ( 1 , 4 ) * 2 ) ;
ent - > nextthink = level . time + 50 ;
gi . WE_SetTempGlobalFogColor ( ent - > pos3 ) ;
}
else
{
ent - > nextthink = level . time + Q_irand ( 1000 , ent - > delay ) ;
}
}
else
{
ent - > nextthink = level . time + Q_irand ( 1000 , ent - > delay ) ;
}
}
else
{
ent - > nextthink = level . time + Q_irand ( 1000 , ent - > delay ) ;
}
}
void SP_CreateRain ( gentity_t * ent )
{
// Different Types Of Rain
//-------------------------
if ( ent - > spawnflags & 1 )
{
G_FindConfigstringIndex ( " lightrain " , CS_WORLD_FX , MAX_WORLD_FX , qtrue ) ;
}
else if ( ent - > spawnflags & 2 )
{
G_FindConfigstringIndex ( " rain " , CS_WORLD_FX , MAX_WORLD_FX , qtrue ) ;
}
else if ( ent - > spawnflags & 4 )
{
G_FindConfigstringIndex ( " heavyrain " , CS_WORLD_FX , MAX_WORLD_FX , qtrue ) ;
// Automatically Get Heavy Fog
//-----------------------------
G_FindConfigstringIndex ( " heavyrainfog " , CS_WORLD_FX , MAX_WORLD_FX , qtrue ) ;
// Automatically Get Lightning & Thunder
//---------------------------------------
ent - > spawnflags | = 64 ;
}
else if ( ent - > spawnflags & 8 )
{
G_EffectIndex ( " world/acid_fizz " ) ;
G_FindConfigstringIndex ( " acidrain " , CS_WORLD_FX , MAX_WORLD_FX , qtrue ) ;
}
// OUTSIDE SHAKE
//===============
if ( ent - > spawnflags & 16 )
{
G_FindConfigstringIndex ( " outsideShake " , CS_WORLD_FX , MAX_WORLD_FX , qtrue ) ;
}
// MISTY FOG
//===========
if ( ent - > spawnflags & 32 )
{
G_FindConfigstringIndex ( " fog " , CS_WORLD_FX , MAX_WORLD_FX , qtrue ) ;
}
// LIGHTNING
//===========
if ( ent - > spawnflags & 64 )
{
G_SoundIndex ( " sound/ambience/thunder1 " ) ;
G_SoundIndex ( " sound/ambience/thunder2 " ) ;
G_SoundIndex ( " sound/ambience/thunder3 " ) ;
G_SoundIndex ( " sound/ambience/thunder4 " ) ;
G_SoundIndex ( " sound/ambience/thunder_close1 " ) ;
G_SoundIndex ( " sound/ambience/thunder_close2 " ) ;
G_EffectIndex ( " env/huge_lightning " ) ;
ent - > e_ThinkFunc = thinkF_fx_rain_think ;
ent - > nextthink = level . time + Q_irand ( 4000 , 8000 ) ;
if ( ! G_SpawnVector ( " flashcolor " , " 200 200 200 " , ent - > pos3 ) )
{
VectorSet ( ent - > pos3 , 200 , 200 , 200 ) ;
}
VectorClear ( ent - > pos2 ) ; // the "off" color
G_SpawnInt ( " flashdelay " , " 12000 " , & ent - > delay ) ;
G_SpawnInt ( " chanceflicker " , " 2 " , & ent - > attackDebounceTime ) ;
G_SpawnInt ( " chancesound " , " 3 " , & ent - > pushDebounceTime ) ;
G_SpawnInt ( " chanceeffect " , " 4 " , & ent - > aimDebounceTime ) ;
}
}
// Added by Aurelio Reis on 10/20/02.
/*QUAKED fx_puff (1 0 0) (-16 -16 -16) (16 16 16)
This world effect will spawn a puff system globally into the level .
Enter any valid puff command as a key and value to setup the puff
system properties .
" count " The number of puffs / particles ( default of 1000 ) .
" whichsystem " Which puff system to use ( currently 0 and 1. Default 0 ) .
// Apply a default puff system.
default < value >
Current defaults are " snowstorm " , " sandstorm " , " foggy " , and " smokey "
// Set the color of the particles (0-1.0).
color ( < red > , < green > , < blue > )
default ( 0.5 , 0.5 , 0.5 )
// Set the alpha (transparency) value for the particles (0-1.0).
alpha < value >
default 0.5
// Set which texture to use for the particles (make sure to include full path).
texture < textures / texture . tga >
default gfx / effects / alpha_smoke2b . tga
// Set the size of particles (from center, like a radius) (MIN 4, MAX 2048).
size < value >
default 100
// Whether the saber should flicker and spark or not (0 false, 1 true).
sabersparks < value >
default 0
// Set texture filtering mode (0 = Bilinear(default), 1 = Nearest(less quality).
filtermode < value >
default 0
// Set the alpha blending mode (0 = src, src-1, 1 = one, one (additive)).
blendmode < value >
default 0
// How much to rotate particles per second (in degree's).
rotate ( < min > , < max > )
default ( 0 , 0 )
// Set the area around the player the puffs cover:
spread ( minX minY minZ ) ( maxX maxY maxZ )
default : ( - 600 - 600 - 500 ) ( 600 600 550 )
// Set the random range that sets the speed the puffs fall:
velocity ( minX minY minZ ) ( maxX maxY maxZ )
default : ( - 15 - 15 - 20 ) ( 15 15 - 70 )
// Set an area of puff blowing:
wind ( windOriginX windOriginY windOriginZ ) ( windVelocityX windVelocityY windVelocityZ ) ( sizeX sizeY sizeZ )
// Set puff blowing data:
blowing duration < int >
blowing low < int >
default : 3
blowing velocity ( min max )
default : ( 30 70 )
blowing size ( minX minY minZ )
default : ( 1000 300 300 )
*/
//----------------------------------------------------------
void SP_CreatePuffSystem ( gentity_t * ent )
{
char temp [ 128 ] ;
// Initialize the puff system to either 1000 particles or whatever they choose.
G_SpawnInt ( " count " , " 1000 " , & ent - > count ) ;
cvar_t * r_weatherScale = gi . cvar ( " r_weatherScale " , " 1 " , CVAR_ARCHIVE ) ;
// See which puff system to use.
int iPuffSystem = 0 ;
int iVal = 0 ;
if ( G_SpawnInt ( " whichsystem " , " 0 " , & iVal ) )
{
iPuffSystem = iVal ;
if ( iPuffSystem < 0 | | iPuffSystem > 1 )
{
iPuffSystem = 0 ;
//ri.Error( ERR_DROP, "Weather Effect: Invalid value for whichsystem key" );
Com_Printf ( " Weather Effect: Invalid value for whichsystem key \n " ) ;
}
}
if ( r_weatherScale - > value > 0.0f )
{
sprintf ( temp , " puff%i init %i " , iPuffSystem , ( int ) ( ent - > count * r_weatherScale - > value ) ) ;
G_FindConfigstringIndex ( temp , CS_WORLD_FX , MAX_WORLD_FX , qtrue ) ;
// Should return here??? It didn't originally...
}
// See whether we should have the saber spark from the puff system.
iVal = 0 ;
G_SpawnInt ( " sabersparks " , " 0 " , & iVal ) ;
if ( iVal = = 1 )
level . worldFlags | = WF_PUFFING ;
else
level . worldFlags & = ~ WF_PUFFING ;
// Go through all the fields and assign the values to the created puff system now.
for ( int i = 0 ; i < 20 ; i + + )
{
char * key = NULL ;
char * value = NULL ;
// Fetch a field.
if ( ! G_SpawnField ( i , & key , & value ) )
continue ;
// Make sure we don't get key's that are worthless.
if ( Q_stricmp ( key , " origin " ) = = 0 | | Q_stricmp ( key , " classname " ) = = 0 | |
Q_stricmp ( key , " count " ) = = 0 | | Q_stricmp ( key , " targetname " ) = = 0 | |
Q_stricmp ( key , " sabersparks " ) = = 0 | | Q_stricmp ( key , " whichsystem " ) = = 0 )
continue ;
// Send the command.
2013-04-23 09:45:35 +00:00
snprintf ( temp , 128 , " puff%i %s %s " , iPuffSystem , key , value ) ;
2013-04-19 02:52:48 +00:00
G_FindConfigstringIndex ( temp , CS_WORLD_FX , MAX_WORLD_FX , qtrue ) ;
}
}
// Don't use this! Too powerful! - Aurelio
/*NOTEINUSE! fx_command (1 0 0) (-16 -16 -16) (16 16 16)
//This effect allows you to issue console commands from within the world editor.
//Use the variables c00 to c99 to issue a maximum of 100 console commands.
//example: c00 r_showtris 1
*/
//----------------------------------------------------------
/*void SP_Command( gentity_t *ent )
{
char * strCommand ;
// Go through all the commands.
for ( int i = 0 ; i < 100 ; i + + )
{
strCommand = NULL ;
// Fetch a command.
G_SpawnString ( va ( " c%02d " , i ) , NULL , & strCommand ) ;
// If it's valid, issue it.
if ( strCommand & & strCommand [ 0 ] )
{
gi . SendConsoleCommand ( strCommand ) ;
}
}
} */
//-----------------
// Explosion Trail
//-----------------
//----------------------------------------------------------
void fx_explosion_trail_think ( gentity_t * ent )
{
vec3_t origin ;
trace_t tr ;
if ( ent - > spawnflags & 1 ) // gravity
{
ent - > s . pos . trType = TR_GRAVITY ;
}
else
{
ent - > s . pos . trType = TR_LINEAR ;
}
EvaluateTrajectory ( & ent - > s . pos , level . time , origin ) ;
gi . trace ( & tr , ent - > currentOrigin , vec3_origin , vec3_origin , origin ,
ent - > owner ? ent - > owner - > s . number : ENTITYNUM_NONE , ent - > clipmask , G2_RETURNONHIT , 10 ) ;
if ( tr . fraction < 1.0f )
{
// never explode or bounce on sky
if ( ! ( tr . surfaceFlags & SURF_NOIMPACT ) )
{
if ( ent - > splashDamage & & ent - > splashRadius )
{
G_RadiusDamage ( tr . endpos , ent , ent - > splashDamage , ent - > splashRadius , ent , MOD_EXPLOSIVE_SPLASH ) ;
}
}
if ( ent - > cameraGroup )
{
// fxFile2....in other words, impact fx
G_PlayEffect ( ent - > cameraGroup , tr . endpos , tr . plane . normal ) ;
}
if ( VALIDSTRING ( ent - > soundSet ) = = true )
{
G_AddEvent ( ent , EV_BMODEL_SOUND , CAS_GetBModelSound ( ent - > soundSet , BMS_END ) ) ;
}
G_FreeEntity ( ent ) ;
return ;
}
G_RadiusDamage ( origin , ent , ent - > damage , ent - > radius , ent , MOD_EXPLOSIVE_SPLASH ) ;
// call the effect with the desired position and orientation
G_PlayEffect ( ent - > fxID , origin , ent - > currentAngles ) ;
ent - > nextthink = level . time + 50 ;
gi . linkentity ( ent ) ;
}
//----------------------------------------------------------
void fx_explosion_trail_use ( gentity_t * self , gentity_t * other , gentity_t * activator )
{
gentity_t * missile = G_Spawn ( ) ;
// We aren't a missile in the truest sense, rather we just move through the world and spawn effects
if ( missile )
{
missile - > classname = " fx_exp_trail " ;
missile - > nextthink = level . time + 50 ;
missile - > e_ThinkFunc = thinkF_fx_explosion_trail_think ;
missile - > s . eType = ET_MOVER ;
missile - > owner = self ;
missile - > s . modelindex = self - > s . modelindex2 ;
missile - > s . pos . trTime = level . time ;
G_SetOrigin ( missile , self - > currentOrigin ) ;
if ( self - > spawnflags & 1 ) // gravity
{
missile - > s . pos . trType = TR_GRAVITY ;
}
else
{
missile - > s . pos . trType = TR_LINEAR ;
}
missile - > spawnflags = self - > spawnflags ;
G_SetAngles ( missile , self - > currentAngles ) ;
VectorScale ( self - > currentAngles , self - > speed , missile - > s . pos . trDelta ) ;
missile - > s . pos . trTime = level . time ;
missile - > radius = self - > radius ;
missile - > damage = self - > damage ;
missile - > splashDamage = self - > splashDamage ;
missile - > splashRadius = self - > splashRadius ;
missile - > fxID = self - > fxID ;
missile - > cameraGroup = self - > cameraGroup ; //fxfile2
missile - > clipmask = MASK_SHOT ;
gi . linkentity ( missile ) ;
if ( VALIDSTRING ( self - > soundSet ) = = true )
{
G_AddEvent ( self , EV_BMODEL_SOUND , CAS_GetBModelSound ( self - > soundSet , BMS_START ) ) ;
missile - > s . loopSound = CAS_GetBModelSound ( self - > soundSet , BMS_MID ) ;
missile - > soundSet = G_NewString ( self - > soundSet ) ; //get my own copy so i can free it when i die
if ( missile - > s . loopSound < 0 )
{
missile - > s . loopSound = 0 ;
}
}
}
}
//----------------------------------------------------------
void fx_explosion_trail_link ( gentity_t * ent )
{
vec3_t dir ;
gentity_t * target = NULL ;
// we ony activate when used
ent - > e_UseFunc = useF_fx_explosion_trail_use ;
if ( ent - > target )
{
// try to use the target to override the orientation
target = G_Find ( target , FOFS ( targetname ) , ent - > target ) ;
if ( ! target )
{
gi . Printf ( S_COLOR_RED " ERROR: fx_explosion_trail %s could not find target %s \n " , ent - > targetname , ent - > target ) ;
G_FreeEntity ( ent ) ;
return ;
}
// Our target is valid so lets use that
VectorSubtract ( target - > s . origin , ent - > s . origin , dir ) ;
VectorNormalize ( dir ) ;
}
else
{
// we are assuming that we have angles, but there are no checks to verify this
AngleVectors ( ent - > s . angles , dir , NULL , NULL ) ;
}
// NOTE: this really isn't an angle, but rather an orientation vector
G_SetAngles ( ent , dir ) ;
}
/*QUAKED fx_explosion_trail (0 0 1) (-8 -8 -8) (8 8 8) GRAVITY
Creates an explosion type trail using the specified effect file , damaging things as it moves through the environment
Can also be used for something like a meteor , just add an impact effect ( fxFile2 ) and a splashDamage and splashRadius
GRAVITY - object uses gravity instead of linear motion
" fxFile " - name of the effect to play for the trail ( default " env/exp_trail_comp " )
" fxFile2 " - effect file to play on impact
" model " - model to attach to the trail
" target " - direction to aim the trail in , required unless you specify angles
" targetname " - ( required ) trail effect spawns only when used .
" speed " - velocity through the world , ( default 350 )
" radius " - damage radius around trail as it travels through the world ( default 128 )
" damage " - radius damage ( default 128 )
" splashDamage " - damage when thing impacts ( default 0 )
" splashRadius " - damage radius on impact ( default 0 )
" soundset " - soundset to use , start sound plays when explosion trail starts , loop sound plays on explosion trail , end sound plays when it impacts
*/
//----------------------------------------------------------
void SP_fx_explosion_trail ( gentity_t * ent )
{
// We have to be useable, otherwise we won't spawn in
if ( ! ent - > targetname )
{
gi . Printf ( S_COLOR_RED " ERROR: fx_explosion_trail at %s has no targetname specified \n " , vtos ( ent - > s . origin ) ) ;
G_FreeEntity ( ent ) ;
return ;
}
// Get our defaults
G_SpawnString ( " fxFile " , " env/exp_trail_comp " , & ent - > fxFile ) ;
G_SpawnInt ( " damage " , " 128 " , & ent - > damage ) ;
G_SpawnFloat ( " radius " , " 128 " , & ent - > radius ) ;
G_SpawnFloat ( " speed " , " 350 " , & ent - > speed ) ;
// Try to associate an effect file, unfortunately we won't know if this worked or not until the CGAME trys to register it...
ent - > fxID = G_EffectIndex ( ent - > fxFile ) ;
if ( ent - > cameraGroup )
{
G_EffectIndex ( ent - > cameraGroup ) ;
}
if ( ent - > model )
{
ent - > s . modelindex2 = G_ModelIndex ( ent - > model ) ;
}
// Give us a bit of time to spawn in the other entities, since we may have to target one of 'em
ent - > e_ThinkFunc = thinkF_fx_explosion_trail_link ;
ent - > nextthink = level . time + 500 ;
// Save our position and link us up!
G_SetOrigin ( ent , ent - > s . origin ) ;
VectorSet ( ent - > maxs , FX_ENT_RADIUS , FX_ENT_RADIUS , FX_ENT_RADIUS ) ;
VectorScale ( ent - > maxs , - 1 , ent - > mins ) ;
gi . linkentity ( ent ) ;
}
//
//
//------------------------------------------
void fx_target_beam_set_debounce ( gentity_t * self )
{
if ( self - > wait > = FRAMETIME )
{
self - > attackDebounceTime = level . time + self - > wait + Q_irand ( - self - > random , self - > random ) ;
}
else if ( self - > wait < 0 )
{
self - > e_UseFunc = useF_NULL ;
}
else
{
self - > attackDebounceTime = level . time + FRAMETIME + Q_irand ( - self - > random , self - > random ) ;
}
}
//------------------------------------------
void fx_target_beam_fire ( gentity_t * ent )
{
trace_t trace ;
vec3_t dir , org , end ;
int ignore ;
qboolean open ;
if ( ! ent - > enemy | | ! ent - > enemy - > inuse )
{ //info_null most likely
ignore = ent - > s . number ;
ent - > enemy = NULL ;
VectorCopy ( ent - > s . origin2 , org ) ;
}
else
{
ignore = ent - > enemy - > s . number ;
VectorCopy ( ent - > enemy - > currentOrigin , org ) ;
}
VectorCopy ( org , ent - > s . origin2 ) ;
VectorSubtract ( org , ent - > s . origin , dir ) ;
VectorNormalize ( dir ) ;
gi . trace ( & trace , ent - > s . origin , NULL , NULL , org , ENTITYNUM_NONE , MASK_SHOT ) ; //ignore
if ( ent - > spawnflags & 2 )
{
open = qtrue ;
VectorCopy ( org , end ) ;
}
else
{
open = qfalse ;
VectorCopy ( trace . endpos , end ) ;
}
if ( trace . fraction < 1.0 )
{
if ( trace . entityNum < ENTITYNUM_WORLD )
{
gentity_t * victim = & g_entities [ trace . entityNum ] ;
if ( victim & & victim - > takedamage )
{
if ( ent - > spawnflags & 4 ) // NO_KNOCKBACK
{
G_Damage ( victim , ent , ent - > activator , dir , trace . endpos , ent - > damage , DAMAGE_NO_KNOCKBACK , MOD_UNKNOWN ) ;
}
else
{
G_Damage ( victim , ent , ent - > activator , dir , trace . endpos , ent - > damage , 0 , MOD_UNKNOWN ) ;
}
}
}
}
G_AddEvent ( ent , EV_TARGET_BEAM_DRAW , ent - > fxID ) ;
VectorCopy ( end , ent - > s . origin2 ) ;
if ( open )
{
VectorScale ( dir , - 1 , ent - > pos1 ) ;
}
else
{
VectorCopy ( trace . plane . normal , ent - > pos1 ) ;
}
ent - > e_ThinkFunc = thinkF_fx_target_beam_think ;
ent - > nextthink = level . time + FRAMETIME ;
}
//------------------------------------------
void fx_target_beam_fire_start ( gentity_t * self )
{
fx_target_beam_set_debounce ( self ) ;
self - > e_ThinkFunc = thinkF_fx_target_beam_think ;
self - > nextthink = level . time + FRAMETIME ;
self - > painDebounceTime = level . time + self - > speed + Q_irand ( - 500 , 500 ) ;
fx_target_beam_fire ( self ) ;
}
//------------------------------------------
void fx_target_beam_use ( gentity_t * self , gentity_t * other , gentity_t * activator )
{
if ( self - > spawnflags & 8 ) // one shot
{
fx_target_beam_fire ( self ) ;
self - > e_ThinkFunc = thinkF_NULL ;
}
else if ( self - > e_ThinkFunc = = thinkF_NULL )
{
self - > e_ThinkFunc = thinkF_fx_target_beam_think ;
self - > nextthink = level . time + 50 ;
}
else
{
self - > e_ThinkFunc = thinkF_NULL ;
}
self - > activator = activator ;
}
//------------------------------------------
void fx_target_beam_think ( gentity_t * ent )
{
if ( ent - > attackDebounceTime > level . time )
{
ent - > nextthink = level . time + FRAMETIME ;
return ;
}
fx_target_beam_fire_start ( ent ) ;
}
//------------------------------------------
void fx_target_beam_link ( gentity_t * ent )
{
gentity_t * target = NULL ;
vec3_t dir ;
float len ;
target = G_Find ( target , FOFS ( targetname ) , ent - > target ) ;
if ( ! target )
{
Com_Printf ( " bolt_link: unable to find target %s \n " , ent - > target ) ;
G_FreeEntity ( ent ) ;
return ;
}
ent - > attackDebounceTime = level . time ;
if ( ! target - > classname | | Q_stricmp ( " info_null " , target - > classname ) )
{ //don't want to set enemy to something that's going to free itself... actually, this could be bad in other ways, too... ent pointer could be freed up and re-used by the time we check it next
G_SetEnemy ( ent , target ) ;
}
VectorSubtract ( target - > s . origin , ent - > s . origin , dir ) ; //er, does it ever use dir?
len = VectorNormalize ( dir ) ; //er, does it use len or dir?
vectoangles ( dir , ent - > s . angles ) ; //er, does it use s.angles?
VectorCopy ( target - > s . origin , ent - > s . origin2 ) ;
if ( ent - > spawnflags & 1 )
{
// Do nothing
ent - > e_ThinkFunc = thinkF_NULL ;
}
else
{
if ( ! ( ent - > spawnflags & 8 ) ) // one_shot, only calls when used
{
// switch think functions to avoid doing the bolt_link every time
ent - > e_ThinkFunc = thinkF_fx_target_beam_think ;
ent - > nextthink = level . time + FRAMETIME ;
}
}
ent - > e_UseFunc = useF_fx_target_beam_use ;
gi . linkentity ( ent ) ;
}
/*QUAKED fx_target_beam (1 0.5 0.5) (-8 -8 -8) (8 8 8) STARTOFF OPEN NO_KNOCKBACK ONE_SHOT NO_IMPACT
Emits specified effect file , doing damage if required
STARTOFF - must be used before it ' s on
OPEN - will draw all the way to the target , regardless of where the trace hits
NO_KNOCKBACK - beam damage does no knockback
" fxFile " - Effect used to draw the beam , ( default " env/targ_beam " )
" fxFile2 " - Effect used for the beam impact effect , ( default " env/targ_beam_impact " )
" targetname " - Fires only when used
" duration " - How many seconds each burst lasts , - 1 will make it stay on forever
" wait " - If always on , how long to wait between blasts , in MILLISECONDS - default / min is 100 ( 1 frame at 10 fps ) , - 1 means it will never fire again
" random " - random amount of seconds added to / subtracted from " wait " each firing
" damage " - How much damage to inflict PER FRAME ( so probably want it kind of low ) , default is none
" target " - ent to point at - you MUST have this . This can be anything you want , including a moving ent - for static beams , just use info_null
*/
//------------------------------------------
void SP_fx_target_beam ( gentity_t * ent )
{
G_SetOrigin ( ent , ent - > s . origin ) ;
ent - > speed * = 1000 ;
ent - > wait * = 1000 ;
ent - > random * = 1000 ;
if ( ent - > speed < FRAMETIME )
{
ent - > speed = FRAMETIME ;
}
G_SpawnInt ( " damage " , " 0 " , & ent - > damage ) ;
G_SpawnString ( " fxFile " , " env/targ_beam " , & ent - > fxFile ) ;
if ( ent - > spawnflags & 16 ) // NO_IMPACT FX
{
ent - > delay = 0 ;
}
else
{
G_SpawnString ( " fxFile2 " , " env/targ_beam_impact " , & ent - > cameraGroup ) ;
ent - > delay = G_EffectIndex ( ent - > cameraGroup ) ;
}
ent - > fxID = G_EffectIndex ( ent - > fxFile ) ;
ent - > activator = ent ;
ent - > owner = NULL ;
ent - > e_ThinkFunc = thinkF_fx_target_beam_link ;
ent - > nextthink = level . time + START_TIME_LINK_ENTS ;
VectorSet ( ent - > maxs , FX_ENT_RADIUS , FX_ENT_RADIUS , FX_ENT_RADIUS ) ;
VectorScale ( ent - > maxs , - 1 , ent - > mins ) ;
gi . linkentity ( ent ) ;
}
/*QUAKED fx_cloudlayer (1 0.3 0.5) (-8 -8 -8) (8 8 8) TUBE ALT
Creates a scalable scrolling cloud layer , mostly for bespin undercity but could be used other places
TUBE - creates cloud layer with tube opening in the middle , must an INNER radius also
ALT - uses slightly different shader , good if using two layers sort of close together
" radius " - outer radius of cloud layer , ( default 2048 )
" random " - inner radius of cloud layer , ( default 128 ) only works for TUBE type
" wait " - adds curvature as it moves out to the edge of the layer . ( default 0 ) , 1 = small up , 3 = up more , - 1 = small down , - 3 = down more , etc .
*/
void SP_fx_cloudlayer ( gentity_t * ent )
{
// HACK: this effect is never played, rather it just caches the shaders I need cgame side
G_EffectIndex ( " world/haze_cache " ) ;
G_SpawnFloat ( " radius " , " 2048 " , & ent - > radius ) ;
G_SpawnFloat ( " random " , " 128 " , & ent - > random ) ;
G_SpawnFloat ( " wait " , " 0 " , & ent - > wait ) ;
ent - > s . eType = ET_CLOUD ; // dumb
G_SetOrigin ( ent , ent - > s . origin ) ;
ent - > contents = 0 ;
VectorSet ( ent - > maxs , 200 , 200 , 200 ) ;
VectorScale ( ent - > maxs , - 1 , ent - > mins ) ;
gi . linkentity ( ent ) ;
2013-04-23 09:45:35 +00:00
}