2020-08-31 18:50:41 +02:00
|
|
|
//=========================================
|
|
|
|
// NEW file for Spirit of Half-Life 0.7
|
|
|
|
// Created 14/01/02
|
|
|
|
//=========================================
|
|
|
|
|
|
|
|
// Spirit of Half-Life's particle system uses "locus triggers" to tell
|
|
|
|
// entities where to perform their actions.
|
|
|
|
|
|
|
|
#include "extdll.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "cbase.h"
|
|
|
|
#include "locus.h"
|
|
|
|
#include "effects.h"
|
|
|
|
#include "decals.h"
|
|
|
|
|
|
|
|
|
|
|
|
Vector CalcLocus_Position( CBaseEntity *pEntity, CBaseEntity *pLocus, const char *szText )
|
|
|
|
{
|
|
|
|
if ((*szText >= '0' && *szText <= '9') || *szText == '-')
|
|
|
|
{ // it's a vector
|
|
|
|
Vector tmp;
|
|
|
|
UTIL_StringToRandomVector( (float *)tmp, szText );
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
CBaseEntity *pCalc = UTIL_FindEntityByTargetname(NULL, szText, pLocus);
|
|
|
|
|
|
|
|
if (pCalc != NULL)
|
|
|
|
{
|
|
|
|
return pCalc->CalcPosition( pLocus );
|
|
|
|
}
|
|
|
|
|
|
|
|
ALERT(at_error, "%s \"%s\" has bad or missing calc_position value \"%s\"\n", STRING(pEntity->pev->classname), STRING(pEntity->pev->targetname), szText);
|
|
|
|
return g_vecZero;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector CalcLocus_Velocity( CBaseEntity *pEntity, CBaseEntity *pLocus, const char *szText )
|
|
|
|
{
|
|
|
|
if ((*szText >= '0' && *szText <= '9') || *szText == '-')
|
|
|
|
{ // it's a vector
|
|
|
|
Vector tmp;
|
|
|
|
UTIL_StringToRandomVector( (float *)tmp, szText );
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
CBaseEntity *pCalc = UTIL_FindEntityByTargetname(NULL, szText, pLocus);
|
|
|
|
|
|
|
|
if (pCalc != NULL)
|
|
|
|
return pCalc->CalcVelocity( pLocus );
|
|
|
|
|
|
|
|
ALERT(at_error, "%s \"%s\" has bad or missing calc_velocity value \"%s\"\n", STRING(pEntity->pev->classname), STRING(pEntity->pev->targetname), szText);
|
|
|
|
return g_vecZero;
|
|
|
|
}
|
|
|
|
|
|
|
|
float CalcLocus_Ratio( CBaseEntity *pLocus, const char *szText )
|
|
|
|
{
|
|
|
|
if ((*szText >= '0' && *szText <= '9') || *szText == '-')
|
|
|
|
{ // assume it's a float
|
|
|
|
return atof( szText );
|
|
|
|
}
|
|
|
|
|
|
|
|
CBaseEntity *pCalc = UTIL_FindEntityByTargetname(NULL, szText, pLocus);
|
|
|
|
|
|
|
|
if (pCalc != NULL)
|
|
|
|
return pCalc->CalcRatio( pLocus );
|
|
|
|
|
|
|
|
ALERT(at_error, "Bad or missing calc_ratio entity \"%s\"\n", szText);
|
|
|
|
return 0; // we need some signal for "fail". NaN, maybe?
|
|
|
|
}
|
|
|
|
|
|
|
|
//=============================================
|
|
|
|
//locus_x effects
|
|
|
|
//=============================================
|
|
|
|
|
|
|
|
// Entity variable
|
|
|
|
class CLocusAlias : public CBaseAlias
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
void PostSpawn( void );
|
|
|
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
|
|
CBaseEntity *FollowAlias( CBaseEntity *pFrom );
|
|
|
|
void FlushChanges( void );
|
|
|
|
|
|
|
|
virtual int Save( CSave &save );
|
|
|
|
virtual int Restore( CRestore &restore );
|
|
|
|
static TYPEDESCRIPTION m_SaveData[];
|
|
|
|
|
|
|
|
EHANDLE m_hValue;
|
|
|
|
EHANDLE m_hChangeTo;
|
|
|
|
};
|
|
|
|
|
|
|
|
TYPEDESCRIPTION CLocusAlias::m_SaveData[] =
|
|
|
|
{
|
|
|
|
DEFINE_FIELD( CLocusAlias, m_hValue, FIELD_EHANDLE),
|
|
|
|
DEFINE_FIELD( CLocusAlias, m_hChangeTo, FIELD_EHANDLE),
|
|
|
|
};
|
|
|
|
|
|
|
|
LINK_ENTITY_TO_CLASS( locus_alias, CLocusAlias );
|
|
|
|
IMPLEMENT_SAVERESTORE( CLocusAlias, CBaseAlias );
|
|
|
|
|
|
|
|
void CLocusAlias::PostSpawn( void )
|
|
|
|
{
|
|
|
|
m_hValue = UTIL_FindEntityByTargetname( NULL, STRING(pev->netname) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CLocusAlias::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
|
|
{
|
|
|
|
m_hChangeTo = pActivator;
|
|
|
|
UTIL_AddToAliasList( this );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CLocusAlias::FlushChanges( void )
|
|
|
|
{
|
|
|
|
m_hValue = m_hChangeTo;
|
|
|
|
m_hChangeTo = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
CBaseEntity *CLocusAlias::FollowAlias( CBaseEntity *pFrom )
|
|
|
|
{
|
|
|
|
if (m_hValue == NULL)
|
|
|
|
return NULL;
|
|
|
|
else if ( pFrom == NULL || (OFFSET(m_hValue->pev) > OFFSET(pFrom->pev)) )
|
|
|
|
{
|
|
|
|
// ALERT(at_console, "LocusAlias returns %s: %f %f %f\n", STRING(m_pValue->pev->targetname), m_pValue->pev->origin.x, m_pValue->pev->origin.y, m_pValue->pev->origin.z);
|
|
|
|
return m_hValue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Beam maker
|
|
|
|
#define BEAM_FSINE 0x10
|
|
|
|
#define BEAM_FSOLID 0x20
|
|
|
|
#define BEAM_FSHADEIN 0x40
|
|
|
|
#define BEAM_FSHADEOUT 0x80
|
|
|
|
|
|
|
|
#define SF_LBEAM_SHADEIN 128
|
|
|
|
#define SF_LBEAM_SHADEOUT 256
|
|
|
|
#define SF_LBEAM_SOLID 512
|
|
|
|
#define SF_LBEAM_SINE 1024
|
|
|
|
|
|
|
|
class CLocusBeam : public CPointEntity
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
void Spawn( void );
|
|
|
|
void Precache( void );
|
|
|
|
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[];
|
|
|
|
|
|
|
|
int m_iszSprite;
|
|
|
|
int m_iszTargetName;
|
|
|
|
int m_iszStart;
|
|
|
|
int m_iszEnd;
|
|
|
|
int m_iWidth;
|
|
|
|
int m_iDistortion;
|
|
|
|
float m_fFrame;
|
|
|
|
int m_iScrollRate;
|
|
|
|
float m_fDuration;
|
|
|
|
float m_fDamage;
|
|
|
|
int m_iDamageType;
|
|
|
|
int m_iFlags;
|
|
|
|
};
|
|
|
|
|
|
|
|
TYPEDESCRIPTION CLocusBeam::m_SaveData[] =
|
|
|
|
{
|
|
|
|
DEFINE_FIELD( CLocusBeam, m_iszSprite, FIELD_STRING),
|
|
|
|
DEFINE_FIELD( CLocusBeam, m_iszTargetName, FIELD_STRING),
|
|
|
|
DEFINE_FIELD( CLocusBeam, m_iszStart, FIELD_STRING),
|
|
|
|
DEFINE_FIELD( CLocusBeam, m_iszEnd, FIELD_STRING),
|
|
|
|
DEFINE_FIELD( CLocusBeam, m_iWidth, FIELD_INTEGER),
|
|
|
|
DEFINE_FIELD( CLocusBeam, m_iDistortion, FIELD_INTEGER),
|
|
|
|
DEFINE_FIELD( CLocusBeam, m_fFrame, FIELD_FLOAT),
|
|
|
|
DEFINE_FIELD( CLocusBeam, m_iScrollRate, FIELD_INTEGER),
|
|
|
|
DEFINE_FIELD( CLocusBeam, m_fDuration, FIELD_FLOAT),
|
|
|
|
DEFINE_FIELD( CLocusBeam, m_fDamage, FIELD_FLOAT),
|
|
|
|
DEFINE_FIELD( CLocusBeam, m_iDamageType, FIELD_INTEGER),
|
|
|
|
DEFINE_FIELD( CLocusBeam, m_iFlags, FIELD_INTEGER),
|
|
|
|
};
|
|
|
|
|
|
|
|
LINK_ENTITY_TO_CLASS( locus_beam, CLocusBeam );
|
|
|
|
IMPLEMENT_SAVERESTORE(CLocusBeam,CPointEntity);
|
|
|
|
|
|
|
|
void CLocusBeam :: KeyValue( KeyValueData *pkvd )
|
|
|
|
{
|
|
|
|
if (FStrEq(pkvd->szKeyName, "m_iszSprite"))
|
|
|
|
{
|
|
|
|
m_iszSprite = ALLOC_STRING(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_iszStart"))
|
|
|
|
{
|
|
|
|
m_iszStart = ALLOC_STRING(pkvd->szValue);
|
|
|
|
pkvd->fHandled = TRUE;
|
|
|
|
}
|
|
|
|
else if (FStrEq(pkvd->szKeyName, "m_iszEnd"))
|
|
|
|
{
|
|
|
|
m_iszEnd = ALLOC_STRING(pkvd->szValue);
|
|
|
|
pkvd->fHandled = TRUE;
|
|
|
|
}
|
|
|
|
else if (FStrEq(pkvd->szKeyName, "m_iWidth"))
|
|
|
|
{
|
|
|
|
m_iWidth = atoi(pkvd->szValue);
|
|
|
|
pkvd->fHandled = TRUE;
|
|
|
|
}
|
|
|
|
else if (FStrEq(pkvd->szKeyName, "m_iDistortion"))
|
|
|
|
{
|
|
|
|
m_iDistortion = atoi(pkvd->szValue);
|
|
|
|
pkvd->fHandled = TRUE;
|
|
|
|
}
|
|
|
|
else if (FStrEq(pkvd->szKeyName, "m_fFrame"))
|
|
|
|
{
|
|
|
|
m_fFrame = atof(pkvd->szValue);
|
|
|
|
pkvd->fHandled = TRUE;
|
|
|
|
}
|
|
|
|
else if (FStrEq(pkvd->szKeyName, "m_iScrollRate"))
|
|
|
|
{
|
|
|
|
m_iScrollRate = atoi(pkvd->szValue);
|
|
|
|
pkvd->fHandled = TRUE;
|
|
|
|
}
|
|
|
|
else if (FStrEq(pkvd->szKeyName, "m_fDuration"))
|
|
|
|
{
|
|
|
|
m_fDuration = atof(pkvd->szValue);
|
|
|
|
pkvd->fHandled = TRUE;
|
|
|
|
}
|
|
|
|
else if (FStrEq(pkvd->szKeyName, "m_fDamage"))
|
|
|
|
{
|
|
|
|
m_fDamage = atof(pkvd->szValue);
|
|
|
|
pkvd->fHandled = TRUE;
|
|
|
|
}
|
|
|
|
else if (FStrEq(pkvd->szKeyName, "m_iDamageType"))
|
|
|
|
{
|
|
|
|
m_iDamageType = atoi(pkvd->szValue);
|
|
|
|
pkvd->fHandled = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
CBaseEntity::KeyValue( pkvd );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CLocusBeam :: Precache ( void )
|
|
|
|
{
|
|
|
|
PRECACHE_MODEL ( (char*)STRING(m_iszSprite) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CLocusBeam::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
|
|
{
|
|
|
|
CBaseEntity *pStartEnt;
|
|
|
|
CBaseEntity *pEndEnt;
|
|
|
|
Vector vecStartPos;
|
|
|
|
Vector vecEndPos;
|
|
|
|
CBeam *pBeam;
|
|
|
|
|
|
|
|
switch(pev->impulse)
|
|
|
|
{
|
|
|
|
case 0: // ents
|
|
|
|
pStartEnt = UTIL_FindEntityByTargetname(NULL, STRING(m_iszStart), pActivator);
|
|
|
|
pEndEnt = UTIL_FindEntityByTargetname(NULL, STRING(m_iszEnd), pActivator);
|
|
|
|
|
|
|
|
if (pStartEnt == NULL || pEndEnt == NULL)
|
|
|
|
return;
|
|
|
|
pBeam = CBeam::BeamCreate( STRING(m_iszSprite), m_iWidth );
|
|
|
|
pBeam->EntsInit( pStartEnt->entindex(), pEndEnt->entindex() );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1: // pointent
|
|
|
|
vecStartPos = CalcLocus_Position( this, pActivator, STRING(m_iszStart) );
|
|
|
|
pEndEnt = UTIL_FindEntityByTargetname(NULL, STRING(m_iszEnd), pActivator);
|
|
|
|
|
|
|
|
if (pEndEnt == NULL)
|
|
|
|
return;
|
|
|
|
pBeam = CBeam::BeamCreate( STRING(m_iszSprite), m_iWidth );
|
|
|
|
pBeam->PointEntInit( vecStartPos, pEndEnt->entindex() );
|
|
|
|
break;
|
|
|
|
case 2: // points
|
|
|
|
vecStartPos = CalcLocus_Position( this, pActivator, STRING(m_iszStart) );
|
|
|
|
vecEndPos = CalcLocus_Position( this, pActivator, STRING(m_iszEnd) );
|
|
|
|
|
|
|
|
pBeam = CBeam::BeamCreate( STRING(m_iszSprite), m_iWidth );
|
|
|
|
pBeam->PointsInit( vecStartPos, vecEndPos );
|
|
|
|
break;
|
|
|
|
case 3: // point & offset
|
|
|
|
vecStartPos = CalcLocus_Position( this, pActivator, STRING(m_iszStart) );
|
|
|
|
vecEndPos = CalcLocus_Velocity( this, pActivator, STRING(m_iszEnd) );
|
|
|
|
|
|
|
|
pBeam = CBeam::BeamCreate( STRING(m_iszSprite), m_iWidth );
|
|
|
|
pBeam->PointsInit( vecStartPos, vecStartPos + vecEndPos );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
pBeam->SetColor( pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z );
|
|
|
|
pBeam->SetBrightness( pev->renderamt );
|
|
|
|
pBeam->SetNoise( m_iDistortion );
|
|
|
|
pBeam->SetFrame( m_fFrame );
|
|
|
|
pBeam->SetScrollRate( m_iScrollRate );
|
|
|
|
pBeam->SetFlags( m_iFlags );
|
|
|
|
pBeam->pev->dmg = m_fDamage;
|
|
|
|
pBeam->pev->frags = m_iDamageType;
|
|
|
|
pBeam->pev->spawnflags |= pev->spawnflags & (SF_BEAM_RING |
|
|
|
|
SF_BEAM_SPARKSTART | SF_BEAM_SPARKEND | SF_BEAM_DECALS);
|
|
|
|
if (m_fDuration)
|
|
|
|
{
|
|
|
|
pBeam->SetThink(&CBeam:: SUB_Remove );
|
|
|
|
pBeam->SetNextThink( m_fDuration );
|
|
|
|
}
|
|
|
|
pBeam->pev->targetname = m_iszTargetName;
|
|
|
|
|
|
|
|
if (pev->target)
|
|
|
|
{
|
|
|
|
FireTargets( STRING(pev->target), pBeam, this, USE_TOGGLE, 0 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CLocusBeam::Spawn( void )
|
|
|
|
{
|
|
|
|
Precache();
|
|
|
|
m_iFlags = 0;
|
|
|
|
if (pev->spawnflags & SF_LBEAM_SHADEIN)
|
|
|
|
m_iFlags |= BEAM_FSHADEIN;
|
|
|
|
if (pev->spawnflags & SF_LBEAM_SHADEOUT)
|
|
|
|
m_iFlags |= BEAM_FSHADEOUT;
|
|
|
|
if (pev->spawnflags & SF_LBEAM_SINE)
|
|
|
|
m_iFlags |= BEAM_FSINE;
|
|
|
|
if (pev->spawnflags & SF_LBEAM_SOLID)
|
|
|
|
m_iFlags |= BEAM_FSOLID;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//=============================================
|
|
|
|
//calc_x entities
|
|
|
|
//=============================================
|
|
|
|
|
|
|
|
class CCalcPosition : public CPointEntity
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Vector CalcPosition( CBaseEntity *pLocus );
|
|
|
|
};
|
|
|
|
|
|
|
|
LINK_ENTITY_TO_CLASS( calc_position, CCalcPosition );
|
|
|
|
|
|
|
|
Vector CCalcPosition::CalcPosition( CBaseEntity *pLocus )
|
|
|
|
{
|
|
|
|
CBaseEntity *pSubject = UTIL_FindEntityByTargetname(NULL, STRING(pev->netname), pLocus);
|
|
|
|
|
|
|
|
Vector vecOffset = CalcLocus_Velocity( this, pLocus, STRING(pev->message));
|
|
|
|
|
|
|
|
if( FNullEnt( pSubject ))
|
|
|
|
return vecOffset;
|
|
|
|
|
|
|
|
Vector vecPosition;
|
|
|
|
Vector vecJunk;
|
|
|
|
|
|
|
|
Vector vecResult;
|
|
|
|
switch (pev->impulse)
|
|
|
|
{
|
|
|
|
case 1: //eyes
|
|
|
|
vecResult = vecOffset + pSubject->EyePosition();
|
|
|
|
//ALERT(at_console, "calc_subpos returns %f %f %f\n", vecResult.x, vecResult.y, vecResult.z);
|
|
|
|
return vecResult;
|
|
|
|
//return vecOffset + pLocus->EyePosition();
|
|
|
|
case 2: // top
|
|
|
|
return vecOffset + pSubject->pev->origin + Vector(
|
|
|
|
(pSubject->pev->mins.x + pSubject->pev->maxs.x)/2,
|
|
|
|
(pSubject->pev->mins.y + pSubject->pev->maxs.y)/2,
|
|
|
|
pSubject->pev->maxs.z
|
|
|
|
);
|
|
|
|
case 3: // centre
|
|
|
|
return vecOffset + pSubject->pev->origin + Vector(
|
|
|
|
(pSubject->pev->mins.x + pSubject->pev->maxs.x)/2,
|
|
|
|
(pSubject->pev->mins.y + pSubject->pev->maxs.y)/2,
|
|
|
|
(pSubject->pev->mins.z + pSubject->pev->maxs.z)/2
|
|
|
|
);
|
|
|
|
case 4: // bottom
|
|
|
|
return vecOffset + pSubject->pev->origin + Vector(
|
|
|
|
(pSubject->pev->mins.x + pSubject->pev->maxs.x)/2,
|
|
|
|
(pSubject->pev->mins.y + pSubject->pev->maxs.y)/2,
|
|
|
|
pSubject->pev->mins.z
|
|
|
|
);
|
|
|
|
case 5:
|
|
|
|
// this could cause problems.
|
|
|
|
// is there a good way to check whether it's really a CBaseAnimating?
|
|
|
|
((CBaseAnimating*)pSubject)->GetAttachment( 0, vecPosition, vecJunk );
|
|
|
|
return vecOffset + vecPosition;
|
|
|
|
case 6:
|
|
|
|
((CBaseAnimating*)pSubject)->GetAttachment( 1, vecPosition, vecJunk );
|
|
|
|
return vecOffset + vecPosition;
|
|
|
|
case 7:
|
|
|
|
((CBaseAnimating*)pSubject)->GetAttachment( 2, vecPosition, vecJunk );
|
|
|
|
return vecOffset + vecPosition;
|
|
|
|
case 8:
|
|
|
|
((CBaseAnimating*)pSubject)->GetAttachment( 3, vecPosition, vecJunk );
|
|
|
|
return vecOffset + vecPosition;
|
|
|
|
case 9:
|
|
|
|
return vecOffset + pSubject->pev->origin + Vector(
|
|
|
|
RANDOM_FLOAT(pSubject->pev->mins.x, pSubject->pev->maxs.x),
|
|
|
|
RANDOM_FLOAT(pSubject->pev->mins.y, pSubject->pev->maxs.y),
|
|
|
|
RANDOM_FLOAT(pSubject->pev->mins.z, pSubject->pev->maxs.z)
|
|
|
|
);
|
|
|
|
default:
|
|
|
|
return vecOffset + pSubject->pev->origin;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//=======================================================
|
|
|
|
|
|
|
|
class CCalcRatio : public CPointEntity
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
float CalcRatio( CBaseEntity *pLocus );
|
|
|
|
};
|
|
|
|
|
|
|
|
LINK_ENTITY_TO_CLASS( calc_ratio, CCalcRatio );
|
|
|
|
|
|
|
|
float CCalcRatio::CalcRatio( CBaseEntity *pLocus )
|
|
|
|
{
|
|
|
|
float fBasis = CalcLocus_Ratio( pLocus, STRING(pev->target));
|
|
|
|
|
|
|
|
switch (pev->impulse)
|
|
|
|
{
|
|
|
|
case 1: fBasis = 1-fBasis; break; //reversed
|
|
|
|
case 2: fBasis = -fBasis; break; //negative
|
|
|
|
case 3: fBasis = 1/fBasis; break; //reciprocal
|
|
|
|
}
|
|
|
|
|
|
|
|
fBasis += CalcLocus_Ratio( pLocus, STRING(pev->netname));
|
|
|
|
fBasis = fBasis * CalcLocus_Ratio( pLocus, STRING(pev->message));
|
|
|
|
|
|
|
|
if (!FStringNull(pev->noise))
|
|
|
|
{
|
|
|
|
float fMin = CalcLocus_Ratio( pLocus, STRING(pev->noise));
|
|
|
|
|
|
|
|
if (!FStringNull(pev->noise1))
|
|
|
|
{
|
|
|
|
float fMax = CalcLocus_Ratio( pLocus, STRING(pev->noise1));
|
|
|
|
|
|
|
|
if (fBasis >= fMin && fBasis <= fMax)
|
|
|
|
return fBasis;
|
|
|
|
switch ((int)pev->frags)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
if (fBasis < fMin)
|
|
|
|
return fMin;
|
|
|
|
else
|
|
|
|
return fMax;
|
|
|
|
case 1:
|
|
|
|
while (fBasis < fMin)
|
|
|
|
fBasis += fMax - fMin;
|
|
|
|
while (fBasis > fMax)
|
|
|
|
fBasis -= fMax - fMin;
|
|
|
|
return fBasis;
|
|
|
|
case 2:
|
|
|
|
while (fBasis < fMin || fBasis > fMax)
|
|
|
|
{
|
|
|
|
if (fBasis < fMin)
|
|
|
|
fBasis = fMin + fMax - fBasis;
|
|
|
|
else
|
|
|
|
fBasis = fMax + fMax - fBasis;
|
|
|
|
}
|
|
|
|
return fBasis;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fBasis > fMin)
|
|
|
|
return fBasis;
|
|
|
|
else
|
|
|
|
return fMin; // crop to nearest value
|
|
|
|
}
|
|
|
|
else if (!FStringNull(pev->noise1))
|
|
|
|
{
|
|
|
|
float fMax = CalcLocus_Ratio( pLocus, STRING(pev->noise1));
|
|
|
|
|
|
|
|
if (fBasis < fMax)
|
|
|
|
return fBasis;
|
|
|
|
else
|
|
|
|
return fMax; // crop to nearest value
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return fBasis;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//=======================================================
|
|
|
|
#define SF_CALCVELOCITY_NORMALIZE 1
|
|
|
|
#define SF_CALCVELOCITY_SWAPZ 2
|
|
|
|
class CCalcSubVelocity : public CPointEntity
|
|
|
|
{
|
|
|
|
Vector Convert( CBaseEntity *pLocus, Vector vecVel );
|
|
|
|
Vector ConvertAngles( CBaseEntity *pLocus, Vector vecAngles );
|
|
|
|
public:
|
|
|
|
Vector CalcVelocity( CBaseEntity *pLocus );
|
|
|
|
};
|
|
|
|
|
|
|
|
LINK_ENTITY_TO_CLASS( calc_subvelocity, CCalcSubVelocity );
|
|
|
|
|
|
|
|
Vector CCalcSubVelocity::CalcVelocity( CBaseEntity *pLocus )
|
|
|
|
{
|
|
|
|
pLocus = UTIL_FindEntityByTargetname( NULL, STRING(pev->netname), pLocus );
|
|
|
|
|
|
|
|
Vector vecAngles;
|
|
|
|
Vector vecJunk;
|
|
|
|
|
|
|
|
switch (pev->impulse)
|
|
|
|
{
|
|
|
|
case 1: //angles
|
|
|
|
return ConvertAngles( pLocus, pLocus->pev->angles );
|
|
|
|
case 2: //v_angle
|
|
|
|
return ConvertAngles( pLocus, pLocus->pev->v_angle );
|
|
|
|
case 5:
|
|
|
|
// this could cause problems.
|
|
|
|
// is there a good way to check whether it's really a CBaseAnimating?
|
|
|
|
((CBaseAnimating*)pLocus)->GetAttachment( 0, vecJunk, vecAngles );
|
|
|
|
return ConvertAngles( pLocus, vecAngles );
|
|
|
|
case 6:
|
|
|
|
((CBaseAnimating*)pLocus)->GetAttachment( 1, vecJunk, vecAngles );
|
|
|
|
return ConvertAngles( pLocus, vecAngles );
|
|
|
|
case 7:
|
|
|
|
((CBaseAnimating*)pLocus)->GetAttachment( 2, vecJunk, vecAngles );
|
|
|
|
return ConvertAngles( pLocus, vecAngles );
|
|
|
|
case 8:
|
|
|
|
((CBaseAnimating*)pLocus)->GetAttachment( 3, vecJunk, vecAngles );
|
|
|
|
return ConvertAngles( pLocus, vecAngles );
|
|
|
|
default:
|
|
|
|
return Convert( pLocus, pLocus->pev->velocity );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector CCalcSubVelocity::Convert( CBaseEntity *pLocus, Vector vecDir )
|
|
|
|
{
|
|
|
|
if (pev->spawnflags & SF_CALCVELOCITY_NORMALIZE)
|
|
|
|
vecDir = vecDir.Normalize();
|
|
|
|
|
|
|
|
float fRatio = CalcLocus_Ratio( pLocus, STRING(pev->noise) );
|
|
|
|
Vector vecOffset = CalcLocus_Velocity( this, pLocus, STRING(pev->message));
|
|
|
|
|
|
|
|
Vector vecResult = vecOffset + (vecDir*fRatio);
|
|
|
|
|
|
|
|
if (pev->spawnflags & SF_CALCVELOCITY_SWAPZ)
|
|
|
|
vecResult.z = -vecResult.z;
|
|
|
|
// ALERT(at_console, "calc_subvel returns (%f %f %f) = (%f %f %f) + ((%f %f %f) * %f)\n", vecResult.x, vecResult.y, vecResult.z, vecOffset.x, vecOffset.y, vecOffset.z, vecDir.x, vecDir.y, vecDir.z, fRatio);
|
|
|
|
return vecResult;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector CCalcSubVelocity::ConvertAngles( CBaseEntity *pLocus, Vector vecAngles )
|
|
|
|
{
|
|
|
|
UTIL_MakeVectors( vecAngles );
|
|
|
|
return Convert( pLocus, gpGlobals->v_forward );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//=======================================================
|
|
|
|
class CCalcVelocityPath : public CPointEntity
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Vector CalcVelocity( CBaseEntity *pLocus );
|
|
|
|
};
|
|
|
|
|
|
|
|
LINK_ENTITY_TO_CLASS( calc_velocity_path, CCalcVelocityPath );
|
|
|
|
|
|
|
|
Vector CCalcVelocityPath::CalcVelocity( CBaseEntity *pLocus )
|
|
|
|
{
|
|
|
|
Vector vecStart = CalcLocus_Position( this, pLocus, STRING(pev->target) );
|
|
|
|
// ALERT(at_console, "vecStart %f %f %f\n", vecStart.x, vecStart.y, vecStart.z);
|
|
|
|
Vector vecOffs;
|
|
|
|
float fFactor = CalcLocus_Ratio( pLocus, STRING(pev->noise) );
|
|
|
|
|
|
|
|
switch ((int)pev->armorvalue)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
vecOffs = CalcLocus_Position( this, pLocus, STRING(pev->netname) ) - vecStart;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
vecOffs = CalcLocus_Velocity( this, pLocus, STRING(pev->netname) );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// ALERT(at_console, "vecOffs %f %f %f\n", vecOffs.x, vecOffs.y, vecOffs.z);
|
|
|
|
|
|
|
|
if (pev->health)
|
|
|
|
{
|
|
|
|
float len = vecOffs.Length();
|
|
|
|
switch ((int)pev->health)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
vecOffs = vecOffs/len;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
vecOffs = vecOffs/(len*len);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
vecOffs = vecOffs/(len*len*len);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
vecOffs = vecOffs*len;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
vecOffs = vecOffs * fFactor;
|
|
|
|
|
|
|
|
if (pev->frags)
|
|
|
|
{
|
|
|
|
TraceResult tr;
|
|
|
|
IGNORE_GLASS iIgnoreGlass = ignore_glass;
|
|
|
|
IGNORE_MONSTERS iIgnoreMonsters = ignore_monsters;
|
|
|
|
|
|
|
|
switch ((int)pev->frags)
|
|
|
|
{
|
|
|
|
case 2:
|
|
|
|
iIgnoreGlass = dont_ignore_glass;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
iIgnoreGlass = dont_ignore_glass;
|
|
|
|
// fall through
|
|
|
|
case 3:
|
|
|
|
iIgnoreMonsters = dont_ignore_monsters;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
UTIL_TraceLine( vecStart, vecStart+vecOffs, iIgnoreMonsters, iIgnoreGlass, NULL, &tr );
|
|
|
|
vecOffs = tr.vecEndPos - vecStart;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ALERT(at_console, "path: %f %f %f\n", vecOffs.x, vecOffs.y, vecOffs.z);
|
|
|
|
return vecOffs;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//=======================================================
|
|
|
|
class CCalcVelocityPolar : public CPointEntity
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Vector CalcVelocity( CBaseEntity *pLocus );
|
|
|
|
};
|
|
|
|
|
|
|
|
LINK_ENTITY_TO_CLASS( calc_velocity_polar, CCalcVelocityPolar );
|
|
|
|
|
|
|
|
Vector CCalcVelocityPolar::CalcVelocity( CBaseEntity *pLocus )
|
|
|
|
{
|
|
|
|
Vector vecBasis = CalcLocus_Velocity( this, pLocus, STRING(pev->netname) );
|
|
|
|
Vector vecAngles = UTIL_VecToAngles( vecBasis ) + pev->angles;
|
|
|
|
Vector vecOffset = CalcLocus_Velocity( this, pLocus, STRING(pev->message) );
|
|
|
|
|
|
|
|
float fFactor = CalcLocus_Ratio( pLocus, STRING(pev->noise) );
|
|
|
|
|
|
|
|
if (!(pev->spawnflags & SF_CALCVELOCITY_NORMALIZE))
|
|
|
|
fFactor = fFactor * vecBasis.Length();
|
|
|
|
|
|
|
|
UTIL_MakeVectors( vecAngles );
|
|
|
|
return (gpGlobals->v_forward * fFactor) + vecOffset;
|
|
|
|
}
|
|
|
|
|
|
|
|
//=======================================================
|
|
|
|
|
|
|
|
// Position marker
|
|
|
|
class CMark : public CPointEntity
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Vector CalcVelocity(CBaseEntity *pLocus) { return pev->movedir; }
|
|
|
|
float CalcRatio(CBaseEntity *pLocus) { return pev->frags; }
|
|
|
|
void Think( void ) { SUB_Remove(); }
|
|
|
|
};
|
|
|
|
|
|
|
|
class CLocusVariable : public CPointEntity
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
void Spawn( void );
|
|
|
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
|
|
Vector CalcVelocity(CBaseEntity *pLocus) { return pev->movedir; }
|
|
|
|
float CalcRatio(CBaseEntity *pLocus) { return pev->frags; }
|
|
|
|
|
|
|
|
void KeyValue( KeyValueData *pkvd );
|
|
|
|
virtual int Save( CSave &save );
|
|
|
|
virtual int Restore( CRestore &restore );
|
|
|
|
|
|
|
|
static TYPEDESCRIPTION m_SaveData[];
|
|
|
|
|
|
|
|
int m_iszPosition;
|
|
|
|
int m_iszVelocity;
|
|
|
|
int m_iszRatio;
|
|
|
|
int m_iszTargetName;
|
|
|
|
int m_iszFireOnSpawn;
|
|
|
|
float m_fDuration;
|
|
|
|
};
|
|
|
|
|
|
|
|
TYPEDESCRIPTION CLocusVariable::m_SaveData[] =
|
|
|
|
{
|
|
|
|
DEFINE_FIELD( CLocusVariable, m_iszPosition, FIELD_STRING),
|
|
|
|
DEFINE_FIELD( CLocusVariable, m_iszVelocity, FIELD_STRING),
|
|
|
|
DEFINE_FIELD( CLocusVariable, m_iszRatio, FIELD_STRING),
|
|
|
|
DEFINE_FIELD( CLocusVariable, m_iszTargetName, FIELD_STRING),
|
|
|
|
DEFINE_FIELD( CLocusVariable, m_iszFireOnSpawn, FIELD_STRING),
|
|
|
|
DEFINE_FIELD( CLocusVariable, m_fDuration, FIELD_FLOAT),
|
|
|
|
};
|
|
|
|
|
|
|
|
IMPLEMENT_SAVERESTORE( CLocusVariable, CPointEntity );
|
|
|
|
LINK_ENTITY_TO_CLASS( locus_variable, CLocusVariable );
|
|
|
|
|
|
|
|
void CLocusVariable :: KeyValue( KeyValueData *pkvd )
|
|
|
|
{
|
|
|
|
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_iszRatio"))
|
|
|
|
{
|
|
|
|
m_iszRatio = ALLOC_STRING(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_iszFireOnSpawn"))
|
|
|
|
{
|
|
|
|
m_iszFireOnSpawn = ALLOC_STRING(pkvd->szValue);
|
|
|
|
pkvd->fHandled = TRUE;
|
|
|
|
}
|
|
|
|
else if (FStrEq(pkvd->szKeyName, "m_fDuration"))
|
|
|
|
{
|
|
|
|
m_fDuration = atof(pkvd->szValue);
|
|
|
|
pkvd->fHandled = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
CPointEntity::KeyValue( pkvd );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CLocusVariable::Spawn( void )
|
|
|
|
{
|
|
|
|
SetMovedir(pev);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CLocusVariable::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
|
|
{
|
|
|
|
Vector vecPos = g_vecZero;
|
|
|
|
Vector vecDir = g_vecZero;
|
|
|
|
float fRatio = 0;
|
|
|
|
if (m_iszPosition)
|
|
|
|
vecPos = CalcLocus_Position(this, pActivator, STRING(m_iszPosition));
|
|
|
|
if (m_iszVelocity)
|
|
|
|
vecDir = CalcLocus_Velocity(this, pActivator, STRING(m_iszVelocity));
|
|
|
|
if (m_iszRatio)
|
|
|
|
fRatio = CalcLocus_Ratio(pActivator, STRING(m_iszRatio));
|
|
|
|
|
|
|
|
if (m_iszTargetName)
|
|
|
|
{
|
|
|
|
CMark *pMark = GetClassPtr( (CMark*)NULL );
|
|
|
|
pMark->pev->classname = MAKE_STRING("mark");
|
|
|
|
pMark->pev->origin = vecPos;
|
|
|
|
pMark->pev->movedir = vecDir;
|
|
|
|
pMark->pev->frags = fRatio;
|
|
|
|
pMark->pev->targetname = m_iszTargetName;
|
|
|
|
pMark->SetNextThink(m_fDuration);
|
|
|
|
|
|
|
|
FireTargets(STRING(m_iszFireOnSpawn), pMark, this, USE_TOGGLE, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pev->origin = vecPos;
|
|
|
|
pev->movedir = vecDir;
|
|
|
|
pev->frags = fRatio;
|
|
|
|
|
|
|
|
FireTargets(STRING(m_iszFireOnSpawn), this, this, USE_TOGGLE, 0);
|
|
|
|
}
|
|
|
|
}
|