This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/server/ents/basefx.cpp
2022-06-27 01:14:55 +03:00

2944 lines
83 KiB
C++
Raw Blame History

//=======================================================================
// Copyright (C) XashXT Group 2006
//=======================================================================
#include "extdll.h"
#include "defaults.h"
#include "utils.h"
#include "cbase.h"
#include "basebeams.h"
#include "baseweapon.h"
#include "decals.h"
#include "basebrush.h"
#include "shake.h"
#include "monsters.h"
#include "client.h"
#include "player.h"
#include "soundent.h"
//=======================================================================
// main functions ()
//=======================================================================
class CBaseParticle : public CBaseLogic
{
public:
void Spawn( void );
void Precache( void ){ pev->netname = UTIL_PrecacheAurora( pev->message ); }
void KeyValue( KeyValueData *pkvd );
void PostActivate( void ){ Switch(); }
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void Switch( void );
};
void CBaseParticle :: KeyValue( KeyValueData *pkvd )
{
if ( FStrEq( pkvd->szKeyName, "aurora" ))
{
pev->message = ALLOC_STRING( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else CBaseLogic::KeyValue( pkvd );
}
void CBaseParticle::Switch( void )
{
int renderfx = (m_iState ? kRenderFxAurora : kRenderFxNone );
if( pev->target )
{
CBaseEntity *pTarget = UTIL_FindEntityByTargetname( NULL, STRING( pev->target ), m_hActivator );
while ( pTarget )
{
UTIL_SetAurora( pTarget, pev->netname );
pTarget->pev->renderfx = renderfx;
pTarget = UTIL_FindEntityByTargetname( pTarget, STRING( pev->target ), m_hActivator );
}
}
else
{
UTIL_SetAurora( this, pev->netname );
pev->renderfx = renderfx;
}
}
void CBaseParticle::Spawn( void )
{
Precache();
UTIL_SetModel( edict(), "sprites/null.spr" );
UTIL_SetOrigin( this, pev->origin );
pev->solid = SOLID_NOT;
if( pev->spawnflags & SF_START_ON || FStringNull( pev->targetname ))
m_iState = STATE_ON;
else m_iState = STATE_OFF;
}
void CBaseParticle::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
m_hActivator = pActivator;
if ( useType == USE_TOGGLE )
{
if( m_iState == STATE_ON )
useType = USE_OFF;
else useType = USE_ON;
}
if ( useType == USE_ON )
{
m_iState = STATE_ON;
Switch();
}
else if ( useType == USE_OFF )
{
m_iState = STATE_OFF;
Switch();
}
else if ( useType == USE_SHOWINFO )
{
DEBUGHEAD;
Msg( "State: %s, ParticleName: %s\n", GetStringForState( GetState()), STRING( pev->netname ));
if ( pev->target ) Msg( "Attach to: %s\n", STRING( pev->target ));
else Msg( "\n" );
}
}
LINK_ENTITY_TO_CLASS( env_particle, CBaseParticle );
//=========================================================
// env_sky, an unreal tournament - style sky effect
//=========================================================
class CEnvSky : public CBaseLogic
{
public:
void StartMessage( CBasePlayer *pPlayer );
void PostSpawn( void );
};
LINK_ENTITY_TO_CLASS( env_sky, CEnvSky );
LINK_ENTITY_TO_CLASS( props_skyportal, CEnvSky );
void CEnvSky :: PostSpawn( void )
{
SetObjectClass( ED_SKYPORTAL );
}
void CEnvSky :: StartMessage( CBasePlayer *pPlayer )
{
#if 0
MESSAGE_BEGIN( MSG_ONE, gmsg.SetSky, NULL, pPlayer->pev );
WRITE_BYTE( 1 ); // mode
WRITE_COORD( pev->origin.x ); // view position
WRITE_COORD( pev->origin.y );
WRITE_COORD( pev->origin.z );
MESSAGE_END();
#endif
}
//=======================================================================
// env_global
//=======================================================================
#define SF_GLOBAL_SET 1 //Set global state to initial state on spawn
class CEnvGlobal : public CBaseLogic
{
public:
void Spawn( void );
void KeyValue( KeyValueData *pkvd );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
};
LINK_ENTITY_TO_CLASS( env_global, CEnvGlobal );
void CEnvGlobal::KeyValue( KeyValueData *pkvd )
{
if(FStrEq(pkvd->szKeyName, "triggermode"))
{
pev->impulse = atoi( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if(FStrEq(pkvd->szKeyName, "initialstate"))
{
pev->button = atoi( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else CBaseLogic::KeyValue( pkvd );
}
void CEnvGlobal::Spawn( void )
{
if ( !m_globalstate ) UTIL_Remove( this );
else if( FBitSet( pev->spawnflags, SF_GLOBAL_SET ) )
{
if ( !gGlobalState.EntityInTable( m_globalstate ) )
gGlobalState.EntityAdd( m_globalstate, gpGlobals->mapname, (GLOBALESTATE)pev->button );
}
}
void CEnvGlobal::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
GLOBALESTATE oldState = gGlobalState.EntityGetState( m_globalstate );
GLOBALESTATE newState;
if (useType == USE_TOGGLE)
{
switch( pev->impulse )
{
case 0:
newState = GLOBAL_OFF;
break;
case 1:
newState = GLOBAL_ON;
break;
case 2:
newState = GLOBAL_DEAD;
break;
case 3:
default:
if ( oldState == GLOBAL_ON ) newState = GLOBAL_OFF;
else if ( oldState == GLOBAL_OFF ) newState = GLOBAL_ON;
else newState = oldState;
}
}
else if(useType == USE_ON ) newState = GLOBAL_ON;
else if(useType == USE_OFF) newState = GLOBAL_OFF;
else if(useType == USE_SET) newState = GLOBAL_DEAD;
if ( gGlobalState.EntityInTable( m_globalstate ))
gGlobalState.EntitySetState( m_globalstate, newState );
else gGlobalState.EntityAdd( m_globalstate, gpGlobals->mapname, newState );
}
//=======================================================================
// env_local
//=======================================================================
class CEnvLocal : public CBaseLogic
{
public:
void Spawn( void );
void Think( void );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
};
LINK_ENTITY_TO_CLASS( env_local, CEnvLocal );
void CEnvLocal::Spawn( void )
{
if ( pev->spawnflags & SF_START_ON )
m_iState = STATE_ON;
else m_iState = STATE_OFF;
}
void CEnvLocal::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
m_hActivator = pActivator; //save activator
pev->scale = value; //save value
if ( IsLockedByMaster( useType ))
return;
if ( useType == USE_TOGGLE )
{
// set use type
if ( m_iState == STATE_TURN_OFF || m_iState == STATE_OFF )
useType = USE_ON;
else if ( m_iState == STATE_TURN_ON || m_iState == STATE_ON )
useType = USE_OFF;
}
if ( useType == USE_ON ) //enable entity
{
if ( m_iState == STATE_TURN_OFF || m_iState == STATE_OFF )
{
//activate turning off entity
if ( m_flDelay ) // we have time to turning on
{
m_iState = STATE_TURN_ON;
SetNextThink( m_flDelay );
}
else // just enable entity
{
m_iState = STATE_ON;
UTIL_FireTargets( pev->target, pActivator, this, USE_ON, pev->scale );
DontThink(); // break thinking
}
}
}
else if ( useType == USE_OFF ) // disable entity
{
if( m_iState == STATE_TURN_ON || m_iState == STATE_ON )
{
// activate turning off entity
if ( m_flWait )
{
// we have time to turning off
m_iState = STATE_TURN_OFF;
SetNextThink( m_flWait );
}
else
{
// just enable entity
m_iState = STATE_OFF;
UTIL_FireTargets( pev->target, pActivator, this, USE_OFF, pev->scale );
DontThink(); // break thinking
}
}
}
else if( useType == USE_SET ) // set explicit mode
{
if( value ) m_iState = STATE_ON;
else m_iState = STATE_OFF;
DontThink(); // break thinking
}
else if( useType == USE_SHOWINFO )
{
DEBUGHEAD;
ALERT( at_console, "time, before enable %g, time, before disable %g\n", m_flDelay, m_flWait );
ALERT( at_console, "current state %s\n", GetStringForState( GetState()) );
}
}
void CEnvLocal::Think( void )
{
if ( m_iState == STATE_TURN_ON )
{
m_iState = STATE_ON;
UTIL_FireTargets( pev->target, m_hActivator, this, USE_ON, pev->scale );
}
else if ( m_iState == STATE_TURN_OFF )
{
m_iState = STATE_OFF;
UTIL_FireTargets( pev->target, m_hActivator, this, USE_OFF, pev->scale );
}
DontThink(); // break thinking
}
//=========================================================
// UTIL_ScreenFade (fade screen)
//=========================================================
#define SF_FADE_IN 0x0001 // Fade in, not out
#define SF_FADE_MODULATE 0x0002 // Modulate, don't blend
#define SF_FADE_ALL 0x0004 // fade all clients
#define SF_FADE_CAMERA 0x0008 // fading only for camera
class CFade : public CBaseLogic
{
public:
void Spawn( void ) { m_iState = STATE_OFF; }
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void KeyValue( KeyValueData *pkvd );
};
LINK_ENTITY_TO_CLASS( env_fade, CFade );
void CFade::KeyValue( KeyValueData *pkvd )
{
if (FStrEq( pkvd->szKeyName, "duration" ))
{
pev->dmg_take = atof( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if (FStrEq( pkvd->szKeyName, "holdtime" ))
{
pev->dmg_save = atof( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else CBaseEntity::KeyValue( pkvd );
}
void CFade::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if ( useType == USE_SHOWINFO )
{
DEBUGHEAD;
Msg( "Fadecolor: %g %g %g, Fadealpha: %g, Fadetime: %g\n", pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, pev->renderamt, pev->dmg_take );
Msg( "HoldTime %g, Mode: %s, Modulate: %s\n", pev->dmg_save, pev->spawnflags & SF_FADE_IN ? "FADE IN" : "FADE OUT", pev->spawnflags & SF_FADE_MODULATE ? "YES" : "NO" );
}
else
{
// setup fade flags
int fadeFlags = 0;
if ( pev->spawnflags & SF_FADE_IN )
fadeFlags |= FFADE_IN;
else fadeFlags |= FFADE_OUT;
if ( pev->spawnflags & SF_FADE_MODULATE ) fadeFlags |= FFADE_MODULATE;
if ( pev->spawnflags & SF_FADE_CAMERA ) fadeFlags |= FFADE_CUSTOMVIEW;
// apply fade
if ( pev->spawnflags & SF_FADE_ALL ) UTIL_ScreenFadeAll( pev->rendercolor, pev->dmg_take, pev->dmg_save, pev->renderamt, fadeFlags );
else UTIL_ScreenFade( pev->rendercolor, pev->dmg_take, pev->dmg_save, pev->renderamt, fadeFlags );
}
}
//=======================================================================
// env_zoom - change fov for player
//=======================================================================
class CEnvZoom : public CBaseLogic
{
void Spawn (void ){ if( !pev->frags ) pev->frags = 90.0f; }
void EXPORT Think( void );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void KeyValue( KeyValueData* pkvd );
void SetFadeTime( void );
};
LINK_ENTITY_TO_CLASS( env_zoom, CEnvZoom );
void CEnvZoom::KeyValue( KeyValueData* pkvd )
{
if( FStrEq( pkvd->szKeyName, "duration" ))
{
pev->takedamage = atof( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if ( FStrEq( pkvd->szKeyName, "fov" ))
{
pev->frags = atof( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else CBaseEntity::KeyValue( pkvd );
}
void CEnvZoom::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if( !pActivator || !pActivator->IsPlayer())
pActivator = UTIL_PlayerByIndex( 1 );
m_hActivator = pActivator; // save activator
if( m_iState == STATE_ON ) return;
if( useType == USE_TOGGLE || useType == USE_ON ) SetFadeTime();
else if( useType == USE_OFF )
((CBasePlayer *)pActivator)->pev->fov = 90.0f;
else if( useType == USE_SHOWINFO )
{
DEBUGHEAD;
ALERT( at_console, "State: %s, Fade time %.00f\n", GetStringForState( GetState()), pev->takedamage );
ALERT( at_console, "Current FOV: %g, Final FOV: %g\n", ((CBasePlayer *)pActivator)->pev->fov, pev->frags );
}
}
void CEnvZoom::SetFadeTime( void )
{
float CurFOV;
float Length;
if( pev->takedamage == 0 ) // instant apply fov
{
((CBasePlayer *)(CBaseEntity *)m_hActivator)->pev->fov = pev->frags;
return;
}
else
{
CurFOV = ((CBasePlayer *)(CBaseEntity *)m_hActivator)->pev->fov;
if( CurFOV == 0.0f )
CurFOV = ((CBasePlayer *)(CBaseEntity *)m_hActivator)->pev->fov = 90.0f;
if( CurFOV > pev->frags ) Length = CurFOV - pev->frags;
else if( CurFOV < pev->frags )
{
Length = pev->frags - CurFOV;
pev->body = 1; // increment fov
}
else return; // no change
pev->health = pev->takedamage / Length;
SetNextThink ( pev->health );
}
}
void CEnvZoom::Think( void )
{
if( Q_rint(((CBasePlayer *)(CBaseEntity *)m_hActivator)->pev->fov ) == Q_rint( pev->frags ))
{
// time is expired
SetThink( NULL );
DontThink();
m_iState = STATE_OFF;
// fire target after finished // transmit final fov
UTIL_FireTargets( pev->target, m_hActivator, this, USE_TOGGLE, pev->frags );
return;
}
else
{
if( pev->body ) ((CBasePlayer *)(CBaseEntity *)m_hActivator)->pev->fov += 0.5f * gpGlobals->frametime;
else ((CBasePlayer *)(CBaseEntity *)m_hActivator)->pev->fov -= 0.5f * gpGlobals->frametime;
}
m_iState = STATE_ON;
SetNextThink ( pev->health );
}
//=========================================================
// env_sound HL1:Legacy
//=========================================================
class CEnvSound : public CPointEntity
{
public:
void KeyValue( KeyValueData* pkvd);
void Spawn( void ){ SetNextThink(0.5); }
void Think( void );
};
LINK_ENTITY_TO_CLASS( env_sound, CEnvSound );
void CEnvSound :: KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "radius"))
{
pev->frags = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "roomtype"))
{
pev->button = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
}
void CEnvSound :: Think( void )
{
CBasePlayer *pPlayer = UTIL_FindPlayerInPVS(edict());
if (pPlayer && pPlayer->m_iSndRoomtype != pev->button)
{
if(UTIL_FindPlayerInSphere( pev->origin, pev->frags ))
{
if(!pev->impulse)
{
pev->impulse = 1;
pPlayer->m_iSndRoomtype = pev->button; //set new dsp
pPlayer->hearNeedsUpdate = 1;
}
}
else pev->impulse = 0;
SetNextThink( 0.25 );
}
else SetNextThink( 0.75 );
}
//=========================================================
// display message
//=========================================================
class CMessage : public CPointEntity
{
public:
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
CBaseEntity *pPlayer = NULL;
if ( IsMultiplayer() ) UTIL_ShowMessageAll( STRING(pev->message) );
else
{
if ( pActivator && pActivator->IsPlayer() ) pPlayer = pActivator;
else pPlayer = UTIL_PlayerByIndex( 1 );
}
if ( pPlayer ) UTIL_ShowMessage( STRING(pev->message), pPlayer );
if ( pev->spawnflags & 1 ) UTIL_Remove( this );
}
};
LINK_ENTITY_TO_CLASS( env_message, CMessage );
//=========================================================
// env_rain, custom client weather effects
//=========================================================
class CEnvRain : public CPointEntity
{
public:
void KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "radius"))
{
pev->armorvalue = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "mode"))
{
pev->button = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
}
};
LINK_ENTITY_TO_CLASS( env_rain, CEnvRain );
//=========================================================
// env_beverage - Beverage Dispenser
//=========================================================
class CEnvBeverage : public CBaseLogic
{
public:
void Spawn( void );
void Precache( void ){ UTIL_PrecacheEntity( "item_sodacan" ); }
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
};
LINK_ENTITY_TO_CLASS( env_beverage, CEnvBeverage );
void CEnvBeverage::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if ( pev->impulse != 0 || pev->health <= 0 )
{
// no more cans while one is waiting in the dispenser, or if I'm out of cans.
return;
}
CBaseEntity *pCan = CBaseEntity::Create( "item_sodacan", pev->origin, pev->angles, edict() );
if ( pev->skin == 6 )
{
// random
pCan->pev->skin = RANDOM_LONG( 0, 5 );
}
else
{
pCan->pev->skin = pev->skin;
}
pev->impulse = 1;
pev->health--;
//SetThink (SUB_Remove);
//pev->nextthink = gpGlobals->time;
}
void CEnvBeverage::Spawn( void )
{
Precache();
pev->solid = SOLID_NOT;
pev->effects = EF_NODRAW;
pev->frags = 0;
if ( pev->health == 0 )
{
pev->health = 10;
}
}
//=======================================================================
// env_sprite - classic HALF-LIFE sprites
//=======================================================================
void CSprite::Spawn( void )
{
Precache();
UTIL_SetModel( ENT( pev ), pev->model );
if( FClassnameIs( pev, "env_monster" ))
{
// test monster from doom1
pev->framerate = 10;
pev->rendermode = kRenderTransAlpha;
pev->solid = SOLID_BBOX;
pev->movetype = MOVETYPE_NONE;
UTIL_SetSize( pev, pev->mins, pev->maxs );
}
else
{
// Smart Field System <20>
if( !pev->renderamt ) pev->renderamt = 200; // light transparency
if( !pev->framerate ) pev->framerate = Frames(); // play sequence at one second
if( !pev->rendermode ) pev->rendermode = kRenderTransAdd;
pev->solid = SOLID_NOT;
pev->movetype = MOVETYPE_NOCLIP;
pev->frame = 0;
pev->angles.x = -pev->angles.x;
pev->angles.y = 180 - pev->angles.y;
pev->angles[1] = 0 - pev->angles[1];
}
SetBits( pev->flags, FL_POINTENTITY );
}
void CSprite::PostSpawn( void )
{
m_pGoalEnt = UTIL_FindEntityByTargetname( NULL, STRING( pev->target ));
if( m_pGoalEnt ) UTIL_SetOrigin( this, m_pGoalEnt->pev->origin );
}
void CSprite::Think( void )
{
SetNextThink( 0 );
if( pev->spawnflags & SF_TEMPSPRITE && gpGlobals->time > pev->dmg_take ) UTIL_Remove(this);
else if( pev->framerate ) Animate( pev->framerate * (gpGlobals->time - pev->dmgtime) );
Move();
pev->dmgtime = gpGlobals->time;
}
void CSprite::Move( void )
{
// Not moving on a path, return
if( !m_pGoalEnt ) return;
// Subtract movement from the previous frame
pev->frags -= pev->speed * gpGlobals->frametime;
// Have we moved enough to reach the target?
if ( pev->frags <= 0 )
{
// Fire the passtarget if there is one
UTIL_FireTargets(m_pGoalEnt->pev->message, this, this, USE_TOGGLE );
if ( FBitSet( m_pGoalEnt->pev->spawnflags, SF_CORNER_FIREONCE ) ) m_pGoalEnt->pev->message = iStringNull;
if ( FBitSet( m_pGoalEnt->pev->spawnflags, SF_CORNER_TELEPORT ) )
{
m_pGoalEnt = m_pGoalEnt->GetNext();
if ( m_pGoalEnt ) UTIL_AssignOrigin( this, m_pGoalEnt->pev->origin);
}
if ( FBitSet( m_pGoalEnt->pev->spawnflags, SF_CORNER_WAITTRIG ) )
{
TurnOff(); //wait for retrigger
return;
}
// Time to go to the next target
m_pGoalEnt = m_pGoalEnt->GetNext();
// Set up next corner
if ( !m_pGoalEnt ) UTIL_SetVelocity( this, g_vecZero );
else
{
pev->target = m_pGoalEnt->pev->targetname; //save last corner
((CPathCorner *)m_pGoalEnt)->GetSpeed( &pev->armorvalue );
Vector delta = m_pGoalEnt->pev->origin - pev->origin;
pev->frags = delta.Length();
pev->movedir = delta.Normalize();
m_flDelay = gpGlobals->time + ((CPathCorner *)m_pGoalEnt)->GetDelay();
}
}
if ( m_flDelay > gpGlobals->time )
pev->speed = UTIL_Approach( 0, pev->speed, 5 * gpGlobals->frametime );
else pev->speed = UTIL_Approach( pev->armorvalue, pev->speed, 5 * gpGlobals->frametime );
float fraction = 2 * gpGlobals->frametime;
UTIL_SetVelocity( this, ((pev->movedir * pev->speed) * fraction) + (pev->velocity * (1-fraction)));
}
void CSprite::TurnOff( void )
{
SetBits( pev->effects, EF_NODRAW );
m_iState = STATE_OFF;
if( m_pGoalEnt ) m_pGoalEnt = m_pGoalEnt->GetPrev();
UTIL_SetVelocity( this, g_vecZero );
DontThink();
}
void CSprite::TurnOn( void )
{
pev->dmgtime = gpGlobals->time;
ClearBits( pev->effects, EF_NODRAW );
pev->frame = 0;
m_iState = STATE_ON;
pev->armorvalue = pev->speed;
m_flDelay = gpGlobals->time;
pev->frags = 0;
Move();
SetNextThink( 0 );
}
void CSprite::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
pActivator = m_hActivator;
if (useType == USE_TOGGLE)
{
if(m_iState == STATE_ON) useType = USE_OFF;
else useType = USE_ON;
}
if (useType == USE_ON) TurnOn();
else if ( useType == USE_OFF ) TurnOff();
else if( useType == USE_SHOWINFO )
{
DEBUGHEAD;
Msg( "State: %s, speed %g\n", GetStringForState( GetState()), pev->speed );
Msg( "NextPath: %s, framerate %g\n", m_pGoalEnt ? STRING(m_pGoalEnt->pev->targetname) : "no path", pev->framerate );
}
}
LINK_ENTITY_TO_CLASS( env_monster, CSprite );
LINK_ENTITY_TO_CLASS( env_sprite, CSprite );
LINK_ENTITY_TO_CLASS( env_glow, CSprite );
//=================================================================
// env_model: like env_sprite, except you can specify a sequence.
//=================================================================
#define SF_DROPTOFLOOR 4
class CEnvModel : public CBaseAnimating
{
void Spawn( void );
void Precache( void ){ UTIL_PrecacheModel( pev->model ); }
void EXPORT Animate( void );
void KeyValue( KeyValueData *pkvd );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
void SetAnim( void );
};
LINK_ENTITY_TO_CLASS( env_model, CEnvModel );
void CEnvModel::KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "mode"))
{
pev->button = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "m_iszSequence"))
{
pev->netname = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else CBaseAnimating::KeyValue( pkvd );
}
void CEnvModel :: Spawn( void )
{
Precache();
UTIL_SetModel( ENT(pev), pev->model );
UTIL_SetOrigin(this, pev->origin);
pev->takedamage = DAMAGE_NO;
if (!(pev->spawnflags & SF_NOTSOLID))
{
pev->solid = SOLID_SLIDEBOX;
UTIL_AutoSetSize();
}
if (pev->spawnflags & SF_DROPTOFLOOR)
{
pev->origin.z += 1;
DROP_TO_FLOOR ( ENT(pev) );
}
InitBoneControllers();
ResetSequenceInfo( );
m_iState = STATE_OFF;
if(pev->spawnflags & SF_START_ON) Use( this, this, USE_ON, 0 );
}
void CEnvModel::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if ( useType == USE_TOGGLE )
{
if( m_iState == STATE_ON )
useType = USE_OFF;
else useType = USE_ON;
}
if ( useType == USE_ON )
{
SetAnim();
SetThink( Animate );
SetNextThink( 0.1 );
m_iState = STATE_ON;
}
else if ( useType == USE_OFF )
{
m_iState = STATE_OFF;
DontThink();
}
else if ( useType == USE_SHOWINFO )
{
DEBUGHEAD;
}
}
void CEnvModel::SetAnim( void )
{
pev->sequence = LookupSequence( STRING( pev->netname ));
if (pev->sequence == -1)pev->sequence = 0;
pev->frame = 0;
ResetSequenceInfo();
}
void CEnvModel::Animate( void )
{
SetNextThink( 0.1 );
StudioFrameAdvance();
if (m_fSequenceFinished )
{
if(pev->button)
{
//pev->frame = 0;
m_iState = STATE_OFF;
DontThink();
}
else SetAnim();
}
}
//=======================================================================
// env_counter - digital 7 segment indicator as default
//=======================================================================
class CDecLED : public CBaseLogic
{
public:
void Spawn( void );
void CheckState( void );
void Precache( void ){ UTIL_PrecacheModel( pev->model, "sprites/decimal.spr" ); }
void KeyValue( KeyValueData *pkvd );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
float Frames( void ) { return MODEL_FRAMES( pev->modelindex ) - 1; }
float flashtime;
float curframe( void )
{
if (pev->frame - floor(pev->frame) > 0.5) return ceil(pev->frame);
else return floor(pev->frame);
}
};
LINK_ENTITY_TO_CLASS( env_counter, CDecLED );
void CDecLED :: Spawn( void )
{
Precache( );
UTIL_SetModel( ENT(pev), pev->model, "sprites/decimal.spr" );
//Smart Field System <20>
if(!pev->renderamt) pev->renderamt = 200; //light transparency
if(!pev->rendermode) pev->rendermode = kRenderTransAdd;
if(!pev->frags) pev->frags = Frames();
if(!pev->impulse) pev->impulse = -1;
CheckState();
pev->solid = SOLID_NOT;
pev->effects = EF_NOINTERP;
pev->movetype = MOVETYPE_NONE;
pev->angles.x = -pev->angles.x;
pev->angles.y = 180 - pev->angles.y;
pev->angles[1] = 0 - pev->angles[1];
pev->button = TRUE;
}
void CDecLED :: CheckState( void )
{
switch( (int)pev->dmg )
{
case 1:
if( pev->impulse >= curframe() ) m_iState = STATE_ON;
else m_iState = STATE_OFF;
break;
case 2:
if( pev->impulse <= curframe() ) m_iState = STATE_ON;
else m_iState = STATE_OFF;
break;
default:
if( pev->impulse == curframe() ) m_iState = STATE_ON;
else m_iState = STATE_OFF;
break;
}
}
void CDecLED :: KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "maxframe"))
{
pev->frags = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "keyframe"))
{
pev->impulse = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "type"))
{
pev->dmg = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else CBaseLogic::KeyValue( pkvd );
}
void CDecLED :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if (useType == USE_ON || useType == USE_TOGGLE)
{
if (pev->frame == pev->frags)
{
UTIL_FireTargets( pev->target, pActivator, this, useType, value );
pev->frame = 0;
}
else pev->frame++;
pev->button = TRUE;
pev->effects &= ~EF_NODRAW;
flashtime = gpGlobals->time + 0.5;
}
else if (useType == USE_OFF )
{
if (pev->frame == 0)
{
UTIL_FireTargets( pev->target, pActivator, this, useType, value );
pev->frame = pev->frags;
}
else pev->frame--;
pev->button = FALSE;
pev->effects &= ~EF_NODRAW;
flashtime = gpGlobals->time + 0.5;
}
else if (useType == USE_SET) //set custom frame
{
if(value != 0)
{
if(value == -1) value = 0; //reset frame
pev->frame = fmod( value, pev->frags + 1);
float next = value / (pev->frags + 1);
if(next) UTIL_FireTargets( pev->target, pActivator, this, useType, next );
pev->button = TRUE;
pev->effects &= ~EF_NODRAW;
flashtime = gpGlobals->time + 0.5;
}
else if(gpGlobals->time > flashtime)
{
if( pev->button)
{
pev->button = FALSE;
pev->effects |= EF_NODRAW;
}
else
{
pev->button = TRUE;
pev->effects &= ~EF_NODRAW;
}
}
}
else if (useType == USE_SHOWINFO)
{
DEBUGHEAD;
Msg( "Current frame: %.0f, Keyframe %d\n", pev->frame, pev->impulse );
Msg( "State: %s, Maxframe %g\n", GetStringForState( GetState()), pev->frags);
}
CheckState();
}
//=======================================================================
// env_shake - earthquake (screen shake)
//=======================================================================
class CShake : public CBaseLogic
{
public:
void Spawn( void ){ m_iState = STATE_OFF; }
void Think( void ) { m_iState = STATE_OFF; };
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if(useType == USE_SHOWINFO)
{
DEBUGHEAD;
Msg( "State: %s, Amplitude: %g, Frequency: %g\n", GetStringForState( GetState()), pev->scale, pev->dmg_save);
Msg( "Radius: %g, Duration: %d, Smoke max scale: %d\n", pev->dmg, pev->dmg_take);
}
else
{
UTIL_ScreenShake( pev->origin, Amplitude(), Frequency(), Duration(), Radius() );
m_iState = STATE_ON;
SetNextThink( Duration() );
}
}
void KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "amplitude"))
{
SetAmplitude( atof(pkvd->szValue) );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "frequency"))
{
SetFrequency( atof(pkvd->szValue) );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "duration"))
{
SetDuration( atof(pkvd->szValue) );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "radius"))
{
SetRadius( atof(pkvd->szValue) );
pkvd->fHandled = TRUE;
}
else CBaseEntity::KeyValue( pkvd );
}
inline float Amplitude( void ) { return pev->scale; }
inline float Frequency( void ) { return pev->dmg_save; }
inline float Duration( void ) { return pev->dmg_take; }
inline float Radius( void ) { return pev->dmg; }
inline void SetAmplitude( float amplitude ) { pev->scale = amplitude; }
inline void SetFrequency( float frequency ) { pev->dmg_save = frequency; }
inline void SetDuration( float duration ) { pev->dmg_take = duration; }
inline void SetRadius( float radius ) { pev->dmg = radius; }
};
LINK_ENTITY_TO_CLASS( env_shake, CShake );
//=======================================================================
// env_sparks - classic HALF-LIFE sparks
//=======================================================================
class CEnvSpark : public CBaseLogic
{
public:
void Spawn(void);
void Think(void);
void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
};
LINK_ENTITY_TO_CLASS(env_spark, CEnvSpark);
void CEnvSpark::Spawn(void)
{
if(!m_flDelay)m_flDelay = 1.0;//Smart field system <20>
if(pev->spawnflags & 64) Use( this, this, USE_ON, 0 );
}
void CEnvSpark::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if (useType == USE_TOGGLE)
{
if(m_iState == STATE_ON) useType = USE_OFF;
else useType = USE_ON;
}
if (useType == USE_ON)
{
m_iState = STATE_ON;
SetNextThink( m_flDelay );
}
else if (useType == USE_OFF)
{
m_iState = STATE_OFF;
DontThink();
}
else if (useType == USE_SHOWINFO)
{
DEBUGHEAD;
Msg( "State: %s, MaxDelay %.2f\n\n", GetStringForState( GetState()), m_flDelay );
}
}
void CEnvSpark::Think(void)
{
float flVolume = RANDOM_FLOAT ( 0.25 , 0.75 ) * 0.4;//random volume range
switch ( RANDOM_LONG(0,5))
{
case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "materials/spark1.wav", flVolume, ATTN_NORM); break;
case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "materials/spark2.wav", flVolume, ATTN_NORM); break;
case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "materials/spark3.wav", flVolume, ATTN_NORM); break;
case 3: EMIT_SOUND(ENT(pev), CHAN_VOICE, "materials/spark4.wav", flVolume, ATTN_NORM); break;
case 4: EMIT_SOUND(ENT(pev), CHAN_VOICE, "materials/spark5.wav", flVolume, ATTN_NORM); break;
case 5: EMIT_SOUND(ENT(pev), CHAN_VOICE, "materials/spark6.wav", flVolume, ATTN_NORM); break;
}
UTIL_Sparks( pev->origin + pev->size * 0.5 );
if(m_iState == STATE_ON) SetNextThink( 0.1 + RANDOM_FLOAT (0, m_flDelay) ); //!!!
}
//=========================================================
// env_explosion (classic explode )
//=========================================================
class CEnvExplosion : public CBaseLogic
{
public:
void KeyValue( KeyValueData *pkvd );
void Precache( void ) { if(pev->message) pev->button = UTIL_PrecacheModel( pev->model ); }
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void Explode( void );
};
LINK_ENTITY_TO_CLASS( env_explosion, CEnvExplosion );
void CEnvExplosion::KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "radius") || FStrEq(pkvd->szKeyName, "iMagnitude"))
{
pev->dmg = atoi(pkvd->szValue);
if(pev->dmg < 10) pev->dmg = 10;
pkvd->fHandled = TRUE;
}
else CBaseEntity::KeyValue( pkvd );
}
void CEnvExplosion::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if (useType == USE_SHOWINFO)
{
DEBUGHEAD;
Msg( "Radius %g\n\n", pev->dmg );
}
else Explode();
}
void CEnvExplosion::Explode( void )
{
short m_usExplode;
short m_usWExplode;
TraceResult tr;
Vector vecSpot = pev->origin;// trace starts here!
UTIL_TraceLine ( vecSpot + Vector( 0, 0, 8 ), vecSpot + Vector ( 0, 0, -32 ), ignore_monsters, ENT(pev), &tr);
if( !FBitSet( pev->spawnflags, 4 ))
{
if( pev->button )//custom sprite
{
m_usExplode = pev->button;
m_usWExplode = pev->button;
}
else
{
m_usExplode = g_sModelIndexFireball;
m_usWExplode = g_sModelIndexWExplosion;
}
}
else
{
m_usExplode = g_sModelIndexNullSprite;
m_usWExplode = g_sModelIndexNullSprite;
}
// Pull out of the wall a bit
if ( tr.flFraction != 1.0 && tr.vecPlaneNormal[2] < 0.7f )
pev->origin = tr.vecEndPos + (tr.vecPlaneNormal * (pev->dmg - 24) * 0.6);
int iContents = UTIL_PointContents ( pev->origin );
entvars_t *pevOwner;
if ( pev->owner ) pevOwner = VARS( pev->owner );
else pevOwner = NULL;
pev->owner = NULL; // can't traceline attack owner if this is set
if ( pev->dmg <= 0 )
pev->dmg = 100; //Smart field system <20>
if( iContents == CONTENTS_WATER )
{
SFX_Explode( m_usWExplode, pev->origin, pev->dmg, TE_EXPLFLAG_NONE );
if(!FBitSet( pev->spawnflags, 1 ))
RadiusDamage ( pev->origin, pev, pevOwner, pev->dmg / 2, pev->dmg * 2.5, CLASS_NONE, DMG_BLAST );
}
else
{
CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, pev->dmg * 5, 3.0 );
SFX_Explode( m_usExplode, pev->origin, pev->dmg, TE_EXPLFLAG_NONE );
if(!FBitSet( pev->spawnflags, 1 ))
RadiusDamage ( pev->origin, pev, pevOwner, pev->dmg, pev->dmg * 2.5, CLASS_NONE, DMG_BLAST );
if(!FBitSet( pev->spawnflags, 8 ))
{
CBaseEntity *pWreckage = Create( "smokeent", pev->origin, pev->angles );
pWreckage->SetNextThink( 0.2 );
pWreckage->pev->impulse = ( pev->dmg - 50 ) * 0.6;
pWreckage->pev->dmgtime = gpGlobals->time + 1.5;
}
if(!FBitSet( pev->spawnflags, 32 ))
{
int sparkCount = RANDOM_LONG(0,3); //make sparks
for ( int i = 0; i < sparkCount; i++ )
Create( "sparkleent", pev->origin, tr.vecPlaneNormal, NULL );
}
if(!FBitSet( pev->spawnflags, 16 ))
{
if ( RANDOM_FLOAT( 0 , 1 ) < 0.5 ) UTIL_DecalTrace( &tr, DECAL_SCORCH1 );
else UTIL_DecalTrace( &tr, DECAL_SCORCH2 );
}
}
if(!FBitSet( pev->spawnflags, 2 )) UTIL_Remove( this );
}
//=========================================================
// gibs (sprite or models gib)
//=========================================================
void CGib :: Spawn( const char *szGibModel )
{
pev->movetype = MOVETYPE_BOUNCE;
pev->friction = 0.55; // deading the bounce a bit
pev->renderamt = 255;
pev->rendermode = kRenderNormal;
pev->renderfx = kRenderFxNone;
pev->solid = SOLID_TRIGGER;
pev->classname = MAKE_STRING( "gib" );
SetObjectClass( ED_NORMAL );
UTIL_SetModel( ENT( pev ), szGibModel );
UTIL_SetSize( pev, g_vecZero, g_vecZero );
m_lifeTime = MAX_GIB_LIFETIME;
m_material = None;
m_cBloodDecals = 5;// how many blood decals this gib can place (1 per bounce until none remain).
}
void CGib :: WaitTillLand ( void )
{
if (!IsInWorld())
{
UTIL_Remove( this );
return;
}
if ( pev->velocity == g_vecZero )
{
if(m_lifeTime == -1) //waiting for pvs
{
SetThink( PVSRemove );
SetNextThink( MAX_GIB_LIFETIME );
}
else
{
SetThink( Fadeout );
SetNextThink( m_lifeTime );
}
if(m_bloodColor != DONT_BLEED)
{
CSoundEnt::InsertSound ( bits_SOUND_MEAT, pev->origin, 384, 25 );
}
}
else SetNextThink( 0.5 );
}
void CGib :: BounceGibTouch ( CBaseEntity *pOther )
{
Vector vecSpot;
TraceResult tr;
if ( pOther != g_pWorld) UTIL_FireTargets( pev->target, pOther, this, USE_ON );
else UTIL_FireTargets( pev->target, pOther, this, USE_SET ); //world touch
if( pev->flags & FL_ONGROUND )
{
pev->velocity = pev->velocity * 0.9;
pev->angles.x = 0;
pev->angles.z = 0;
pev->avelocity.x = 0;
pev->avelocity.z = 0;
}
else
{
if (m_cBloodDecals > 0 && m_bloodColor != DONT_BLEED )
{
vecSpot = pev->origin + Vector ( 0 , 0 , 8 ); //move up a bit, and trace down.
UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -24 ), ignore_monsters, ENT(pev), & tr);
UTIL_BloodDecalTrace( &tr, m_bloodColor );
m_cBloodDecals--;
}
if ( m_material != None && RANDOM_LONG(0,2) == 0 )
{
float volume;
float zvel = fabs(pev->velocity.z);
volume = 0.8 * min(1.0, ((float)zvel) / 450.0);
CBaseBrush::PlayRandomSound( edict(), (Materials)m_material, volume );
}
}
}
void CGib :: StickyGibTouch ( CBaseEntity *pOther )
{
Vector vecSpot;
TraceResult tr;
if(m_lifeTime == -1) //waiting for pvs
{
SetThink( PVSRemove );
SetNextThink( MAX_GIB_LIFETIME );
}
else
{
SetThink( Fadeout );
SetNextThink( m_lifeTime );
}
if ( pOther != g_pWorld )
{
UTIL_FireTargets( pev->target, pOther, this, USE_ON );
UTIL_Remove( this );
return;
}
else UTIL_FireTargets( pev->target, pOther, this, USE_SET ); //world touch
UTIL_TraceLine ( pev->origin, pev->origin + pev->velocity * 32, ignore_monsters, ENT(pev), & tr);
UTIL_BloodDecalTrace( &tr, m_bloodColor );
pev->velocity = tr.vecPlaneNormal * -1;
pev->angles = UTIL_VecToAngles ( pev->velocity );
pev->velocity = g_vecZero;
pev->avelocity = g_vecZero;
pev->movetype = MOVETYPE_NONE;
}
CGib *CGib :: CreateGib( CBaseEntity *pVictim, const char *szGibModel, int gibtype )
{
CGib *pGib = GetClassPtr( (CGib *)NULL );
pGib->Spawn( szGibModel );
dstudiohdr_t *pstudiohdr = (dstudiohdr_t *)(GET_MODEL_PTR( ENT(pGib->pev) ));
if (! pstudiohdr) return NULL;
dstudiobodyparts_t *pbodypart = (dstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex);
if ( pVictim ) //spawn at gibbed monster
{
if(gibtype == 1) //skull gib
{
pGib->pev->body = 0; //spawn skull
pGib->pev->origin = pVictim->pev->origin + pVictim->pev->view_ofs;
edict_t *pentPlayer = FIND_CLIENT_IN_PVS( pGib->edict());
if ( RANDOM_LONG ( 0, 100 ) <= 5 && pentPlayer )
{
// 5% chance head will be thrown at player's face.
entvars_t *pevPlayer;
pevPlayer = VARS( pentPlayer );
pGib->pev->velocity = ( ( pevPlayer->origin + pevPlayer->view_ofs ) - pGib->pev->origin ).Normalize() * 300;
pGib->pev->velocity.z += 100;
}
else pGib->pev->velocity = Vector (RANDOM_FLOAT(-100,100), RANDOM_FLOAT(-100,100), RANDOM_FLOAT(200,300));
}
else
{
pGib->pev->body = RANDOM_LONG(1, pbodypart->nummodels - 1); //random gibs
// spawn the gib somewhere in the monster's bounding volume
pGib->pev->origin.x = pVictim->pev->absmin.x + pVictim->pev->size.x * (RANDOM_FLOAT ( 0 , 1 ) );
pGib->pev->origin.y = pVictim->pev->absmin.y + pVictim->pev->size.y * (RANDOM_FLOAT ( 0 , 1 ) );
pGib->pev->origin.z = pVictim->pev->absmin.z + pVictim->pev->size.z * (RANDOM_FLOAT ( 0 , 1 ) ) + 1;
// make the gib fly away from the attack vector
pGib->pev->velocity = g_vecAttackDir * -1;
// mix in some noise
pGib->pev->velocity.x += RANDOM_FLOAT ( -0.25, 0.25 );
pGib->pev->velocity.y += RANDOM_FLOAT ( -0.25, 0.25 );
pGib->pev->velocity.z += RANDOM_FLOAT ( -0.25, 0.25 );
pGib->pev->velocity = pGib->pev->velocity * RANDOM_FLOAT ( 300, 400 );
}
//shared settings
pGib->pev->avelocity.x = RANDOM_FLOAT ( 100, 200 );
pGib->pev->avelocity.y = RANDOM_FLOAT ( 100, 300 );
pGib->m_bloodColor = (CBaseEntity::Instance(pVictim->edict()))->BloodColor();
if ( pVictim->pev->health > -50) pGib->pev->velocity = pGib->pev->velocity * 0.7;
else if ( pVictim->pev->health > -200) pGib->pev->velocity = pGib->pev->velocity * 2;
else pGib->pev->velocity = pGib->pev->velocity * 4;
//LimitVelocity
float length = pGib->pev->velocity.Length();
if ( length > (MAX_VELOCITY / 2))
pGib->pev->velocity = pGib->pev->velocity.Normalize() * MAX_VELOCITY / 2;
}
// global settings
UTIL_SetSize ( pGib->pev, g_vecZero, g_vecZero );
if(gibtype == 0 || gibtype == 1) //normal random gibs
{
pGib->pev->solid = SOLID_BBOX;
pGib->SetTouch( BounceGibTouch );
pGib->SetThink( WaitTillLand );
pGib->SetNextThink( 4 );
}
if(gibtype == 2) //sticky gib
{
pGib->pev->movetype = MOVETYPE_TOSS;
pGib->SetTouch( StickyGibTouch );
}
return pGib;
}
//=========================================================
// env_shooter (sprite or models shooter)
//=========================================================
class CEnvShooter : public CBaseLogic
{
void Precache( void ) { if(ParseGibFile()) Setup(); }
void KeyValue( KeyValueData *pkvd );
void Spawn( void );
int ParseGibFile( void );
void Setup( void );
void Think( void );
CBaseEntity *CreateGib( Vector vecPos, Vector vecVel );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
//this is will be restoring on precache - no need to save
Materials m_Material;
Physics m_Physics;
string_t entity;
RandomRange velocity;
RandomRange variance;
RandomRange lifetime;
};
LINK_ENTITY_TO_CLASS( env_shooter, CEnvShooter );
void CEnvShooter::Spawn( void )
{
Precache();
pev->effects = EF_NODRAW;
if ( m_flDelay == 0 ) m_flDelay = 0.1;
UTIL_LinearVector( this );//movement direction
}
void CEnvShooter :: KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "file"))
{
pev->message = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "gibcount"))
{
pev->impulse = pev->button = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "gibname"))
{
m_sSet = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "gibtarget"))
{
pev->netname = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else CBaseLogic::KeyValue( pkvd );
}
void CEnvShooter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
m_hActivator = pActivator;
SetNextThink( 0 );
}
void CEnvShooter :: Think ( void )
{
TraceResult tr; //don't create stack monsters
UTIL_TraceLine ( pev->origin, pev->origin - Vector ( 0, 0, 2048 ), ignore_monsters, ENT(pev), &tr );
Vector mins = pev->origin - Vector( 34, 34, 0 );
Vector maxs = pev->origin + Vector( 34, 34, 0 );
maxs.z = pev->origin.z;
mins.z = tr.vecEndPos.z;
CBaseEntity *pList[2];
if (UTIL_EntitiesInBox( pList, 2, mins, maxs, FL_CLIENT|FL_MONSTER ))
{
// don't build a stack of monsters!
SetNextThink( m_flDelay );
return;
}
Vector vecShootDir = pev->movedir;
vecShootDir = vecShootDir + gpGlobals->v_up * variance.Random();
vecShootDir = vecShootDir + gpGlobals->v_right * variance.Random();
vecShootDir = vecShootDir + gpGlobals->v_forward * variance.Random();
vecShootDir = vecShootDir.Normalize();
CBaseEntity *pGib = CreateGib(pev->origin, vecShootDir * velocity.Random() );
if ( pGib )UTIL_FireTargets( pev->target, pGib, this, USE_TOGGLE, 0 );
if(pev->button > 0) pev->impulse--;
if ( pev->impulse <= 0 )
{
if ( pev->spawnflags & SF_FIREONCE )
{
UTIL_Remove( this );
return;
}
else
{
pev->impulse = pev->button;
DontThink();
}
}
SetNextThink( m_flDelay );
}
void CEnvShooter :: Setup( void )
{
//Smart field system <20>
if(!FStringNull( m_sMaster )) UTIL_PrecacheModel( m_sMaster );
if(!FStringNull( entity )) UTIL_PrecacheEntity( entity );
if(velocity.m_flMax == 0) velocity.m_flMax = 100;
if(velocity.m_flMax > MAX_VELOCITY) velocity.m_flMax = MAX_VELOCITY;
if(lifetime.Random() == 0)lifetime = RandomRange( -1.0 );
if(pev->scale == 0)pev->scale = 1;
CBaseBrush::MaterialSoundPrecache( m_Material );
//setup physics
pev->solid = SOLID_SLIDEBOX;
switch( m_Physics )
{
case Noclip: pev->team = MOVETYPE_NOCLIP; pev->solid = SOLID_NOT; break;
case Bounce: pev->team = MOVETYPE_BOUNCE; break;
case Sticky: pev->team = MOVETYPE_TOSS; pev->solid = SOLID_BBOX; break;
case Fly: pev->team = MOVETYPE_FLY; break;
case Toss: pev->team = MOVETYPE_TOSS; break;
}
}
int CEnvShooter :: ParseGibFile( void )
{
char *token;
char *afile = (char *)LOAD_FILE( STRING( pev->message ), NULL );
const char *pfile = afile;
if( !pfile )
{
ALERT( at_warning, "Gib script file for %s not found!\n", STRING( pev->targetname ));
return 0;
}
else
{
while( pfile )
{
token = COM_ParseToken( &pfile );
if ( !FStriCmp( token, "model" ))
{
token = COM_ParseToken( &pfile );
m_sMaster = ALLOC_STRING( token );
}
else if ( !FStriCmp( token, "entity" ))
{
token = COM_ParseToken( &pfile );
entity = ALLOC_STRING( token );
}
else if ( !FStriCmp( token, "speed" ))
{
token = COM_ParseToken( &pfile );
velocity = RandomRange((char *)STRING(ALLOC_STRING(token)));
}
else if ( !FStriCmp( token, "variance" ))
{
token = COM_ParseToken( &pfile );
variance = RandomRange((char *)STRING(ALLOC_STRING(token)));
}
else if ( !FStriCmp( token, "livetime" ))
{
token = COM_ParseToken( &pfile );
lifetime = RandomRange((char *)STRING(ALLOC_STRING(token)));
}
else if ( !FStriCmp( token, "friction" ))
{
token = COM_ParseToken( &pfile );
RandomRange((char *)STRING(ALLOC_STRING(token)));
Msg("param %s, min %g max %g\n", token, m_flMin, m_flMax );
pev->friction = RANDOM_FLOAT( m_flMin, m_flMax );
}
else if ( !FStriCmp( token, "scale" ))
{
token = COM_ParseToken( &pfile );
RandomRange((char *)STRING(ALLOC_STRING(token)));
Msg("param %s, min %g max %g\n", token, m_flMin, m_flMax );
pev->scale = RANDOM_FLOAT( m_flMin, m_flMax );
}
else if ( !FStriCmp( token, "body" ))
{
token = COM_ParseToken( &pfile );
RandomRange((char *)STRING(ALLOC_STRING(token)));
Msg("param %s, min %g max %g\n", token, m_flMin, m_flMax );
pev->body = RANDOM_FLOAT( m_flMin, m_flMax - 1 );
}
else if ( !FStriCmp( token, "skin" ))
{
token = COM_ParseToken( &pfile );
RandomRange((char *)STRING(ALLOC_STRING(token)));
Msg("param %s, min %g max %g\n", token, m_flMin, m_flMax );
pev->skin = RANDOM_FLOAT( m_flMin, m_flMax );
}
else if ( !FStriCmp( token, "frame" ))
{
token = COM_ParseToken( &pfile );
RandomRange((char *)STRING(ALLOC_STRING(token)));
Msg("param %s, min %g max %g\n", token, m_flMin, m_flMax );
pev->frame = RANDOM_FLOAT( m_flMin, m_flMax );
}
else if ( !FStriCmp( token, "alpha" ))
{
token = COM_ParseToken( &pfile );
RandomRange((char *)STRING(ALLOC_STRING(token)));
Msg("param %s, min %g max %g\n", token, m_flMin, m_flMax );
pev->renderamt = RANDOM_FLOAT( m_flMin, m_flMax );
}
else if ( !FStriCmp( token, "color" ))
{
token = COM_ParseToken( &pfile );
UTIL_StringToVector((float *)pev->rendercolor, token );
}
else if ( !FStriCmp( token, "rendermode" ))
{
token = COM_ParseToken( &pfile );
if ( !FStriCmp( token, "normal" )) pev->rendermode = kRenderNormal;
else if ( !FStriCmp( token, "color" )) pev->rendermode = kRenderTransColor;
else if ( !FStriCmp( token, "texture" )) pev->rendermode = kRenderTransTexture;
else if ( !FStriCmp( token, "glow" )) pev->rendermode = kRenderGlow;
else if ( !FStriCmp( token, "solid" )) pev->rendermode = kRenderTransAlpha;
else if ( !FStriCmp( token, "additive" )) pev->rendermode = kRenderTransAdd;
}
else if ( !FStriCmp( token, "sfx" ))
{
token = COM_ParseToken( &pfile );
if ( !FStriCmp( token, "hologramm" )) pev->renderfx = kRenderFxHologram;
else if ( !FStriCmp( token, "glowshell" )) pev->renderfx = kRenderFxGlowShell;
}
else if ( !FStriCmp( token, "size" ))
{
UTIL_StringToVector((float*)pev->size, token);
pev->size = pev->size/2;
}
else if ( !FStriCmp( token, "material" ))
{
token = COM_ParseToken( &pfile );
if ( !FStriCmp( token, "none" )) m_Material = None;
else if ( !FStriCmp( token, "bones" )) m_Material = Bones;
else if ( !FStriCmp( token, "flesh" )) m_Material = Flesh;
else if ( !FStriCmp( token, "cinder block" )) m_Material = CinderBlock;
else if ( !FStriCmp( token, "concrete" )) m_Material = Concrete;
else if ( !FStriCmp( token, "rocks" )) m_Material = Rocks;
else if ( !FStriCmp( token, "computer" )) m_Material = Computer;
else if ( !FStriCmp( token, "glass" )) m_Material = Glass;
else if ( !FStriCmp( token, "metalplate" )) m_Material = MetalPlate;
else if ( !FStriCmp( token, "metal" )) m_Material = Metal;
else if ( !FStriCmp( token, "airduct" )) m_Material = AirDuct;
else if ( !FStriCmp( token, "ceiling tile" )) m_Material = CeilingTile;
else if ( !FStriCmp( token, "wood" )) m_Material = Wood;
}
else if ( !FStriCmp( token, "physics" ))
{
token = COM_ParseToken( &pfile );
if ( !FStriCmp( token, "bounce" )) m_Physics = Bounce;
else if ( !FStriCmp( token, "sticky" )) m_Physics = Sticky;
else if ( !FStriCmp( token, "noclip" )) m_Physics = Noclip;
else if ( !FStriCmp( token, "fly" )) m_Physics = Fly;
else if ( !FStriCmp( token, "toss" )) m_Physics = Toss;
}
}
COM_FreeFile( afile );
if( FStringNull( m_sMaster) && FStringNull( entity ))
{
ALERT( at_warning, "model or entity not specified for %s\n", STRING( pev->targetname ));
return 0;
}
return 1;
}
}
CBaseEntity *CEnvShooter :: CreateGib ( Vector vecPos, Vector vecVel )
{
if( !FStringNull( entity ))//custom precached entity
{
CBaseEntity *pEnt = CBaseEntity::CreateGib( (char *)STRING( entity ), (char *)STRING( m_sMaster));
//CBaseEntity *pEnt = CBaseEntity::Create( (char *)STRING( entity ), pev->origin, g_vecZero, edict() );
//if(!pEnt && pEnt->edict()) return NULL;
if(!pEnt) return NULL;
//UTIL_SetOrigin( pEnt, vecPos );
pEnt->pev->origin = vecPos;
pEnt->pev->velocity = vecVel;
pEnt->pev->renderamt = pev->renderamt;
//pEnt->pev->model = m_sMaster;
pEnt->pev->rendermode = pev->rendermode;
pEnt->pev->rendercolor = pev->rendercolor;
pEnt->pev->renderfx = pev->renderfx;
pEnt->pev->target = pev->netname;
pEnt->pev->skin = pev->skin;
pEnt->pev->body = pev->body;
pEnt->pev->scale = pev->scale;
pEnt->pev->frame = pev->frame;
pEnt->pev->friction = pev->friction;
pEnt->pev->movetype = pev->team;
pEnt->pev->solid = pev->solid;
pEnt->pev->targetname = m_sSet;
//UTIL_SetModel(ENT(pEnt->pev), m_sMaster );
return pEnt;
}
else if(m_Physics == Bounce || m_Physics == Sticky) // normal or sticky gib
{
CGib *pGib = CGib::CreateGib( NULL, (char *)STRING( m_sMaster ), m_Physics );
if(!pGib && pGib->edict()) return NULL;
pGib->pev->body = pev->body;
pGib->pev->origin = vecPos;
pGib->pev->velocity = vecVel;
pGib->m_material = m_Material;
pGib->pev->rendermode = pev->rendermode;
pGib->pev->renderamt = pev->renderamt;
pGib->pev->rendercolor = pev->rendercolor;
pGib->pev->renderfx = pev->renderfx;
pGib->pev->target = pev->netname;
pGib->pev->friction = pev->friction;
pGib->pev->scale = pev->scale;
pGib->pev->skin = pev->skin;
pGib->pev->avelocity.x = RANDOM_FLOAT ( 100, 200 );
pGib->pev->avelocity.y = RANDOM_FLOAT ( 100, 300 );
pGib->m_lifeTime = pev->health;
pGib->pev->scale = pev->scale;
pGib->pev->frame = pev->frame;
pGib->pev->targetname = m_sSet;
return pGib;
}
else //not custom entity, other physics type
{
CShot *pShot = CShot::CreateShot ( (char *)STRING( m_sMaster ), pev->size );
if(!pShot && pShot->edict()) return NULL;
pShot->pev->origin = vecPos;
pShot->pev->velocity = vecVel;
pShot->pev->renderamt = pev->renderamt;
pShot->pev->rendermode = pev->rendermode;
pShot->pev->rendercolor = pev->rendercolor;
pShot->pev->renderfx = pev->renderfx;
pShot->pev->target = pev->netname;
pShot->pev->skin = pev->skin;
pShot->pev->body = pev->body;
pShot->pev->scale = pev->scale;
pShot->pev->frame = pev->frame;
pShot->pev->framerate = pev->framerate;
pShot->pev->friction = pev->friction;
pShot->pev->movetype = pev->team;
pShot->pev->targetname = m_sSet;
if (pev->health || pev->health == -1)
{
//animate it
if (pShot->pev->framerate && pShot->Frames() > 1.0)
{
pShot->AnimateAndDie( 10 );
pShot->pev->dmg_take = gpGlobals->time + pev->health;
pShot->SetNextThink( 0 );
pShot->pev->dmgtime = gpGlobals->time;
}
else if( pev->health )
{
pShot->SetThink( Fadeout );
pShot->SetNextThink(pev->health);
}
else
{
pShot->SetThink( PVSRemove );
pShot->SetNextThink( MAX_GIB_LIFETIME );
}
}
return pShot;
}
return NULL;
}
//=========================================================
// LRC - Decal effect
//=========================================================
class CEnvDecal : public CPointEntity
{
public:
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void KeyValue( KeyValueData *pkvd );
};
LINK_ENTITY_TO_CLASS( env_decal, CEnvDecal );
void CEnvDecal :: KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "texture"))
{
pev->message = ALLOC_STRING( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else CBaseEntity::KeyValue( pkvd );
}
void CEnvDecal::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if( useType == USE_SHOWINFO)
{
DEBUGHEAD;
Msg("Decal name %s\n\n", GetStringForDecalName( pev->message ));
}
else
{
int m_decal = UTIL_LoadDecalPreset( pev->message );
switch(m_decal)
{
case 1: pev->skin = gDecals[ DECAL_GUNSHOT1 + RANDOM_LONG(0,4)].index; break;
case 2: pev->skin = gDecals[ DECAL_BLOOD1 + RANDOM_LONG(0,5)].index; break;
case 3: pev->skin = gDecals[ DECAL_YBLOOD1 + RANDOM_LONG(0,5)].index; break;
case 4: pev->skin = gDecals[ DECAL_GLASSBREAK1 + RANDOM_LONG(0,2)].index; break;
case 5: pev->skin = gDecals[ DECAL_BIGSHOT1 + RANDOM_LONG(0,4)].index; break;
case 6: pev->skin = gDecals[ DECAL_SCORCH1 + RANDOM_LONG(0,1)].index; break;
case 7: pev->skin = gDecals[ DECAL_SPIT1 + RANDOM_LONG(0,1)].index; break;
default: pev->skin = DECAL_INDEX(STRING(m_decal)); break;
}
Vector vecPos = pev->origin;
UTIL_MakeVectors(pev->angles);
Vector vecOffs = gpGlobals->v_forward;
vecOffs = vecOffs.Normalize() * MAP_HALFSIZE;
TraceResult trace;
UTIL_TraceLine( vecPos, vecPos+vecOffs, ignore_monsters, NULL, &trace );
if (trace.flFraction == 1.0) return; // didn't hit anything, oh well
int entityIndex = (short)ENTINDEX(trace.pHit);
SFX_Decal( trace.vecEndPos, pev->skin, entityIndex, (int)VARS(trace.pHit)->modelindex );
}
}
//=========================================================
// env_warpball
//=========================================================
#define SF_REMOVE_ON_FIRE 0x0001
#define SF_KILL_CENTER 0x0002
class CEnvWarpBall : public CBaseLogic
{
public:
void Precache( void );
void Spawn( void ) { Precache(); }
void KeyValue( KeyValueData *pkvd );
void Think( void );
void Affect( void );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
Vector vecOrigin;
};
LINK_ENTITY_TO_CLASS( env_warpball, CEnvWarpBall );
void CEnvWarpBall :: KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "radius"))
{
pev->button = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
if (FStrEq(pkvd->szKeyName, "warp_target"))
{
pev->message = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
if (FStrEq(pkvd->szKeyName, "damage_delay"))
{
pev->frags = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else CBaseEntity::KeyValue( pkvd );
}
void CEnvWarpBall::Precache( void )
{
UTIL_PrecacheModel( "sprites/lgtning.spr" );
UTIL_PrecacheModel( "sprites/Fexplo1.spr" );
UTIL_PrecacheSound( "debris/beamstart2.wav" );
UTIL_PrecacheSound( "debris/beamstart7.wav" );
}
void CEnvWarpBall::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
pActivator = m_hActivator; //save it for later
if (useType == USE_TOGGLE || useType == USE_ON) Affect();
else if( useType == USE_SET && value > 10) pev->button = value;
else if( useType == USE_SHOWINFO )
{
DEBUGHEAD;
Msg( "Radius: %d, Warp target %s\n\n", pev->button, STRING( pev->message ));
}
}
void CEnvWarpBall::Affect( void )
{
int iTimes = 0;
int iDrawn = 0;
TraceResult tr;
Vector vecDest;
CBeam *pBeam;
CBaseEntity *pEntity = UTIL_FindEntityByTargetname ( NULL, STRING(pev->message));
edict_t *pos;
if(pEntity)//target found ?
{
vecOrigin = pEntity->pev->origin;
pos = pEntity->edict();
}
else
{ //use as center
vecOrigin = pev->origin;
pos = edict();
}
EMIT_SOUND( pos, CHAN_BODY, "debris/beamstart2.wav", 1, ATTN_NORM );
UTIL_ScreenShake( vecOrigin, 6, 160, 1.0, pev->button );
CSprite *pSpr = CSprite::SpriteCreate( "sprites/Fexplo1.spr", vecOrigin, TRUE );
pSpr->SetTransparency(kRenderGlow, 77, 210, 130, 255, kRenderFxNoDissipation);
pSpr->AnimateAndDie( 18 );
EMIT_SOUND( pos, CHAN_ITEM, "debris/beamstart7.wav", 1, ATTN_NORM );
int iBeams = RANDOM_LONG(20, 40);
while (iDrawn < iBeams && iTimes < (iBeams * 3))
{
vecDest = pev->button * (Vector(RANDOM_FLOAT(-1,1), RANDOM_FLOAT(-1,1), RANDOM_FLOAT(-1,1)).Normalize());
UTIL_TraceLine( vecOrigin, vecOrigin + vecDest, ignore_monsters, NULL, &tr);
if (tr.flFraction != 1.0)
{
// we hit something.
iDrawn++;
pBeam = CBeam::BeamCreate("sprites/lgtning.spr", 200);
pBeam->PointsInit( vecOrigin, tr.vecEndPos );
pBeam->SetColor( 20, 243, 20 );
pBeam->SetNoise( 65 );
pBeam->SetBrightness( 220 );
pBeam->SetWidth( 30 );
pBeam->SetScrollRate( 35 );
pBeam->SetThink( Remove );
pBeam->pev->nextthink = gpGlobals->time + RANDOM_FLOAT(0.5, 1.6);
}
iTimes++;
}
SetNextThink( pev->frags );
}
void CEnvWarpBall::Think( void )
{
FireTargets();
if ( pev->spawnflags & SF_KILL_CENTER ) //Blue-Shift strange feature
{
CBaseEntity *pMonster = NULL;
while ((pMonster = UTIL_FindEntityInSphere( pMonster, vecOrigin, 72 )) != NULL)
{
if ( FBitSet( pMonster->pev->flags, FL_MONSTER ) || FBitSet( pMonster->pev->flags, FL_CLIENT ))
pMonster->TakeDamage ( pev, pev, 100, DMG_GENERIC );
}
}
if ( pev->spawnflags & SF_REMOVE_ON_FIRE ) UTIL_Remove( this );
}
//=======================================================================
// base beams ()
//=======================================================================
LINK_ENTITY_TO_CLASS( beam, CBeam );
void CBeam::Spawn( void )
{
pev->solid = SOLID_NOT;
}
void CBeam::SetStartEntity( edict_t *pEnt )
{
pev->owner = pEnt;
}
void CBeam::SetEndEntity( edict_t *pEnt )
{
pev->aiment = pEnt;
}
const Vector &CBeam::GetStartPos( void )
{
int type = GetType();
if( type == BEAM_ENTS )
{
edict_t *pent = GetStartEntity();
if ( pent )
return pent->v.origin;
}
return pev->origin;
}
const Vector &CBeam::GetEndPos( void )
{
int type = GetType();
if( type == BEAM_ENTS || type == BEAM_ENTPOINT )
{
edict_t *pent = GetEndEntity();
if ( pent )
return pent->v.oldorigin;
}
return pev->oldorigin;
}
CBeam *CBeam::BeamCreate( const char *pSpriteName, int width )
{
// Create a new entity with CBeam private data
CBeam *pBeam = GetClassPtr( (CBeam *)NULL );
pBeam->pev->classname = MAKE_STRING( "beam" );
pBeam->BeamInit( pSpriteName, width );
return pBeam;
}
void CBeam::BeamInit( const char *pSpriteName, int width )
{
SetObjectClass( ED_BEAM );
SetColor( 255, 255, 255 );
SetBrightness( 255 );
SetNoise( 0 );
SetFrame( 0 );
SetScrollRate( 0 );
pev->model = MAKE_STRING( pSpriteName );
SetTexture( UTIL_PrecacheModel( pev->model ) );
SetWidth( width );
pev->skin = 0;
pev->sequence = 0;
pev->rendermode = 0;
}
void CBeam::PointsInit( const Vector &start, const Vector &end )
{
SetType( BEAM_POINTS );
SetStartPos( start );
SetEndPos( end );
SetStartAttachment( 0 );
SetEndAttachment( 0 );
RelinkBeam();
}
void CBeam::HoseInit( const Vector &start, const Vector &direction )
{
SetType( BEAM_HOSE );
SetStartPos( start );
SetEndPos( direction );
SetStartAttachment( 0 );
SetEndAttachment( 0 );
RelinkBeam();
}
void CBeam::PointEntInit( const Vector &start, edict_t *pEnd )
{
SetType( BEAM_ENTPOINT );
SetStartPos( start );
SetEndEntity( pEnd );
SetStartAttachment( 0 );
SetEndAttachment( 0 );
RelinkBeam();
}
void CBeam::EntsInit( edict_t *pStart, edict_t *pEnd )
{
SetType( BEAM_ENTS );
SetStartEntity( pStart );
SetEndEntity( pEnd );
SetStartAttachment( 0 );
SetEndAttachment( 0 );
RelinkBeam();
}
void CBeam::RelinkBeam( void )
{
const Vector &startPos = GetStartPos(), &endPos = GetEndPos();
pev->mins.x = min( startPos.x, endPos.x );
pev->mins.y = min( startPos.y, endPos.y );
pev->mins.z = min( startPos.z, endPos.z );
pev->maxs.x = max( startPos.x, endPos.x );
pev->maxs.y = max( startPos.y, endPos.y );
pev->maxs.z = max( startPos.z, endPos.z );
pev->mins = pev->mins - pev->origin;
pev->maxs = pev->maxs - pev->origin;
UTIL_SetSize( pev, pev->mins, pev->maxs );
UTIL_SetOrigin( this, pev->origin );
}
void CBeam::SetObjectCollisionBox( void )
{
const Vector &startPos = GetStartPos(), &endPos = GetEndPos();
pev->absmin.x = min( startPos.x, endPos.x );
pev->absmin.y = min( startPos.y, endPos.y );
pev->absmin.z = min( startPos.z, endPos.z );
pev->absmax.x = max( startPos.x, endPos.x );
pev->absmax.y = max( startPos.y, endPos.y );
pev->absmax.z = max( startPos.z, endPos.z );
}
void CBeam::Touch( CBaseEntity *pOther )
{
if ( pOther->pev->flags & (FL_CLIENT | FL_MONSTER) )
{
if ( pev->owner )
{
CBaseEntity *pOwner = CBaseEntity::Instance(pev->owner);
pOwner->Use( pOther, this, USE_TOGGLE, 0 );
}
}
}
CBaseEntity* CBeam::GetTripEntity( TraceResult *ptr )
{
CBaseEntity* pTrip;
if (ptr->flFraction == 1.0 || ptr->pHit == NULL) return NULL;
pTrip = CBaseEntity::Instance(ptr->pHit);
if (pTrip == NULL) return NULL;
if (pTrip->pev->flags & (FL_CLIENT | FL_MONSTER ) && !pTrip->IsPushable())//physics ents can move too
return pTrip;
return NULL;
}
void CBeam::BeamDamage( TraceResult *ptr )
{
RelinkBeam();
if ( ptr->flFraction != 1.0 && ptr->pHit != NULL )
{
CBaseEntity *pHit = CBaseEntity::Instance(ptr->pHit);
if ( pHit )
{
if (pev->dmg > 0)
{
ClearMultiDamage();
pHit->TraceAttack( pev, pev->dmg * (gpGlobals->time - pev->dmgtime), (ptr->vecEndPos - pev->origin).Normalize(), ptr, DMG_ENERGYBEAM );
ApplyMultiDamage( pev, pev );
if ( pev->dmg > 40 && pHit->IsBSPModel())//wall damage
{
UTIL_DecalTrace( ptr, DECAL_BIGSHOT1 + RANDOM_LONG(0,4) );
}
}
else pHit->TakeHealth( -(pev->dmg * (gpGlobals->time - pev->dmgtime)), DMG_GENERIC );
}
}
pev->dmgtime = gpGlobals->time;
}
CBaseEntity *CBeam::RandomTargetname( const char *szName )
{
int total = 0;
CBaseEntity *pEntity = NULL;
CBaseEntity *pNewEntity = NULL;
while ((pNewEntity = UTIL_FindEntityByTargetname( pNewEntity, szName )) != NULL)
{
total++;
if (RANDOM_LONG(0,total-1) < 1) pEntity = pNewEntity;
}
return pEntity;
}
void CBeam::DoSparks( const Vector &start, const Vector &end )
{
if ( pev->dmg > 100 ) UTIL_Sparks( start );
if ( pev->dmg > 40 ) UTIL_Sparks( end );
}
//=======================================================================
// env_beam - toggleable beam
//=======================================================================
class CEnvBeam : public CBeam
{
public:
void Spawn( void );
void Precache( void );
void KeyValue( KeyValueData *pkvd );
void Activate( void );
void Think( void );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
int IsPointEntity( CBaseEntity *pEnt );
void BeamUpdatePoints( void );
void BeamUpdateVars( void );
CBaseEntity *pEnd;
};
LINK_ENTITY_TO_CLASS( env_beam, CEnvBeam );
void CEnvBeam::Precache( void )
{
pev->team = UTIL_PrecacheModel( pev->message, "sprites/laserbeam.spr" );
CBeam::Precache();
}
int CEnvBeam::IsPointEntity( CBaseEntity *pEnt )
{
if( pEnt->pev->modelindex && ( pEnt->m_iClassType != ED_BEAM ))
return 0;
return 1;
}
void CEnvBeam::KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "endpoint"))
{
pev->netname = ALLOC_STRING( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "damage"))
{
pev->dmg = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "sprite"))
{
pev->message = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "width"))
{
SetWidth( atoi(pkvd->szValue));
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "noisewidth"))
{
SetNoise( atoi(pkvd->szValue));
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "shade"))
{
pev->frags = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else CBeam::KeyValue( pkvd );
}
void CEnvBeam::BeamUpdateVars( void )
{
pev->skin = 0;
pev->sequence = 0;
pev->rendermode = 0;
SetTexture( pev->team );
BeamUpdatePoints();
SetFrame( 0 );
SetScrollRate( pev->speed );
if ( pev->frags == 1 ) SetFlags( BEAM_FSHADEIN );
if ( pev->frags == 2 ) SetFlags( BEAM_FSHADEOUT );
if ( pev->renderamt == 255 ) SetFlags( BEAM_FSOLID );
else SetFlags( 0 );
}
void CEnvBeam::Activate( void )
{
BeamUpdateVars();
CBeam::Activate();
}
void CEnvBeam::BeamUpdatePoints( void )
{
int beamType;
pEnd = UTIL_FindEntityByTargetname ( NULL, STRING(pev->netname) );
if( !pEnd ) return;
int pointEnd = IsPointEntity( pEnd );
beamType = BEAM_ENTS;
if ( !pointEnd )
beamType = BEAM_ENTPOINT;
else beamType = BEAM_POINTS;
SetType( beamType );
if ( beamType == BEAM_POINTS || beamType == BEAM_ENTPOINT || beamType == BEAM_HOSE )
{
SetStartPos( pev->origin );
if ( beamType == BEAM_POINTS || beamType == BEAM_HOSE )
SetEndPos( pEnd->pev->origin );
else SetEndEntity( ENT( pEnd->pev ) );
}
else
{
SetStartEntity( ENT( pev ) );
SetEndEntity( ENT( pEnd->pev ) );
}
RelinkBeam();
}
void CEnvBeam::Spawn( void )
{
UTIL_SetModel( edict(), "sprites/null.spr" ); // beam start point
pev->solid = SOLID_NOT; // remove model & collisions
Precache();
if( FStringNull( pev->netname ))
{
ALERT( at_warning, "%s end entity not found!\n", STRING( pev->classname ));
UTIL_Remove( this );
return;
}
pev->dmgtime = gpGlobals->time;
if( pev->rendercolor == g_vecZero ) pev->rendercolor = Vector( 255, 255, 255 );
if( pev->spawnflags & SF_START_ON ) Use( this, this, USE_ON, 0 );
}
void CEnvBeam::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if (useType == USE_TOGGLE)
{
if(m_iState == STATE_ON) useType = USE_OFF;
else useType = USE_ON;
}
if (useType == USE_ON)
{
m_iState = STATE_ON;
BeamUpdatePoints();
pev->effects &= ~EF_NODRAW;
SetNextThink( 0 );
pev->dmgtime = gpGlobals->time;
}
else if (useType == USE_OFF)
{
m_iState = STATE_OFF;
pev->effects |= EF_NODRAW;
DontThink();
}
else if(useType == USE_SET) //set new damage level
{
pev->dmg = value;
}
else if(useType == USE_RESET) //set new brightness
{
if(value)pev->renderamt = value;
BeamUpdateVars();
}
else if (useType == USE_SHOWINFO)
{
DEBUGHEAD;
Msg( "State: %s, Damage %g\n", GetStringForState( GetState()), pev->dmg );
Msg("Beam model %s\n", STRING( pev->message ));
}
}
void CEnvBeam::Think( void )
{
if ( pev->dmg || !FStringNull(pev->message))//apply damage & trip entity
{
TraceResult tr;
UTIL_TraceLine( pev->origin, pEnd->pev->origin, dont_ignore_monsters, NULL, &tr );
BeamDamage( &tr );
CBaseEntity* pTrip = GetTripEntity( &tr );
if (pTrip)
{
if (!FBitSet(pev->spawnflags, SF_BEAM_TRIPPED))
{
UTIL_FireTargets(pev->target, pTrip, this, USE_TOGGLE);
pev->spawnflags |= SF_BEAM_TRIPPED;
}
}
else pev->spawnflags &= ~SF_BEAM_TRIPPED;
}
SetNextThink( 0.1 );
}
//=======================================================================
// env_laser - classic HALF-LIFE laser
//=======================================================================
LINK_ENTITY_TO_CLASS( env_laser, CLaser );
TYPEDESCRIPTION CLaser::m_SaveData[] =
{
DEFINE_FIELD( CLaser, m_pStartSprite, FIELD_CLASSPTR ),
DEFINE_FIELD( CLaser, m_pEndSprite, FIELD_CLASSPTR ),
};
IMPLEMENT_SAVERESTORE( CLaser, CBeam );
void CLaser::Spawn( void )
{
pev->frame = 0;
pev->solid = SOLID_NOT; // Remove model & collisions
Precache();
}
void CLaser::Activate( void )
{
if ( m_pStartSprite && m_pEndSprite )
EntsInit( m_pStartSprite->edict(), m_pEndSprite->edict() );
}
void CLaser::SetObjectCollisionBox( void )
{
if ( m_pStartSprite && m_pEndSprite )
{
const Vector &startPos = m_pStartSprite->pev->origin, &endPos = m_pEndSprite->pev->origin;
pev->absmin.x = min( startPos.x, endPos.x );
pev->absmin.y = min( startPos.y, endPos.y );
pev->absmin.z = min( startPos.z, endPos.z );
pev->absmax.x = max( startPos.x, endPos.x );
pev->absmax.y = max( startPos.y, endPos.y );
pev->absmax.z = max( startPos.z, endPos.z );
}
else
{
pev->absmin = g_vecZero;
pev->absmax = g_vecZero;
}
}
void CLaser::PostSpawn( void )
{
if (!FStringNull(pev->netname))
{
m_pStartSprite = CSprite::SpriteCreate( (char *)STRING(pev->netname), pev->origin, TRUE );
if (m_pStartSprite) m_pStartSprite->SetTransparency( kRenderGlow, pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, pev->renderamt, pev->renderfx );
else m_pStartSprite = CSprite::SpriteCreate( "sprites/null.spr", pev->origin, TRUE );
}
else m_pStartSprite = CSprite::SpriteCreate( "sprites/null.spr", pev->origin, TRUE );
m_pEndSprite = CSprite::SpriteCreate( "sprites/null.spr", pev->origin, TRUE );
if ( pev->spawnflags & SF_START_ON ) TurnOn();
else TurnOff();
}
void CLaser::Precache( void )
{
pev->modelindex = UTIL_PrecacheModel( pev->model, "sprites/laserbeam.spr" );
UTIL_PrecacheModel( pev->netname );
}
void CLaser::KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "sprite"))
{
pev->model = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "startsprite"))
{
pev->netname = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "width"))
{
SetWidth( atof(pkvd->szValue) );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "noisewidth"))
{
SetNoise( atoi(pkvd->szValue) );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "damage"))
{
pev->dmg = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else CBeam::KeyValue( pkvd );
}
void CLaser::TurnOff( void )
{
SetBits(pev->effects, EF_NODRAW );
m_iState = STATE_OFF;
if ( m_pStartSprite )
{
m_pStartSprite->TurnOff();
UTIL_SetVelocity(m_pStartSprite, g_vecZero);
}
if ( m_pEndSprite )
{
m_pEndSprite->TurnOff();
UTIL_SetVelocity(m_pEndSprite, g_vecZero);
}
DontThink();
}
void CLaser::TurnOn( void )
{
ClearBits( pev->effects, EF_NODRAW );
if ( m_pStartSprite )
m_pStartSprite->TurnOn();
if ( m_pEndSprite )
m_pEndSprite->TurnOn();
pev->dmgtime = gpGlobals->time;
m_iState = STATE_ON;
SetScrollRate( pev->speed );
SetFlags( BEAM_FSHADEOUT );
SetNextThink( 0 );
}
void CLaser::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if (useType == USE_TOGGLE)
{
if(m_iState == STATE_ON) useType = USE_OFF;
else useType = USE_ON;
}
if (useType == USE_ON) TurnOn();
else if(useType == USE_OFF) TurnOff();
else if (useType == USE_SHOWINFO)
{
DEBUGHEAD;
Msg( "State: %s, Damage %g\n", GetStringForState( GetState()), pev->dmg );
Msg("Laser model %s\n", STRING( pev->model ));
}
}
void CLaser::FireAtPoint( Vector startpos, TraceResult &tr )
{
if (m_pStartSprite && m_pEndSprite)
{
UTIL_SetVelocity(m_pStartSprite, (startpos - m_pStartSprite->pev->origin)*100 );
UTIL_SetVelocity(m_pEndSprite, (tr.vecEndPos - m_pEndSprite->pev->origin)*100 );
}
BeamDamage( &tr );
DoSparks( startpos, tr.vecEndPos );
}
void CLaser:: Think( void )
{
Vector startpos = pev->origin;
TraceResult tr;
UTIL_MakeVectors( pev->angles );
Vector vecProject = startpos + gpGlobals->v_forward * MAP_HALFSIZE;
UTIL_TraceLine( startpos, vecProject, dont_ignore_monsters, ignore_glass, NULL, &tr );
FireAtPoint( startpos, tr );
if(m_iState == STATE_ON) SetNextThink( 0.01 ); //!!!
}
//=========================================================
// env_lightning - random zap strike
//=========================================================
class CEnvLightning : public CBeam
{
public:
void Spawn( void );
void Precache( void );
void KeyValue( KeyValueData *pkvd );
void Think( void );
void RandomPoint( Vector &vecSrc );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void BeamDamage( TraceResult *ptr );
};
LINK_ENTITY_TO_CLASS( env_lightning, CEnvLightning );
void CEnvLightning::Precache( void )
{
pev->team = UTIL_PrecacheModel( pev->message, "sprites/laserbeam.spr" );
CBeam::Precache();
}
void CEnvLightning::KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "lifetime"))//beam lifetime (leave blank for toggle beam)
{
pev->armorvalue = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "damage"))
{
pev->dmg = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "sprite"))
{
pev->message = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "width"))
{
pev->button = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "noisewidth"))
{
pev->impulse = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "radius"))
{
pev->frags = atof( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else CBeam::KeyValue( pkvd );
}
void CEnvLightning::BeamDamage( TraceResult *ptr )
{
RelinkBeam();
if ( ptr->flFraction != 1.0 && ptr->pHit != NULL )
{
CBaseEntity *pHit = CBaseEntity::Instance(ptr->pHit);
if ( pHit )
{
if (pev->dmg > 0)
{
ClearMultiDamage();
pHit->TraceAttack( pev, pev->dmg * (gpGlobals->time - pev->dmgtime), (ptr->vecEndPos - pev->origin).Normalize(), ptr, DMG_ENERGYBEAM );
ApplyMultiDamage( pev, pev );
if ( pev->dmg > 40 && pHit->IsBSPModel())//wall damage
{
UTIL_DecalTrace( ptr, DECAL_BIGSHOT1 + RANDOM_LONG(0,4) );
}
}
else pHit->TakeHealth( -(pev->dmg * (gpGlobals->time - pev->dmgtime)), DMG_GENERIC );
}
}
pev->dmgtime = gpGlobals->time;
}
void CEnvLightning::RandomPoint( Vector &vecSrc )
{
int iLoops = 0;
for (iLoops = 0; iLoops < 10; iLoops++)
{
Vector vecDir1 = Vector( RANDOM_FLOAT( -1.0, 1.0 ), RANDOM_FLOAT( -1.0, 1.0 ),RANDOM_FLOAT( -1.0, 1.0 ) );
vecDir1 = vecDir1.Normalize();
TraceResult tr1;
UTIL_TraceLine( vecSrc, vecSrc + vecDir1 * pev->frags, ignore_monsters, ENT(pev), &tr1 );
if ((tr1.vecEndPos - vecSrc).Length() < pev->frags * 0.1) continue;
if (tr1.flFraction == 1.0) continue;
SFX_Zap ( pev, vecSrc, tr1.vecEndPos );
DoSparks( vecSrc, tr1.vecEndPos );
BeamDamage( &tr1 );
UTIL_FireTargets( pev->target, this, this, USE_TOGGLE );
break;
}
}
void CEnvLightning::Spawn( void )
{
UTIL_SetModel(edict(), "sprites/null.spr");//beam start point
pev->solid = SOLID_NOT; // Remove model & collisions
Precache();
pev->dmgtime = gpGlobals->time;
if (pev->rendercolor == g_vecZero) pev->rendercolor = Vector(255, 255, 255);
if(pev->spawnflags & SF_START_ON) Use( this, this, USE_ON, 0 );
}
void CEnvLightning::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if (useType == USE_TOGGLE)
{
if(m_iState == STATE_ON) useType = USE_OFF;
else useType = USE_ON;
}
if (useType == USE_ON)
{
m_iState = STATE_ON;
pev->effects &= ~EF_NODRAW;
SetNextThink( 0 );
pev->dmgtime = gpGlobals->time;
}
else if (useType == USE_OFF)
{
m_iState = STATE_OFF;
pev->effects |= EF_NODRAW;
DontThink();
}
else if(useType == USE_SET)
{
}
else if (useType == USE_SHOWINFO)
{
DEBUGHEAD;
Msg( "State: %s, MaxDelay %.2f\n\n", GetStringForState( GetState()), m_flDelay );
}
}
void CEnvLightning::Think( void )
{
RandomPoint( pev->origin );
SetNextThink( pev->armorvalue + RANDOM_FLOAT( 0, m_flDelay ) );
}
//=======================================================================
// env_beamring - make ring from beams
//=======================================================================
class CEnvBeamRing : public CBeam
{
public:
void Spawn( void );
void Think( void );
void Precache( void );
void KeyValue( KeyValueData *pkvd );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
};
LINK_ENTITY_TO_CLASS( env_beamring, CEnvBeamRing );
void CEnvBeamRing::Precache( void )
{
pev->team = UTIL_PrecacheModel( pev->message, "sprites/laserbeam.spr" );
CBeam::Precache();
}
void CEnvBeamRing::KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "lifetime"))//beam lifetime (leave blank for toggle beam)
{
pev->armorvalue = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "sprite"))
{
pev->message = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "width"))
{
pev->button = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "noisewidth"))
{
pev->impulse = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "radius"))
{
pev->frags = atof( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else CBeam::KeyValue( pkvd );
}
void CEnvBeamRing::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if (useType == USE_TOGGLE)
{
if(m_iState == STATE_ON) useType = USE_OFF;
else useType = USE_ON;
}
if (useType == USE_ON)
{
m_iState = STATE_ON;
pev->effects &= ~EF_NODRAW;
SetNextThink( 0 );
pev->dmgtime = gpGlobals->time;
}
else if (useType == USE_OFF)
{
m_iState = STATE_OFF;
pev->effects |= EF_NODRAW;
DontThink();
}
else if(useType == USE_SET)
{
}
else if (useType == USE_SHOWINFO)
{
DEBUGHEAD;
Msg( "State: %s, MaxDelay %.2f\n\n", GetStringForState( GetState()), m_flDelay );
}
}
void CEnvBeamRing::Spawn( void )
{
UTIL_SetModel(edict(), "sprites/null.spr");//beam start point
pev->solid = SOLID_NOT; // Remove model & collisions
Precache();
pev->dmgtime = gpGlobals->time;
if (pev->rendercolor == g_vecZero) pev->rendercolor = Vector(255, 255, 255);
if(pev->frags == 0)pev->frags = 20;
//create second point
Vector vecAngles, vecPos;
vecAngles = pev->angles;
UTIL_MakeVectors(vecAngles);
vecPos = pev->origin + (gpGlobals->v_forward * pev->frags);
CBaseEntity *pRing = CBaseEntity::Create( "info_target", vecPos, vecAngles, edict() );
if(m_iParent)pRing->m_iParent = m_iParent;
pev->enemy = pRing->edict(); //save our pointer
if(pev->spawnflags & SF_START_ON) Use( this, this, USE_ON, 0 );
}
void CEnvBeamRing::Think( void )
{
CBaseEntity *pRing = CBaseEntity::Instance(pev->enemy);
SFX_Ring( pev, pRing->pev );
SetNextThink( pev->armorvalue + RANDOM_FLOAT( 0, m_flDelay ) );
}
//=====================================================
// env_render: change render parameters
//=====================================================
#define SF_RENDER_MASKFX (1<<0)
#define SF_RENDER_MASKAMT (1<<1)
#define SF_RENDER_MASKMODE (1<<2)
#define SF_RENDER_MASKCOLOR (1<<3)
class CRenderFxManager : public CBaseLogic
{
public:
void Affect( void );
void KeyValue( KeyValueData *pkvd );
void Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
m_hActivator = pActivator; Affect();
}
};
LINK_ENTITY_TO_CLASS( env_render, CRenderFxManager );
void CRenderFxManager :: KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "fadetime"))
{
pev->speed = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else CBaseEntity::KeyValue( pkvd );
}
void CRenderFxManager::Affect( void )
{
BOOL first = TRUE;
if(FStringNull(pev->target)) return;
CBaseEntity* pTarget = UTIL_FindEntityByTargetname( NULL, STRING(pev->target), m_hActivator);
while ( pTarget != NULL )
{
entvars_t *pevTarget = pTarget->pev;
if (pev->speed == 0) // aplly settings instantly ?
{
if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKAMT ) )
pevTarget->renderamt = pev->renderamt;
if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKCOLOR ) )
pevTarget->rendercolor = pev->rendercolor;
if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKFX ) )
pevTarget->renderfx = pev->renderfx;
if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKMODE ) )
pevTarget->rendermode = pev->rendermode;
pevTarget->scale = pev->scale;
pevTarget->framerate = pev->framerate;
if (first) UTIL_FireTargets( pev->netname, pTarget, this, USE_TOGGLE );
}
else
{
if (!pevTarget->renderamt && !pevTarget->rendermode) pevTarget->renderamt = 255;
pevTarget->renderfx = pev->renderfx;
pevTarget->rendermode = pev->rendermode;
CBaseEntity *pFader = Create( "faderent", pev->origin, pev->angles, pTarget->edict());
pFader->pev->renderamt = pevTarget->renderamt;
pFader->pev->rendercolor = pevTarget->rendercolor;
pFader->pev->scale = pevTarget->scale;
if (pFader->pev->scale == 0) pFader->pev->scale = 1;
pFader->pev->spawnflags = pev->spawnflags;
if (first) pFader->pev->target = pev->netname;
pFader->pev->max_health = pev->framerate - pevTarget->framerate;
pFader->pev->health = pev->renderamt - pevTarget->renderamt;
pFader->pev->movedir.x = pev->rendercolor.x - pevTarget->rendercolor.x;
pFader->pev->movedir.y = pev->rendercolor.y - pevTarget->rendercolor.y;
pFader->pev->movedir.z = pev->rendercolor.z - pevTarget->rendercolor.z;
if ( pev->scale ) pFader->pev->frags = pev->scale - pevTarget->scale;
else pFader->pev->frags = 0;
pFader->pev->dmgtime = gpGlobals->time;
pFader->pev->speed = pev->speed;
pFader->SetNextThink( 0 );
pFader->Spawn();
}
first = FALSE;//not a first target
pTarget = UTIL_FindEntityByTargetname( pTarget, STRING(pev->target), m_hActivator );
}
}