You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
781 lines
21 KiB
781 lines
21 KiB
//========================================= |
|
// 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 == 0) |
|
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 ( 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 = NULL; |
|
|
|
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; |
|
} |
|
|
|
if( !pBeam ) |
|
return; |
|
|
|
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)); |
|
|
|
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); |
|
} |
|
}
|
|
|