forked from a1batross/Paranoia2_original
5218 lines
124 KiB
C++
5218 lines
124 KiB
C++
/***
|
|
*
|
|
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
|
*
|
|
* This product contains software technology licensed from Id
|
|
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
|
* All Rights Reserved.
|
|
*
|
|
* Use, distribution, and modification of this source code and/or resulting
|
|
* object code is restricted to non-commercial enhancements to products from
|
|
* Valve LLC. All other use, distribution, or modification is prohibited
|
|
* without written permission from Valve LLC.
|
|
*
|
|
****/
|
|
#include "extdll.h"
|
|
#include "util.h"
|
|
#include "cbase.h"
|
|
#include "monsters.h"
|
|
#include "customentity.h"
|
|
#include "effects.h"
|
|
#include "weapons.h"
|
|
#include "decals.h"
|
|
#include "game.h"
|
|
#include "func_break.h"
|
|
#include "shake.h"
|
|
#include "player.h" //LRC - footstep stuff
|
|
#include "locus.h" //LRC - locus utilities
|
|
#include "movewith.h" //LRC - the DesiredThink system
|
|
#include <stringlib.h>
|
|
|
|
#define SF_GIBSHOOTER_REPEATABLE 1 // allows a gibshooter to be refired
|
|
|
|
#define SF_FUNNEL_REVERSE 1 // funnel effect repels particles instead of attracting them.
|
|
#define SF_FUNNEL_REPEATABLE 2 // allows a funnel to be refired
|
|
|
|
|
|
//LRC - make info_target an entity class in its own right
|
|
class CInfoTarget : public CPointEntity
|
|
{
|
|
public:
|
|
void Spawn( void );
|
|
void Precache( void );
|
|
};
|
|
|
|
LINK_ENTITY_TO_CLASS( info_target, CInfoTarget );
|
|
|
|
//LRC- force an info_target to use the sprite null.spr
|
|
#define SF_TARGET_HACK_VISIBLE 1
|
|
|
|
// Landmark class
|
|
void CInfoTarget :: Spawn( void )
|
|
{
|
|
//Precache();
|
|
pev->solid = SOLID_NOT;
|
|
if (pev->spawnflags & SF_TARGET_HACK_VISIBLE)
|
|
{
|
|
PRECACHE_MODEL("sprites/null.spr");
|
|
SET_MODEL(ENT(pev),"sprites/null.spr");
|
|
UTIL_SetSize(pev, g_vecZero, g_vecZero);
|
|
}
|
|
}
|
|
|
|
void CInfoTarget :: Precache( void )
|
|
{
|
|
if (pev->spawnflags & SF_TARGET_HACK_VISIBLE)
|
|
PRECACHE_MODEL("sprites/null.spr");
|
|
}
|
|
|
|
|
|
class CBubbling : public CBaseEntity
|
|
{
|
|
public:
|
|
void Spawn( void );
|
|
void Precache( void );
|
|
void KeyValue( KeyValueData *pkvd );
|
|
|
|
void EXPORT FizzThink( void );
|
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
|
|
virtual int Save( CSave &save );
|
|
virtual int Restore( CRestore &restore );
|
|
virtual int ObjectCaps( void ) { return CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
|
|
static TYPEDESCRIPTION m_SaveData[];
|
|
|
|
int m_density;
|
|
int m_frequency;
|
|
int m_bubbleModel;
|
|
int m_state;
|
|
|
|
virtual STATE GetState( void ) { return m_state?STATE_ON:STATE_OFF; };
|
|
};
|
|
|
|
LINK_ENTITY_TO_CLASS( env_bubbles, CBubbling );
|
|
|
|
TYPEDESCRIPTION CBubbling::m_SaveData[] =
|
|
{
|
|
DEFINE_FIELD( CBubbling, m_density, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CBubbling, m_frequency, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CBubbling, m_state, FIELD_INTEGER ),
|
|
// Let spawn restore this!
|
|
// DEFINE_FIELD( CBubbling, m_bubbleModel, FIELD_INTEGER ),
|
|
};
|
|
|
|
IMPLEMENT_SAVERESTORE( CBubbling, CBaseEntity );
|
|
|
|
|
|
#define SF_BUBBLES_STARTOFF 0x0001
|
|
|
|
void CBubbling::Spawn( void )
|
|
{
|
|
Precache( );
|
|
SET_MODEL( ENT(pev), STRING(pev->model) ); // Set size
|
|
|
|
pev->solid = SOLID_NOT; // Remove model & collisions
|
|
pev->renderamt = 0; // The engine won't draw this model if this is set to 0 and blending is on
|
|
pev->rendermode = kRenderTransTexture;
|
|
int speed = pev->speed > 0 ? pev->speed : -pev->speed;
|
|
|
|
// HACKHACK!!! - Speed in rendercolor
|
|
pev->rendercolor.x = speed >> 8;
|
|
pev->rendercolor.y = speed & 255;
|
|
pev->rendercolor.z = (pev->speed < 0) ? 1 : 0;
|
|
|
|
|
|
if ( !(pev->spawnflags & SF_BUBBLES_STARTOFF) )
|
|
{
|
|
SetThink(&CBubbling:: FizzThink );
|
|
SetNextThink( 2.0 );
|
|
m_state = 1;
|
|
}
|
|
else
|
|
m_state = 0;
|
|
}
|
|
|
|
void CBubbling::Precache( void )
|
|
{
|
|
m_bubbleModel = PRECACHE_MODEL("sprites/bubble.spr"); // Precache bubble sprite
|
|
}
|
|
|
|
|
|
void CBubbling::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
if ( ShouldToggle( useType, m_state ) )
|
|
m_state = !m_state;
|
|
|
|
if ( m_state )
|
|
{
|
|
SetThink(&CBubbling:: FizzThink );
|
|
SetNextThink( 0.1 );
|
|
}
|
|
else
|
|
{
|
|
SetThink( NULL );
|
|
DontThink();
|
|
}
|
|
}
|
|
|
|
|
|
void CBubbling::KeyValue( KeyValueData *pkvd )
|
|
{
|
|
if (FStrEq(pkvd->szKeyName, "density"))
|
|
{
|
|
m_density = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "frequency"))
|
|
{
|
|
m_frequency = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "current"))
|
|
{
|
|
pev->speed = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else
|
|
CBaseEntity::KeyValue( pkvd );
|
|
}
|
|
|
|
|
|
void CBubbling::FizzThink( void )
|
|
{
|
|
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, VecBModelOrigin(pev) );
|
|
WRITE_BYTE( TE_FIZZ );
|
|
WRITE_SHORT( (short)ENTINDEX( edict() ) );
|
|
WRITE_SHORT( (short)m_bubbleModel );
|
|
WRITE_BYTE( m_density );
|
|
MESSAGE_END();
|
|
|
|
if ( m_frequency > 19 ) // frequencies above 20 are treated as 20.
|
|
SetNextThink( 0.5 );
|
|
else
|
|
SetNextThink( 2.5 - (0.1 * m_frequency) );
|
|
}
|
|
|
|
// --------------------------------------------------
|
|
//
|
|
// Beams
|
|
//
|
|
// --------------------------------------------------
|
|
|
|
LINK_ENTITY_TO_CLASS( beam, CBeam );
|
|
|
|
void CBeam::Spawn( void )
|
|
{
|
|
pev->solid = SOLID_NOT; // Remove model & collisions
|
|
Precache( );
|
|
}
|
|
|
|
void CBeam::Precache( void )
|
|
{
|
|
if ( pev->owner )
|
|
SetStartEntity( ENTINDEX( pev->owner ) );
|
|
if ( pev->aiment )
|
|
SetEndEntity( ENTINDEX( pev->aiment ) );
|
|
}
|
|
|
|
void CBeam::SetStartEntity( int entityIndex )
|
|
{
|
|
pev->sequence = (entityIndex & 0x0FFF) | ((pev->sequence&0xF000)<<12);
|
|
pev->owner = g_engfuncs.pfnPEntityOfEntIndex( entityIndex );
|
|
}
|
|
|
|
void CBeam::SetEndEntity( int entityIndex )
|
|
{
|
|
pev->skin = (entityIndex & 0x0FFF) | ((pev->skin&0xF000)<<12);
|
|
pev->aiment = g_engfuncs.pfnPEntityOfEntIndex( entityIndex );
|
|
}
|
|
|
|
|
|
// These don't take attachments into account
|
|
const Vector &CBeam::GetStartPos( void )
|
|
{
|
|
if ( GetType() == BEAM_ENTS )
|
|
{
|
|
edict_t *pent = g_engfuncs.pfnPEntityOfEntIndex( GetStartEntity() );
|
|
return pent->v.origin;
|
|
}
|
|
return pev->origin;
|
|
}
|
|
|
|
|
|
const Vector &CBeam::GetEndPos( void )
|
|
{
|
|
int type = GetType();
|
|
if ( type == BEAM_POINTS || type == BEAM_HOSE )
|
|
{
|
|
return pev->angles;
|
|
}
|
|
|
|
edict_t *pent = g_engfuncs.pfnPEntityOfEntIndex( GetEndEntity() );
|
|
if ( pent )
|
|
return pent->v.origin;
|
|
return pev->angles;
|
|
}
|
|
|
|
|
|
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 )
|
|
{
|
|
pev->flags |= FL_CUSTOMENTITY;
|
|
SetColor( 255, 255, 255 );
|
|
SetBrightness( 255 );
|
|
SetNoise( 0 );
|
|
SetFrame( 0 );
|
|
SetScrollRate( 0 );
|
|
pev->model = MAKE_STRING( pSpriteName );
|
|
SetTexture( PRECACHE_MODEL( (char *)pSpriteName ) );
|
|
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, int endIndex )
|
|
{
|
|
SetType( BEAM_ENTPOINT );
|
|
SetStartPos( start );
|
|
SetEndEntity( endIndex );
|
|
SetStartAttachment( 0 );
|
|
SetEndAttachment( 0 );
|
|
RelinkBeam();
|
|
}
|
|
|
|
void CBeam::EntsInit( int startIndex, int endIndex )
|
|
{
|
|
SetType( BEAM_ENTS );
|
|
SetStartEntity( startIndex );
|
|
SetEndEntity( endIndex );
|
|
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 );
|
|
}
|
|
|
|
#if 0
|
|
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 );
|
|
}
|
|
#endif
|
|
|
|
|
|
void CBeam::TriggerTouch( 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 );
|
|
}
|
|
ALERT( at_debug, "Firing targets!!!\n" );
|
|
}
|
|
}
|
|
|
|
|
|
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->spawnflags & (SF_BEAM_SPARKSTART|SF_BEAM_SPARKEND) )
|
|
{
|
|
if ( pev->spawnflags & SF_BEAM_SPARKSTART )
|
|
{
|
|
UTIL_Sparks( start );
|
|
}
|
|
if ( pev->spawnflags & SF_BEAM_SPARKEND )
|
|
{
|
|
UTIL_Sparks( end );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
class CLightning : public CBeam
|
|
{
|
|
public:
|
|
void Spawn( void );
|
|
void Precache( void );
|
|
void KeyValue( KeyValueData *pkvd );
|
|
void Activate( void );
|
|
|
|
void EXPORT StrikeThink( void );
|
|
void EXPORT TripThink( void );
|
|
void RandomArea( void );
|
|
void RandomPoint( Vector &vecSrc );
|
|
void Zap( const Vector &vecSrc, const Vector &vecDest );
|
|
void EXPORT StrikeUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
void EXPORT ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
|
|
inline BOOL ServerSide( void )
|
|
{
|
|
if ( m_life == 0 && !(pev->spawnflags & SF_BEAM_RING) )
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
virtual int Save( CSave &save );
|
|
virtual int Restore( CRestore &restore );
|
|
static TYPEDESCRIPTION m_SaveData[];
|
|
|
|
void BeamUpdatePoints( void ); //LRC
|
|
void BeamUpdateVars( void );
|
|
|
|
virtual STATE GetState( void ) { return m_active?STATE_OFF:STATE_ON; };
|
|
|
|
int m_active;
|
|
int m_iszStartEntity;
|
|
int m_iszEndEntity;
|
|
float m_life;
|
|
int m_boltWidth;
|
|
int m_noiseAmplitude;
|
|
int m_brightness;
|
|
int m_speed;
|
|
float m_restrike;
|
|
int m_spriteTexture;
|
|
int m_iszSpriteName;
|
|
int m_frameStart;
|
|
|
|
float m_radius;
|
|
};
|
|
|
|
LINK_ENTITY_TO_CLASS( env_lightning, CLightning );
|
|
LINK_ENTITY_TO_CLASS( env_beam, CLightning );
|
|
|
|
// UNDONE: Jay -- This is only a test
|
|
#if _DEBUG
|
|
class CTripBeam : public CLightning
|
|
{
|
|
void Spawn( void );
|
|
};
|
|
LINK_ENTITY_TO_CLASS( trip_beam, CTripBeam );
|
|
|
|
void CTripBeam::Spawn( void )
|
|
{
|
|
CLightning::Spawn();
|
|
SetTouch(&CTripBeam:: TriggerTouch );
|
|
pev->solid = SOLID_TRIGGER;
|
|
RelinkBeam();
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
TYPEDESCRIPTION CLightning::m_SaveData[] =
|
|
{
|
|
DEFINE_FIELD( CLightning, m_active, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CLightning, m_iszStartEntity, FIELD_STRING ),
|
|
DEFINE_FIELD( CLightning, m_iszEndEntity, FIELD_STRING ),
|
|
DEFINE_FIELD( CLightning, m_life, FIELD_FLOAT ),
|
|
DEFINE_FIELD( CLightning, m_boltWidth, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CLightning, m_noiseAmplitude, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CLightning, m_brightness, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CLightning, m_speed, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CLightning, m_restrike, FIELD_FLOAT ),
|
|
DEFINE_FIELD( CLightning, m_spriteTexture, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CLightning, m_iszSpriteName, FIELD_STRING ),
|
|
DEFINE_FIELD( CLightning, m_frameStart, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CLightning, m_radius, FIELD_FLOAT ),
|
|
};
|
|
|
|
IMPLEMENT_SAVERESTORE( CLightning, CBeam );
|
|
|
|
|
|
void CLightning::Spawn( void )
|
|
{
|
|
if ( FStringNull( m_iszSpriteName ) )
|
|
{
|
|
SetThink(&CLightning:: SUB_Remove );
|
|
return;
|
|
}
|
|
pev->solid = SOLID_NOT; // Remove model & collisions
|
|
Precache( );
|
|
|
|
pev->dmgtime = gpGlobals->time;
|
|
|
|
//LRC- a convenience for mappers. Will this mess anything up?
|
|
if (pev->rendercolor == g_vecZero)
|
|
pev->rendercolor = Vector(255, 255, 255);
|
|
|
|
if (pev->frags == 0)
|
|
{
|
|
pev->frags = DMG_ENERGYBEAM;
|
|
}
|
|
|
|
if ( ServerSide() )
|
|
{
|
|
SetThink( NULL );
|
|
if ( pev->dmg != 0 || !FStringNull(pev->target) )
|
|
{
|
|
SetThink(&CLightning:: TripThink );
|
|
SetNextThink( 0.1 );
|
|
}
|
|
if ( pev->targetname )
|
|
{
|
|
if ( !(pev->spawnflags & SF_BEAM_STARTON) )
|
|
{
|
|
pev->effects |= EF_NODRAW;
|
|
m_active = 0;
|
|
DontThink();
|
|
}
|
|
else
|
|
m_active = 1;
|
|
|
|
SetUse(&CLightning:: ToggleUse );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_active = 0;
|
|
if ( !FStringNull(pev->targetname) )
|
|
{
|
|
SetUse(&CLightning:: StrikeUse );
|
|
}
|
|
if ( FStringNull(pev->targetname) || FBitSet(pev->spawnflags, SF_BEAM_STARTON) )
|
|
{
|
|
SetThink(&CLightning:: StrikeThink );
|
|
SetNextThink( 1.0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
void CLightning::Precache( void )
|
|
{
|
|
m_spriteTexture = PRECACHE_MODEL( (char *)STRING(m_iszSpriteName) );
|
|
CBeam::Precache();
|
|
}
|
|
|
|
|
|
void CLightning::Activate( void )
|
|
{
|
|
if ( ServerSide() )
|
|
BeamUpdateVars();
|
|
|
|
CBeam::Activate();
|
|
}
|
|
|
|
|
|
void CLightning::KeyValue( KeyValueData *pkvd )
|
|
{
|
|
if (FStrEq(pkvd->szKeyName, "LightningStart"))
|
|
{
|
|
m_iszStartEntity = ALLOC_STRING( pkvd->szValue );
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "LightningEnd"))
|
|
{
|
|
m_iszEndEntity = ALLOC_STRING( pkvd->szValue );
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "life"))
|
|
{
|
|
m_life = atof(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "BoltWidth"))
|
|
{
|
|
m_boltWidth = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "NoiseAmplitude"))
|
|
{
|
|
m_noiseAmplitude = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "TextureScroll"))
|
|
{
|
|
m_speed = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "StrikeTime"))
|
|
{
|
|
m_restrike = atof(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "texture"))
|
|
{
|
|
m_iszSpriteName = ALLOC_STRING(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "framestart"))
|
|
{
|
|
m_frameStart = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "Radius"))
|
|
{
|
|
m_radius = atof( pkvd->szValue );
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "damage"))
|
|
{
|
|
pev->dmg = atof(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else
|
|
CBeam::KeyValue( pkvd );
|
|
}
|
|
|
|
|
|
void CLightning::ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
if ( !ShouldToggle( useType, m_active ) )
|
|
return;
|
|
if ( m_active )
|
|
{
|
|
m_active = 0;
|
|
SUB_UseTargets( this, USE_OFF, 0 ); //LRC
|
|
pev->effects |= EF_NODRAW;
|
|
DontThink();
|
|
}
|
|
else
|
|
{
|
|
m_active = 1;
|
|
SUB_UseTargets( this, USE_ON, 0 ); //LRC
|
|
BeamUpdatePoints();
|
|
pev->effects &= ~EF_NODRAW;
|
|
DoSparks( GetStartPos(), GetEndPos() );
|
|
if ( pev->dmg > 0 )
|
|
{
|
|
SetNextThink( 0 );
|
|
pev->dmgtime = gpGlobals->time;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CLightning::StrikeUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
if ( !ShouldToggle( useType, m_active ) )
|
|
return;
|
|
|
|
if ( m_active )
|
|
{
|
|
m_active = 0;
|
|
SetThink( NULL );
|
|
}
|
|
else
|
|
{
|
|
SetThink(&CLightning:: StrikeThink );
|
|
SetNextThink( 0.1 );
|
|
}
|
|
|
|
if ( !FBitSet( pev->spawnflags, SF_BEAM_TOGGLE ) )
|
|
SetUse( NULL );
|
|
}
|
|
|
|
|
|
int IsPointEntity( CBaseEntity *pEnt )
|
|
{
|
|
// ALERT(at_console, "IsPE: %s, %d\n", STRING(pEnt->pev->classname), pEnt->pev->modelindex);
|
|
if (pEnt->pev->modelindex && !(pEnt->pev->flags & FL_CUSTOMENTITY)) //LRC- follow (almost) any entity that has a model
|
|
return 0;
|
|
else
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void CLightning::StrikeThink( void )
|
|
{
|
|
if ( m_life != 0 && m_restrike != -1) //LRC non-restriking beams! what an idea!
|
|
{
|
|
if ( pev->spawnflags & SF_BEAM_RANDOM )
|
|
SetNextThink( m_life + RANDOM_FLOAT( 0, m_restrike ) );
|
|
else
|
|
SetNextThink( m_life + m_restrike );
|
|
}
|
|
m_active = 1;
|
|
|
|
if (FStringNull(m_iszEndEntity))
|
|
{
|
|
if (FStringNull(m_iszStartEntity))
|
|
{
|
|
RandomArea( );
|
|
}
|
|
else
|
|
{
|
|
CBaseEntity *pStart = RandomTargetname( STRING(m_iszStartEntity) );
|
|
if (pStart != NULL)
|
|
RandomPoint( pStart->pev->origin );
|
|
else
|
|
ALERT( at_debug, "env_beam: unknown entity \"%s\"\n", STRING(m_iszStartEntity) );
|
|
}
|
|
return;
|
|
}
|
|
|
|
CBaseEntity *pStart = RandomTargetname( STRING(m_iszStartEntity) );
|
|
CBaseEntity *pEnd = RandomTargetname( STRING(m_iszEndEntity) );
|
|
|
|
if ( pStart != NULL && pEnd != NULL )
|
|
{
|
|
if ( IsPointEntity( pStart ) || IsPointEntity( pEnd ) )
|
|
{
|
|
if ( pev->spawnflags & SF_BEAM_RING)
|
|
{
|
|
// don't work
|
|
//LRC- FIXME: tell the user there's a problem.
|
|
return;
|
|
}
|
|
}
|
|
|
|
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
|
|
if ( IsPointEntity( pStart ) || IsPointEntity( pEnd ) )
|
|
{
|
|
if ( !IsPointEntity( pEnd ) ) // One point entity must be in pEnd
|
|
{
|
|
CBaseEntity *pTemp;
|
|
pTemp = pStart;
|
|
pStart = pEnd;
|
|
pEnd = pTemp;
|
|
}
|
|
if ( !IsPointEntity( pStart ) ) // One sided
|
|
{
|
|
WRITE_BYTE( TE_BEAMENTPOINT );
|
|
WRITE_SHORT( pStart->entindex() );
|
|
WRITE_COORD( pEnd->pev->origin.x);
|
|
WRITE_COORD( pEnd->pev->origin.y);
|
|
WRITE_COORD( pEnd->pev->origin.z);
|
|
}
|
|
else
|
|
{
|
|
WRITE_BYTE( TE_BEAMPOINTS);
|
|
WRITE_COORD( pStart->pev->origin.x);
|
|
WRITE_COORD( pStart->pev->origin.y);
|
|
WRITE_COORD( pStart->pev->origin.z);
|
|
WRITE_COORD( pEnd->pev->origin.x);
|
|
WRITE_COORD( pEnd->pev->origin.y);
|
|
WRITE_COORD( pEnd->pev->origin.z);
|
|
}
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
if ( pev->spawnflags & SF_BEAM_RING)
|
|
WRITE_BYTE( TE_BEAMRING );
|
|
else
|
|
WRITE_BYTE( TE_BEAMENTS );
|
|
WRITE_SHORT( pStart->entindex() );
|
|
WRITE_SHORT( pEnd->entindex() );
|
|
}
|
|
|
|
WRITE_SHORT( m_spriteTexture );
|
|
WRITE_BYTE( m_frameStart ); // framestart
|
|
WRITE_BYTE( (int)pev->framerate); // framerate
|
|
WRITE_BYTE( (int)(m_life*10.0) ); // life
|
|
WRITE_BYTE( m_boltWidth ); // width
|
|
WRITE_BYTE( m_noiseAmplitude ); // noise
|
|
WRITE_BYTE( (int)pev->rendercolor.x ); // r, g, b
|
|
WRITE_BYTE( (int)pev->rendercolor.y ); // r, g, b
|
|
WRITE_BYTE( (int)pev->rendercolor.z ); // r, g, b
|
|
WRITE_BYTE( pev->renderamt ); // brightness
|
|
WRITE_BYTE( m_speed ); // speed
|
|
MESSAGE_END();
|
|
DoSparks( pStart->pev->origin, pEnd->pev->origin );
|
|
if ( pev->dmg || !FStringNull(pev->target))
|
|
{
|
|
TraceResult tr;
|
|
UTIL_TraceLine( pStart->pev->origin, pEnd->pev->origin, dont_ignore_monsters, NULL, &tr );
|
|
if (pev->dmg)
|
|
BeamDamageInstant( &tr, pev->dmg );
|
|
|
|
//LRC - tripbeams
|
|
CBaseEntity* pTrip;
|
|
if (!FStringNull(pev->target) && (pTrip = GetTripEntity( &tr )) != NULL)
|
|
FireTargets(STRING(pev->target), pTrip, 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 ( FStringNull(pev->netname))
|
|
{
|
|
if (pTrip->pev->flags & (FL_CLIENT | FL_MONSTER))
|
|
return pTrip;
|
|
else
|
|
return NULL;
|
|
}
|
|
else if ( FClassnameIs(pTrip->pev, STRING(pev->netname) ))
|
|
return pTrip;
|
|
else if ( FStrEq( STRING(pTrip->pev->targetname), STRING(pev->netname) ))
|
|
return pTrip;
|
|
else
|
|
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, pev->frags );
|
|
ApplyMultiDamage( pev, pev );
|
|
if ( pev->spawnflags & SF_BEAM_DECALS )
|
|
{
|
|
if ( pHit->IsBSPModel() )
|
|
UTIL_TraceCustomDecal( ptr, "shot" );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//LRC - beams that heal people
|
|
pHit->TakeHealth( -(pev->dmg * (gpGlobals->time - pev->dmgtime)), DMG_GENERIC );
|
|
}
|
|
}
|
|
}
|
|
pev->dmgtime = gpGlobals->time;
|
|
}
|
|
|
|
//LRC - used to be DamageThink, but now it's more general.
|
|
void CLightning::TripThink( void )
|
|
{
|
|
SetNextThink( 0.1 );
|
|
TraceResult tr;
|
|
|
|
//ALERT(at_console,"TripThink\n");
|
|
|
|
if (pev->dmg != 0)
|
|
{
|
|
UTIL_TraceLine( GetStartPos(), GetEndPos(), dont_ignore_monsters, NULL, &tr );
|
|
BeamDamage( &tr );
|
|
}
|
|
|
|
//LRC - tripbeams
|
|
if (!FStringNull(pev->target))
|
|
{
|
|
//HACKHACK Set simple box using this really nice global!
|
|
gpGlobals->trace_flags = FTRACE_SIMPLEBOX;
|
|
UTIL_TraceLine( GetStartPos(), GetEndPos(), dont_ignore_monsters, NULL, &tr );
|
|
CBaseEntity *pTrip = GetTripEntity( &tr );
|
|
if (pTrip)
|
|
{
|
|
if (!FBitSet(pev->spawnflags, SF_BEAM_TRIPPED))
|
|
{
|
|
FireTargets(STRING(pev->target), pTrip, this, USE_TOGGLE, 0);
|
|
pev->spawnflags |= SF_BEAM_TRIPPED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pev->spawnflags &= ~SF_BEAM_TRIPPED;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void CLightning::Zap( const Vector &vecSrc, const Vector &vecDest )
|
|
{
|
|
#if 1
|
|
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
|
|
WRITE_BYTE( TE_BEAMPOINTS);
|
|
WRITE_COORD(vecSrc.x);
|
|
WRITE_COORD(vecSrc.y);
|
|
WRITE_COORD(vecSrc.z);
|
|
WRITE_COORD(vecDest.x);
|
|
WRITE_COORD(vecDest.y);
|
|
WRITE_COORD(vecDest.z);
|
|
WRITE_SHORT( m_spriteTexture );
|
|
WRITE_BYTE( m_frameStart ); // framestart
|
|
WRITE_BYTE( (int)pev->framerate); // framerate
|
|
WRITE_BYTE( (int)(m_life*10.0) ); // life
|
|
WRITE_BYTE( m_boltWidth ); // width
|
|
WRITE_BYTE( m_noiseAmplitude ); // noise
|
|
WRITE_BYTE( (int)pev->rendercolor.x ); // r, g, b
|
|
WRITE_BYTE( (int)pev->rendercolor.y ); // r, g, b
|
|
WRITE_BYTE( (int)pev->rendercolor.z ); // r, g, b
|
|
WRITE_BYTE( pev->renderamt ); // brightness
|
|
WRITE_BYTE( m_speed ); // speed
|
|
MESSAGE_END();
|
|
#else
|
|
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
|
|
WRITE_BYTE(TE_LIGHTNING);
|
|
WRITE_COORD(vecSrc.x);
|
|
WRITE_COORD(vecSrc.y);
|
|
WRITE_COORD(vecSrc.z);
|
|
WRITE_COORD(vecDest.x);
|
|
WRITE_COORD(vecDest.y);
|
|
WRITE_COORD(vecDest.z);
|
|
WRITE_BYTE(10);
|
|
WRITE_BYTE(50);
|
|
WRITE_BYTE(40);
|
|
WRITE_SHORT(m_spriteTexture);
|
|
MESSAGE_END();
|
|
#endif
|
|
DoSparks( vecSrc, vecDest );
|
|
}
|
|
|
|
void CLightning::RandomArea( void )
|
|
{
|
|
int iLoops = 0;
|
|
|
|
for (iLoops = 0; iLoops < 10; iLoops++)
|
|
{
|
|
Vector vecSrc = pev->origin;
|
|
|
|
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 * m_radius, ignore_monsters, ENT(pev), &tr1 );
|
|
|
|
if (tr1.flFraction == 1.0)
|
|
continue;
|
|
|
|
Vector vecDir2;
|
|
do {
|
|
vecDir2 = Vector( RANDOM_FLOAT( -1.0, 1.0 ), RANDOM_FLOAT( -1.0, 1.0 ),RANDOM_FLOAT( -1.0, 1.0 ) );
|
|
} while (DotProduct(vecDir1, vecDir2 ) > 0);
|
|
vecDir2 = vecDir2.Normalize();
|
|
TraceResult tr2;
|
|
UTIL_TraceLine( vecSrc, vecSrc + vecDir2 * m_radius, ignore_monsters, ENT(pev), &tr2 );
|
|
|
|
if (tr2.flFraction == 1.0)
|
|
continue;
|
|
|
|
if ((tr1.vecEndPos - tr2.vecEndPos).Length() < m_radius * 0.1)
|
|
continue;
|
|
|
|
UTIL_TraceLine( tr1.vecEndPos, tr2.vecEndPos, ignore_monsters, ENT(pev), &tr2 );
|
|
|
|
if (tr2.flFraction != 1.0)
|
|
continue;
|
|
|
|
Zap( tr1.vecEndPos, tr2.vecEndPos );
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void CLightning::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 * m_radius, ignore_monsters, ENT(pev), &tr1 );
|
|
|
|
if ((tr1.vecEndPos - vecSrc).Length() < m_radius * 0.1)
|
|
continue;
|
|
|
|
if (tr1.flFraction == 1.0)
|
|
continue;
|
|
|
|
Zap( vecSrc, tr1.vecEndPos );
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// LRC: Called whenever the beam gets turned on, in case an alias changed or one of the points has moved.
|
|
void CLightning::BeamUpdatePoints( void )
|
|
{
|
|
int beamType;
|
|
int pointStart, pointEnd;
|
|
|
|
CBaseEntity *pStart = UTIL_FindEntityByTargetname ( NULL, STRING(m_iszStartEntity) );
|
|
CBaseEntity *pEnd = UTIL_FindEntityByTargetname ( NULL, STRING(m_iszEndEntity) );
|
|
if (!pStart || !pEnd) return;
|
|
pointStart = IsPointEntity( pStart );
|
|
pointEnd = IsPointEntity( pEnd );
|
|
|
|
beamType = BEAM_ENTS;
|
|
if ( pointStart || pointEnd )
|
|
{
|
|
if ( !pointStart ) // One point entity must be in pStart
|
|
{
|
|
CBaseEntity *pTemp;
|
|
// Swap start & end
|
|
pTemp = pStart;
|
|
pStart = pEnd;
|
|
pEnd = pTemp;
|
|
int swap = pointStart;
|
|
pointStart = pointEnd;
|
|
pointEnd = swap;
|
|
}
|
|
if ( !pointEnd )
|
|
beamType = BEAM_ENTPOINT;
|
|
else
|
|
beamType = BEAM_POINTS;
|
|
}
|
|
|
|
SetType( beamType );
|
|
if ( beamType == BEAM_POINTS || beamType == BEAM_ENTPOINT || beamType == BEAM_HOSE )
|
|
{
|
|
SetStartPos( pStart->pev->origin );
|
|
if ( beamType == BEAM_POINTS || beamType == BEAM_HOSE )
|
|
SetEndPos( pEnd->pev->origin );
|
|
else
|
|
SetEndEntity( ENTINDEX(ENT(pEnd->pev)) );
|
|
}
|
|
else
|
|
{
|
|
SetStartEntity( ENTINDEX(ENT(pStart->pev)) );
|
|
SetEndEntity( ENTINDEX(ENT(pEnd->pev)) );
|
|
}
|
|
|
|
RelinkBeam();
|
|
}
|
|
|
|
void CLightning::BeamUpdateVars( void )
|
|
{
|
|
pev->skin = 0;
|
|
pev->sequence = 0;
|
|
pev->rendermode = 0;
|
|
pev->flags |= FL_CUSTOMENTITY;
|
|
pev->model = m_iszSpriteName;
|
|
SetTexture( m_spriteTexture );
|
|
|
|
BeamUpdatePoints(); //LRC
|
|
|
|
SetWidth( m_boltWidth );
|
|
SetNoise( m_noiseAmplitude );
|
|
SetFrame( m_frameStart );
|
|
SetScrollRate( m_speed );
|
|
if ( pev->spawnflags & SF_BEAM_SHADEIN )
|
|
SetFlags( BEAM_FSHADEIN );
|
|
else if ( pev->spawnflags & SF_BEAM_SHADEOUT )
|
|
SetFlags( BEAM_FSHADEOUT );
|
|
else if ( pev->spawnflags & SF_BEAM_SOLID )
|
|
SetFlags( BEAM_FSOLID );
|
|
}
|
|
|
|
|
|
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 ),
|
|
DEFINE_FIELD( CLaser, m_iszStartSpriteName, FIELD_STRING ),
|
|
DEFINE_FIELD( CLaser, m_iszEndSpriteName, FIELD_STRING ),
|
|
DEFINE_FIELD( CLaser, m_firePosition, FIELD_POSITION_VECTOR ),
|
|
DEFINE_FIELD( CLaser, m_iProjection, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CLaser, m_iStoppedBy, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CLaser, m_iszStartPosition, FIELD_STRING ),
|
|
};
|
|
|
|
IMPLEMENT_SAVERESTORE( CLaser, CBeam );
|
|
|
|
void CLaser::Spawn( void )
|
|
{
|
|
if ( FStringNull( pev->model ) )
|
|
{
|
|
SetThink(&CLaser:: SUB_Remove );
|
|
return;
|
|
}
|
|
pev->solid = SOLID_NOT; // Remove model & collisions
|
|
Precache( );
|
|
|
|
SetThink(&CLaser:: StrikeThink );
|
|
pev->flags |= FL_CUSTOMENTITY;
|
|
}
|
|
|
|
void CLaser::PostSpawn( void )
|
|
{
|
|
if ( m_iszStartSpriteName )
|
|
{
|
|
//LRC: allow the spritename to be the name of an env_sprite
|
|
CBaseEntity *pTemp = UTIL_FindEntityByTargetname(NULL, STRING(m_iszStartSpriteName));
|
|
if (pTemp == NULL)
|
|
{
|
|
m_pStartSprite = CSprite::SpriteCreate( STRING(m_iszStartSpriteName), pev->origin, TRUE );
|
|
if (m_pStartSprite)
|
|
m_pStartSprite->SetTransparency( kRenderGlow, pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, pev->renderamt, pev->renderfx );
|
|
}
|
|
else if (!FClassnameIs(pTemp->pev, "env_sprite"))
|
|
{
|
|
ALERT(at_error, "env_laser \"%s\" found startsprite %s, but can't use: not an env_sprite\n", STRING(pev->targetname), STRING(m_iszStartSpriteName));
|
|
m_pStartSprite = NULL;
|
|
}
|
|
else
|
|
{
|
|
// use an env_sprite defined by the mapper
|
|
m_pStartSprite = (CSprite*)pTemp;
|
|
m_pStartSprite->pev->movetype = MOVETYPE_NOCLIP;
|
|
}
|
|
}
|
|
else if ( pev->spawnflags & SF_LASER_INTERPOLATE) // interpolated lasers must have sprites at the start
|
|
{
|
|
m_pStartSprite = CSprite::SpriteCreate( "sprites/null.spr", pev->origin, TRUE );
|
|
}
|
|
else
|
|
m_pStartSprite = NULL;
|
|
|
|
|
|
if ( m_iszEndSpriteName )
|
|
{
|
|
CBaseEntity *pTemp = UTIL_FindEntityByTargetname(NULL, STRING(m_iszEndSpriteName));
|
|
if (pTemp == NULL)
|
|
{
|
|
m_pEndSprite = CSprite::SpriteCreate( STRING(m_iszEndSpriteName), pev->origin, TRUE );
|
|
if (m_pEndSprite)
|
|
m_pEndSprite->SetTransparency( kRenderGlow, pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, pev->renderamt, pev->renderfx );
|
|
}
|
|
else if (!FClassnameIs(pTemp->pev, "env_sprite"))
|
|
{
|
|
ALERT(at_error, "env_laser \"%s\" found endsprite %s, but can't use: not an env_sprite\n", STRING(pev->targetname), STRING(m_iszEndSpriteName));
|
|
m_pEndSprite = NULL;
|
|
}
|
|
else
|
|
{
|
|
// use an env_sprite defined by the mapper
|
|
m_pEndSprite = (CSprite*)pTemp;
|
|
m_pEndSprite->pev->movetype = MOVETYPE_NOCLIP;
|
|
}
|
|
}
|
|
else if ( pev->spawnflags & SF_LASER_INTERPOLATE) // interpolated lasers must have sprites at the end
|
|
{
|
|
m_pEndSprite = CSprite::SpriteCreate( "sprites/null.spr", pev->origin, TRUE );
|
|
}
|
|
else
|
|
m_pEndSprite = NULL;
|
|
|
|
//LRC
|
|
if ( m_pStartSprite && m_pEndSprite && pev->spawnflags & SF_LASER_INTERPOLATE )
|
|
EntsInit( m_pStartSprite->entindex(), m_pEndSprite->entindex() );
|
|
else
|
|
PointsInit( pev->origin, pev->origin );
|
|
|
|
if ( pev->targetname && !(pev->spawnflags & SF_BEAM_STARTON) )
|
|
TurnOff();
|
|
else
|
|
TurnOn();
|
|
}
|
|
|
|
void CLaser::Precache( void )
|
|
{
|
|
PRECACHE_MODEL( "sprites/null.spr" );
|
|
pev->modelindex = PRECACHE_MODEL( (char *)STRING(pev->model) );
|
|
if ( m_iszStartSpriteName )
|
|
{
|
|
// UGLY HACK to check whether this is a filename: does it contain a dot?
|
|
const char *c = STRING(m_iszStartSpriteName);
|
|
while (*c)
|
|
{
|
|
if (*c == '.')
|
|
{
|
|
PRECACHE_MODEL( (char *)STRING(m_iszStartSpriteName) );
|
|
break;
|
|
}
|
|
c++; // the magic word?
|
|
}
|
|
}
|
|
|
|
if ( m_iszEndSpriteName )
|
|
{
|
|
const char *c = STRING(m_iszEndSpriteName);
|
|
while (*c)
|
|
{
|
|
if (*c == '.')
|
|
{
|
|
PRECACHE_MODEL( (char *)STRING(m_iszEndSpriteName) );
|
|
break;
|
|
}
|
|
c++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CLaser::KeyValue( KeyValueData *pkvd )
|
|
{
|
|
if (FStrEq(pkvd->szKeyName, "LaserStart"))
|
|
{
|
|
m_iszStartPosition = ALLOC_STRING( pkvd->szValue );
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "LaserTarget"))
|
|
{
|
|
pev->message = ALLOC_STRING( pkvd->szValue );
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_iTowardsMode"))
|
|
{
|
|
m_iTowardsMode = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "width"))
|
|
{
|
|
SetWidth( atof(pkvd->szValue) );
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "NoiseAmplitude"))
|
|
{
|
|
SetNoise( atoi(pkvd->szValue) );
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "TextureScroll"))
|
|
{
|
|
SetScrollRate( atoi(pkvd->szValue) );
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "texture"))
|
|
{
|
|
pev->model = ALLOC_STRING(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "StartSprite"))
|
|
{
|
|
m_iszStartSpriteName = ALLOC_STRING(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "EndSprite"))
|
|
{
|
|
m_iszEndSpriteName = ALLOC_STRING(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "framestart"))
|
|
{
|
|
pev->frame = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "damage"))
|
|
{
|
|
pev->dmg = atof(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_iProjection"))
|
|
{
|
|
m_iProjection = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_iStoppedBy"))
|
|
{
|
|
m_iStoppedBy = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else
|
|
CBeam::KeyValue( pkvd );
|
|
}
|
|
|
|
|
|
void CLaser::TurnOff( void )
|
|
{
|
|
pev->effects |= EF_NODRAW;
|
|
DontThink();
|
|
if ( m_pStartSprite )
|
|
{
|
|
m_pStartSprite->TurnOff();
|
|
UTIL_SetVelocity(m_pStartSprite, g_vecZero); //LRC
|
|
}
|
|
if ( m_pEndSprite )
|
|
{
|
|
m_pEndSprite->TurnOff();
|
|
UTIL_SetVelocity(m_pEndSprite, g_vecZero); //LRC
|
|
}
|
|
}
|
|
|
|
|
|
void CLaser::TurnOn( void )
|
|
{
|
|
pev->effects &= ~EF_NODRAW;
|
|
|
|
if ( m_pStartSprite )
|
|
m_pStartSprite->TurnOn();
|
|
|
|
if ( m_pEndSprite )
|
|
m_pEndSprite->TurnOn();
|
|
|
|
pev->dmgtime = gpGlobals->time;
|
|
|
|
if ( pev->spawnflags & SF_BEAM_SHADEIN )
|
|
SetFlags( BEAM_FSHADEIN );
|
|
else if ( pev->spawnflags & SF_BEAM_SHADEOUT )
|
|
SetFlags( BEAM_FSHADEOUT );
|
|
else if ( pev->spawnflags & SF_BEAM_SOLID )
|
|
SetFlags( BEAM_FSOLID );
|
|
|
|
SetNextThink( 0 );
|
|
}
|
|
|
|
|
|
void CLaser::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
int active = (GetState() == STATE_ON);
|
|
|
|
if ( !ShouldToggle( useType, active ) )
|
|
return;
|
|
if ( active )
|
|
TurnOff();
|
|
else
|
|
TurnOn();
|
|
}
|
|
|
|
|
|
void CLaser::FireAtPoint( Vector startpos, TraceResult &tr )
|
|
{
|
|
if (pev->spawnflags & SF_LASER_INTERPOLATE && m_pStartSprite && m_pEndSprite)
|
|
{
|
|
UTIL_SetVelocity(m_pStartSprite, (startpos - m_pStartSprite->pev->origin)*10 );
|
|
UTIL_SetVelocity(m_pEndSprite, (tr.vecEndPos - m_pEndSprite->pev->origin)*10 );
|
|
}
|
|
else
|
|
{
|
|
if (m_pStartSprite)
|
|
UTIL_AssignOrigin( m_pStartSprite, startpos );
|
|
|
|
if (m_pEndSprite)
|
|
UTIL_AssignOrigin( m_pEndSprite, tr.vecEndPos );
|
|
|
|
SetStartPos( startpos );
|
|
SetEndPos( tr.vecEndPos );
|
|
}
|
|
|
|
BeamDamage( &tr );
|
|
DoSparks( startpos, tr.vecEndPos );
|
|
}
|
|
|
|
void CLaser::StrikeThink( void )
|
|
{
|
|
Vector startpos = pev->origin;
|
|
if (m_iszStartPosition)
|
|
{
|
|
startpos = CalcLocus_Position(this, NULL, STRING(m_iszStartPosition));
|
|
}
|
|
|
|
if (m_iTowardsMode)
|
|
{
|
|
m_firePosition = startpos + CalcLocus_Velocity(this, NULL, STRING(pev->message));
|
|
}
|
|
else
|
|
{
|
|
CBaseEntity *pEnd = RandomTargetname( STRING(pev->message) );
|
|
|
|
if ( pEnd )
|
|
m_firePosition = pEnd->pev->origin;
|
|
}
|
|
|
|
TraceResult tr;
|
|
|
|
//LRC
|
|
// UTIL_TraceLine( pev->origin, m_firePosition, dont_ignore_monsters, NULL, &tr );
|
|
IGNORE_GLASS iIgnoreGlass;
|
|
if (m_iStoppedBy % 2) // if it's an odd number
|
|
iIgnoreGlass = ignore_glass;
|
|
else
|
|
iIgnoreGlass = dont_ignore_glass;
|
|
|
|
IGNORE_MONSTERS iIgnoreMonsters;
|
|
if (m_iStoppedBy <= 1)
|
|
iIgnoreMonsters = dont_ignore_monsters;
|
|
else if (m_iStoppedBy <= 3)
|
|
iIgnoreMonsters = missile;
|
|
else
|
|
iIgnoreMonsters = ignore_monsters;
|
|
|
|
if ( m_iProjection )
|
|
{
|
|
Vector vecProject = startpos + 4096*((m_firePosition - startpos).Normalize());
|
|
UTIL_TraceLine( startpos, vecProject, iIgnoreMonsters, iIgnoreGlass, NULL, &tr );
|
|
}
|
|
else
|
|
{
|
|
UTIL_TraceLine( startpos, m_firePosition, iIgnoreMonsters, iIgnoreGlass, NULL, &tr );
|
|
}
|
|
|
|
FireAtPoint( startpos, tr );
|
|
|
|
//LRC - tripbeams
|
|
if (pev->target)
|
|
{
|
|
//HACKHACK Set simple box using this really nice global!
|
|
gpGlobals->trace_flags = FTRACE_SIMPLEBOX;
|
|
UTIL_TraceLine( startpos, m_firePosition, dont_ignore_monsters, NULL, &tr );
|
|
CBaseEntity *pTrip = GetTripEntity( &tr );
|
|
if (pTrip)
|
|
{
|
|
if (!FBitSet(pev->spawnflags, SF_BEAM_TRIPPED))
|
|
{
|
|
FireTargets(STRING(pev->target), pTrip, this, USE_TOGGLE, 0);
|
|
pev->spawnflags |= SF_BEAM_TRIPPED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pev->spawnflags &= ~SF_BEAM_TRIPPED;
|
|
}
|
|
}
|
|
SetNextThink( 0.1 );
|
|
}
|
|
|
|
|
|
|
|
class CGlow : public CPointEntity
|
|
{
|
|
public:
|
|
void Spawn( void );
|
|
void Think( void );
|
|
void Animate( float frames );
|
|
virtual int Save( CSave &save );
|
|
virtual int Restore( CRestore &restore );
|
|
static TYPEDESCRIPTION m_SaveData[];
|
|
|
|
float m_lastTime;
|
|
float m_maxFrame;
|
|
};
|
|
|
|
LINK_ENTITY_TO_CLASS( env_glow, CGlow );
|
|
|
|
TYPEDESCRIPTION CGlow::m_SaveData[] =
|
|
{
|
|
DEFINE_FIELD( CGlow, m_lastTime, FIELD_TIME ),
|
|
DEFINE_FIELD( CGlow, m_maxFrame, FIELD_FLOAT ),
|
|
};
|
|
|
|
IMPLEMENT_SAVERESTORE( CGlow, CPointEntity );
|
|
|
|
void CGlow::Spawn( void )
|
|
{
|
|
pev->solid = SOLID_NOT;
|
|
pev->movetype = MOVETYPE_NONE;
|
|
pev->frame = 0;
|
|
|
|
PRECACHE_MODEL( (char *)STRING(pev->model) );
|
|
SET_MODEL( ENT(pev), STRING(pev->model) );
|
|
|
|
m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1;
|
|
if ( m_maxFrame > 1.0 && pev->framerate != 0 )
|
|
SetNextThink( 0.1 );
|
|
|
|
m_lastTime = gpGlobals->time;
|
|
}
|
|
|
|
|
|
void CGlow::Think( void )
|
|
{
|
|
Animate( pev->framerate * (gpGlobals->time - m_lastTime) );
|
|
|
|
SetNextThink( 0.1 );
|
|
m_lastTime = gpGlobals->time;
|
|
}
|
|
|
|
|
|
void CGlow::Animate( float frames )
|
|
{
|
|
if ( m_maxFrame > 0 )
|
|
pev->frame = fmod( pev->frame + frames, m_maxFrame );
|
|
}
|
|
|
|
|
|
LINK_ENTITY_TO_CLASS( env_sprite, CSprite );
|
|
|
|
TYPEDESCRIPTION CSprite::m_SaveData[] =
|
|
{
|
|
DEFINE_FIELD( CSprite, m_lastTime, FIELD_TIME ),
|
|
DEFINE_FIELD( CSprite, m_maxFrame, FIELD_FLOAT ),
|
|
};
|
|
|
|
IMPLEMENT_SAVERESTORE( CSprite, CPointEntity );
|
|
|
|
void CSprite::Spawn( void )
|
|
{
|
|
pev->solid = SOLID_NOT;
|
|
pev->movetype = MOVETYPE_NONE;
|
|
pev->frame = 0;
|
|
|
|
Precache();
|
|
SET_MODEL( ENT(pev), STRING(pev->model) );
|
|
|
|
m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1;
|
|
if ( pev->targetname && !(pev->spawnflags & SF_SPRITE_STARTON) )
|
|
TurnOff();
|
|
else
|
|
TurnOn();
|
|
|
|
// Worldcraft only sets y rotation, copy to Z
|
|
if ( pev->angles.y != 0 && pev->angles.z == 0 )
|
|
{
|
|
pev->angles.z = pev->angles.y;
|
|
pev->angles.y = 0;
|
|
}
|
|
}
|
|
|
|
|
|
void CSprite::Precache( void )
|
|
{
|
|
PRECACHE_MODEL( (char *)STRING(pev->model) );
|
|
|
|
// Reset attachment after save/restore
|
|
if ( pev->aiment )
|
|
SetAttachment( pev->aiment, pev->body );
|
|
else
|
|
{
|
|
// Clear attachment
|
|
pev->skin = 0;
|
|
pev->body = 0;
|
|
}
|
|
}
|
|
|
|
|
|
void CSprite::SpriteInit( const char *pSpriteName, const Vector &origin )
|
|
{
|
|
pev->model = MAKE_STRING(pSpriteName);
|
|
pev->origin = origin;
|
|
Spawn();
|
|
}
|
|
|
|
CSprite *CSprite::SpriteCreate( const char *pSpriteName, const Vector &origin, BOOL animate )
|
|
{
|
|
CSprite *pSprite = GetClassPtr( (CSprite *)NULL );
|
|
pSprite->SpriteInit( pSpriteName, origin );
|
|
pSprite->pev->classname = MAKE_STRING("env_sprite");
|
|
pSprite->pev->solid = SOLID_NOT;
|
|
pSprite->pev->movetype = MOVETYPE_NOCLIP;
|
|
if ( animate )
|
|
pSprite->TurnOn();
|
|
|
|
return pSprite;
|
|
}
|
|
|
|
|
|
void CSprite::AnimateThink( void )
|
|
{
|
|
Animate( pev->framerate * (gpGlobals->time - m_lastTime) );
|
|
|
|
SetNextThink( 0.1 );
|
|
m_lastTime = gpGlobals->time;
|
|
}
|
|
|
|
void CSprite::AnimateUntilDead( void )
|
|
{
|
|
if ( gpGlobals->time > pev->dmgtime )
|
|
UTIL_Remove(this);
|
|
else
|
|
{
|
|
AnimateThink();
|
|
SetNextThink( 0 );
|
|
}
|
|
}
|
|
|
|
void CSprite::Expand( float scaleSpeed, float fadeSpeed )
|
|
{
|
|
pev->speed = scaleSpeed;
|
|
pev->health = fadeSpeed;
|
|
SetThink(&CSprite:: ExpandThink );
|
|
|
|
SetNextThink( 0 );
|
|
m_lastTime = gpGlobals->time;
|
|
}
|
|
|
|
|
|
void CSprite::ExpandThink( void )
|
|
{
|
|
float frametime = gpGlobals->time - m_lastTime;
|
|
pev->scale += pev->speed * frametime;
|
|
pev->renderamt -= pev->health * frametime;
|
|
if ( pev->renderamt <= 0 )
|
|
{
|
|
pev->renderamt = 0;
|
|
UTIL_Remove( this );
|
|
}
|
|
else
|
|
{
|
|
SetNextThink( 0.1 );
|
|
m_lastTime = gpGlobals->time;
|
|
}
|
|
}
|
|
|
|
|
|
void CSprite::Animate( float frames )
|
|
{
|
|
pev->frame += frames;
|
|
if ( pev->frame > m_maxFrame )
|
|
{
|
|
if ( pev->spawnflags & SF_SPRITE_ONCE )
|
|
{
|
|
TurnOff();
|
|
}
|
|
else
|
|
{
|
|
if ( m_maxFrame > 0 )
|
|
pev->frame = fmod( pev->frame, m_maxFrame );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CSprite::TurnOff( void )
|
|
{
|
|
pev->effects |= EF_NODRAW;
|
|
DontThink();
|
|
}
|
|
|
|
|
|
void CSprite::TurnOn( void )
|
|
{
|
|
if (pev->message)
|
|
{
|
|
CBaseEntity *pTemp = UTIL_FindEntityByTargetname(NULL, STRING(pev->message));
|
|
if (pTemp)
|
|
SetAttachment(pTemp->edict(), pev->frags);
|
|
else
|
|
return;
|
|
}
|
|
pev->effects &= ~EF_NODRAW;
|
|
if ( (pev->framerate && m_maxFrame > 1.0) || (pev->spawnflags & SF_SPRITE_ONCE) )
|
|
{
|
|
SetThink(&CSprite:: AnimateThink );
|
|
SetNextThink( 0 );
|
|
m_lastTime = gpGlobals->time;
|
|
}
|
|
pev->frame = 0;
|
|
}
|
|
|
|
|
|
void CSprite::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
int on = !(pev->effects & EF_NODRAW);
|
|
if ( ShouldToggle( useType, on ) )
|
|
{
|
|
if ( on )
|
|
{
|
|
SUB_UseTargets( this, USE_OFF, 0 ); //LRC
|
|
TurnOff();
|
|
}
|
|
else
|
|
{
|
|
SUB_UseTargets( this, USE_ON, 0 ); //LRC
|
|
TurnOn();
|
|
}
|
|
}
|
|
}
|
|
|
|
//=================================================================
|
|
// env_model: like env_sprite, except you can specify a sequence.
|
|
//=================================================================
|
|
#define SF_ENVMODEL_OFF 1
|
|
#define SF_ENVMODEL_DROPTOFLOOR 2
|
|
#define SF_ENVMODEL_SOLID 4
|
|
#define SF_ENVMODEL_NEWLIGHTING 8
|
|
|
|
class CEnvModel : public CBaseAnimating
|
|
{
|
|
void Spawn( void );
|
|
void Precache( void );
|
|
void EXPORT Think( void );
|
|
void KeyValue( KeyValueData *pkvd );
|
|
STATE GetState( void );
|
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
|
|
|
|
virtual int Save( CSave &save );
|
|
virtual int Restore( CRestore &restore );
|
|
static TYPEDESCRIPTION m_SaveData[];
|
|
|
|
void SetSequence( void );
|
|
|
|
string_t m_iszSequence_On;
|
|
string_t m_iszSequence_Off;
|
|
int m_iAction_On;
|
|
int m_iAction_Off;
|
|
};
|
|
|
|
TYPEDESCRIPTION CEnvModel::m_SaveData[] =
|
|
{
|
|
DEFINE_FIELD( CEnvModel, m_iszSequence_On, FIELD_STRING ),
|
|
DEFINE_FIELD( CEnvModel, m_iszSequence_Off, FIELD_STRING ),
|
|
DEFINE_FIELD( CEnvModel, m_iAction_On, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CEnvModel, m_iAction_Off, FIELD_INTEGER ),
|
|
};
|
|
|
|
IMPLEMENT_SAVERESTORE( CEnvModel, CBaseAnimating );
|
|
LINK_ENTITY_TO_CLASS( env_model, CEnvModel );
|
|
|
|
void CEnvModel::KeyValue( KeyValueData *pkvd )
|
|
{
|
|
if (FStrEq(pkvd->szKeyName, "m_iszSequence_On"))
|
|
{
|
|
m_iszSequence_On = ALLOC_STRING(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_iszSequence_Off"))
|
|
{
|
|
m_iszSequence_Off = ALLOC_STRING(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_iAction_On"))
|
|
{
|
|
m_iAction_On = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_iAction_Off"))
|
|
{
|
|
m_iAction_Off = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else
|
|
{
|
|
CBaseAnimating::KeyValue( pkvd );
|
|
}
|
|
}
|
|
|
|
void CEnvModel :: Spawn( void )
|
|
{
|
|
Precache();
|
|
SET_MODEL( ENT(pev), STRING(pev->model) );
|
|
UTIL_SetOrigin(this, pev->origin);
|
|
|
|
#if 0 // g-cont. just for testing gloss-effect
|
|
pev->movetype = MOVETYPE_NOCLIP;
|
|
pev->avelocity = Vector( 5, 5, 5 );
|
|
#endif
|
|
if (pev->spawnflags & SF_ENVMODEL_SOLID)
|
|
{
|
|
pev->solid = SOLID_SLIDEBOX;
|
|
UTIL_SetSize(pev, Vector(-10, -10, -10), Vector(10, 10, 10)); //LRCT
|
|
}
|
|
|
|
if (pev->spawnflags & SF_ENVMODEL_DROPTOFLOOR)
|
|
{
|
|
pev->origin.z += 1;
|
|
DROP_TO_FLOOR ( ENT(pev) );
|
|
}
|
|
|
|
if( !m_pMoveWith && FBitSet( pev->spawnflags, SF_ENVMODEL_NEWLIGHTING ))
|
|
{
|
|
// tell the client about static entity
|
|
SetBits( pev->iuser1, CF_STATIC_ENTITY );
|
|
}
|
|
|
|
SetBoneController( 0, 0 );
|
|
SetBoneController( 1, 0 );
|
|
|
|
SetSequence();
|
|
|
|
SetNextThink( 0.1 );
|
|
}
|
|
|
|
void CEnvModel::Precache( void )
|
|
{
|
|
PRECACHE_MODEL( (char *)STRING(pev->model) );
|
|
}
|
|
|
|
STATE CEnvModel::GetState( void )
|
|
{
|
|
if (pev->spawnflags & SF_ENVMODEL_OFF)
|
|
return STATE_OFF;
|
|
else
|
|
return STATE_ON;
|
|
}
|
|
|
|
void CEnvModel::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
if (ShouldToggle(useType, !(pev->spawnflags & SF_ENVMODEL_OFF)))
|
|
{
|
|
if (pev->spawnflags & SF_ENVMODEL_OFF)
|
|
pev->spawnflags &= ~SF_ENVMODEL_OFF;
|
|
else
|
|
pev->spawnflags |= SF_ENVMODEL_OFF;
|
|
|
|
SetSequence();
|
|
SetNextThink( 0.1 );
|
|
}
|
|
}
|
|
|
|
void CEnvModel::Think( void )
|
|
{
|
|
int iTemp;
|
|
|
|
// ALERT(at_console, "env_model Think fr=%f\n", pev->framerate);
|
|
|
|
StudioFrameAdvance ( ); // set m_fSequenceFinished if necessary
|
|
|
|
// if (m_fSequenceLoops)
|
|
// {
|
|
// SetNextThink( 1E6 );
|
|
// return; // our work here is done.
|
|
// }
|
|
if (m_fSequenceFinished && !m_fSequenceLoops)
|
|
{
|
|
if (pev->spawnflags & SF_ENVMODEL_OFF)
|
|
iTemp = m_iAction_Off;
|
|
else
|
|
iTemp = m_iAction_On;
|
|
|
|
switch (iTemp)
|
|
{
|
|
// case 1: // loop
|
|
// pev->animtime = gpGlobals->time;
|
|
// m_fSequenceFinished = FALSE;
|
|
// m_flLastEventCheck = gpGlobals->time;
|
|
// pev->frame = 0;
|
|
// break;
|
|
case 2: // change state
|
|
if (pev->spawnflags & SF_ENVMODEL_OFF)
|
|
pev->spawnflags &= ~SF_ENVMODEL_OFF;
|
|
else
|
|
pev->spawnflags |= SF_ENVMODEL_OFF;
|
|
SetSequence();
|
|
break;
|
|
default: //remain frozen
|
|
return;
|
|
}
|
|
}
|
|
SetNextThink( 0.1 );
|
|
}
|
|
|
|
void CEnvModel :: SetSequence( void )
|
|
{
|
|
int iszSeq;
|
|
|
|
if (pev->spawnflags & SF_ENVMODEL_OFF)
|
|
iszSeq = m_iszSequence_Off;
|
|
else
|
|
iszSeq = m_iszSequence_On;
|
|
|
|
if (!iszSeq)
|
|
return;
|
|
pev->sequence = LookupSequence( STRING( iszSeq ));
|
|
|
|
if (pev->sequence == -1)
|
|
{
|
|
if (pev->targetname)
|
|
ALERT( at_error, "env_model %s: unknown sequence \"%s\"\n", STRING( pev->targetname ), STRING( iszSeq ));
|
|
else
|
|
ALERT( at_error, "env_model: unknown sequence \"%s\"\n", STRING( pev->targetname ), STRING( iszSeq ));
|
|
pev->sequence = 0;
|
|
}
|
|
|
|
pev->frame = 0;
|
|
ResetSequenceInfo( );
|
|
|
|
if (pev->spawnflags & SF_ENVMODEL_OFF)
|
|
{
|
|
if (m_iAction_Off == 1)
|
|
m_fSequenceLoops = 1;
|
|
else
|
|
m_fSequenceLoops = 0;
|
|
}
|
|
else
|
|
{
|
|
if (m_iAction_On == 1)
|
|
m_fSequenceLoops = 1;
|
|
else
|
|
m_fSequenceLoops = 0;
|
|
}
|
|
}
|
|
|
|
// =================== ENV_STATIC ==============================================
|
|
#define SF_STATIC_SOLID BIT( 0 )
|
|
#define SF_STATIC_DROPTOFLOOR BIT( 1 )
|
|
#define SF_STATIC_NOSHADOW BIT( 2 ) // hlrad affected
|
|
|
|
class CEnvStatic : public CBaseEntity
|
|
{
|
|
public:
|
|
void Spawn( void );
|
|
void AutoSetSize( void );
|
|
virtual int ObjectCaps( void ) { return 0; }
|
|
void SetObjectCollisionBox( void );
|
|
void KeyValue( KeyValueData *pkvd );
|
|
int vertex_light_cache;
|
|
int surface_light_cache;
|
|
};
|
|
|
|
LINK_ENTITY_TO_CLASS( env_static, CEnvStatic );
|
|
|
|
void CEnvStatic :: KeyValue( KeyValueData *pkvd )
|
|
{
|
|
if( FStrEq(pkvd->szKeyName, "xform"))
|
|
{
|
|
UTIL_StringToVector( (float*)pev->startpos, pkvd->szValue );
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if( FStrEq(pkvd->szKeyName, "vlight_cache"))
|
|
{
|
|
vertex_light_cache = atoi( pkvd->szValue );
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if( FStrEq(pkvd->szKeyName, "flight_cache"))
|
|
{
|
|
surface_light_cache = atoi( pkvd->szValue );
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else CBaseEntity::KeyValue( pkvd );
|
|
}
|
|
|
|
void CEnvStatic :: Spawn( void )
|
|
{
|
|
if( pev->startpos == g_vecZero )
|
|
pev->startpos = Vector( pev->scale, pev->scale, pev->scale );
|
|
|
|
if( surface_light_cache )
|
|
{
|
|
SetBits( pev->iuser1, CF_STATIC_LIGHTMAPPED );
|
|
pev->colormap = surface_light_cache;
|
|
}
|
|
else
|
|
{
|
|
pev->colormap = vertex_light_cache;
|
|
}
|
|
|
|
// check xform values
|
|
if( pev->startpos.x < 0.01f ) pev->startpos.x = 1.0f;
|
|
if( pev->startpos.y < 0.01f ) pev->startpos.y = 1.0f;
|
|
if( pev->startpos.z < 0.01f ) pev->startpos.z = 1.0f;
|
|
if( pev->startpos.x > 16.0f ) pev->startpos.x = 16.0f;
|
|
if( pev->startpos.y > 16.0f ) pev->startpos.y = 16.0f;
|
|
if( pev->startpos.z > 16.0f ) pev->startpos.z = 16.0f;
|
|
|
|
PRECACHE_MODEL( (char *)STRING(pev->model) );
|
|
SET_MODEL( ENT(pev), STRING(pev->model) );
|
|
|
|
// tell the client about static entity
|
|
SetBits( pev->iuser1, CF_STATIC_ENTITY );
|
|
|
|
if( FBitSet( pev->spawnflags, SF_STATIC_SOLID ))
|
|
{
|
|
if( g_fPhysicInitialized )
|
|
pev->solid = SOLID_CUSTOM;
|
|
pev->movetype = MOVETYPE_NONE;
|
|
AutoSetSize();
|
|
}
|
|
|
|
if( FBitSet( pev->spawnflags, SF_STATIC_DROPTOFLOOR ))
|
|
{
|
|
TraceResult trace;
|
|
Vector vecStart = pev->origin;
|
|
Vector vecEnd = pev->origin - Vector( 0, 0, 256 );
|
|
|
|
TRACE_LINE( vecStart, vecEnd, TRUE, edict(), &trace );
|
|
|
|
if( !trace.fAllSolid && trace.flFraction < 1.0f )
|
|
UTIL_SetOrigin( this, trace.vecEndPos );
|
|
}
|
|
else
|
|
{
|
|
UTIL_SetOrigin( this, pev->origin );
|
|
}
|
|
|
|
if( g_fXashEngine )
|
|
{
|
|
if( FBitSet( pev->spawnflags, SF_STATIC_SOLID ))
|
|
{
|
|
if( !g_precache_meshes || g_precache_meshes->value )
|
|
{
|
|
if( !UTIL_GetCollisionMesh( pev->modelindex ))
|
|
{
|
|
// for some reasons we can't build collision mesh
|
|
// for this model, just make it non-solid
|
|
pev->solid = SOLID_NOT;
|
|
MAKE_STATIC( edict() );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// remove from server
|
|
MAKE_STATIC( edict() );
|
|
}
|
|
}
|
|
}
|
|
|
|
void CEnvStatic :: SetObjectCollisionBox( void )
|
|
{
|
|
Vector angles = pev->angles;
|
|
angles.x = -angles.x; // Stupid Quake bug workaround
|
|
|
|
// expand for rotation
|
|
TransformAABB( matrix4x4( pev->origin, angles ), pev->mins, pev->maxs, pev->absmin, pev->absmax );
|
|
|
|
pev->absmin.x -= 1;
|
|
pev->absmin.y -= 1;
|
|
pev->absmin.z -= 1;
|
|
pev->absmax.x += 1;
|
|
pev->absmax.y += 1;
|
|
pev->absmax.z += 1;
|
|
}
|
|
|
|
// automatically set collision box
|
|
void CEnvStatic :: AutoSetSize( void )
|
|
{
|
|
studiohdr_t *pstudiohdr;
|
|
pstudiohdr = (studiohdr_t *)GET_MODEL_PTR( edict() );
|
|
|
|
if( pstudiohdr == NULL )
|
|
{
|
|
UTIL_SetSize( pev, Vector( -10, -10, -10 ), Vector( 10, 10, 10 ));
|
|
ALERT( at_error, "env_static: unable to fetch model pointer!\n" );
|
|
return;
|
|
}
|
|
|
|
mstudioseqdesc_t *pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex);
|
|
UTIL_SetSize( pev, pseqdesc[pev->sequence].bbmin * pev->startpos, pseqdesc[pev->sequence].bbmax * pev->startpos );
|
|
}
|
|
|
|
#define SF_GIBSHOOTER_REPEATABLE 1 // allows a gibshooter to be refired
|
|
#define SF_GIBSHOOTER_DEBUG 4 //LRC
|
|
|
|
class CGibShooter : public CBaseDelay
|
|
{
|
|
public:
|
|
virtual void Spawn( void );
|
|
void Precache( void );
|
|
void KeyValue( KeyValueData *pkvd );
|
|
void EXPORT ShootThink( void );
|
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
|
|
virtual CBaseEntity *CreateGib( Vector vecPos, Vector vecVel );
|
|
|
|
virtual int Save( CSave &save );
|
|
virtual int Restore( CRestore &restore );
|
|
static TYPEDESCRIPTION m_SaveData[];
|
|
|
|
int m_iGibs;
|
|
int m_iGibCapacity;
|
|
int m_iGibMaterial;
|
|
int m_iGibModelIndex;
|
|
// float m_flGibVelocity;
|
|
float m_flVariance;
|
|
float m_flGibLife;
|
|
int m_iszTargetname;
|
|
int m_iszPosition;
|
|
int m_iszVelocity;
|
|
int m_iszVelFactor;
|
|
int m_iszSpawnTarget;
|
|
int m_iBloodColor;
|
|
};
|
|
|
|
TYPEDESCRIPTION CGibShooter::m_SaveData[] =
|
|
{
|
|
DEFINE_FIELD( CGibShooter, m_iGibs, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CGibShooter, m_iGibCapacity, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CGibShooter, m_iGibMaterial, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CGibShooter, m_iGibModelIndex, FIELD_INTEGER ),
|
|
// DEFINE_FIELD( CGibShooter, m_flGibVelocity, FIELD_FLOAT ),
|
|
DEFINE_FIELD( CGibShooter, m_flVariance, FIELD_FLOAT ),
|
|
DEFINE_FIELD( CGibShooter, m_flGibLife, FIELD_FLOAT ),
|
|
DEFINE_FIELD( CGibShooter, m_iszTargetname, FIELD_STRING),
|
|
DEFINE_FIELD( CGibShooter, m_iszPosition, FIELD_STRING),
|
|
DEFINE_FIELD( CGibShooter, m_iszVelocity, FIELD_STRING),
|
|
DEFINE_FIELD( CGibShooter, m_iszVelFactor, FIELD_STRING),
|
|
DEFINE_FIELD( CGibShooter, m_iszSpawnTarget, FIELD_STRING),
|
|
DEFINE_FIELD( CGibShooter, m_iBloodColor, FIELD_INTEGER ),
|
|
};
|
|
|
|
IMPLEMENT_SAVERESTORE( CGibShooter, CBaseDelay );
|
|
LINK_ENTITY_TO_CLASS( gibshooter, CGibShooter );
|
|
|
|
|
|
void CGibShooter :: Precache ( void )
|
|
{
|
|
if ( g_Language == LANGUAGE_GERMAN )
|
|
{
|
|
m_iGibModelIndex = PRECACHE_MODEL ("models/germanygibs.mdl");
|
|
}
|
|
else if (m_iBloodColor == BLOOD_COLOR_YELLOW)
|
|
{
|
|
m_iGibModelIndex = PRECACHE_MODEL ("models/agibs.mdl");
|
|
}
|
|
else
|
|
{
|
|
m_iGibModelIndex = PRECACHE_MODEL ("models/hgibs.mdl");
|
|
}
|
|
}
|
|
|
|
|
|
void CGibShooter::KeyValue( KeyValueData *pkvd )
|
|
{
|
|
if (FStrEq(pkvd->szKeyName, "m_iGibs"))
|
|
{
|
|
m_iGibs = m_iGibCapacity = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_flVelocity"))
|
|
{
|
|
m_iszVelFactor = ALLOC_STRING(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_flVariance"))
|
|
{
|
|
m_flVariance = atof(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_flGibLife"))
|
|
{
|
|
m_flGibLife = atof(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_iszTargetName"))
|
|
{
|
|
m_iszTargetname = ALLOC_STRING(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_iszPosition"))
|
|
{
|
|
m_iszPosition = ALLOC_STRING(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_iszVelocity"))
|
|
{
|
|
m_iszVelocity = ALLOC_STRING(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_iszVelFactor"))
|
|
{
|
|
m_iszVelFactor = ALLOC_STRING(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_iszSpawnTarget"))
|
|
{
|
|
m_iszSpawnTarget = ALLOC_STRING(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_iBloodColor"))
|
|
{
|
|
m_iBloodColor = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else
|
|
{
|
|
CBaseDelay::KeyValue( pkvd );
|
|
}
|
|
}
|
|
|
|
void CGibShooter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
m_hActivator = pActivator;
|
|
SetThink(&CGibShooter:: ShootThink );
|
|
SetNextThink( 0 );
|
|
}
|
|
|
|
void CGibShooter::Spawn( void )
|
|
{
|
|
Precache();
|
|
|
|
pev->solid = SOLID_NOT;
|
|
pev->effects |= EF_NODRAW;
|
|
|
|
// if ( m_flDelay == 0 )
|
|
// {
|
|
// m_flDelay = 0.1;
|
|
// }
|
|
|
|
if ( m_flGibLife == 0 )
|
|
{
|
|
m_flGibLife = 25;
|
|
}
|
|
|
|
SetMovedir ( pev );
|
|
if (pev->body == 0)
|
|
pev->body = MODEL_FRAMES( m_iGibModelIndex );
|
|
}
|
|
|
|
|
|
CBaseEntity *CGibShooter :: CreateGib ( Vector vecPos, Vector vecVel )
|
|
{
|
|
if ( CVAR_GET_FLOAT("violence_hgibs") == 0 )
|
|
return NULL;
|
|
|
|
CGib *pGib = GetClassPtr( (CGib *)NULL );
|
|
// if (pGib)
|
|
// ALERT(at_console, "Gib created ok\n");
|
|
|
|
pGib->pev->origin = vecPos;
|
|
pGib->pev->velocity = vecVel;
|
|
|
|
if (m_iBloodColor == BLOOD_COLOR_YELLOW)
|
|
{
|
|
pGib->Spawn( "models/agibs.mdl" );
|
|
pGib->m_bloodColor = BLOOD_COLOR_YELLOW;
|
|
}
|
|
else if (m_iBloodColor)
|
|
{
|
|
pGib->Spawn( "models/hgibs.mdl" );
|
|
pGib->m_bloodColor = m_iBloodColor;
|
|
}
|
|
else
|
|
{
|
|
pGib->Spawn( "models/hgibs.mdl" );
|
|
pGib->m_bloodColor = BLOOD_COLOR_RED;
|
|
}
|
|
|
|
if ( pev->body <= 1 )
|
|
{
|
|
ALERT ( at_aiconsole, "GibShooter Body is <= 1!\n" );
|
|
}
|
|
|
|
pGib->pev->body = RANDOM_LONG ( 1, pev->body - 1 );// avoid throwing random amounts of the 0th gib. (skull).
|
|
|
|
float thinkTime = pGib->m_fNextThink - gpGlobals->time;
|
|
|
|
pGib->m_lifeTime = (m_flGibLife * RANDOM_FLOAT( 0.95, 1.05 )); // +/- 5%
|
|
if ( pGib->m_lifeTime < thinkTime )
|
|
{
|
|
pGib->SetNextThink( pGib->m_lifeTime );
|
|
pGib->m_lifeTime = 0;
|
|
}
|
|
|
|
pGib->pev->avelocity.x = RANDOM_FLOAT ( 100, 200 );
|
|
pGib->pev->avelocity.y = RANDOM_FLOAT ( 100, 300 );
|
|
|
|
return pGib;
|
|
}
|
|
|
|
|
|
void CGibShooter :: ShootThink ( void )
|
|
{
|
|
int i;
|
|
if (m_flDelay == 0) // LRC - delay is 0, fire them all at once.
|
|
{
|
|
i = m_iGibs;
|
|
}
|
|
else
|
|
{
|
|
i = 1;
|
|
SetNextThink( m_flDelay );
|
|
}
|
|
|
|
while (i > 0)
|
|
{
|
|
Vector vecShootDir;
|
|
Vector vecPos;
|
|
float flGibVelocity;
|
|
if (!FStringNull(m_iszVelFactor))
|
|
flGibVelocity = CalcLocus_Ratio(m_hActivator, STRING(m_iszVelFactor));
|
|
else
|
|
flGibVelocity = 1;
|
|
|
|
if (!FStringNull(m_iszVelocity))
|
|
{
|
|
vecShootDir = CalcLocus_Velocity(this, m_hActivator, STRING(m_iszVelocity));
|
|
flGibVelocity = flGibVelocity * vecShootDir.Length();
|
|
vecShootDir = vecShootDir.Normalize();
|
|
}
|
|
else
|
|
vecShootDir = pev->movedir;
|
|
|
|
vecShootDir = vecShootDir + gpGlobals->v_right * RANDOM_FLOAT( -1, 1) * m_flVariance;;
|
|
vecShootDir = vecShootDir + gpGlobals->v_forward * RANDOM_FLOAT( -1, 1) * m_flVariance;;
|
|
vecShootDir = vecShootDir + gpGlobals->v_up * RANDOM_FLOAT( -1, 1) * m_flVariance;;
|
|
|
|
vecShootDir = vecShootDir.Normalize();
|
|
|
|
if (!FStringNull(m_iszPosition))
|
|
vecPos = CalcLocus_Position(this, m_hActivator, STRING(m_iszPosition));
|
|
else
|
|
vecPos = pev->origin;
|
|
CBaseEntity *pGib = CreateGib(vecPos, vecShootDir * flGibVelocity);
|
|
|
|
if ( pGib )
|
|
{
|
|
pGib->pev->targetname = m_iszTargetname;
|
|
// pGib->pev->velocity = vecShootDir * flGibVelocity;
|
|
|
|
if (pev->spawnflags & SF_GIBSHOOTER_DEBUG)
|
|
ALERT(at_debug, "DEBUG: %s \"%s\" creates a shot at %f %f %f; vel %f %f %f; pos \"%s\"\n", STRING(pev->classname), STRING(pev->targetname), pGib->pev->origin.x, pGib->pev->origin.y, pGib->pev->origin.z, pGib->pev->velocity.x, pGib->pev->velocity.y, pGib->pev->velocity.z, STRING(m_iszPosition));
|
|
|
|
if (m_iszSpawnTarget)
|
|
FireTargets( STRING(m_iszSpawnTarget), pGib, this, USE_TOGGLE, 0 );
|
|
}
|
|
|
|
i--;
|
|
m_iGibs--;
|
|
}
|
|
|
|
if ( m_iGibs <= 0 )
|
|
{
|
|
if ( pev->spawnflags & SF_GIBSHOOTER_REPEATABLE )
|
|
{
|
|
m_iGibs = m_iGibCapacity;
|
|
SetThink ( NULL );
|
|
DontThink();
|
|
}
|
|
else
|
|
{
|
|
SetThink(&CGibShooter :: SUB_Remove );
|
|
SetNextThink( 0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Shooter particle
|
|
class CShot : public CSprite
|
|
{
|
|
public:
|
|
void Touch ( CBaseEntity *pOther );
|
|
};
|
|
|
|
void CShot :: Touch ( CBaseEntity *pOther )
|
|
{
|
|
if (pev->teleport_time > gpGlobals->time)
|
|
return;
|
|
// don't fire too often in collisions!
|
|
// teleport_time is the soonest this can be touched again.
|
|
pev->teleport_time = gpGlobals->time + 0.1;
|
|
|
|
if (pev->netname)
|
|
FireTargets( STRING(pev->netname), this, this, USE_TOGGLE, 0 );
|
|
if (pev->message && pOther && pOther != g_pWorld)
|
|
FireTargets( STRING(pev->message), pOther, this, USE_TOGGLE, 0 );
|
|
}
|
|
|
|
class CEnvShooter : public CGibShooter
|
|
{
|
|
void Precache( void );
|
|
void KeyValue( KeyValueData *pkvd );
|
|
virtual int Save( CSave &save );
|
|
virtual int Restore( CRestore &restore );
|
|
void Spawn( void );
|
|
|
|
static TYPEDESCRIPTION m_SaveData[];
|
|
|
|
CBaseEntity *CreateGib( Vector vecPos, Vector vecVel );
|
|
|
|
int m_iszTouch;
|
|
int m_iszTouchOther;
|
|
int m_iPhysics;
|
|
float m_fFriction;
|
|
Vector m_vecSize;
|
|
};
|
|
|
|
TYPEDESCRIPTION CEnvShooter::m_SaveData[] =
|
|
{
|
|
DEFINE_FIELD( CEnvShooter, m_iszTouch, FIELD_STRING),
|
|
DEFINE_FIELD( CEnvShooter, m_iszTouchOther, FIELD_STRING),
|
|
DEFINE_FIELD( CEnvShooter, m_iPhysics, FIELD_INTEGER),
|
|
DEFINE_FIELD( CEnvShooter, m_fFriction, FIELD_FLOAT),
|
|
DEFINE_FIELD( CEnvShooter, m_vecSize, FIELD_VECTOR),
|
|
};
|
|
|
|
IMPLEMENT_SAVERESTORE(CEnvShooter,CGibShooter);
|
|
LINK_ENTITY_TO_CLASS( env_shooter, CEnvShooter );
|
|
|
|
void CEnvShooter::Spawn( void )
|
|
{
|
|
int iBody = pev->body;
|
|
CGibShooter::Spawn();
|
|
pev->body = iBody;
|
|
}
|
|
|
|
void CEnvShooter :: KeyValue( KeyValueData *pkvd )
|
|
{
|
|
if (FStrEq(pkvd->szKeyName, "shootmodel"))
|
|
{
|
|
pev->model = ALLOC_STRING(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "shootsounds"))
|
|
{
|
|
int iNoise = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
switch( iNoise )
|
|
{
|
|
case 0:
|
|
m_iGibMaterial = matGlass;
|
|
break;
|
|
case 1:
|
|
m_iGibMaterial = matWood;
|
|
break;
|
|
case 2:
|
|
m_iGibMaterial = matMetal;
|
|
break;
|
|
case 3:
|
|
m_iGibMaterial = matFlesh;
|
|
break;
|
|
case 4:
|
|
m_iGibMaterial = matRocks;
|
|
break;
|
|
|
|
default:
|
|
case -1:
|
|
m_iGibMaterial = matNone;
|
|
break;
|
|
}
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_iszTouch"))
|
|
{
|
|
m_iszTouch = ALLOC_STRING(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_iszTouchOther"))
|
|
{
|
|
m_iszTouchOther = ALLOC_STRING(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_iPhysics"))
|
|
{
|
|
m_iPhysics = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_fFriction"))
|
|
{
|
|
m_fFriction = atof(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_vecSize"))
|
|
{
|
|
UTIL_StringToVector((float*)m_vecSize, pkvd->szValue);
|
|
m_vecSize = m_vecSize/2;
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else
|
|
{
|
|
CGibShooter::KeyValue( pkvd );
|
|
}
|
|
}
|
|
|
|
|
|
void CEnvShooter :: Precache ( void )
|
|
{
|
|
if (pev->model)
|
|
m_iGibModelIndex = PRECACHE_MODEL( (char *)STRING(pev->model) );
|
|
CBreakable::MaterialSoundPrecache( (Materials)m_iGibMaterial );
|
|
}
|
|
|
|
|
|
CBaseEntity *CEnvShooter :: CreateGib ( Vector vecPos, Vector vecVel )
|
|
{
|
|
if (m_iPhysics <= 1) // normal gib or sticky gib
|
|
{
|
|
CGib *pGib = GetClassPtr( (CGib *)NULL );
|
|
|
|
pGib->pev->origin = vecPos;
|
|
pGib->pev->velocity = vecVel;
|
|
|
|
pGib->Spawn( STRING(pev->model) );
|
|
if (m_iPhysics) // sticky gib
|
|
{
|
|
pGib->pev->movetype = MOVETYPE_TOSS;
|
|
pGib->pev->solid = SOLID_BBOX;
|
|
UTIL_SetSize ( pGib->pev, Vector ( 0, 0 ,0 ), Vector ( 0, 0, 0 ) );
|
|
pGib->SetTouch(&CGib::StickyGibTouch);
|
|
}
|
|
if ( pev->body > 0 )
|
|
pGib->pev->body = RANDOM_LONG( 0, pev->body-1 );
|
|
if (m_iBloodColor)
|
|
pGib->m_bloodColor = m_iBloodColor;
|
|
else
|
|
pGib->m_bloodColor = DONT_BLEED;
|
|
pGib->m_material = m_iGibMaterial;
|
|
|
|
pGib->pev->rendermode = pev->rendermode;
|
|
pGib->pev->renderamt = pev->renderamt;
|
|
pGib->pev->rendercolor = pev->rendercolor;
|
|
pGib->pev->renderfx = pev->renderfx;
|
|
pGib->pev->scale = pev->scale;
|
|
pGib->pev->skin = pev->skin;
|
|
|
|
float thinkTime = pGib->m_fNextThink - gpGlobals->time;
|
|
|
|
pGib->m_lifeTime = (m_flGibLife * RANDOM_FLOAT( 0.95, 1.05 )); // +/- 5%
|
|
if ( pGib->m_lifeTime < thinkTime )
|
|
{
|
|
pGib->SetNextThink( pGib->m_lifeTime );
|
|
pGib->m_lifeTime = 0;
|
|
}
|
|
|
|
pGib->pev->avelocity.x = RANDOM_FLOAT ( 100, 200 );
|
|
pGib->pev->avelocity.y = RANDOM_FLOAT ( 100, 300 );
|
|
|
|
return pGib;
|
|
}
|
|
|
|
// special shot
|
|
CShot *pShot = GetClassPtr( (CShot*)NULL );
|
|
pShot->pev->classname = MAKE_STRING("shot");
|
|
pShot->pev->solid = SOLID_SLIDEBOX;
|
|
pShot->pev->origin = vecPos;
|
|
pShot->pev->velocity = vecVel;
|
|
SET_MODEL(ENT(pShot->pev), STRING(pev->model));
|
|
UTIL_SetSize(pShot->pev, -m_vecSize, m_vecSize);
|
|
pShot->pev->renderamt = pev->renderamt;
|
|
pShot->pev->rendermode = pev->rendermode;
|
|
pShot->pev->rendercolor = pev->rendercolor;
|
|
pShot->pev->renderfx = pev->renderfx;
|
|
pShot->pev->netname = m_iszTouch;
|
|
pShot->pev->message = m_iszTouchOther;
|
|
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 = m_fFriction;
|
|
|
|
switch (m_iPhysics)
|
|
{
|
|
case 2: pShot->pev->movetype = MOVETYPE_NOCLIP; pShot->pev->solid = SOLID_NOT; break;
|
|
case 3: pShot->pev->movetype = MOVETYPE_FLYMISSILE; break;
|
|
case 4: pShot->pev->movetype = MOVETYPE_BOUNCEMISSILE; break;
|
|
case 5: pShot->pev->movetype = MOVETYPE_TOSS; break;
|
|
case 6: pShot->pev->movetype = MOVETYPE_BOUNCE; break;
|
|
}
|
|
|
|
if (pShot->pev->framerate)
|
|
{
|
|
pShot->m_maxFrame = (float) MODEL_FRAMES( pShot->pev->modelindex ) - 1;
|
|
if (pShot->m_maxFrame > 1.0)
|
|
{
|
|
if (m_flGibLife)
|
|
{
|
|
pShot->pev->dmgtime = gpGlobals->time + m_flGibLife;
|
|
pShot->SetThink(& CSprite::AnimateUntilDead );
|
|
}
|
|
else
|
|
{
|
|
pShot->SetThink(& CSprite::AnimateThink );
|
|
}
|
|
pShot->SetNextThink( 0 );
|
|
pShot->m_lastTime = gpGlobals->time;
|
|
return pShot;
|
|
}
|
|
}
|
|
|
|
// if it's not animating
|
|
if (m_flGibLife)
|
|
{
|
|
pShot->SetThink(&CShot::SUB_Remove);
|
|
pShot->SetNextThink(m_flGibLife);
|
|
}
|
|
return pShot;
|
|
}
|
|
|
|
|
|
|
|
|
|
class CTestEffect : public CBaseDelay
|
|
{
|
|
public:
|
|
void Spawn( void );
|
|
void Precache( void );
|
|
// void KeyValue( KeyValueData *pkvd );
|
|
void EXPORT TestThink( void );
|
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
|
|
int m_iLoop;
|
|
int m_iBeam;
|
|
CBeam *m_pBeam[24];
|
|
float m_flBeamTime[24];
|
|
float m_flStartTime;
|
|
};
|
|
|
|
|
|
LINK_ENTITY_TO_CLASS( test_effect, CTestEffect );
|
|
|
|
void CTestEffect::Spawn( void )
|
|
{
|
|
Precache( );
|
|
}
|
|
|
|
void CTestEffect::Precache( void )
|
|
{
|
|
PRECACHE_MODEL( "sprites/lgtning.spr" );
|
|
}
|
|
|
|
void CTestEffect::TestThink( void )
|
|
{
|
|
int i;
|
|
float t = (gpGlobals->time - m_flStartTime);
|
|
|
|
if (m_iBeam < 24)
|
|
{
|
|
CBeam *pbeam = CBeam::BeamCreate( "sprites/lgtning.spr", 100 );
|
|
|
|
TraceResult tr;
|
|
|
|
Vector vecSrc = pev->origin;
|
|
Vector vecDir = Vector( RANDOM_FLOAT( -1.0, 1.0 ), RANDOM_FLOAT( -1.0, 1.0 ),RANDOM_FLOAT( -1.0, 1.0 ) );
|
|
vecDir = vecDir.Normalize();
|
|
UTIL_TraceLine( vecSrc, vecSrc + vecDir * 128, ignore_monsters, ENT(pev), &tr);
|
|
|
|
pbeam->PointsInit( vecSrc, tr.vecEndPos );
|
|
// pbeam->SetColor( 80, 100, 255 );
|
|
pbeam->SetColor( 255, 180, 100 );
|
|
pbeam->SetWidth( 100 );
|
|
pbeam->SetScrollRate( 12 );
|
|
|
|
m_flBeamTime[m_iBeam] = gpGlobals->time;
|
|
m_pBeam[m_iBeam] = pbeam;
|
|
m_iBeam++;
|
|
|
|
#if 0
|
|
Vector vecMid = (vecSrc + tr.vecEndPos) * 0.5;
|
|
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
|
|
WRITE_BYTE(TE_DLIGHT);
|
|
WRITE_COORD(vecMid.x); // X
|
|
WRITE_COORD(vecMid.y); // Y
|
|
WRITE_COORD(vecMid.z); // Z
|
|
WRITE_BYTE( 20 ); // radius * 0.1
|
|
WRITE_BYTE( 255 ); // r
|
|
WRITE_BYTE( 180 ); // g
|
|
WRITE_BYTE( 100 ); // b
|
|
WRITE_BYTE( 20 ); // time * 10
|
|
WRITE_BYTE( 0 ); // decay * 0.1
|
|
MESSAGE_END( );
|
|
#endif
|
|
}
|
|
|
|
if (t < 3.0)
|
|
{
|
|
for (i = 0; i < m_iBeam; i++)
|
|
{
|
|
t = (gpGlobals->time - m_flBeamTime[i]) / ( 3 + m_flStartTime - m_flBeamTime[i]);
|
|
m_pBeam[i]->SetBrightness( 255 * t );
|
|
// m_pBeam[i]->SetScrollRate( 20 * t );
|
|
}
|
|
SetNextThink( 0.1 );
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < m_iBeam; i++)
|
|
{
|
|
UTIL_Remove( m_pBeam[i] );
|
|
}
|
|
m_flStartTime = gpGlobals->time;
|
|
m_iBeam = 0;
|
|
// pev->nextthink = gpGlobals->time;
|
|
SetThink( NULL );
|
|
}
|
|
}
|
|
|
|
|
|
void CTestEffect::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
SetThink(&CTestEffect:: TestThink );
|
|
SetNextThink( 0.1 );
|
|
m_flStartTime = gpGlobals->time;
|
|
}
|
|
|
|
|
|
|
|
// Blood effects
|
|
class CBlood : public CPointEntity
|
|
{
|
|
public:
|
|
void Spawn( void );
|
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
void KeyValue( KeyValueData *pkvd );
|
|
|
|
inline int Color( void ) { return pev->impulse; }
|
|
inline float BloodAmount( void ) { return pev->dmg; }
|
|
|
|
inline void SetColor( int color ) { pev->impulse = color; }
|
|
inline void SetBloodAmount( float amount ) { pev->dmg = amount; }
|
|
|
|
Vector Direction( CBaseEntity *pActivator ); //LRC - added pActivator, for locus system
|
|
Vector BloodPosition( CBaseEntity *pActivator );
|
|
|
|
private:
|
|
};
|
|
|
|
LINK_ENTITY_TO_CLASS( env_blood, CBlood );
|
|
|
|
|
|
|
|
#define SF_BLOOD_RANDOM 0x0001
|
|
#define SF_BLOOD_STREAM 0x0002
|
|
#define SF_BLOOD_PLAYER 0x0004
|
|
#define SF_BLOOD_DECAL 0x0008
|
|
|
|
void CBlood::Spawn( void )
|
|
{
|
|
pev->solid = SOLID_NOT;
|
|
pev->movetype = MOVETYPE_NONE;
|
|
pev->frame = 0;
|
|
SetMovedir( pev );
|
|
if (Color() == 0) SetColor( BLOOD_COLOR_RED );
|
|
}
|
|
|
|
|
|
void CBlood::KeyValue( KeyValueData *pkvd )
|
|
{
|
|
if (FStrEq(pkvd->szKeyName, "color"))
|
|
{
|
|
int color = atoi(pkvd->szValue);
|
|
switch( color )
|
|
{
|
|
case 1:
|
|
SetColor( BLOOD_COLOR_YELLOW );
|
|
break;
|
|
default:
|
|
SetColor( BLOOD_COLOR_RED );
|
|
break;
|
|
}
|
|
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "amount"))
|
|
{
|
|
SetBloodAmount( atof(pkvd->szValue) );
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else
|
|
CPointEntity::KeyValue( pkvd );
|
|
}
|
|
|
|
|
|
Vector CBlood::Direction( CBaseEntity *pActivator )
|
|
{
|
|
if ( pev->spawnflags & SF_BLOOD_RANDOM )
|
|
return UTIL_RandomBloodVector();
|
|
else if (pev->netname)
|
|
return CalcLocus_Velocity(this, pActivator, STRING(pev->netname));
|
|
else
|
|
return pev->movedir;
|
|
}
|
|
|
|
|
|
Vector CBlood::BloodPosition( CBaseEntity *pActivator )
|
|
{
|
|
if ( pev->spawnflags & SF_BLOOD_PLAYER )
|
|
{
|
|
edict_t *pPlayer;
|
|
|
|
if ( pActivator && pActivator->IsPlayer() )
|
|
{
|
|
pPlayer = pActivator->edict();
|
|
}
|
|
else
|
|
pPlayer = g_engfuncs.pfnPEntityOfEntIndex( 1 );
|
|
if ( pPlayer )
|
|
return (pPlayer->v.origin + pPlayer->v.view_ofs) + Vector( RANDOM_FLOAT(-10,10), RANDOM_FLOAT(-10,10), RANDOM_FLOAT(-10,10) );
|
|
// if no player found, fall through
|
|
}
|
|
else if (pev->target)
|
|
{
|
|
return CalcLocus_Position(this, pActivator, STRING(pev->target));
|
|
}
|
|
|
|
return pev->origin;
|
|
}
|
|
|
|
|
|
void CBlood::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
if ( pev->spawnflags & SF_BLOOD_STREAM )
|
|
UTIL_BloodStream( BloodPosition(pActivator), Direction(pActivator), (Color() == BLOOD_COLOR_RED) ? 70 : Color(), BloodAmount() );
|
|
else
|
|
UTIL_BloodDrips( BloodPosition(pActivator), Direction(pActivator), Color(), BloodAmount() );
|
|
|
|
if ( pev->spawnflags & SF_BLOOD_DECAL )
|
|
{
|
|
Vector forward = Direction(pActivator);
|
|
Vector start = BloodPosition( pActivator );
|
|
TraceResult tr;
|
|
|
|
UTIL_TraceLine( start, start + forward * BloodAmount() * 2, ignore_monsters, NULL, &tr );
|
|
if ( tr.flFraction != 1.0 )
|
|
UTIL_BloodDecalTrace( &tr, Color() );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Screen shake
|
|
class CShake : public CPointEntity
|
|
{
|
|
public:
|
|
void Spawn( void );
|
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
void KeyValue( KeyValueData *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; }
|
|
|
|
STATE m_iState; //LRC
|
|
virtual STATE GetState( void ) { return m_iState; }; //LRC
|
|
void Think( void ) { m_iState = STATE_OFF; }; //LRC
|
|
private:
|
|
};
|
|
|
|
LINK_ENTITY_TO_CLASS( env_shake, CShake );
|
|
|
|
// pev->scale is amplitude
|
|
// pev->dmg_save is frequency
|
|
// pev->dmg_take is duration
|
|
// pev->dmg is radius
|
|
// radius of 0 means all players
|
|
// NOTE: UTIL_ScreenShake() will only shake players who are on the ground
|
|
|
|
#define SF_SHAKE_EVERYONE 0x0001 // Don't check radius
|
|
// UNDONE: These don't work yet
|
|
#define SF_SHAKE_DISRUPT 0x0002 // Disrupt controls
|
|
#define SF_SHAKE_INAIR 0x0004 // Shake players in air
|
|
|
|
void CShake::Spawn( void )
|
|
{
|
|
pev->solid = SOLID_NOT;
|
|
pev->movetype = MOVETYPE_NONE;
|
|
pev->frame = 0;
|
|
|
|
m_iState = STATE_OFF; //LRC
|
|
|
|
if ( pev->spawnflags & SF_SHAKE_EVERYONE )
|
|
pev->dmg = 0;
|
|
}
|
|
|
|
|
|
void CShake::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
|
|
CPointEntity::KeyValue( pkvd );
|
|
}
|
|
|
|
|
|
void CShake::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
UTIL_ScreenShake( pev->origin, Amplitude(), Frequency(), Duration(), Radius() );
|
|
m_iState = STATE_ON; //LRC
|
|
SetNextThink( Duration() ); //LRC
|
|
}
|
|
|
|
|
|
class CFade : public CPointEntity
|
|
{
|
|
public:
|
|
void Spawn( void );
|
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
void KeyValue( KeyValueData *pkvd );
|
|
|
|
virtual STATE GetState( void ) { return m_iState; }; // LRC
|
|
void Think( void ); //LRC
|
|
|
|
inline float Duration( void ) { return pev->dmg_take; }
|
|
inline float HoldTime( void ) { return pev->dmg_save; }
|
|
|
|
inline void SetDuration( float duration ) { pev->dmg_take = duration; }
|
|
inline void SetHoldTime( float hold ) { pev->dmg_save = hold; }
|
|
|
|
STATE m_iState; // LRC. Don't saverestore this value, it's not worth it.
|
|
private:
|
|
};
|
|
|
|
LINK_ENTITY_TO_CLASS( env_fade, CFade );
|
|
|
|
// pev->dmg_take is duration
|
|
// pev->dmg_save is hold duration
|
|
#define SF_FADE_IN 0x0001 // Fade in, not out
|
|
#define SF_FADE_MODULATE 0x0002 // Modulate, don't blend
|
|
#define SF_FADE_ONLYONE 0x0004
|
|
#define SF_FADE_PERMANENT 0x0008 //LRC - hold permanently
|
|
|
|
void CFade::Spawn( void )
|
|
{
|
|
pev->solid = SOLID_NOT;
|
|
pev->movetype = MOVETYPE_NONE;
|
|
pev->frame = 0;
|
|
|
|
m_iState = STATE_OFF; //LRC
|
|
}
|
|
|
|
|
|
void CFade::KeyValue( KeyValueData *pkvd )
|
|
{
|
|
if (FStrEq(pkvd->szKeyName, "duration"))
|
|
{
|
|
SetDuration( atof(pkvd->szValue) );
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "holdtime"))
|
|
{
|
|
SetHoldTime( atof(pkvd->szValue) );
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else
|
|
CPointEntity::KeyValue( pkvd );
|
|
}
|
|
|
|
|
|
void CFade::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
int fadeFlags = 0;
|
|
|
|
m_iState = STATE_TURN_ON; //LRC
|
|
SetNextThink( Duration() ); //LRC
|
|
|
|
if ( !(pev->spawnflags & SF_FADE_IN) )
|
|
fadeFlags |= FFADE_OUT;
|
|
|
|
if ( pev->spawnflags & SF_FADE_MODULATE )
|
|
fadeFlags |= FFADE_MODULATE;
|
|
|
|
if ( pev->spawnflags & SF_FADE_PERMANENT ) //LRC
|
|
fadeFlags |= FFADE_STAYOUT; //LRC
|
|
|
|
if ( pev->spawnflags & SF_FADE_ONLYONE )
|
|
{
|
|
if ( pActivator->IsNetClient() )
|
|
{
|
|
UTIL_ScreenFade( pActivator, pev->rendercolor, Duration(), HoldTime(), pev->renderamt, fadeFlags );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UTIL_ScreenFadeAll( pev->rendercolor, Duration(), HoldTime(), pev->renderamt, fadeFlags );
|
|
}
|
|
SUB_UseTargets( this, USE_TOGGLE, 0 );
|
|
}
|
|
|
|
//LRC: a bolt-on state!
|
|
void CFade::Think( void )
|
|
{
|
|
if (m_iState == STATE_TURN_ON)
|
|
{
|
|
m_iState = STATE_ON;
|
|
if (!( pev->spawnflags & SF_FADE_PERMANENT))
|
|
SetNextThink( HoldTime() );
|
|
}
|
|
else
|
|
m_iState = STATE_OFF;
|
|
}
|
|
|
|
|
|
class CMessage : public CPointEntity
|
|
{
|
|
public:
|
|
void Spawn( void );
|
|
void Precache( void );
|
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
void KeyValue( KeyValueData *pkvd );
|
|
private:
|
|
};
|
|
|
|
LINK_ENTITY_TO_CLASS( env_message, CMessage );
|
|
|
|
|
|
void CMessage::Spawn( void )
|
|
{
|
|
Precache();
|
|
|
|
pev->solid = SOLID_NOT;
|
|
pev->movetype = MOVETYPE_NONE;
|
|
|
|
switch( pev->impulse )
|
|
{
|
|
case 1: // Medium radius
|
|
pev->speed = ATTN_STATIC;
|
|
break;
|
|
|
|
case 2: // Large radius
|
|
pev->speed = ATTN_NORM;
|
|
break;
|
|
|
|
case 3: //EVERYWHERE
|
|
pev->speed = ATTN_NONE;
|
|
break;
|
|
|
|
default:
|
|
case 0: // Small radius
|
|
pev->speed = ATTN_IDLE;
|
|
break;
|
|
}
|
|
pev->impulse = 0;
|
|
|
|
// No volume, use normal
|
|
if ( pev->scale <= 0 )
|
|
pev->scale = 1.0;
|
|
}
|
|
|
|
|
|
void CMessage::Precache( void )
|
|
{
|
|
if ( pev->noise )
|
|
PRECACHE_SOUND( (char *)STRING(pev->noise) );
|
|
}
|
|
|
|
void CMessage::KeyValue( KeyValueData *pkvd )
|
|
{
|
|
if (FStrEq(pkvd->szKeyName, "messagesound"))
|
|
{
|
|
pev->noise = ALLOC_STRING(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "messagevolume"))
|
|
{
|
|
pev->scale = atof(pkvd->szValue) * 0.1;
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "messageattenuation"))
|
|
{
|
|
pev->impulse = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else
|
|
CPointEntity::KeyValue( pkvd );
|
|
}
|
|
|
|
|
|
void CMessage::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
CBaseEntity *pPlayer = NULL;
|
|
|
|
if ( pev->spawnflags & SF_MESSAGE_ALL )
|
|
UTIL_ShowMessageAll( STRING(pev->message) );
|
|
else
|
|
{
|
|
if ( pActivator && pActivator->IsPlayer() )
|
|
pPlayer = pActivator;
|
|
else
|
|
{
|
|
pPlayer = CBaseEntity::Instance( g_engfuncs.pfnPEntityOfEntIndex( 1 ) );
|
|
}
|
|
if ( pPlayer )
|
|
UTIL_ShowMessage( STRING(pev->message), pPlayer );
|
|
}
|
|
if ( pev->noise )
|
|
{
|
|
EMIT_SOUND( edict(), CHAN_BODY, STRING(pev->noise), pev->scale, pev->speed );
|
|
}
|
|
if ( pev->spawnflags & SF_MESSAGE_ONCE )
|
|
UTIL_Remove( this );
|
|
|
|
SUB_UseTargets( this, USE_TOGGLE, 0 );
|
|
}
|
|
|
|
|
|
|
|
//=========================================================
|
|
// FunnelEffect
|
|
//=========================================================
|
|
class CEnvFunnel : public CBaseDelay
|
|
{
|
|
public:
|
|
void Spawn( void );
|
|
void Precache( void );
|
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
|
|
int m_iSprite; // Don't save, precache
|
|
};
|
|
|
|
void CEnvFunnel :: Precache ( void )
|
|
{
|
|
//LRC
|
|
if (pev->netname)
|
|
m_iSprite = PRECACHE_MODEL ( (char*)STRING(pev->netname) );
|
|
else
|
|
m_iSprite = PRECACHE_MODEL ( "sprites/flare6.spr" );
|
|
}
|
|
|
|
LINK_ENTITY_TO_CLASS( env_funnel, CEnvFunnel );
|
|
|
|
void CEnvFunnel::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
//LRC
|
|
Vector vecPos;
|
|
if (pev->message)
|
|
vecPos = CalcLocus_Position( this, pActivator, STRING(pev->message) );
|
|
else
|
|
vecPos = pev->origin;
|
|
|
|
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
|
|
WRITE_BYTE( TE_LARGEFUNNEL );
|
|
WRITE_COORD( vecPos.x );
|
|
WRITE_COORD( vecPos.y );
|
|
WRITE_COORD( vecPos.z );
|
|
WRITE_SHORT( m_iSprite );
|
|
|
|
if ( pev->spawnflags & SF_FUNNEL_REVERSE )// funnel flows in reverse?
|
|
{
|
|
WRITE_SHORT( 1 );
|
|
}
|
|
else
|
|
{
|
|
WRITE_SHORT( 0 );
|
|
}
|
|
|
|
|
|
MESSAGE_END();
|
|
|
|
if (!(pev->spawnflags & SF_FUNNEL_REPEATABLE))
|
|
{
|
|
SetThink(&CEnvFunnel:: SUB_Remove );
|
|
SetNextThink( 0 );
|
|
}
|
|
}
|
|
|
|
void CEnvFunnel::Spawn( void )
|
|
{
|
|
Precache();
|
|
pev->solid = SOLID_NOT;
|
|
pev->effects |= EF_NODRAW;
|
|
}
|
|
|
|
|
|
//=========================================================
|
|
// LRC - All the particle effects from Quake 1
|
|
//=========================================================
|
|
#define SF_QUAKEFX_REPEATABLE 1
|
|
class CEnvQuakeFx : public CPointEntity
|
|
{
|
|
public:
|
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
};
|
|
|
|
LINK_ENTITY_TO_CLASS( env_quakefx, CEnvQuakeFx );
|
|
|
|
void CEnvQuakeFx::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
Vector vecPos;
|
|
if (pev->message)
|
|
vecPos = CalcLocus_Position( this, pActivator, STRING(pev->message) );
|
|
else
|
|
vecPos = pev->origin;
|
|
|
|
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
|
|
WRITE_BYTE( pev->impulse );
|
|
WRITE_COORD( vecPos.x );
|
|
WRITE_COORD( vecPos.y );
|
|
WRITE_COORD( vecPos.z );
|
|
if (pev->impulse == TE_PARTICLEBURST)
|
|
{
|
|
WRITE_SHORT( pev->armortype ); // radius
|
|
WRITE_BYTE( pev->frags ); // particle colour
|
|
WRITE_BYTE( pev->health * 10 ); // duration
|
|
}
|
|
else if (pev->impulse == TE_EXPLOSION2)
|
|
{
|
|
// these fields seem to have no effect - except that it
|
|
// crashes when I send "0" for the number of colours..
|
|
WRITE_BYTE( 0 ); // colour
|
|
WRITE_BYTE( 1 ); // number of colours
|
|
}
|
|
MESSAGE_END();
|
|
|
|
if (!(pev->spawnflags & SF_QUAKEFX_REPEATABLE))
|
|
{
|
|
SetThink(&CEnvQuakeFx:: SUB_Remove );
|
|
SetNextThink( 0 );
|
|
}
|
|
}
|
|
|
|
|
|
//=========================================================
|
|
// LRC - Beam Trail effect
|
|
//=========================================================
|
|
#define SF_BEAMTRAIL_OFF 1
|
|
class CEnvBeamTrail : public CPointEntity
|
|
{
|
|
public:
|
|
void Spawn( void );
|
|
void Precache( void );
|
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
STATE GetState( void );
|
|
void EXPORT StartTrailThink ( void );
|
|
void Affect( CBaseEntity *pTarget, USE_TYPE useType );
|
|
|
|
int m_iSprite; // Don't save, precache
|
|
};
|
|
|
|
void CEnvBeamTrail :: Precache ( void )
|
|
{
|
|
if (pev->target)
|
|
PRECACHE_MODEL("sprites/null.spr");
|
|
if (pev->netname)
|
|
m_iSprite = PRECACHE_MODEL ( (char*)STRING(pev->netname) );
|
|
}
|
|
|
|
LINK_ENTITY_TO_CLASS( env_beamtrail, CEnvBeamTrail );
|
|
|
|
STATE CEnvBeamTrail :: GetState ( void )
|
|
{
|
|
if (pev->spawnflags & SF_BEAMTRAIL_OFF)
|
|
return STATE_OFF;
|
|
else
|
|
return STATE_ON;
|
|
}
|
|
|
|
void CEnvBeamTrail :: StartTrailThink ( void )
|
|
{
|
|
pev->spawnflags |= SF_BEAMTRAIL_OFF; // fake turning off, so the Use turns it on properly
|
|
Use(this, this, USE_ON, 0);
|
|
}
|
|
|
|
void CEnvBeamTrail::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
if (pev->target)
|
|
{
|
|
CBaseEntity *pTarget = UTIL_FindEntityByTargetname(NULL, STRING(pev->target), pActivator );
|
|
while (pTarget)
|
|
{
|
|
Affect(pTarget, useType);
|
|
pTarget = UTIL_FindEntityByTargetname(pTarget, STRING(pev->target), pActivator );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!ShouldToggle( useType ))
|
|
return;
|
|
Affect(this, useType);
|
|
}
|
|
|
|
if (useType == USE_ON)
|
|
pev->spawnflags &= ~SF_BEAMTRAIL_OFF;
|
|
else if (useType == USE_OFF)
|
|
pev->spawnflags |= SF_BEAMTRAIL_OFF;
|
|
else if (useType == USE_TOGGLE)
|
|
{
|
|
if (pev->spawnflags & SF_BEAMTRAIL_OFF)
|
|
pev->spawnflags &= ~SF_BEAMTRAIL_OFF;
|
|
else
|
|
pev->spawnflags |= SF_BEAMTRAIL_OFF;
|
|
}
|
|
}
|
|
|
|
void CEnvBeamTrail::Affect( CBaseEntity *pTarget, USE_TYPE useType )
|
|
{
|
|
if (useType == USE_ON || pev->spawnflags & SF_BEAMTRAIL_OFF)
|
|
{
|
|
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
|
|
WRITE_BYTE( TE_BEAMFOLLOW );
|
|
WRITE_SHORT(pTarget->entindex()); // entity
|
|
WRITE_SHORT( m_iSprite ); // model
|
|
WRITE_BYTE( pev->health*10 ); // life
|
|
WRITE_BYTE( pev->armorvalue ); // width
|
|
WRITE_BYTE( pev->rendercolor.x ); // r, g, b
|
|
WRITE_BYTE( pev->rendercolor.y ); // r, g, b
|
|
WRITE_BYTE( pev->rendercolor.z ); // r, g, b
|
|
WRITE_BYTE( pev->renderamt ); // brightness
|
|
MESSAGE_END();
|
|
}
|
|
else
|
|
{
|
|
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
|
|
WRITE_BYTE(TE_KILLBEAM);
|
|
WRITE_SHORT(pTarget->entindex());
|
|
MESSAGE_END();
|
|
}
|
|
}
|
|
|
|
void CEnvBeamTrail::Spawn( void )
|
|
{
|
|
Precache();
|
|
|
|
SET_MODEL(ENT(pev), "sprites/null.spr");
|
|
UTIL_SetSize(pev, Vector(0, 0, 0), Vector(0, 0, 0));
|
|
|
|
if (!(pev->spawnflags & SF_BEAMTRAIL_OFF))
|
|
{
|
|
SetThink(&CEnvBeamTrail::StartTrailThink);
|
|
UTIL_DesiredThink( this );
|
|
}
|
|
}
|
|
|
|
//=========================================================
|
|
//LRC- the long-awaited effect. (Rain, in the desert? :)
|
|
//
|
|
//FIXME: give designers a _lot_ more control.
|
|
//=========================================================
|
|
#define MAX_RAIN_BEAMS 32
|
|
|
|
#define AXIS_X 1
|
|
#define AXIS_Y 2
|
|
#define AXIS_Z 0
|
|
|
|
#define EXTENT_OBSTRUCTED 1
|
|
#define EXTENT_ARCING 2
|
|
#define EXTENT_OBSTRUCTED_REVERSE 3
|
|
#define EXTENT_ARCING_REVERSE 4
|
|
#define EXTENT_ARCING_THROUGH 5 //AJH
|
|
|
|
class CEnvRain : public CBaseEntity
|
|
{
|
|
public:
|
|
void Spawn( void );
|
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
void Think( void );
|
|
void Precache( void );
|
|
void KeyValue( KeyValueData *pkvd );
|
|
virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
|
|
|
|
virtual int Save( CSave &save );
|
|
virtual int Restore( CRestore &restore );
|
|
static TYPEDESCRIPTION m_SaveData[];
|
|
|
|
STATE m_iState;
|
|
int m_spriteTexture;
|
|
int m_iszSpriteName; // have to saverestore this, the beams keep a link to it
|
|
int m_dripSize;
|
|
int m_minDripSpeed;
|
|
int m_maxDripSpeed;
|
|
int m_burstSize;
|
|
int m_brightness;
|
|
int m_pitch; // don't saverestore this
|
|
float m_flUpdateTime;
|
|
float m_flMaxUpdateTime;
|
|
// CBeam* m_pBeams[MAX_RAIN_BEAMS];
|
|
int m_axis;
|
|
int m_iExtent;
|
|
float m_fLifeTime;
|
|
int m_iNoise;
|
|
|
|
virtual STATE GetState( void ) { return m_iState; };
|
|
};
|
|
|
|
LINK_ENTITY_TO_CLASS( env_rain, CEnvRain );
|
|
|
|
TYPEDESCRIPTION CEnvRain::m_SaveData[] =
|
|
{
|
|
DEFINE_FIELD( CEnvRain, m_iState, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CEnvRain, m_spriteTexture, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CEnvRain, m_dripSize, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CEnvRain, m_minDripSpeed, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CEnvRain, m_maxDripSpeed, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CEnvRain, m_burstSize, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CEnvRain, m_brightness, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CEnvRain, m_flUpdateTime, FIELD_FLOAT ),
|
|
DEFINE_FIELD( CEnvRain, m_flMaxUpdateTime, FIELD_FLOAT ),
|
|
DEFINE_FIELD( CEnvRain, m_iszSpriteName, FIELD_STRING ),
|
|
DEFINE_FIELD( CEnvRain, m_axis, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CEnvRain, m_iExtent, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CEnvRain, m_fLifeTime, FIELD_FLOAT ),
|
|
DEFINE_FIELD( CEnvRain, m_iNoise, FIELD_INTEGER ),
|
|
// DEFINE_FIELD( CEnvRain, m_pBeams, FIELD_CLASSPTR, MAX_RAIN_BEAMS ),
|
|
};
|
|
|
|
IMPLEMENT_SAVERESTORE( CEnvRain, CBaseEntity );
|
|
|
|
void CEnvRain::Precache( void )
|
|
{
|
|
m_spriteTexture = PRECACHE_MODEL( (char *)STRING(m_iszSpriteName) );
|
|
}
|
|
|
|
void CEnvRain::KeyValue( KeyValueData *pkvd )
|
|
{
|
|
if (FStrEq(pkvd->szKeyName, "m_dripSize"))
|
|
{
|
|
m_dripSize = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_burstSize"))
|
|
{
|
|
m_burstSize = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_dripSpeed"))
|
|
{
|
|
int temp = atoi(pkvd->szValue);
|
|
m_maxDripSpeed = temp + (temp/4);
|
|
m_minDripSpeed = temp - (temp/4);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_brightness"))
|
|
{
|
|
m_brightness = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_flUpdateTime"))
|
|
{
|
|
m_flUpdateTime = atof(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_flMaxUpdateTime"))
|
|
{
|
|
m_flMaxUpdateTime = atof(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "pitch"))
|
|
{
|
|
m_pitch = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "texture"))
|
|
{
|
|
m_iszSpriteName = ALLOC_STRING(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_axis"))
|
|
{
|
|
m_axis = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_iExtent"))
|
|
{
|
|
m_iExtent = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_fLifeTime"))
|
|
{
|
|
m_fLifeTime = atof(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_iNoise"))
|
|
{
|
|
m_iNoise = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else
|
|
CBaseEntity::KeyValue( pkvd );
|
|
}
|
|
|
|
void CEnvRain::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
if (!ShouldToggle(useType)) return;
|
|
|
|
if (m_iState == STATE_ON)
|
|
{
|
|
m_iState = STATE_OFF;
|
|
DontThink();
|
|
}
|
|
else
|
|
{
|
|
m_iState = STATE_ON;
|
|
SetNextThink( 0.1 );
|
|
}
|
|
}
|
|
|
|
#define SF_RAIN_START_OFF 1
|
|
|
|
void CEnvRain::Spawn( void )
|
|
{
|
|
Precache();
|
|
SET_MODEL( ENT(pev), STRING(pev->model) ); // Set size
|
|
pev->solid = SOLID_NOT;
|
|
pev->effects |= EF_NODRAW;
|
|
|
|
if (pev->rendercolor == g_vecZero)
|
|
pev->rendercolor = Vector(255,255,255);
|
|
|
|
if (m_pitch)
|
|
pev->angles.x = m_pitch;
|
|
else if (pev->angles.x == 0) // don't allow horizontal rain.
|
|
pev->angles.x = 90;
|
|
|
|
if (m_burstSize == 0) // in case the level designer forgot to set it.
|
|
m_burstSize = 2;
|
|
|
|
if (pev->spawnflags & SF_RAIN_START_OFF)
|
|
m_iState = STATE_OFF;
|
|
else
|
|
{
|
|
m_iState = STATE_ON;
|
|
SetNextThink( 0.1 );
|
|
}
|
|
}
|
|
|
|
void CEnvRain::Think( void )
|
|
{
|
|
// ALERT(at_console,"RainThink %d %d %d %s\n",m_spriteTexture,m_dripSize,m_brightness,STRING(m_iszSpriteName));
|
|
Vector vecSrc;
|
|
Vector vecDest;
|
|
|
|
UTIL_MakeVectors(pev->angles);
|
|
Vector vecOffs = gpGlobals->v_forward;
|
|
switch (m_axis)
|
|
{
|
|
case AXIS_X:
|
|
vecOffs = vecOffs * (pev->size.x / vecOffs.x);
|
|
break;
|
|
case AXIS_Y:
|
|
vecOffs = vecOffs * (pev->size.y / vecOffs.y);
|
|
break;
|
|
case AXIS_Z:
|
|
vecOffs = vecOffs * (pev->size.z / vecOffs.z);
|
|
break;
|
|
}
|
|
|
|
// ALERT(at_console,"RainThink offs.z = %f, size.z = %f\n",vecOffs.z,pev->size.z);
|
|
|
|
int repeats;
|
|
if (!m_fLifeTime && !m_flUpdateTime && !m_flMaxUpdateTime)
|
|
repeats = m_burstSize * 3;
|
|
else
|
|
repeats = m_burstSize;
|
|
|
|
int drawn = 0;
|
|
int tries = 0;
|
|
TraceResult tr;
|
|
BOOL bDraw;
|
|
|
|
while (drawn < repeats && tries < (repeats*3))
|
|
{
|
|
tries++;
|
|
if (m_axis == AXIS_X)
|
|
vecSrc.x = pev->maxs.x;
|
|
else
|
|
vecSrc.x = pev->mins.x + RANDOM_LONG(0, pev->size.x);
|
|
if (m_axis == AXIS_Y)
|
|
vecSrc.y = pev->maxs.y;
|
|
else
|
|
vecSrc.y = pev->mins.y + RANDOM_LONG(0, pev->size.y);
|
|
if (m_axis == AXIS_Z)
|
|
vecSrc.z = pev->maxs.z;
|
|
else
|
|
vecSrc.z = pev->mins.z + RANDOM_LONG(0, pev->size.z);
|
|
vecDest = vecSrc - vecOffs;
|
|
bDraw = TRUE;
|
|
|
|
switch (m_iExtent)
|
|
{
|
|
case EXTENT_OBSTRUCTED:
|
|
UTIL_TraceLine( vecSrc, vecDest, ignore_monsters, NULL, &tr);
|
|
vecDest = tr.vecEndPos;
|
|
break;
|
|
case EXTENT_OBSTRUCTED_REVERSE:
|
|
UTIL_TraceLine( vecDest, vecSrc, ignore_monsters, NULL, &tr);
|
|
vecSrc = tr.vecEndPos;
|
|
break;
|
|
case EXTENT_ARCING:
|
|
UTIL_TraceLine( vecSrc, vecDest, ignore_monsters, NULL, &tr);
|
|
if (tr.flFraction == 1.0) bDraw = FALSE;
|
|
vecDest = tr.vecEndPos;
|
|
break;
|
|
case EXTENT_ARCING_THROUGH: //AJH - Arcs full length of brush only when blocked
|
|
UTIL_TraceLine( vecDest, vecSrc, dont_ignore_monsters, NULL, &tr);
|
|
if (tr.flFraction == 1.0) bDraw = FALSE;
|
|
break;
|
|
case EXTENT_ARCING_REVERSE:
|
|
UTIL_TraceLine( vecDest, vecSrc, ignore_monsters, NULL, &tr);
|
|
if (tr.flFraction == 1.0) bDraw = FALSE;
|
|
vecSrc = tr.vecEndPos;
|
|
break;
|
|
}
|
|
// vecDest.z = pev->mins.z;
|
|
if (!bDraw) continue;
|
|
|
|
drawn++;
|
|
|
|
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
|
|
WRITE_BYTE( TE_BEAMPOINTS );
|
|
WRITE_COORD(vecDest.x);
|
|
WRITE_COORD(vecDest.y);
|
|
WRITE_COORD(vecDest.z);
|
|
WRITE_COORD(vecSrc.x);
|
|
WRITE_COORD(vecSrc.y);
|
|
WRITE_COORD(vecSrc.z);
|
|
WRITE_SHORT( m_spriteTexture );
|
|
WRITE_BYTE( (int)0 ); // framestart
|
|
WRITE_BYTE( (int)0 ); // framerate
|
|
if (m_fLifeTime) // life
|
|
WRITE_BYTE( (int)(m_fLifeTime*10) );
|
|
else if (m_flMaxUpdateTime)
|
|
WRITE_BYTE( (int)( RANDOM_FLOAT(m_flUpdateTime, m_flMaxUpdateTime)*30 ));
|
|
else
|
|
WRITE_BYTE( (int)(m_flUpdateTime * 30) ); // life
|
|
WRITE_BYTE( m_dripSize ); // width
|
|
WRITE_BYTE( m_iNoise ); // noise
|
|
WRITE_BYTE( (int)pev->rendercolor.x ); // r,
|
|
WRITE_BYTE( (int)pev->rendercolor.y ); // g,
|
|
WRITE_BYTE( (int)pev->rendercolor.z ); // b
|
|
WRITE_BYTE( m_brightness ); // brightness
|
|
WRITE_BYTE( (int)RANDOM_LONG(m_minDripSpeed,m_maxDripSpeed) ); // speed
|
|
MESSAGE_END();
|
|
}
|
|
|
|
// drawn will be false if we didn't draw anything.
|
|
if (pev->target && drawn)
|
|
FireTargets(STRING(pev->target), this, this, USE_TOGGLE, 0);
|
|
|
|
if (m_flMaxUpdateTime)
|
|
SetNextThink( RANDOM_FLOAT(m_flMaxUpdateTime, m_flUpdateTime) );
|
|
else if (m_flUpdateTime)
|
|
SetNextThink( m_flUpdateTime );
|
|
}
|
|
|
|
//==================================================================
|
|
//LRC- Xen monsters' warp-in effect, for those too lazy to build it. :)
|
|
//==================================================================
|
|
class CEnvWarpBall : public CBaseEntity
|
|
{
|
|
public:
|
|
void Precache( void );
|
|
void Spawn( void ) { Precache(); }
|
|
void Think( void );
|
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
|
|
};
|
|
|
|
LINK_ENTITY_TO_CLASS( env_warpball, CEnvWarpBall );
|
|
|
|
void CEnvWarpBall::Precache( void )
|
|
{
|
|
PRECACHE_MODEL( "sprites/lgtning.spr" );
|
|
PRECACHE_MODEL( "sprites/Fexplo1.spr" );
|
|
PRECACHE_MODEL( "sprites/XFlare1.spr" );
|
|
PRECACHE_SOUND( "debris/beamstart2.wav" );
|
|
PRECACHE_SOUND( "debris/beamstart7.wav" );
|
|
}
|
|
|
|
void CEnvWarpBall::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
int iTimes = 0;
|
|
int iDrawn = 0;
|
|
TraceResult tr;
|
|
Vector vecDest;
|
|
CBeam *pBeam;
|
|
while (iDrawn<pev->frags && iTimes<(pev->frags * 3)) // try to draw <frags> beams, but give up after 3x<frags> tries.
|
|
{
|
|
vecDest = pev->health * (Vector(RANDOM_FLOAT(-1,1), RANDOM_FLOAT(-1,1), RANDOM_FLOAT(-1,1)).Normalize());
|
|
UTIL_TraceLine( pev->origin, pev->origin + vecDest, ignore_monsters, NULL, &tr);
|
|
if (tr.flFraction != 1.0)
|
|
{
|
|
// we hit something.
|
|
iDrawn++;
|
|
pBeam = CBeam::BeamCreate("sprites/lgtning.spr",200);
|
|
pBeam->PointsInit( pev->origin, tr.vecEndPos );
|
|
pBeam->SetColor( 197, 243, 169 );
|
|
pBeam->SetNoise( 65 );
|
|
pBeam->SetBrightness( 150 );
|
|
pBeam->SetWidth( 18 );
|
|
pBeam->SetScrollRate( 35 );
|
|
pBeam->SetThink(&CBeam:: SUB_Remove );
|
|
pBeam->SetNextThink( 1 );
|
|
}
|
|
iTimes++;
|
|
}
|
|
EMIT_SOUND( edict(), CHAN_BODY, "debris/beamstart2.wav", 1, ATTN_NORM );
|
|
|
|
CSprite *pSpr = CSprite::SpriteCreate( "sprites/Fexplo1.spr", pev->origin, TRUE );
|
|
pSpr->AnimateAndDie( 10 );
|
|
pSpr->SetTransparency(kRenderGlow, 77, 210, 130, 255, kRenderFxNoDissipation);
|
|
|
|
pSpr = CSprite::SpriteCreate( "sprites/XFlare1.spr", pev->origin, TRUE );
|
|
pSpr->AnimateAndDie( 10 );
|
|
pSpr->SetTransparency(kRenderGlow, 184, 250, 214, 255, kRenderFxNoDissipation);
|
|
|
|
SetNextThink( 0.5 );
|
|
}
|
|
|
|
void CEnvWarpBall::Think( void )
|
|
{
|
|
EMIT_SOUND( edict(), CHAN_ITEM, "debris/beamstart7.wav", 1, ATTN_NORM );
|
|
SUB_UseTargets( this, USE_TOGGLE, 0);
|
|
}
|
|
|
|
//==================================================================
|
|
//LRC- Shockwave effect, like when a Houndeye attacks.
|
|
//==================================================================
|
|
#define SF_SHOCKWAVE_CENTERED 1
|
|
#define SF_SHOCKWAVE_REPEATABLE 2
|
|
|
|
class CEnvShockwave : public CPointEntity
|
|
{
|
|
public:
|
|
void Precache( void );
|
|
void Spawn( void ) { Precache(); }
|
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
void KeyValue( KeyValueData *pkvd );
|
|
virtual int Save( CSave &save );
|
|
virtual int Restore( CRestore &restore );
|
|
static TYPEDESCRIPTION m_SaveData[];
|
|
|
|
void DoEffect( Vector vecPos );
|
|
|
|
int m_iTime;
|
|
int m_iRadius;
|
|
int m_iHeight;
|
|
int m_iScrollRate;
|
|
int m_iNoise;
|
|
int m_iFrameRate;
|
|
int m_iStartFrame;
|
|
int m_iSpriteTexture;
|
|
char m_cType;
|
|
int m_iszPosition;
|
|
};
|
|
|
|
LINK_ENTITY_TO_CLASS( env_shockwave, CEnvShockwave );
|
|
|
|
TYPEDESCRIPTION CEnvShockwave::m_SaveData[] =
|
|
{
|
|
DEFINE_FIELD( CEnvShockwave, m_iHeight, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CEnvShockwave, m_iTime, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CEnvShockwave, m_iRadius, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CEnvShockwave, m_iScrollRate, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CEnvShockwave, m_iNoise, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CEnvShockwave, m_iFrameRate, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CEnvShockwave, m_iStartFrame, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CEnvShockwave, m_iSpriteTexture, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CEnvShockwave, m_cType, FIELD_CHARACTER ),
|
|
DEFINE_FIELD( CEnvShockwave, m_iszPosition, FIELD_STRING ),
|
|
};
|
|
|
|
IMPLEMENT_SAVERESTORE( CEnvShockwave, CBaseEntity );
|
|
|
|
void CEnvShockwave::Precache( void )
|
|
{
|
|
m_iSpriteTexture = PRECACHE_MODEL( (char *)STRING(pev->netname) );
|
|
}
|
|
|
|
void CEnvShockwave::KeyValue( KeyValueData *pkvd )
|
|
{
|
|
if (FStrEq(pkvd->szKeyName, "m_iTime"))
|
|
{
|
|
m_iTime = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_iRadius"))
|
|
{
|
|
m_iRadius = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_iHeight"))
|
|
{
|
|
m_iHeight = atoi(pkvd->szValue)/2; //LRC- the actual height is doubled when drawn
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_iScrollRate"))
|
|
{
|
|
m_iScrollRate = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_iNoise"))
|
|
{
|
|
m_iNoise = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_iFrameRate"))
|
|
{
|
|
m_iFrameRate = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_iStartFrame"))
|
|
{
|
|
m_iStartFrame = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_iszPosition"))
|
|
{
|
|
m_iszPosition = ALLOC_STRING(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_cType"))
|
|
{
|
|
m_cType = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else
|
|
CBaseEntity::KeyValue( pkvd );
|
|
}
|
|
|
|
void CEnvShockwave::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
Vector vecPos;
|
|
if (m_iszPosition)
|
|
vecPos = CalcLocus_Position( this, pActivator, STRING(m_iszPosition) );
|
|
else
|
|
vecPos = pev->origin;
|
|
|
|
if (!(pev->spawnflags & SF_SHOCKWAVE_CENTERED))
|
|
vecPos.z += m_iHeight;
|
|
|
|
// blast circle
|
|
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
|
|
if (m_cType)
|
|
WRITE_BYTE( m_cType );
|
|
else
|
|
WRITE_BYTE( TE_BEAMCYLINDER );
|
|
WRITE_COORD( vecPos.x );// coord coord coord (center position)
|
|
WRITE_COORD( vecPos.y );
|
|
WRITE_COORD( vecPos.z );
|
|
WRITE_COORD( vecPos.x );// coord coord coord (axis and radius)
|
|
WRITE_COORD( vecPos.y );
|
|
WRITE_COORD( vecPos.z + m_iRadius );
|
|
WRITE_SHORT( m_iSpriteTexture ); // short (sprite index)
|
|
WRITE_BYTE( m_iStartFrame ); // byte (starting frame)
|
|
WRITE_BYTE( m_iFrameRate ); // byte (frame rate in 0.1's)
|
|
WRITE_BYTE( m_iTime ); // byte (life in 0.1's)
|
|
WRITE_BYTE( m_iHeight ); // byte (line width in 0.1's)
|
|
WRITE_BYTE( m_iNoise ); // byte (noise amplitude in 0.01's)
|
|
WRITE_BYTE( pev->rendercolor.x ); // byte,byte,byte (color)
|
|
WRITE_BYTE( pev->rendercolor.y );
|
|
WRITE_BYTE( pev->rendercolor.z );
|
|
WRITE_BYTE( pev->renderamt ); // byte (brightness)
|
|
WRITE_BYTE( m_iScrollRate ); // byte (scroll speed in 0.1's)
|
|
MESSAGE_END();
|
|
|
|
if (!(pev->spawnflags & SF_SHOCKWAVE_REPEATABLE))
|
|
{
|
|
SetThink(&CEnvShockwave:: SUB_Remove );
|
|
SetNextThink( 0 );
|
|
}
|
|
}
|
|
|
|
//==================================================================
|
|
//LRC- env_dlight; Dynamic Entity Light creator
|
|
//==================================================================
|
|
#define SF_DLIGHT_ONLYONCE 1
|
|
#define SF_DLIGHT_STARTON 2
|
|
class CEnvDLight : public CPointEntity
|
|
{
|
|
public:
|
|
void PostSpawn( void );
|
|
virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
void Think( void );
|
|
void DesiredAction( void );
|
|
virtual void MakeLight( int iTime );
|
|
virtual int Save( CSave &save );
|
|
virtual int Restore( CRestore &restore );
|
|
static TYPEDESCRIPTION m_SaveData[];
|
|
STATE GetState( void )
|
|
{
|
|
if (pev->spawnflags & SF_DLIGHT_STARTON)
|
|
return STATE_ON;
|
|
else
|
|
return STATE_OFF;
|
|
}
|
|
|
|
Vector m_vecPos;
|
|
int m_iKey;
|
|
static int ms_iNextFreeKey;
|
|
};
|
|
|
|
LINK_ENTITY_TO_CLASS( env_dlight, CEnvDLight );
|
|
|
|
TYPEDESCRIPTION CEnvDLight::m_SaveData[] =
|
|
{
|
|
DEFINE_FIELD( CEnvDLight, m_vecPos, FIELD_VECTOR ),
|
|
DEFINE_FIELD( CEnvDLight, m_iKey, FIELD_INTEGER ),
|
|
};
|
|
|
|
IMPLEMENT_SAVERESTORE( CEnvDLight, CPointEntity );
|
|
|
|
int CEnvDLight::ms_iNextFreeKey = 1;
|
|
|
|
void CEnvDLight::PostSpawn( void )
|
|
{
|
|
// each env_dlight uses its own key to reference the light on the client
|
|
m_iKey = ms_iNextFreeKey;
|
|
ms_iNextFreeKey++;
|
|
|
|
if (FStringNull(pev->targetname) || pev->spawnflags & SF_DLIGHT_STARTON)
|
|
{
|
|
UTIL_DesiredAction(this);
|
|
}
|
|
}
|
|
|
|
void CEnvDLight::DesiredAction( void )
|
|
{
|
|
pev->spawnflags &= ~SF_DLIGHT_STARTON;
|
|
Use(this, this, USE_ON, 0);
|
|
}
|
|
|
|
void CEnvDLight::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
if (!ShouldToggle(useType))
|
|
{
|
|
return;
|
|
}
|
|
if (GetState() == STATE_ON)
|
|
{
|
|
// turn off
|
|
MakeLight(false);
|
|
pev->spawnflags &= ~SF_DLIGHT_STARTON;
|
|
DontThink();
|
|
return;
|
|
}
|
|
|
|
if (pev->message)
|
|
{
|
|
m_vecPos = CalcLocus_Position( this, pActivator, STRING(pev->message) );
|
|
}
|
|
else
|
|
{
|
|
m_vecPos = pev->origin;
|
|
}
|
|
|
|
// turn on
|
|
MakeLight(true);
|
|
pev->spawnflags |= SF_DLIGHT_STARTON;
|
|
|
|
if (pev->health)
|
|
{
|
|
SetNextThink(pev->health);
|
|
}
|
|
else
|
|
{
|
|
if (pev->spawnflags & SF_DLIGHT_ONLYONCE)
|
|
{
|
|
SetThink( SUB_Remove );
|
|
SetNextThink( 0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
extern int gmsgKeyedDLight;
|
|
|
|
void CEnvDLight::MakeLight( BOOL bActive)
|
|
{
|
|
MESSAGE_BEGIN( MSG_ALL, gmsgKeyedDLight, NULL );
|
|
WRITE_BYTE( m_iKey );
|
|
WRITE_BYTE( bActive ); // visible?
|
|
if (bActive)
|
|
{
|
|
WRITE_COORD( m_vecPos.x ); // X
|
|
WRITE_COORD( m_vecPos.y ); // Y
|
|
WRITE_COORD( m_vecPos.z ); // Z
|
|
WRITE_BYTE( pev->renderamt ); // radius * 0.1
|
|
WRITE_BYTE( pev->rendercolor.x ); // r
|
|
WRITE_BYTE( pev->rendercolor.y ); // g
|
|
WRITE_BYTE( pev->rendercolor.z ); // b
|
|
}
|
|
MESSAGE_END();
|
|
}
|
|
|
|
void CEnvDLight::Think( void )
|
|
{
|
|
// turn off the light
|
|
MakeLight( false );
|
|
pev->spawnflags &= ~SF_DLIGHT_STARTON;
|
|
|
|
if (pev->spawnflags & SF_DLIGHT_ONLYONCE)
|
|
{
|
|
SetThink( SUB_Remove );
|
|
SetNextThink( 0 );
|
|
}
|
|
}
|
|
|
|
//==================================================================
|
|
//LRC- env_elight; Dynamic Entity Light creator
|
|
//==================================================================
|
|
class CEnvELight : public CEnvDLight
|
|
{
|
|
public:
|
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
void MakeLight(int iTime);
|
|
virtual int Save( CSave &save );
|
|
virtual int Restore( CRestore &restore );
|
|
static TYPEDESCRIPTION m_SaveData[];
|
|
|
|
EHANDLE m_hAttach;
|
|
};
|
|
|
|
LINK_ENTITY_TO_CLASS( env_elight, CEnvELight );
|
|
|
|
TYPEDESCRIPTION CEnvELight::m_SaveData[] =
|
|
{
|
|
DEFINE_FIELD( CEnvELight, m_hAttach, FIELD_EHANDLE ),
|
|
};
|
|
|
|
IMPLEMENT_SAVERESTORE( CEnvELight, CEnvDLight );
|
|
|
|
void CEnvELight::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
if (pev->target)
|
|
{
|
|
m_hAttach = UTIL_FindEntityByTargetname( NULL, STRING(pev->target), pActivator);
|
|
if (m_hAttach == NULL)
|
|
{
|
|
ALERT(at_console, "env_elight \"%s\" can't find target %s\n", STRING(pev->targetname), STRING(pev->target));
|
|
return; // error?
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_hAttach = this;
|
|
}
|
|
|
|
CEnvDLight::Use(pActivator, pCaller, useType, value);
|
|
}
|
|
|
|
void CEnvELight::MakeLight(int iTime)
|
|
{
|
|
if (m_hAttach == NULL)
|
|
{
|
|
DontThink();
|
|
pev->takedamage = 0;
|
|
return;
|
|
}
|
|
|
|
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
|
|
WRITE_BYTE( TE_ELIGHT );
|
|
WRITE_SHORT( m_hAttach->entindex( ) + 0x1000 * pev->impulse ); // entity, attachment
|
|
WRITE_COORD( m_vecPos.x ); // X
|
|
WRITE_COORD( m_vecPos.y ); // Y
|
|
WRITE_COORD( m_vecPos.z ); // Z
|
|
WRITE_COORD( pev->renderamt ); // radius * 0.1
|
|
WRITE_BYTE( pev->rendercolor.x ); // r
|
|
WRITE_BYTE( pev->rendercolor.y ); // g
|
|
WRITE_BYTE( pev->rendercolor.z ); // b
|
|
WRITE_BYTE( iTime ); // time * 10
|
|
WRITE_COORD( pev->frags ); // decay * 0.1
|
|
MESSAGE_END( );
|
|
}
|
|
|
|
//=========================================================
|
|
// Beverage Dispenser
|
|
// overloaded pev->frags, is now a flag for whether or not a can is stuck in the dispenser.
|
|
// overloaded pev->health, is now how many cans remain in the machine.
|
|
//=========================================================
|
|
class CEnvBeverage : public CBaseDelay
|
|
{
|
|
public:
|
|
void Spawn( void );
|
|
void Precache( void );
|
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
|
|
// it's 'on' while there are cans left
|
|
virtual STATE GetState( void ) { return (pev->health > 0)?STATE_ON:STATE_OFF; };
|
|
};
|
|
|
|
void CEnvBeverage :: Precache ( void )
|
|
{
|
|
PRECACHE_MODEL( "models/can.mdl" );
|
|
PRECACHE_SOUND( "weapons/g_bounce3.wav" );
|
|
}
|
|
|
|
LINK_ENTITY_TO_CLASS( env_beverage, CEnvBeverage );
|
|
|
|
void CEnvBeverage::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
if ( pev->frags != 0 || pev->health <= 0 )
|
|
{
|
|
// no more cans while one is waiting in the dispenser, or if I'm out of cans.
|
|
return;
|
|
}
|
|
|
|
Vector vecPos;
|
|
if (pev->target)
|
|
vecPos = CalcLocus_Position( this, pActivator, STRING(pev->target) );
|
|
else
|
|
vecPos = pev->origin;
|
|
|
|
CBaseEntity *pCan = CBaseEntity::Create( "item_sodacan", vecPos, pev->angles, edict() );
|
|
|
|
if ( pev->skin == 6 )
|
|
{
|
|
// random
|
|
pCan->pev->skin = RANDOM_LONG( 0, 5 );
|
|
}
|
|
else
|
|
{
|
|
pCan->pev->skin = pev->skin;
|
|
}
|
|
|
|
pev->frags = 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;
|
|
}
|
|
}
|
|
|
|
//=========================================================
|
|
// Soda can
|
|
//=========================================================
|
|
class CItemSoda : public CBaseEntity
|
|
{
|
|
public:
|
|
void Spawn( void );
|
|
void Precache( void );
|
|
void EXPORT CanThink ( void );
|
|
void EXPORT CanTouch ( CBaseEntity *pOther );
|
|
};
|
|
|
|
void CItemSoda :: Precache ( void )
|
|
{
|
|
// added for Nemo1024 --LRC
|
|
PRECACHE_MODEL( "models/can.mdl" );
|
|
PRECACHE_SOUND( "weapons/g_bounce3.wav" );
|
|
}
|
|
|
|
LINK_ENTITY_TO_CLASS( item_sodacan, CItemSoda );
|
|
|
|
void CItemSoda::Spawn( void )
|
|
{
|
|
Precache();
|
|
pev->solid = SOLID_NOT;
|
|
pev->movetype = MOVETYPE_TOSS;
|
|
|
|
SET_MODEL ( ENT(pev), "models/can.mdl" );
|
|
UTIL_SetSize ( pev, Vector ( 0, 0, 0 ), Vector ( 0, 0, 0 ) );
|
|
|
|
SetThink(&CItemSoda::CanThink);
|
|
SetNextThink( 0.5 );
|
|
}
|
|
|
|
void CItemSoda::CanThink ( void )
|
|
{
|
|
EMIT_SOUND (ENT(pev), CHAN_WEAPON, "weapons/g_bounce3.wav", 1, ATTN_NORM );
|
|
|
|
pev->solid = SOLID_TRIGGER;
|
|
UTIL_SetSize ( pev, Vector ( -8, -8, 0 ), Vector ( 8, 8, 8 ) );
|
|
SetThink ( NULL );
|
|
SetTouch(&CItemSoda:: CanTouch );
|
|
}
|
|
|
|
void CItemSoda::CanTouch ( CBaseEntity *pOther )
|
|
{
|
|
if ( !pOther->IsPlayer() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// spoit sound here
|
|
|
|
pOther->TakeHealth( 1, DMG_GENERIC );// a bit of health.
|
|
|
|
if ( !FNullEnt( pev->owner ) )
|
|
{
|
|
// tell the machine the can was taken
|
|
pev->owner->v.frags = 0;
|
|
}
|
|
|
|
pev->solid = SOLID_NOT;
|
|
pev->movetype = MOVETYPE_NONE;
|
|
pev->effects |= EF_NODRAW;
|
|
SetTouch ( NULL );
|
|
SetThink(&CItemSoda:: SUB_Remove );
|
|
SetNextThink( 0 );
|
|
}
|
|
|
|
//=========================================================
|
|
// LRC - env_fog, extended a bit from the DMC version
|
|
//=========================================================
|
|
#define SF_FOG_ACTIVE 1
|
|
#define SF_FOG_FADING 0x8000
|
|
|
|
class CEnvFog : public CBaseEntity
|
|
{
|
|
public:
|
|
void Spawn( void );
|
|
void Precache( void );
|
|
void EXPORT ResumeThink( void );
|
|
void EXPORT Resume2Think( void );
|
|
void EXPORT TurnOn( void );
|
|
void EXPORT TurnOff( void );
|
|
void EXPORT FadeInDone( void );
|
|
void EXPORT FadeOutDone( void );
|
|
void SendData( Vector col, int fFadeTime, int StartDist, int iEndDist);
|
|
void KeyValue( KeyValueData *pkvd );
|
|
virtual int Save( CSave &save );
|
|
virtual int Restore( CRestore &restore );
|
|
static TYPEDESCRIPTION m_SaveData[];
|
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
|
|
STATE GetState( void );
|
|
|
|
int m_iStartDist;
|
|
int m_iEndDist;
|
|
float m_iFadeIn;
|
|
float m_iFadeOut;
|
|
float m_fHoldTime;
|
|
float m_fFadeStart; // if we're fading in/out, then when did the fade start?
|
|
};
|
|
|
|
TYPEDESCRIPTION CEnvFog::m_SaveData[] =
|
|
{
|
|
DEFINE_FIELD( CEnvFog, m_iStartDist, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CEnvFog, m_iEndDist, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CEnvFog, m_iFadeIn, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CEnvFog, m_iFadeOut, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CEnvFog, m_fHoldTime, FIELD_FLOAT ),
|
|
DEFINE_FIELD( CEnvFog, m_fFadeStart, FIELD_TIME ),
|
|
};
|
|
|
|
IMPLEMENT_SAVERESTORE( CEnvFog, CBaseEntity );
|
|
|
|
void CEnvFog :: KeyValue( KeyValueData *pkvd )
|
|
{
|
|
if (FStrEq(pkvd->szKeyName, "startdist"))
|
|
{
|
|
m_iStartDist = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "enddist"))
|
|
{
|
|
m_iEndDist = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "fadein"))
|
|
{
|
|
m_iFadeIn = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "fadeout"))
|
|
{
|
|
m_iFadeOut = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "holdtime"))
|
|
{
|
|
m_fHoldTime = atof(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else
|
|
CBaseEntity::KeyValue( pkvd );
|
|
}
|
|
|
|
STATE CEnvFog::GetState( void )
|
|
{
|
|
if (pev->spawnflags & SF_FOG_ACTIVE)
|
|
{
|
|
if (pev->spawnflags & SF_FOG_FADING)
|
|
return STATE_TURN_ON;
|
|
else
|
|
return STATE_ON;
|
|
}
|
|
else
|
|
{
|
|
if (pev->spawnflags & SF_FOG_FADING)
|
|
return STATE_TURN_OFF;
|
|
else
|
|
return STATE_OFF;
|
|
}
|
|
}
|
|
|
|
void CEnvFog :: Spawn ( void )
|
|
{
|
|
pev->effects |= EF_NODRAW;
|
|
|
|
if (pev->targetname == 0)
|
|
pev->spawnflags |= SF_FOG_ACTIVE;
|
|
|
|
if (pev->spawnflags & SF_FOG_ACTIVE)
|
|
{
|
|
SetThink(&CEnvFog :: TurnOn );
|
|
UTIL_DesiredThink( this );
|
|
}
|
|
|
|
// Precache is now used only to continue after a game has loaded.
|
|
// Precache();
|
|
|
|
// things get messed up if we try to draw fog with a startdist
|
|
// or an enddist of 0, so we don't allow it.
|
|
if (m_iStartDist == 0) m_iStartDist = 1;
|
|
if (m_iEndDist == 0) m_iEndDist = 1;
|
|
}
|
|
|
|
void CEnvFog :: Precache ( void )
|
|
{
|
|
if (pev->spawnflags & SF_FOG_ACTIVE)
|
|
{
|
|
SetThink(&CEnvFog :: ResumeThink );
|
|
SetNextThink( 0.1 );
|
|
}
|
|
}
|
|
|
|
extern int gmsgSetFog;
|
|
|
|
void CEnvFog :: TurnOn ( void )
|
|
{
|
|
// ALERT(at_console, "Fog turnon %f\n", gpGlobals->time);
|
|
|
|
pev->spawnflags |= SF_FOG_ACTIVE;
|
|
|
|
if( m_iFadeIn )
|
|
{
|
|
pev->spawnflags |= SF_FOG_FADING;
|
|
SendData( pev->rendercolor, m_iFadeIn, m_iStartDist, m_iEndDist);
|
|
SetNextThink( m_iFadeIn );
|
|
SetThink(&CEnvFog :: FadeInDone );
|
|
}
|
|
else
|
|
{
|
|
pev->spawnflags &= ~SF_FOG_FADING;
|
|
SendData( pev->rendercolor, 0, m_iStartDist, m_iEndDist);
|
|
if (m_fHoldTime)
|
|
{
|
|
SetNextThink( m_fHoldTime );
|
|
SetThink(&CEnvFog :: TurnOff );
|
|
}
|
|
}
|
|
}
|
|
|
|
void CEnvFog :: TurnOff ( void )
|
|
{
|
|
// ALERT(at_console, "Fog turnoff\n");
|
|
|
|
pev->spawnflags &= ~SF_FOG_ACTIVE;
|
|
|
|
if( m_iFadeOut )
|
|
{
|
|
pev->spawnflags |= SF_FOG_FADING;
|
|
SendData( pev->rendercolor, -m_iFadeOut, m_iStartDist, m_iEndDist);
|
|
SetNextThink( m_iFadeOut );
|
|
SetThink(&CEnvFog :: FadeOutDone );
|
|
}
|
|
else
|
|
{
|
|
pev->spawnflags &= ~SF_FOG_FADING;
|
|
SendData( g_vecZero, 0, 0, 0 );
|
|
DontThink();
|
|
}
|
|
}
|
|
|
|
//yes, this intermediate think function is necessary.
|
|
// the engine seems to ignore the nextthink time when starting up.
|
|
// So this function gets called immediately after the precache finishes,
|
|
// regardless of what nextthink time is specified.
|
|
void CEnvFog :: ResumeThink ( void )
|
|
{
|
|
// ALERT(at_console, "Fog resume %f\n", gpGlobals->time);
|
|
SetThink(&CEnvFog ::FadeInDone);
|
|
SetNextThink(0.1);
|
|
}
|
|
|
|
void CEnvFog :: FadeInDone ( void )
|
|
{
|
|
pev->spawnflags &= ~SF_FOG_FADING;
|
|
SendData( pev->rendercolor, 0, m_iStartDist, m_iEndDist);
|
|
|
|
if (m_fHoldTime)
|
|
{
|
|
SetNextThink( m_fHoldTime );
|
|
SetThink(&CEnvFog :: TurnOff );
|
|
}
|
|
}
|
|
|
|
void CEnvFog :: FadeOutDone ( void )
|
|
{
|
|
pev->spawnflags &= ~SF_FOG_FADING;
|
|
SendData( g_vecZero, 0, 0, 0);
|
|
}
|
|
|
|
void CEnvFog :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
// ALERT(at_console, "Fog use %s %s\n", GetStringForUseType(useType), GetStringForState(GetState()));
|
|
if (ShouldToggle(useType))
|
|
{
|
|
if (pev->spawnflags & SF_FOG_ACTIVE)
|
|
TurnOff();
|
|
else
|
|
TurnOn();
|
|
}
|
|
}
|
|
|
|
void CEnvFog :: SendData ( Vector col, int iFadeTime, int iStartDist, int iEndDist )
|
|
{
|
|
// ALERT(at_console, "Fog send (%d %d %d), %d - %d\n", col.x, col.y, col.z, iStartDist, iEndDist);
|
|
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
|
|
{
|
|
CBasePlayer *pPlayer = (CBasePlayer*)UTIL_PlayerByIndex( i );
|
|
if ( pPlayer )
|
|
{
|
|
MESSAGE_BEGIN( MSG_ONE, gmsgSetFog, NULL, pPlayer->pev );
|
|
WRITE_BYTE ( col.x );
|
|
WRITE_BYTE ( col.y );
|
|
WRITE_BYTE ( col.z );
|
|
WRITE_SHORT ( iFadeTime );
|
|
WRITE_SHORT ( iStartDist );
|
|
WRITE_SHORT ( iEndDist );
|
|
MESSAGE_END();
|
|
|
|
// pPlayer->m_iFogStartDist = iStartDist;
|
|
// pPlayer->m_iFogEndDist = iEndDist;
|
|
// pPlayer->m_vecFogColor = col;
|
|
// pPlayer->m_bClientFogRefresh = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
LINK_ENTITY_TO_CLASS( env_fog, CEnvFog );
|
|
|
|
//=========================================================
|
|
// LRC - env_sky, an unreal tournament-style sky effect
|
|
//=========================================================
|
|
class CEnvSky : public CBaseEntity
|
|
{
|
|
public:
|
|
void Activate( void );
|
|
void Think( void );
|
|
};
|
|
|
|
void CEnvSky :: Activate ( void )
|
|
{
|
|
pev->effects |= EF_NODRAW;
|
|
pev->nextthink = gpGlobals->time + 1.0;
|
|
}
|
|
|
|
extern int gmsgSetSky;
|
|
|
|
void CEnvSky :: Think ()
|
|
{
|
|
MESSAGE_BEGIN(MSG_BROADCAST, gmsgSetSky, NULL);
|
|
WRITE_BYTE(1); // mode
|
|
WRITE_COORD(pev->origin.x); // view position
|
|
WRITE_COORD(pev->origin.y);
|
|
WRITE_COORD(pev->origin.z);
|
|
MESSAGE_END();
|
|
}
|
|
|
|
LINK_ENTITY_TO_CLASS( env_sky, CEnvSky );
|
|
|
|
|
|
|
|
//=========================================================
|
|
// LRC - env_particle, uses the aurora particle system
|
|
//=========================================================
|
|
//extern int gmsgParticle = 0;
|
|
#define SF_PARTICLE_ON 1
|
|
|
|
class CParticle : public CPointEntity
|
|
{
|
|
public:
|
|
void Spawn( void );
|
|
void Precache( void );
|
|
void SendInitMessage( CBasePlayer *player ); // buz
|
|
|
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
};
|
|
|
|
LINK_ENTITY_TO_CLASS( env_particle, CParticle );
|
|
|
|
void CParticle::Spawn( void )
|
|
{
|
|
pev->solid = SOLID_NOT;
|
|
pev->movetype = MOVETYPE_NONE;
|
|
pev->renderamt = 128;
|
|
pev->rendermode = kRenderTransTexture;
|
|
|
|
// 'body' determines whether the effect is active or not
|
|
pev->body = (pev->spawnflags & SF_PARTICLE_ON) != 0;
|
|
|
|
Precache();
|
|
|
|
UTIL_SetOrigin(this, pev->origin);
|
|
SET_MODEL(edict(), "sprites/null.spr");
|
|
}
|
|
|
|
|
|
void CParticle::Precache( void )
|
|
{
|
|
PRECACHE_MODEL("sprites/null.spr");
|
|
}
|
|
|
|
void CParticle::SendInitMessage( CBasePlayer *player )
|
|
{
|
|
MESSAGE_BEGIN( MSG_ONE, gmsgParticle, NULL, player->pev );
|
|
WRITE_ENTITY( entindex() );
|
|
WRITE_STRING( STRING(pev->message) );
|
|
WRITE_BYTE( 0 ); // attachment
|
|
MESSAGE_END();
|
|
}
|
|
|
|
void CParticle::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
if ( ShouldToggle( useType, pev->body ) )
|
|
{
|
|
pev->body = !pev->body;
|
|
}
|
|
}
|
|
|
|
// ======= rain =========
|
|
void CRainSettings :: Spawn()
|
|
{
|
|
pev->solid = SOLID_NOT;
|
|
pev->movetype = MOVETYPE_NONE;
|
|
pev->effects |= EF_NODRAW;
|
|
}
|
|
|
|
void CRainSettings::KeyValue( KeyValueData *pkvd )
|
|
{
|
|
if (FStrEq(pkvd->szKeyName, "m_flDistance"))
|
|
{
|
|
Rain_Distance = atof(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_iMode"))
|
|
{
|
|
Rain_Mode = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else
|
|
{
|
|
CBaseEntity::KeyValue( pkvd );
|
|
}
|
|
}
|
|
|
|
LINK_ENTITY_TO_CLASS( rain_settings, CRainSettings );
|
|
|
|
TYPEDESCRIPTION CRainSettings::m_SaveData[] =
|
|
{
|
|
DEFINE_FIELD( CRainSettings, Rain_Distance, FIELD_FLOAT ),
|
|
DEFINE_FIELD( CRainSettings, Rain_Mode, FIELD_INTEGER ),
|
|
}; IMPLEMENT_SAVERESTORE( CRainSettings, CBaseEntity );
|
|
|
|
void CRainModify::Spawn()
|
|
{
|
|
pev->solid = SOLID_NOT;
|
|
pev->movetype = MOVETYPE_NONE;
|
|
pev->effects |= EF_NODRAW;
|
|
|
|
if (FStringNull(pev->targetname))
|
|
pev->spawnflags |= 1;
|
|
}
|
|
|
|
void CRainModify::KeyValue( KeyValueData *pkvd )
|
|
{
|
|
if (FStrEq(pkvd->szKeyName, "m_iDripsPerSecond"))
|
|
{
|
|
Rain_Drips = atoi(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_flWindX"))
|
|
{
|
|
Rain_windX = atof(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_flWindY"))
|
|
{
|
|
Rain_windY = atof(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_flRandX"))
|
|
{
|
|
Rain_randX = atof(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_flRandY"))
|
|
{
|
|
Rain_randY = atof(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "m_flTime"))
|
|
{
|
|
fadeTime = atof(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else
|
|
{
|
|
CBaseEntity::KeyValue( pkvd );
|
|
}
|
|
}
|
|
|
|
void CRainModify::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
if (pev->spawnflags & 1)
|
|
return; // constant
|
|
|
|
if (gpGlobals->deathmatch)
|
|
{
|
|
ALERT(at_console, "Rain error: only static rain in multiplayer\n");
|
|
return; // not in multiplayer
|
|
}
|
|
|
|
CBasePlayer *pPlayer;
|
|
pPlayer = (CBasePlayer *)CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex(1));
|
|
|
|
if (fadeTime)
|
|
{ // write to 'ideal' settings
|
|
pPlayer->Rain_ideal_dripsPerSecond = Rain_Drips;
|
|
pPlayer->Rain_ideal_randX = Rain_randX;
|
|
pPlayer->Rain_ideal_randY = Rain_randY;
|
|
pPlayer->Rain_ideal_windX = Rain_windX;
|
|
pPlayer->Rain_ideal_windY = Rain_windY;
|
|
|
|
pPlayer->Rain_endFade = gpGlobals->time + fadeTime;
|
|
pPlayer->Rain_nextFadeUpdate = gpGlobals->time + 1;
|
|
}
|
|
else
|
|
{
|
|
pPlayer->Rain_dripsPerSecond = Rain_Drips;
|
|
pPlayer->Rain_randX = Rain_randX;
|
|
pPlayer->Rain_randY = Rain_randY;
|
|
pPlayer->Rain_windX = Rain_windX;
|
|
pPlayer->Rain_windY = Rain_windY;
|
|
|
|
pPlayer->Rain_needsUpdate = 1;
|
|
}
|
|
}
|
|
|
|
LINK_ENTITY_TO_CLASS( rain_modify, CRainModify );
|
|
|
|
TYPEDESCRIPTION CRainModify::m_SaveData[] =
|
|
{
|
|
DEFINE_FIELD( CRainModify, fadeTime, FIELD_FLOAT ),
|
|
DEFINE_FIELD( CRainModify, Rain_Drips, FIELD_INTEGER ),
|
|
DEFINE_FIELD( CRainModify, Rain_randX, FIELD_FLOAT ),
|
|
DEFINE_FIELD( CRainModify, Rain_randY, FIELD_FLOAT ),
|
|
DEFINE_FIELD( CRainModify, Rain_windX, FIELD_FLOAT ),
|
|
DEFINE_FIELD( CRainModify, Rain_windY, FIELD_FLOAT ),
|
|
}; IMPLEMENT_SAVERESTORE( CRainModify, CBaseEntity );
|
|
|
|
// =================================
|
|
// buz: static decals
|
|
//
|
|
// netname - decal group name
|
|
// skin - direction specified
|
|
// =================================
|
|
class CStaticDecal : public CPointEntity
|
|
{
|
|
public:
|
|
void KeyValue( KeyValueData *pkvd )
|
|
{
|
|
if (FStrEq(pkvd->szKeyName, "texture"))
|
|
{
|
|
pev->netname = ALLOC_STRING(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else CBaseEntity::KeyValue( pkvd );
|
|
}
|
|
|
|
int PasteDecal( int dir )
|
|
{
|
|
Vector vecdir = g_vecZero;
|
|
vecdir[dir % 3] = (dir & 1) ? 32.0f : -32.0f;
|
|
|
|
TraceResult tr;
|
|
UTIL_TraceLine ( pev->origin, pev->origin + vecdir, ignore_monsters, edict(), &tr );
|
|
return UTIL_TraceCustomDecal( &tr, STRING( pev->netname ), pev->angles.y, TRUE );
|
|
}
|
|
|
|
void Spawn( void )
|
|
{
|
|
if( pev->skin <= 0 || pev->skin > 6 )
|
|
{
|
|
// try all directions
|
|
for( int i = 0; i < 6; i++ )
|
|
if( PasteDecal( i )) break;
|
|
if( i == 6 ) ALERT( at_warning, "failed to place decal %s\n", STRING( pev->netname ));
|
|
}
|
|
else
|
|
{
|
|
// try specified direction
|
|
PasteDecal( pev->skin - 1 );
|
|
}
|
|
|
|
// NOTE: don't need to keep this entity
|
|
// with new custom decal save\restore system
|
|
UTIL_Remove( this );
|
|
}
|
|
};
|
|
|
|
LINK_ENTITY_TO_CLASS( env_static_decal, CStaticDecal );
|
|
LINK_ENTITY_TO_CLASS( infodecal, CStaticDecal ); // now an alias
|
|
|
|
// =================================
|
|
// g-cont: puddles
|
|
//
|
|
// just a prefab
|
|
// =================================
|
|
class CPuddleDecal : public CPointEntity
|
|
{
|
|
public:
|
|
void Spawn( void )
|
|
{
|
|
TraceResult tr;
|
|
UTIL_TraceLine ( pev->origin, pev->origin + Vector( 0.0f, 0.0f, -64.0f ), ignore_monsters, edict(), &tr );
|
|
UTIL_TraceCustomDecal( &tr, "puddle", pev->angles.y, TRUE );
|
|
|
|
// NOTE: don't need to keep this entity
|
|
// with new custom decal save\restore system
|
|
UTIL_Remove( this );
|
|
}
|
|
};
|
|
|
|
LINK_ENTITY_TO_CLASS( env_puddle, CPuddleDecal );
|
|
|
|
// =================================
|
|
// buz: 3d sky info messages
|
|
//
|
|
// envpos_sky: sets view origin in 3d sky
|
|
// origin - origin
|
|
// skin - ambientlight
|
|
// body - shadelight
|
|
// flags - use amblight hack | use shadelight hack
|
|
//
|
|
// envpos_world: sets view origin in world (when sky movement requed)
|
|
// origin - origin
|
|
// health - speed
|
|
//
|
|
// =================================
|
|
extern int gmsgSkymarker_Sky;
|
|
extern int gmsgSkymarker_World;
|
|
|
|
class CEnvPos_Sky : public CPointEntity
|
|
{
|
|
public:
|
|
void Spawn()
|
|
{
|
|
pev->solid = SOLID_NOT;
|
|
pev->movetype = MOVETYPE_NONE;
|
|
pev->effects |= EF_NODRAW;
|
|
}
|
|
|
|
void SendInitMessage( CBasePlayer *player )
|
|
{
|
|
MESSAGE_BEGIN( MSG_ONE, gmsgSkymarker_Sky, NULL, player->pev );
|
|
WRITE_COORD( pev->origin.x );
|
|
WRITE_COORD( pev->origin.y );
|
|
WRITE_COORD( pev->origin.z );
|
|
MESSAGE_END();
|
|
}
|
|
};
|
|
|
|
|
|
class CEnvPos_World : public CPointEntity
|
|
{
|
|
public:
|
|
void Spawn()
|
|
{
|
|
pev->solid = SOLID_NOT;
|
|
pev->movetype = MOVETYPE_NONE;
|
|
pev->effects |= EF_NODRAW;
|
|
}
|
|
|
|
void SendInitMessage( CBasePlayer *player )
|
|
{
|
|
MESSAGE_BEGIN( MSG_ONE, gmsgSkymarker_World, NULL, player->pev );
|
|
WRITE_COORD( pev->origin.x );
|
|
WRITE_COORD( pev->origin.y );
|
|
WRITE_COORD( pev->origin.z );
|
|
WRITE_COORD( pev->health );
|
|
MESSAGE_END();
|
|
}
|
|
};
|
|
|
|
LINK_ENTITY_TO_CLASS( envpos_sky, CEnvPos_Sky );
|
|
LINK_ENTITY_TO_CLASS( envpos_world, CEnvPos_World );
|
|
|
|
|
|
|
|
// buz: trigger_followme
|
|
// formally, it does not any special, just fires target entity with chosen use type,
|
|
// and player sent as caller
|
|
|
|
class CTriggerFollow : public CPointEntity
|
|
{
|
|
public:
|
|
void Spawn()
|
|
{
|
|
pev->solid = SOLID_NOT;
|
|
pev->movetype = MOVETYPE_NONE;
|
|
pev->effects |= EF_NODRAW;
|
|
}
|
|
|
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
CBaseEntity *pEnt = CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex(1));
|
|
if (pEnt && pEnt->IsPlayer())
|
|
{
|
|
USE_TYPE send = USE_TOGGLE;
|
|
if (pev->impulse == 0) send = USE_ON;
|
|
else if (pev->impulse == 1) send = USE_OFF;
|
|
FireTargets(STRING(pev->target), this, pEnt, send, 0);
|
|
}
|
|
else
|
|
ALERT(at_console, "ERROR: cant get player!\n");
|
|
}
|
|
};
|
|
|
|
LINK_ENTITY_TO_CLASS( trigger_followme, CTriggerFollow );
|
|
|
|
|
|
// buz: dynamic light entity
|
|
#define SF_DYNLIGHT_STARTOFF 1
|
|
#define SF_DYNLIGHT_NOSHADOW 2
|
|
#define SF_DYNLIGHT_NOBUMP 4
|
|
#define SF_DYNLIGHT_FLARE 8
|
|
|
|
class CDynamicLight : public CPointEntity
|
|
{
|
|
public:
|
|
void Spawn()
|
|
{
|
|
pev->solid = SOLID_NOT;
|
|
pev->movetype = MOVETYPE_NONE;
|
|
|
|
Precache();
|
|
|
|
if( pev->sequence )
|
|
pev->renderfx = 72; // dynamic light with avi-texture
|
|
else pev->renderfx = 71; // dynamic light
|
|
|
|
SET_MODEL(ENT(pev),"sprites/null.spr"); // should be visible to send to client
|
|
|
|
pev->renderamt = pev->renderamt / 8;
|
|
|
|
// spotlight
|
|
if( pev->scale )
|
|
{
|
|
// create second PVS point
|
|
pev->enemy = Create( "info_target", pev->origin, g_vecZero, edict() )->edict();
|
|
SET_MODEL( pev->enemy, "sprites/null.spr" ); // allow to collect visibility info
|
|
UTIL_SetSize ( VARS( pev->enemy ), Vector ( -8, -8, -8 ), Vector ( 8, 8, 8 ) );
|
|
|
|
// to prevent disapperaing from PVS (renderamt is premultiplied by 0.125)
|
|
UTIL_SetSize( pev, Vector( -pev->renderamt, -pev->renderamt, -pev->renderamt ), Vector( pev->renderamt, pev->renderamt, pev->renderamt ));
|
|
}
|
|
else
|
|
{
|
|
// to prevent disapperaing from PVS (renderamt is premultiplied by 0.125)
|
|
UTIL_SetSize( pev, Vector( -pev->renderamt * 4, -pev->renderamt * 4, -pev->renderamt * 4 ), Vector( pev->renderamt * 4, pev->renderamt * 4, pev->renderamt * 4 ));
|
|
}
|
|
|
|
if( pev->spawnflags & SF_DYNLIGHT_NOSHADOW )
|
|
pev->effects |= EF_NOSHADOW;
|
|
if( pev->spawnflags & SF_DYNLIGHT_NOBUMP )
|
|
pev->effects |= EF_NOBUMP;
|
|
if( pev->spawnflags & SF_DYNLIGHT_FLARE )
|
|
pev->effects |= EF_LENSFLARE;
|
|
|
|
if( pev->spawnflags & SF_DYNLIGHT_STARTOFF )
|
|
{
|
|
pev->effects |= EF_NODRAW;
|
|
}
|
|
else if( pev->sequence )
|
|
{
|
|
SetThink( CineThink );
|
|
SetNextThink( 0.1f );
|
|
}
|
|
else if( pev->scale )
|
|
{
|
|
SetThink( PVSThink );
|
|
SetNextThink( 0.1f );
|
|
}
|
|
}
|
|
|
|
void Precache()
|
|
{
|
|
PRECACHE_MODEL("sprites/null.spr");
|
|
|
|
if( !FStringNull( pev->message ))
|
|
{
|
|
const char *ext = UTIL_FileExtension( STRING( pev->message ));
|
|
|
|
if( !Q_stricmp( ext, "avi" ))
|
|
{
|
|
// 0 if movie not found
|
|
pev->sequence = UTIL_PrecacheMovie( pev->message );
|
|
}
|
|
}
|
|
}
|
|
|
|
STATE GetState( void )
|
|
{
|
|
if (pev->effects & EF_NODRAW)
|
|
return STATE_OFF;
|
|
else
|
|
return STATE_ON;
|
|
}
|
|
|
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
if( useType == USE_ON )
|
|
pev->effects &= ~EF_NODRAW;
|
|
else if( useType == USE_OFF )
|
|
pev->effects |= EF_NODRAW;
|
|
else if( useType == USE_TOGGLE )
|
|
{
|
|
if( pev->effects & EF_NODRAW )
|
|
pev->effects &= ~EF_NODRAW;
|
|
else pev->effects |= EF_NODRAW;
|
|
}
|
|
|
|
if( pev->effects & EF_NODRAW )
|
|
{
|
|
DontThink();
|
|
}
|
|
else if( pev->sequence )
|
|
{
|
|
SetThink( CineThink );
|
|
SetNextThink( 0.1f );
|
|
}
|
|
else if( pev->scale )
|
|
{
|
|
SetThink( PVSThink );
|
|
SetNextThink( 0.1f );
|
|
}
|
|
}
|
|
|
|
void UpdatePVSPoint( void )
|
|
{
|
|
TraceResult tr;
|
|
Vector forward;
|
|
|
|
UTIL_MakeVectorsPrivate( pev->angles, forward, NULL, NULL );
|
|
Vector vecSrc = pev->origin + forward * 8.0f;
|
|
Vector vecEnd = vecSrc + forward * (pev->renderamt * 8.0f);
|
|
UTIL_TraceLine( vecSrc, vecEnd, ignore_monsters, edict(), &tr );
|
|
|
|
// this is our second PVS point
|
|
CBaseEntity *pVisHelper = CBaseEntity::Instance( pev->enemy );
|
|
if( pVisHelper ) UTIL_SetOrigin( pVisHelper, tr.vecEndPos + tr.vecPlaneNormal * 8.0f );
|
|
}
|
|
|
|
void EXPORT CineThink( void )
|
|
{
|
|
UpdatePVSPoint();
|
|
|
|
// update as 30 frames per second
|
|
pev->fuser2 += CIN_FRAMETIME;
|
|
SetNextThink( CIN_FRAMETIME );
|
|
}
|
|
|
|
void EXPORT PVSThink( void )
|
|
{
|
|
UpdatePVSPoint();
|
|
|
|
// static light should be updated in case
|
|
// moving platform under them
|
|
SetNextThink( m_pMoveWith ? 0.01f : 0.1f );
|
|
}
|
|
};
|
|
|
|
LINK_ENTITY_TO_CLASS( env_dynlight, CDynamicLight );
|
|
|
|
|
|
// =================== FUNC_SCREENMOVIE ==============================================
|
|
|
|
#define SF_SCREENMOVIE_START_ON BIT( 0 )
|
|
#define SF_SCREENMOVIE_PASSABLE BIT( 1 )
|
|
#define SF_SCREENMOVIE_LOOPED BIT( 2 )
|
|
#define SF_SCREENMOVIE_MONOCRHOME BIT( 3 ) // black & white
|
|
#define SF_SCREENMOVIE_SOUND BIT( 4 ) // allow sound
|
|
|
|
class CFuncScreenMovie : public CBaseDelay
|
|
{
|
|
public:
|
|
void Spawn( void );
|
|
void Precache( 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; }
|
|
STATE GetState( void ) { return (pev->body) ? STATE_ON : STATE_OFF; }
|
|
void EXPORT CineThink( void );
|
|
};
|
|
|
|
LINK_ENTITY_TO_CLASS( func_screenmovie, CFuncScreenMovie );
|
|
|
|
void CFuncScreenMovie::KeyValue( KeyValueData *pkvd )
|
|
{
|
|
if( FStrEq( pkvd->szKeyName, "movie" ))
|
|
{
|
|
pev->message = ALLOC_STRING( pkvd->szValue );
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else CBaseDelay::KeyValue( pkvd );
|
|
}
|
|
|
|
void CFuncScreenMovie :: Precache( void )
|
|
{
|
|
// store movie name as event index
|
|
pev->sequence = UTIL_PrecacheMovie( pev->message, FBitSet( pev->spawnflags, SF_SCREENMOVIE_SOUND ));
|
|
}
|
|
|
|
void CFuncScreenMovie :: Spawn( void )
|
|
{
|
|
Precache();
|
|
|
|
pev->movetype = MOVETYPE_PUSH;
|
|
|
|
if( FBitSet( pev->spawnflags, SF_SCREENMOVIE_PASSABLE ))
|
|
pev->solid = SOLID_NOT;
|
|
else pev->solid = SOLID_BSP;
|
|
|
|
SET_MODEL( ENT(pev), STRING(pev->model) );
|
|
pev->effects |= EF_SCREENMOVIE;
|
|
|
|
if( FBitSet( pev->spawnflags, SF_SCREENMOVIE_LOOPED ))
|
|
pev->iuser1 |= CF_LOOPED_MOVIE;
|
|
|
|
if( FBitSet( pev->spawnflags, SF_SCREENMOVIE_MONOCRHOME ))
|
|
pev->iuser1 |= CF_MONOCHROME;
|
|
|
|
if( FBitSet( pev->spawnflags, SF_SCREENMOVIE_SOUND ))
|
|
pev->iuser1 |= CF_MOVIE_SOUND;
|
|
|
|
// enable monitor
|
|
if( FBitSet( pev->spawnflags, SF_SCREENMOVIE_START_ON ))
|
|
{
|
|
SetThink( SUB_CallUseToggle );
|
|
SetNextThink( 0.1 );
|
|
}
|
|
}
|
|
|
|
void CFuncScreenMovie :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
if( !pev->sequence )
|
|
{
|
|
ALERT( at_error, "func_screenmovie with name %s can't loaded video %s\n", STRING( pev->targetname ), STRING( pev->message ));
|
|
return;
|
|
}
|
|
|
|
SetThink( CineThink );
|
|
|
|
if( ShouldToggle( useType ))
|
|
{
|
|
pev->body = !pev->body;
|
|
|
|
if( pev->body )
|
|
SetNextThink( CIN_FRAMETIME );
|
|
else DontThink();
|
|
}
|
|
}
|
|
|
|
void CFuncScreenMovie :: CineThink( void )
|
|
{
|
|
// update as 30 frames per second
|
|
pev->fuser2 += CIN_FRAMETIME;
|
|
SetNextThink( CIN_FRAMETIME );
|
|
}
|
|
|
|
class CBlurEffect : public CBaseDelay
|
|
{
|
|
public:
|
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
void ApplyBlur( CBasePlayer *pPlayer );
|
|
void KeyValue( KeyValueData *pkvd );
|
|
void Think( void );
|
|
|
|
virtual int Save( CSave &save );
|
|
virtual int Restore( CRestore &restore );
|
|
static TYPEDESCRIPTION m_SaveData[];
|
|
|
|
virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
|
|
|
|
CBasePlayer *m_pPlayer;
|
|
};
|
|
|
|
TYPEDESCRIPTION CBlurEffect :: m_SaveData[] =
|
|
{
|
|
DEFINE_FIELD( CBlurEffect, m_pPlayer, FIELD_CLASSPTR ),
|
|
}; IMPLEMENT_SAVERESTORE( CBlurEffect, CBaseDelay );
|
|
|
|
LINK_ENTITY_TO_CLASS( env_blur, CBlurEffect );
|
|
|
|
void CBlurEffect :: KeyValue( KeyValueData *pkvd )
|
|
{
|
|
if (FStrEq(pkvd->szKeyName, "fadetime"))
|
|
{
|
|
pev->frags = atof(pkvd->szValue);
|
|
pev->frags = bound( 0.0f, pev->frags, 1000.0f );
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "magnitude"))
|
|
{
|
|
pev->armorvalue = atof(pkvd->szValue);
|
|
pev->armorvalue = bound( 0.0f, pev->armorvalue, 1.0f );
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else
|
|
CBaseDelay::KeyValue( pkvd );
|
|
}
|
|
|
|
void CBlurEffect :: ApplyBlur( CBasePlayer *pPlayer )
|
|
{
|
|
if( !pPlayer ) return; // not spawned?
|
|
|
|
m_pPlayer = pPlayer;
|
|
|
|
if( pev->frags )
|
|
{
|
|
pev->health = m_pPlayer->m_flBlurAmount; // start pos
|
|
pev->max_health = pev->armorvalue - pPlayer->m_flBlurAmount;
|
|
pev->dmgtime = gpGlobals->time;
|
|
SetNextThink( 0.01 );
|
|
}
|
|
else
|
|
{
|
|
m_pPlayer->m_flBlurAmount = pev->armorvalue;
|
|
pev->max_health = pev->armorvalue;
|
|
pev->health = pev->dmgtime = 0.0f;
|
|
}
|
|
}
|
|
|
|
void CBlurEffect :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
if( pev->dmgtime ) return; // fading out
|
|
|
|
if( !pActivator || !pActivator->IsPlayer( ))
|
|
ApplyBlur( (CBasePlayer *)UTIL_PlayerByIndex( 1 ));
|
|
else ApplyBlur( (CBasePlayer *)pActivator );
|
|
}
|
|
|
|
void CBlurEffect :: Think( void )
|
|
{
|
|
float elapsed = gpGlobals->time - pev->dmgtime;
|
|
float f = elapsed / pev->frags;
|
|
f = bound( 0.0f, f, 1.0f );
|
|
|
|
m_pPlayer->m_flBlurAmount = pev->health + pev->max_health * f;
|
|
|
|
if( f == 1.0f ) // hit 100% fade
|
|
{
|
|
pev->dmgtime = 0.0f;
|
|
return;
|
|
}
|
|
|
|
SetNextThink( 0.01 );
|
|
}
|
|
|
|
//=======================
|
|
// Gradient sprite class
|
|
//=======================
|
|
|
|
class CGradientControl : public CBaseEntity
|
|
{
|
|
public:
|
|
void Spawn( void );
|
|
void Think( void );
|
|
int m_iGradAmt;
|
|
int m_iGlowAmt;
|
|
};
|
|
|
|
void CGradientControl::Spawn( void )
|
|
{
|
|
m_iGradAmt = 0;
|
|
m_iGlowAmt = 0;
|
|
SetNextThink(0.01);
|
|
}
|
|
|
|
void CGradientControl::Think( void )
|
|
{
|
|
CBaseEntity *pPlayer, *pGlow, *pGradient;
|
|
pPlayer = UTIL_FindEntityByClassname( NULL, "player" );
|
|
pGlow = UTIL_FindEntityByTargetname( NULL, STRING( pev->target ) );
|
|
pGradient = UTIL_FindEntityByTargetname( NULL, STRING( pev->message ) );
|
|
|
|
if (pPlayer && pGlow && pGradient)
|
|
{
|
|
if ( !m_iGradAmt) m_iGradAmt = pGradient->pev->renderamt;
|
|
|
|
if ( !m_iGlowAmt) m_iGlowAmt = pGlow->pev->renderamt;
|
|
|
|
TraceResult tr;
|
|
UTIL_TraceLine( pev->origin, pPlayer->pev->origin, ignore_monsters, ENT(pev), &tr );
|
|
Vector vecDir = pev->origin - pPlayer->pev->origin;
|
|
|
|
float flDist = vecDir.Length();
|
|
float flDist2 = flDist;
|
|
|
|
flDist-=60;
|
|
|
|
if ( flDist < 0 ) flDist = 0;
|
|
|
|
if ( flDist <= pev->health )
|
|
{
|
|
pGradient->pev->renderamt = fabs( flDist / pev->health * m_iGradAmt );
|
|
pGlow->pev->renderamt = fabs( pev->health / flDist2 * m_iGlowAmt );
|
|
}
|
|
else
|
|
{
|
|
pGradient->pev->renderamt = m_iGradAmt;
|
|
pGlow->pev->renderamt = m_iGlowAmt;
|
|
}
|
|
}
|
|
|
|
SetNextThink(0.01);
|
|
}
|
|
|
|
LINK_ENTITY_TO_CLASS( env_gradient, CGradientControl );
|