cs16-client-legacy/dlls/triggers.cpp

2495 lines
55 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 "stdafx.h"
#include "cbase.h"
#include "player.h"
#include "saverestore.h"
#include "trains.h"
#include "gamerules.h"
#include "weapons.h"
#include "hostage.h"
#define savesolid team
#define GRENADETYPE_SMOKE 1
#define GRENADETYPE_FLASH 2
class CBaseGrenCatch : public CBaseEntity
{
public:
void Spawn(void);
void KeyValue(KeyValueData *pkvd);
int Save(CSave &save);
int Restore(CRestore &restore);
int ObjectCaps(void) { return CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
void Touch(CBaseEntity *pOther);
void Think(void);
public:
static TYPEDESCRIPTION m_SaveData[];
public:
int m_NeedGrenadeType;
string_t sTriggerOnGrenade;
string_t sDisableOnGrenade;
bool m_fSmokeTouching;
bool m_fFlashTouched;
};
TYPEDESCRIPTION CBaseGrenCatch::m_SaveData[] =
{
DEFINE_FIELD(CBaseGrenCatch, m_NeedGrenadeType, FIELD_INTEGER),
DEFINE_FIELD(CBaseGrenCatch, m_fSmokeTouching, FIELD_BOOLEAN),
DEFINE_FIELD(CBaseGrenCatch, m_fFlashTouched, FIELD_BOOLEAN),
DEFINE_FIELD(CBaseGrenCatch, sTriggerOnGrenade, FIELD_STRING),
DEFINE_FIELD(CBaseGrenCatch, sDisableOnGrenade, FIELD_STRING),
};
IMPLEMENT_SAVERESTORE(CBaseGrenCatch, CBaseEntity);
LINK_ENTITY_TO_CLASS(func_grencatch, CBaseGrenCatch);
void CBaseGrenCatch::Spawn(void)
{
pev->solid = SOLID_TRIGGER;
pev->flags |= FL_WORLDBRUSH;
pev->effects |= EF_NODRAW;
SET_MODEL(ENT(pev), STRING(pev->model));
pev->nextthink = gpGlobals->time + 0.1;
}
void CBaseGrenCatch::Touch(CBaseEntity *pOther)
{
if (!pOther)
return;
if (strstr(STRING(pev->model), "flash"))
m_fFlashTouched = true;
}
void CBaseGrenCatch::Think(void)
{
CGrenade *pGrenade;
bool m_fSmokeTouchingLastFrame;
CBaseEntity *pTrigger;
Vector vMax, vMin;
m_fSmokeTouchingLastFrame = m_fSmokeTouching;
m_fSmokeTouching = false;
pGrenade = NULL;
while (pGrenade = (CGrenade *)UTIL_FindEntityByClassname(pGrenade, "grenade"))
{
vMin = pGrenade->pev->mins;
vMax = pGrenade->pev->maxs;
UTIL_SetSize(pGrenade->pev, Vector(-8, -8, 0), Vector(8, 8, 0));
if (pGrenade->Intersects(this) && strstr(STRING(pGrenade->pev->model), "smoke"))
{
if (pGrenade->pev->velocity.Length() == 0)
m_fSmokeTouching = true;
}
pGrenade->pev->mins = vMin;
pGrenade->pev->maxs = vMax;
}
if ((m_NeedGrenadeType == GRENADETYPE_SMOKE && m_fSmokeTouching && !m_fSmokeTouchingLastFrame) || (m_NeedGrenadeType == GRENADETYPE_FLASH && m_fFlashTouched))
{
FireTargets(STRING(sTriggerOnGrenade), this, this, USE_TOGGLE, 0);
if (m_NeedGrenadeType == GRENADETYPE_SMOKE)
{
CBaseEntity *pEntity = NULL;
while (pEntity = UTIL_FindEntityByTargetname(pEntity, STRING(sDisableOnGrenade)))
{
pEntity->pev->savesolid = pEntity->pev->solid;
pEntity->pev->solid = SOLID_NOT;
}
}
else if (m_NeedGrenadeType == GRENADETYPE_FLASH)
pev->flags |= FL_KILLME;
}
if (m_fSmokeTouchingLastFrame && !m_fSmokeTouching)
{
pTrigger = NULL;
while (pTrigger = UTIL_FindEntityByTargetname(pTrigger, STRING(sDisableOnGrenade)))
{
pTrigger->pev->solid = pTrigger->pev->savesolid;
pTrigger->pev->savesolid = 0;
UTIL_SetOrigin(pTrigger->pev, pTrigger->pev->origin);
}
}
pev->nextthink = gpGlobals->time + 0.1;
}
void CBaseGrenCatch::KeyValue(KeyValueData *pkvd)
{
if (FStrEq(pkvd->szKeyName, "triggerongrenade"))
{
sTriggerOnGrenade = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "disableongrenade"))
{
sDisableOnGrenade = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "grenadetype"))
{
if (!strcmp(pkvd->szValue, "smoke"))
{
m_NeedGrenadeType = GRENADETYPE_SMOKE;
pkvd->fHandled = TRUE;
}
else if (!strcmp(pkvd->szValue, "flash"))
{
m_NeedGrenadeType = GRENADETYPE_FLASH;
pkvd->fHandled = TRUE;
}
}
else
CBaseEntity::KeyValue(pkvd);
}
#define MAX_ITEM_COUNTS 32
class CFuncWeaponCheck : public CBaseEntity
{
public:
void Spawn(void);
void KeyValue(KeyValueData *pkvd);
int Save(CSave &save);
int Restore(CRestore &restore);
void Touch(CBaseEntity *pOther);
public:
inline float GetNoItemDelay(void) { return pev->speed; }
inline void SetNoItemDelay(float delay) { pev->speed = delay; }
public:
static TYPEDESCRIPTION m_SaveData[];
public:
string_t sTriggerWithItems;
string_t sTriggerNoItems;
string_t sMaster[MAX_ITEM_COUNTS];
string_t sItemName;
int iItemCount;
int iAnyWeapon;
};
TYPEDESCRIPTION CFuncWeaponCheck::m_SaveData[] =
{
DEFINE_FIELD(CFuncWeaponCheck, sTriggerWithItems, FIELD_STRING),
DEFINE_FIELD(CFuncWeaponCheck, sTriggerNoItems, FIELD_STRING),
DEFINE_FIELD(CFuncWeaponCheck, iItemCount, FIELD_INTEGER),
DEFINE_ARRAY(CFuncWeaponCheck, sMaster, FIELD_STRING, MAX_ITEM_COUNTS),
DEFINE_FIELD(CFuncWeaponCheck, sItemName, FIELD_STRING),
DEFINE_FIELD(CFuncWeaponCheck, iAnyWeapon, FIELD_INTEGER),
};
IMPLEMENT_SAVERESTORE(CFuncWeaponCheck, CBaseEntity);
LINK_ENTITY_TO_CLASS(func_weaponcheck, CFuncWeaponCheck);
void CFuncWeaponCheck::Spawn(void)
{
pev->dmgtime = 0;
pev->solid = SOLID_TRIGGER;
pev->flags |= FL_WORLDBRUSH;
pev->solid |= EF_NODRAW;
SET_MODEL(ENT(pev), STRING(pev->model));
}
void CFuncWeaponCheck::Touch(CBaseEntity *pOther)
{
if (!UTIL_IsMasterTriggered(sMaster[0], pOther))
return;
if (!pOther)
return;
if (!pOther->IsPlayer())
return;
CBasePlayer *pPlayer = (CBasePlayer *)pOther;
for (int i = 1; i <= iItemCount; i++)
{
if (iAnyWeapon)
{
if (pPlayer->HasNamedPlayerItem(STRING(sMaster[i])))
break;
continue;
}
if (!pPlayer->HasNamedPlayerItem(STRING(sMaster[i])))
{
if (pev->dmgtime < gpGlobals->time)
{
if (pev->speed > -1)
{
FireTargets(STRING(sTriggerNoItems), pOther, pOther, USE_TOGGLE, 0);
pev->dmgtime = pev->speed + gpGlobals->time;
if (!pev->speed)
pev->speed = -1;
}
}
return;
}
}
FireTargets(STRING(sTriggerWithItems), pOther, pOther, USE_TOGGLE, 0);
SUB_Remove();
}
void CFuncWeaponCheck::KeyValue(KeyValueData *pkvd)
{
if (FStrEq(pkvd->szKeyName, "trigger_items"))
{
sTriggerWithItems = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "trigger_noitems"))
{
sTriggerNoItems = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "trigger_noitems_delay"))
{
pev->speed = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (strstr(pkvd->szKeyName, "item"))
{
if (iItemCount < MAX_ITEM_COUNTS)
sMaster[++iItemCount] = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "master"))
{
sMaster[0] = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "any_weapon"))
{
iAnyWeapon = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CBaseEntity::KeyValue(pkvd);
}
#define SF_TRIGGER_PUSH_START_OFF 2
#define SF_TRIGGER_HURT_TARGETONCE 1
#define SF_TRIGGER_HURT_START_OFF 2
#define SF_TRIGGER_HURT_NO_CLIENTS 8
#define SF_TRIGGER_HURT_CLIENTONLYFIRE 16
#define SF_TRIGGER_HURT_CLIENTONLYTOUCH 32
extern DLL_GLOBAL BOOL g_fGameOver;
extern void SetMovedir(entvars_t *pev);
class CFrictionModifier : public CBaseEntity
{
public:
void Spawn(void);
void KeyValue(KeyValueData *pkvd);
int Save(CSave &save);
int Restore(CRestore &restore);
int ObjectCaps(void) { return CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
public:
void EXPORT ChangeFriction(CBaseEntity *pOther);
public:
static TYPEDESCRIPTION m_SaveData[];
public:
float m_frictionFraction;
};
LINK_ENTITY_TO_CLASS(func_friction, CFrictionModifier);
TYPEDESCRIPTION CFrictionModifier::m_SaveData[] =
{
DEFINE_FIELD(CFrictionModifier, m_frictionFraction, FIELD_FLOAT),
};
IMPLEMENT_SAVERESTORE(CFrictionModifier, CBaseEntity);
void CFrictionModifier::Spawn(void)
{
pev->solid = SOLID_TRIGGER;
SET_MODEL(ENT(pev), STRING(pev->model));
pev->movetype = MOVETYPE_NONE;
SetTouch(&CFrictionModifier::ChangeFriction);
}
void CFrictionModifier::ChangeFriction(CBaseEntity *pOther)
{
if (pOther->pev->movetype != MOVETYPE_BOUNCEMISSILE && pOther->pev->movetype != MOVETYPE_BOUNCE)
pOther->pev->friction = m_frictionFraction;
}
void CFrictionModifier::KeyValue(KeyValueData *pkvd)
{
if (FStrEq(pkvd->szKeyName, "modifier"))
{
m_frictionFraction = atof(pkvd->szValue) / 100;
pkvd->fHandled = TRUE;
}
else
CBaseEntity::KeyValue(pkvd);
}
#define SF_AUTO_FIREONCE 0x0001
class CAutoTrigger : public CBaseDelay
{
public:
void KeyValue(KeyValueData *pkvd);
void Spawn(void);
void Precache(void);
void Think(void);
int ObjectCaps(void) { return CBaseDelay::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
int Save(CSave &save);
int Restore(CRestore &restore);
public:
static TYPEDESCRIPTION m_SaveData[];
private:
int m_globalstate;
USE_TYPE triggerType;
};
LINK_ENTITY_TO_CLASS(trigger_auto, CAutoTrigger);
TYPEDESCRIPTION CAutoTrigger::m_SaveData[] =
{
DEFINE_FIELD(CAutoTrigger, m_globalstate, FIELD_STRING),
DEFINE_FIELD(CAutoTrigger, triggerType, FIELD_INTEGER),
};
IMPLEMENT_SAVERESTORE(CAutoTrigger, CBaseDelay);
void CAutoTrigger::KeyValue(KeyValueData *pkvd)
{
if (FStrEq(pkvd->szKeyName, "globalstate"))
{
m_globalstate = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "triggerstate"))
{
int type = atoi(pkvd->szValue);
switch (type)
{
case 0: triggerType = USE_OFF; break;
case 2: triggerType = USE_TOGGLE; break;
default: triggerType = USE_ON; break;
}
pkvd->fHandled = TRUE;
}
else
CBaseDelay::KeyValue(pkvd);
}
void CAutoTrigger::Spawn(void)
{
Precache();
}
void CAutoTrigger::Precache(void)
{
pev->nextthink = gpGlobals->time + 0.1;
}
void CAutoTrigger::Think(void)
{
if (!m_globalstate || gGlobalState.EntityGetState(m_globalstate) == GLOBAL_ON)
{
SUB_UseTargets(this, triggerType, 0);
if (pev->spawnflags & SF_AUTO_FIREONCE)
UTIL_Remove(this);
}
}
#define SF_RELAY_FIREONCE 0x0001
class CTriggerRelay : public CBaseDelay
{
public:
void KeyValue(KeyValueData *pkvd);
void Spawn(void);
void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
int ObjectCaps(void) { return CBaseDelay::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
int Save(CSave &save);
int Restore(CRestore &restore);
public:
static TYPEDESCRIPTION m_SaveData[];
private:
USE_TYPE triggerType;
};
LINK_ENTITY_TO_CLASS(trigger_relay, CTriggerRelay);
TYPEDESCRIPTION CTriggerRelay::m_SaveData[] =
{
DEFINE_FIELD(CTriggerRelay, triggerType, FIELD_INTEGER),
};
IMPLEMENT_SAVERESTORE(CTriggerRelay, CBaseDelay);
void CTriggerRelay::KeyValue(KeyValueData *pkvd)
{
if (FStrEq(pkvd->szKeyName, "triggerstate"))
{
int type = atoi(pkvd->szValue);
switch (type)
{
case 0: triggerType = USE_OFF; break;
case 2: triggerType = USE_TOGGLE; break;
default: triggerType = USE_ON; break;
}
pkvd->fHandled = TRUE;
}
else
CBaseDelay::KeyValue(pkvd);
}
void CTriggerRelay::Spawn(void)
{
}
void CTriggerRelay::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
{
SUB_UseTargets(this, triggerType, 0);
if (pev->spawnflags & SF_RELAY_FIREONCE)
UTIL_Remove(this);
}
#define SF_MULTIMAN_CLONE 0x80000000
#define SF_MULTIMAN_THREAD 0x00000001
class CMultiManager : public CBaseToggle
{
public:
void KeyValue(KeyValueData *pkvd);
void Spawn(void);
void Restart(void);
BOOL HasTarget(string_t targetname);
int ObjectCaps(void) { return CBaseToggle::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
int Save(CSave &save);
int Restore(CRestore &restore);
public:
void EXPORT ManagerThink(void);
void EXPORT ManagerUse(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
private:
inline BOOL IsClone(void) { return (pev->spawnflags & SF_MULTIMAN_CLONE) ? TRUE : FALSE; }
inline BOOL ShouldClone(void)
{
if (IsClone())
return FALSE;
return (pev->spawnflags & SF_MULTIMAN_THREAD) ? TRUE : FALSE;
}
CMultiManager *Clone(void);
public:
static TYPEDESCRIPTION m_SaveData[];
public:
int m_cTargets;
int m_index;
float m_startTime;
int m_iTargetName[MAX_MULTI_TARGETS];
float m_flTargetDelay[MAX_MULTI_TARGETS];
};
LINK_ENTITY_TO_CLASS(multi_manager, CMultiManager);
TYPEDESCRIPTION CMultiManager::m_SaveData[] =
{
DEFINE_FIELD(CMultiManager, m_cTargets, FIELD_INTEGER),
DEFINE_FIELD(CMultiManager, m_index, FIELD_INTEGER),
DEFINE_FIELD(CMultiManager, m_startTime, FIELD_TIME),
DEFINE_ARRAY(CMultiManager, m_iTargetName, FIELD_STRING, MAX_MULTI_TARGETS),
DEFINE_ARRAY(CMultiManager, m_flTargetDelay, FIELD_FLOAT, MAX_MULTI_TARGETS),
};
IMPLEMENT_SAVERESTORE(CMultiManager, CBaseToggle);
void CMultiManager::KeyValue(KeyValueData *pkvd)
{
if (FStrEq(pkvd->szKeyName, "wait"))
{
m_flWait = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
{
if (m_cTargets < MAX_MULTI_TARGETS)
{
char tmp[128];
UTIL_StripToken(pkvd->szKeyName, tmp);
m_iTargetName[m_cTargets] = ALLOC_STRING(tmp);
m_flTargetDelay[m_cTargets++] = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
}
}
void CMultiManager::Spawn(void)
{
pev->solid = SOLID_NOT;
SetUse(&CMultiManager::ManagerUse);
SetThink(&CMultiManager::ManagerThink);
int swapped = 1;
while (swapped)
{
swapped = 0;
for (int i = 1; i < m_cTargets; i++)
{
if (m_flTargetDelay[i] < m_flTargetDelay[i - 1])
{
int name = m_iTargetName[i];
float delay = m_flTargetDelay[i];
m_iTargetName[i] = m_iTargetName[i - 1];
m_flTargetDelay[i] = m_flTargetDelay[i - 1];
m_iTargetName[i - 1] = name;
m_flTargetDelay[i - 1] = delay;
swapped = 1;
}
}
}
}
void CMultiManager::Restart(void)
{
edict_t *pentTarget = NULL;
for (int i = 0; i < m_cTargets; i++)
{
const char *name = STRING(m_iTargetName[i]);
if (!name)
continue;
pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(pev->target));
if (FNullEnt(pentTarget))
break;
CBaseEntity *pTarget = (CBaseEntity *)CBaseEntity::Instance(pentTarget);
if (pTarget && !(pTarget->pev->flags & FL_KILLME))
pTarget->Restart();
}
SetThink(NULL);
if (IsClone())
{
UTIL_Remove(this);
return;
}
SetUse(&CMultiManager::ManagerUse);
m_index = 0;
}
BOOL CMultiManager::HasTarget(string_t targetname)
{
for (int i = 0; i < m_cTargets; i++)
{
if (FStrEq(STRING(targetname), STRING(m_iTargetName[i])))
return TRUE;
}
return FALSE;
}
void CMultiManager::ManagerThink(void)
{
float time = gpGlobals->time - m_startTime;
while (m_index < m_cTargets && m_flTargetDelay[m_index] <= time)
{
FireTargets(STRING(m_iTargetName[m_index]), m_hActivator, this, USE_TOGGLE, 0);
m_index++;
}
if (m_index >= m_cTargets)
{
SetThink(NULL);
if (IsClone())
{
UTIL_Remove(this);
return;
}
SetUse(&CMultiManager::ManagerUse);
}
else
pev->nextthink = m_startTime + m_flTargetDelay[m_index];
}
CMultiManager *CMultiManager::Clone(void)
{
CMultiManager *pMulti = GetClassPtr((CMultiManager *)NULL);
edict_t *pEdict = pMulti->pev->pContainingEntity;
memcpy(pMulti->pev, pev, sizeof(*pev));
pMulti->pev->pContainingEntity = pEdict;
pMulti->pev->spawnflags |= SF_MULTIMAN_CLONE;
pMulti->m_cTargets = m_cTargets;
memcpy(pMulti->m_iTargetName, m_iTargetName, sizeof(m_iTargetName));
memcpy(pMulti->m_flTargetDelay, m_flTargetDelay, sizeof(m_flTargetDelay));
return pMulti;
}
void CMultiManager::ManagerUse(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
{
if (ShouldClone())
{
CMultiManager *pClone = Clone();
pClone->ManagerUse(pActivator, pCaller, useType, value);
return;
}
m_hActivator = pActivator;
m_index = 0;
m_startTime = gpGlobals->time;
SetUse(NULL);
SetThink(&CMultiManager::ManagerThink);
pev->nextthink = gpGlobals->time;
}
#define SF_RENDER_MASKFX (1<<0)
#define SF_RENDER_MASKAMT (1<<1)
#define SF_RENDER_MASKMODE (1<<2)
#define SF_RENDER_MASKCOLOR (1<<3)
class CRenderFxManager : public CBaseEntity
{
public:
void Spawn(void);
void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
};
LINK_ENTITY_TO_CLASS(env_render, CRenderFxManager);
void CRenderFxManager::Spawn(void)
{
pev->solid = SOLID_NOT;
}
void CRenderFxManager::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
{
if (FStringNull(pev->target))
return;
edict_t *pentTarget = NULL;
while (1)
{
pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(pev->target));
if (FNullEnt(pentTarget))
break;
entvars_t *pevTarget = VARS(pentTarget);
if (!FBitSet(pev->spawnflags, SF_RENDER_MASKFX))
pevTarget->renderfx = pev->renderfx;
if (!FBitSet(pev->spawnflags, SF_RENDER_MASKAMT))
pevTarget->renderamt = pev->renderamt;
if (!FBitSet(pev->spawnflags, SF_RENDER_MASKMODE))
pevTarget->rendermode = pev->rendermode;
if (!FBitSet(pev->spawnflags, SF_RENDER_MASKCOLOR))
pevTarget->rendercolor = pev->rendercolor;
}
}
class CBaseTrigger : public CBaseToggle
{
public:
void KeyValue(KeyValueData *pkvd);
int ObjectCaps(void) { return CBaseToggle::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
public:
void EXPORT TeleportTouch(CBaseEntity *pOther);
void EXPORT MultiTouch(CBaseEntity *pOther);
void EXPORT HurtTouch (CBaseEntity *pOther);
void EXPORT CDAudioTouch(CBaseEntity *pOther);
void ActivateMultiTrigger(CBaseEntity *pActivator);
void EXPORT MultiWaitOver(void);
void EXPORT CounterUse(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
void EXPORT ToggleUse(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
void InitTrigger(void);
};
LINK_ENTITY_TO_CLASS(trigger, CBaseTrigger);
void CBaseTrigger::InitTrigger(void)
{
if (pev->angles != g_vecZero)
SetMovedir(pev);
pev->solid = SOLID_TRIGGER;
pev->movetype = MOVETYPE_NONE;
SET_MODEL(ENT(pev), STRING(pev->model));
if (CVAR_GET_FLOAT("showtriggers") == 0)
SetBits(pev->effects, EF_NODRAW);
}
void CBaseTrigger::KeyValue(KeyValueData *pkvd)
{
if (FStrEq(pkvd->szKeyName, "damage"))
{
pev->dmg = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "count"))
{
m_cTriggersLeft = (int) atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "damagetype"))
{
m_bitsDamageInflict = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CBaseToggle::KeyValue(pkvd);
}
class CTriggerHurt : public CBaseTrigger
{
public:
void Spawn(void);
void EXPORT RadiationThink(void);
};
LINK_ENTITY_TO_CLASS(trigger_hurt, CTriggerHurt);
class CTriggerMonsterJump : public CBaseTrigger
{
public:
void Spawn(void);
void Touch(CBaseEntity *pOther);
void Think(void);
};
LINK_ENTITY_TO_CLASS(trigger_monsterjump, CTriggerMonsterJump);
void CTriggerMonsterJump::Spawn(void)
{
SetMovedir(pev);
InitTrigger();
pev->nextthink = 0;
pev->speed = 200;
m_flHeight = 150;
if (!FStringNull(pev->targetname))
{
pev->solid = SOLID_NOT;
UTIL_SetOrigin(pev, pev->origin);
SetUse(&CBaseTrigger::ToggleUse);
}
}
void CTriggerMonsterJump::Think(void)
{
pev->solid = SOLID_NOT;
UTIL_SetOrigin(pev, pev->origin);
SetThink(NULL);
}
void CTriggerMonsterJump::Touch(CBaseEntity *pOther)
{
entvars_t *pevOther = pOther->pev;
if (!FBitSet(pevOther->flags, FL_MONSTER))
return;
pevOther->origin.z += 1;
if (FBitSet(pevOther->flags, FL_ONGROUND))
pevOther->flags &= ~FL_ONGROUND;
pevOther->velocity = pev->movedir * pev->speed;
pevOther->velocity.z += m_flHeight;
pev->nextthink = gpGlobals->time;
}
class CTriggerCDAudio : public CBaseTrigger
{
public:
void Spawn(void);
void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
void Touch(CBaseEntity *pOther);
void PlayTrack(void);
};
LINK_ENTITY_TO_CLASS(trigger_cdaudio, CTriggerCDAudio);
void CTriggerCDAudio::Touch(CBaseEntity *pOther)
{
if (!pOther->IsPlayer())
return;
PlayTrack();
}
void CTriggerCDAudio::Spawn(void)
{
InitTrigger();
}
void CTriggerCDAudio::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
{
PlayTrack();
}
void PlayCDTrack(int iTrack)
{
edict_t *pClient = g_engfuncs.pfnPEntityOfEntIndex(1);
if (!pClient)
return;
if (iTrack < -1 || iTrack > 30)
{
ALERT(at_console, "TriggerCDAudio - Track %d out of range\n");
return;
}
if (iTrack == -1)
{
CLIENT_COMMAND(pClient, "cd pause\n");
}
else
{
char string[64];
sprintf(string, "cd play %3d\n", iTrack);
CLIENT_COMMAND(pClient, string);
}
}
void CTriggerCDAudio::PlayTrack(void)
{
PlayCDTrack((int)pev->health);
SetTouch(NULL);
UTIL_Remove(this);
}
class CTargetCDAudio : public CPointEntity
{
public:
void Spawn(void);
void KeyValue(KeyValueData *pkvd);
void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
void Think(void);
void Play(void);
};
LINK_ENTITY_TO_CLASS(target_cdaudio, CTargetCDAudio);
void CTargetCDAudio::KeyValue(KeyValueData *pkvd)
{
if (FStrEq(pkvd->szKeyName, "radius"))
{
pev->scale = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CPointEntity::KeyValue(pkvd);
}
void CTargetCDAudio::Spawn(void)
{
pev->solid = SOLID_NOT;
pev->movetype = MOVETYPE_NONE;
if (pev->scale > 0)
pev->nextthink = gpGlobals->time + 1;
}
void CTargetCDAudio::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
{
Play();
}
void CTargetCDAudio::Think(void)
{
edict_t *pClient = g_engfuncs.pfnPEntityOfEntIndex(1);
if (!pClient)
return;
pev->nextthink = gpGlobals->time + 0.5;
if ((pClient->v.origin - pev->origin).Length() <= pev->scale)
Play();
}
void CTargetCDAudio::Play(void)
{
PlayCDTrack((int)pev->health);
UTIL_Remove(this);
}
void CTriggerHurt::Spawn(void)
{
InitTrigger();
SetTouch(&CBaseTrigger::HurtTouch);
if (!FStringNull(pev->targetname))
SetUse(&CBaseTrigger::ToggleUse);
else
SetUse(NULL);
if (m_bitsDamageInflict & DMG_RADIATION)
{
SetThink(&CTriggerHurt::RadiationThink);
pev->nextthink = gpGlobals->time + RANDOM_FLOAT(0, 0.5);
}
if (FBitSet(pev->spawnflags, SF_TRIGGER_HURT_START_OFF))
pev->solid = SOLID_NOT;
UTIL_SetOrigin(pev, pev->origin);
}
void CTriggerHurt::RadiationThink(void)
{
Vector origin = pev->origin;
Vector view_ofs = pev->view_ofs;
pev->origin = (pev->absmin + pev->absmax) * 0.5;
pev->view_ofs = pev->view_ofs * 0;
edict_t *pentPlayer = FIND_CLIENT_IN_PVS(edict());
pev->origin = origin;
pev->view_ofs = view_ofs;
if (!FNullEnt(pentPlayer))
{
CBasePlayer *pPlayer = GetClassPtr((CBasePlayer *)VARS(pentPlayer));
entvars_t *pevTarget = VARS(pentPlayer);
Vector vecSpot1 = (pev->absmin + pev->absmax) * 0.5;
Vector vecSpot2 = (pevTarget->absmin + pevTarget->absmax) * 0.5;
Vector vecRange = vecSpot1 - vecSpot2;
float flRange = vecRange.Length();
if (pPlayer->m_flgeigerRange >= flRange)
pPlayer->m_flgeigerRange = flRange;
}
pev->nextthink = gpGlobals->time + 0.25;
}
void CBaseTrigger::ToggleUse(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
{
if (pev->solid == SOLID_NOT)
{
pev->solid = SOLID_TRIGGER;
gpGlobals->force_retouch++;
}
else
pev->solid = SOLID_NOT;
UTIL_SetOrigin(pev, pev->origin);
}
void CBaseTrigger::HurtTouch(CBaseEntity *pOther)
{
if (!pOther->pev->takedamage)
return;
if ((pev->spawnflags & SF_TRIGGER_HURT_CLIENTONLYTOUCH) && !pOther->IsPlayer())
return;
if ((pev->spawnflags & SF_TRIGGER_HURT_NO_CLIENTS) && pOther->IsPlayer())
return;
if (g_pGameRules->IsMultiplayer())
{
if (pev->dmgtime > gpGlobals->time)
{
if (gpGlobals->time != pev->pain_finished)
{
if (pOther->IsPlayer())
{
int playerMask = 1 << (pOther->entindex() - 1);
if (pev->impulse & playerMask)
return;
pev->impulse |= playerMask;
}
else
return;
}
}
else
{
pev->impulse = 0;
if (pOther->IsPlayer())
{
int playerMask = 1 << (pOther->entindex() - 1);
pev->impulse |= playerMask;
}
}
}
else if (pev->dmgtime > gpGlobals->time && gpGlobals->time != pev->pain_finished)
return;
float fldmg = pev->dmg * 0.5;
if (fldmg < 0)
pOther->TakeHealth(-fldmg, m_bitsDamageInflict);
else
pOther->TakeDamage(pev, pev, fldmg, m_bitsDamageInflict);
pev->pain_finished = gpGlobals->time;
pev->dmgtime = gpGlobals->time + 0.5;
if (pev->target)
{
if (pev->spawnflags & SF_TRIGGER_HURT_CLIENTONLYFIRE)
{
if (!pOther->IsPlayer())
return;
}
SUB_UseTargets(pOther, USE_TOGGLE, 0);
if (pev->spawnflags & SF_TRIGGER_HURT_TARGETONCE)
pev->target = 0;
}
}
class CTriggerMultiple : public CBaseTrigger
{
public:
void Spawn(void);
};
LINK_ENTITY_TO_CLASS(trigger_multiple, CTriggerMultiple);
void CTriggerMultiple::Spawn(void)
{
if (!m_flWait)
m_flWait = 0.2;
InitTrigger();
SetTouch(&CBaseTrigger::MultiTouch);
}
class CTriggerOnce : public CTriggerMultiple
{
public:
void Spawn(void);
};
LINK_ENTITY_TO_CLASS(trigger_once, CTriggerOnce);
void CTriggerOnce::Spawn(void)
{
m_flWait = -1;
CTriggerMultiple::Spawn();
}
void CBaseTrigger::MultiTouch(CBaseEntity *pOther)
{
entvars_t *pevToucher = pOther->pev;
if (((pevToucher->flags & FL_CLIENT) && !(pev->spawnflags & SF_TRIGGER_NOCLIENTS)) || ((pevToucher->flags & FL_MONSTER) && (pev->spawnflags & SF_TRIGGER_ALLOWMONSTERS)) || (pev->spawnflags & SF_TRIGGER_PUSHABLES) && FClassnameIs(pevToucher, "func_pushable"))
ActivateMultiTrigger(pOther);
}
void CBaseTrigger::ActivateMultiTrigger(CBaseEntity *pActivator)
{
if (pev->nextthink > gpGlobals->time)
return;
if (!UTIL_IsMasterTriggered(m_sMaster, pActivator))
return;
if (FClassnameIs(pev, "trigger_secret"))
{
if (!pev->enemy || !FClassnameIs(pev->enemy, "player"))
return;
gpGlobals->found_secrets++;
}
if (!FStringNull(pev->noise))
EMIT_SOUND(ENT(pev), CHAN_VOICE, (char *)STRING(pev->noise), 1, ATTN_NORM);
m_hActivator = pActivator;
SUB_UseTargets(m_hActivator, USE_TOGGLE, 0);
if (pev->message && pActivator->IsPlayer())
UTIL_ShowMessage(STRING(pev->message), pActivator);
if (m_flWait > 0)
{
SetThink(&CBaseTrigger::MultiWaitOver);
pev->nextthink = gpGlobals->time + m_flWait;
}
else
{
SetTouch(NULL);
pev->nextthink = gpGlobals->time + 0.1;
SetThink(&CBaseEntity::SUB_Remove);
}
}
void CBaseTrigger::MultiWaitOver(void)
{
SetThink(NULL);
}
void CBaseTrigger::CounterUse(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
{
m_cTriggersLeft--;
m_hActivator = pActivator;
if (m_cTriggersLeft < 0)
return;
BOOL fTellActivator = (m_hActivator != 0) && FClassnameIs(m_hActivator->pev, "player") && !FBitSet(pev->spawnflags, SPAWNFLAG_NOMESSAGE);
if (m_cTriggersLeft)
{
if (fTellActivator)
{
switch (m_cTriggersLeft)
{
case 1: ALERT(at_console, "Only 1 more to go..."); break;
case 2: ALERT(at_console, "Only 2 more to go..."); break;
case 3: ALERT(at_console, "Only 3 more to go..."); break;
default: ALERT(at_console, "There are more to go..."); break;
}
}
return;
}
if (fTellActivator)
ALERT(at_console, "Sequence completed!");
ActivateMultiTrigger(m_hActivator);
}
class CTriggerCounter : public CBaseTrigger
{
public:
void Spawn(void);
};
LINK_ENTITY_TO_CLASS(trigger_counter, CTriggerCounter);
void CTriggerCounter::Spawn(void)
{
m_flWait = -1;
if (!m_cTriggersLeft)
m_cTriggersLeft = 2;
SetUse(&CBaseTrigger::CounterUse);
}
class CTriggerVolume : public CPointEntity
{
public:
void Spawn(void);
};
LINK_ENTITY_TO_CLASS(trigger_transition, CTriggerVolume);
void CTriggerVolume::Spawn(void)
{
pev->solid = SOLID_NOT;
pev->movetype = MOVETYPE_NONE;
SET_MODEL(ENT(pev), STRING(pev->model));
pev->model = 0;
pev->modelindex = 0;
}
class CFireAndDie : public CBaseDelay
{
public:
void Spawn(void);
void Precache(void);
void Think(void);
int ObjectCaps(void) { return CBaseDelay::ObjectCaps() | FCAP_FORCE_TRANSITION; }
};
LINK_ENTITY_TO_CLASS(fireanddie, CFireAndDie);
void CFireAndDie::Spawn(void)
{
if (pev->classname)
RemoveEntityHashValue(pev, STRING(pev->classname), CLASSNAME);
pev->classname = MAKE_STRING("fireanddie");
AddEntityHashValue(pev, STRING(pev->classname), CLASSNAME);
}
void CFireAndDie::Precache(void)
{
pev->nextthink = gpGlobals->time + m_flDelay;
}
void CFireAndDie::Think(void)
{
SUB_UseTargets(this, USE_TOGGLE, 0);
UTIL_Remove(this);
}
#define SF_CHANGELEVEL_USEONLY 0x0002
class CChangeLevel : public CBaseTrigger
{
public:
void Spawn(void);
void KeyValue(KeyValueData *pkvd);
int Save(CSave &save);
int Restore(CRestore &restore);
public:
void EXPORT UseChangeLevel(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
void EXPORT TriggerChangeLevel(void);
void EXPORT ExecuteChangeLevel(void);
void EXPORT TouchChangeLevel(CBaseEntity *pOther);
void ChangeLevelNow(CBaseEntity *pActivator);
static edict_t *FindLandmark(const char *pLandmarkName);
static int ChangeList(LEVELLIST *pLevelList, int maxList);
static int AddTransitionToList(LEVELLIST *pLevelList, int listCount, const char *pMapName, const char *pLandmarkName, edict_t *pentLandmark);
static int InTransitionVolume(CBaseEntity *pEntity, char *pVolumeName);
public:
static TYPEDESCRIPTION m_SaveData[];
public:
char m_szMapName[cchMapNameMost];
char m_szLandmarkName[cchMapNameMost];
int m_changeTarget;
float m_changeTargetDelay;
};
LINK_ENTITY_TO_CLASS(trigger_changelevel, CChangeLevel);
TYPEDESCRIPTION CChangeLevel::m_SaveData[] =
{
DEFINE_ARRAY(CChangeLevel, m_szMapName, FIELD_CHARACTER, cchMapNameMost),
DEFINE_ARRAY(CChangeLevel, m_szLandmarkName, FIELD_CHARACTER, cchMapNameMost),
DEFINE_FIELD(CChangeLevel, m_changeTarget, FIELD_STRING),
DEFINE_FIELD(CChangeLevel, m_changeTargetDelay, FIELD_FLOAT),
};
IMPLEMENT_SAVERESTORE(CChangeLevel, CBaseTrigger);
void CChangeLevel::KeyValue(KeyValueData *pkvd)
{
if (FStrEq(pkvd->szKeyName, "map"))
{
if (strlen(pkvd->szValue) >= cchMapNameMost)
ALERT(at_error, "Map name '%s' too long (32 chars)\n", pkvd->szValue);
strcpy(m_szMapName, pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "landmark"))
{
if (strlen(pkvd->szValue) >= cchMapNameMost)
ALERT(at_error, "Landmark name '%s' too long (32 chars)\n", pkvd->szValue);
strcpy(m_szLandmarkName, pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "changetarget"))
{
m_changeTarget = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "changedelay"))
{
m_changeTargetDelay = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CBaseTrigger::KeyValue(pkvd);
}
void CChangeLevel::Spawn(void)
{
if (FStrEq(m_szMapName, ""))
ALERT(at_console, "a trigger_changelevel doesn't have a map");
if (FStrEq(m_szLandmarkName, ""))
ALERT(at_console, "trigger_changelevel to %s doesn't have a landmark", m_szMapName);
if (!FStringNull(pev->targetname))
SetUse(&CChangeLevel::UseChangeLevel);
InitTrigger();
if (!(pev->spawnflags & SF_CHANGELEVEL_USEONLY))
SetTouch(&CChangeLevel::TouchChangeLevel);
}
void CChangeLevel::ExecuteChangeLevel(void)
{
MESSAGE_BEGIN(MSG_ALL, SVC_CDTRACK);
WRITE_BYTE(3);
WRITE_BYTE(3);
MESSAGE_END();
MESSAGE_BEGIN(MSG_ALL, SVC_INTERMISSION);
MESSAGE_END();
}
FILE_GLOBAL char st_szNextMap[cchMapNameMost];
FILE_GLOBAL char st_szNextSpot[cchMapNameMost];
edict_t *CChangeLevel::FindLandmark(const char *pLandmarkName)
{
edict_t *pentLandmark = FIND_ENTITY_BY_STRING(NULL, "targetname", pLandmarkName);
while (!FNullEnt(pentLandmark))
{
if (FClassnameIs(pentLandmark, "info_landmark"))
return pentLandmark;
else
pentLandmark = FIND_ENTITY_BY_STRING(pentLandmark, "targetname", pLandmarkName);
}
ALERT(at_error, "Can't find landmark %s\n", pLandmarkName);
return NULL;
}
void CChangeLevel::UseChangeLevel(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
{
ChangeLevelNow(pActivator);
}
void CChangeLevel::ChangeLevelNow(CBaseEntity *pActivator)
{
ASSERT(!FStrEq(m_szMapName, ""));
if (g_pGameRules->IsDeathmatch())
return;
if (gpGlobals->time == pev->dmgtime)
return;
pev->dmgtime = gpGlobals->time;
CBaseEntity *pPlayer = CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex(1));
if (!InTransitionVolume(pPlayer, m_szLandmarkName))
{
ALERT(at_aiconsole, "Player isn't in the transition volume %s, aborting\n", m_szLandmarkName);
return;
}
if (m_changeTarget)
{
CFireAndDie *pFireAndDie = GetClassPtr((CFireAndDie *)NULL);
if (pFireAndDie)
{
pFireAndDie->pev->target = m_changeTarget;
pFireAndDie->m_flDelay = m_changeTargetDelay;
pFireAndDie->pev->origin = pPlayer->pev->origin;
DispatchSpawn(pFireAndDie->edict());
}
}
strcpy(st_szNextMap, m_szMapName);
m_hActivator = pActivator;
SUB_UseTargets(pActivator, USE_TOGGLE, 0);
st_szNextSpot[0] = '\0';
edict_t *pentLandmark = FindLandmark(m_szLandmarkName);
if (!FNullEnt(pentLandmark))
{
strcpy(st_szNextSpot, m_szLandmarkName);
gpGlobals->vecLandmarkOffset = VARS(pentLandmark)->origin;
}
ALERT(at_console, "CHANGE LEVEL: %s %s\n", st_szNextMap, st_szNextSpot);
CHANGE_LEVEL(st_szNextMap, st_szNextSpot);
}
void CChangeLevel::TouchChangeLevel(CBaseEntity *pOther)
{
if (!FClassnameIs(pOther->pev, "player"))
return;
ChangeLevelNow(pOther);
}
int CChangeLevel::AddTransitionToList(LEVELLIST *pLevelList, int listCount, const char *pMapName, const char *pLandmarkName, edict_t *pentLandmark)
{
if (!pLevelList || !pMapName || !pLandmarkName || !pentLandmark)
return 0;
for (int i = 0; i < listCount; i++)
{
if (pLevelList[i].pentLandmark == pentLandmark && !strcmp(pLevelList[i].mapName, pMapName))
return 0;
}
strcpy(pLevelList[listCount].mapName, pMapName);
strcpy(pLevelList[listCount].landmarkName, pLandmarkName);
pLevelList[listCount].pentLandmark = pentLandmark;
pLevelList[listCount].vecLandmarkOrigin = VARS(pentLandmark)->origin;
return 1;
}
int BuildChangeList(LEVELLIST *pLevelList, int maxList)
{
return CChangeLevel::ChangeList(pLevelList, maxList);
}
int CChangeLevel::InTransitionVolume(CBaseEntity *pEntity, char *pVolumeName)
{
if (pEntity->ObjectCaps() & FCAP_FORCE_TRANSITION)
return 1;
if (pEntity->pev->movetype == MOVETYPE_FOLLOW)
{
if (pEntity->pev->aiment)
pEntity = CBaseEntity::Instance(pEntity->pev->aiment);
}
int inVolume = 1;
edict_t *pentVolume = FIND_ENTITY_BY_TARGETNAME(NULL, pVolumeName);
while (!FNullEnt(pentVolume))
{
CBaseEntity *pVolume = CBaseEntity::Instance(pentVolume);
if (pVolume && FClassnameIs(pVolume->pev, "trigger_transition"))
{
if (pVolume->Intersects(pEntity))
return 1;
inVolume = 0;
}
pentVolume = FIND_ENTITY_BY_TARGETNAME(pentVolume, pVolumeName);
}
return inVolume;
}
#define MAX_ENTITY 512
int CChangeLevel::ChangeList(LEVELLIST *pLevelList, int maxList)
{
int count = 0;
edict_t *pentChangelevel = FIND_ENTITY_BY_STRING(NULL, "classname", "trigger_changelevel");
if (FNullEnt(pentChangelevel))
return 0;
while (!FNullEnt(pentChangelevel))
{
CChangeLevel *pTrigger = GetClassPtr((CChangeLevel *)VARS(pentChangelevel));
if (pTrigger)
{
edict_t *pentLandmark = FindLandmark(pTrigger->m_szLandmarkName);
if (pentLandmark)
{
if (AddTransitionToList(pLevelList, count, pTrigger->m_szMapName, pTrigger->m_szLandmarkName, pentLandmark))
{
count++;
if (count >= maxList)
break;
}
}
}
pentChangelevel = FIND_ENTITY_BY_STRING(pentChangelevel, "classname", "trigger_changelevel");
}
if (gpGlobals->pSaveData && ((SAVERESTOREDATA *)gpGlobals->pSaveData)->pTable)
{
CSave saveHelper((SAVERESTOREDATA *)gpGlobals->pSaveData);
for (int i = 0; i < count; i++)
{
int entityCount = 0;
CBaseEntity *pEntList[MAX_ENTITY];
int entityFlags[MAX_ENTITY];
edict_t *pent = UTIL_EntitiesInPVS(pLevelList[i].pentLandmark);
while (!FNullEnt(pent))
{
CBaseEntity *pEntity = CBaseEntity::Instance(pent);
if (pEntity)
{
int caps = pEntity->ObjectCaps();
if (!(caps & FCAP_DONT_SAVE))
{
int flags = 0;
if (caps & FCAP_ACROSS_TRANSITION)
flags |= FENTTABLE_MOVEABLE;
if (pEntity->pev->globalname && !pEntity->IsDormant())
flags |= FENTTABLE_GLOBAL;
if (flags)
{
pEntList[entityCount] = pEntity;
entityFlags[entityCount] = flags;
entityCount++;
if (entityCount > MAX_ENTITY)
ALERT(at_error, "Too many entities across a transition!");
}
}
}
pent = pent->v.chain;
}
for (int j = 0; j < entityCount; j++)
{
if (entityFlags[j] && InTransitionVolume(pEntList[j], pLevelList[i].landmarkName))
{
int index = saveHelper.EntityIndex(pEntList[j]);
saveHelper.EntityFlagsSet(index, entityFlags[j] | (1 << i));
}
}
}
}
return count;
}
void NextLevel(void)
{
CChangeLevel *pChange;
edict_t *pent = FIND_ENTITY_BY_CLASSNAME(NULL, "trigger_changelevel");
if (FNullEnt(pent))
{
gpGlobals->mapname = ALLOC_STRING("start");
pChange = GetClassPtr((CChangeLevel *)NULL);
strcpy(pChange->m_szMapName, "start");
}
else
pChange = GetClassPtr((CChangeLevel *)VARS(pent));
strcpy(st_szNextMap, pChange->m_szMapName);
g_fGameOver = TRUE;
if (pChange->pev->nextthink < gpGlobals->time)
{
pChange->SetThink(&CChangeLevel::ExecuteChangeLevel);
pChange->pev->nextthink = gpGlobals->time + 0.1;
}
}
class CLadder : public CBaseTrigger
{
public:
void KeyValue(KeyValueData *pkvd);
void Spawn(void);
void Precache(void);
};
LINK_ENTITY_TO_CLASS(func_ladder, CLadder);
void CLadder::KeyValue(KeyValueData *pkvd)
{
CBaseTrigger::KeyValue(pkvd);
}
void CLadder::Precache(void)
{
pev->solid = SOLID_NOT;
pev->skin = CONTENTS_LADDER;
if (CVAR_GET_FLOAT("showtriggers") == 0)
{
pev->rendermode = kRenderTransTexture;
pev->renderamt = 0;
}
pev->effects &= ~EF_NODRAW;
}
void CLadder::Spawn(void)
{
Precache();
SET_MODEL(ENT(pev), STRING(pev->model));
pev->movetype = MOVETYPE_PUSH;
}
class CTriggerPush : public CBaseTrigger
{
public:
void Spawn(void);
void KeyValue(KeyValueData *pkvd);
void Touch(CBaseEntity *pOther);
};
LINK_ENTITY_TO_CLASS(trigger_push, CTriggerPush);
void CTriggerPush::KeyValue(KeyValueData *pkvd)
{
CBaseTrigger::KeyValue(pkvd);
}
void CTriggerPush::Spawn(void)
{
if (pev->angles == g_vecZero)
pev->angles.y = 360;
InitTrigger();
if (!pev->speed)
pev->speed = 100;
if (FBitSet(pev->spawnflags, SF_TRIGGER_PUSH_START_OFF))
pev->solid = SOLID_NOT;
SetUse(&CBaseTrigger::ToggleUse);
UTIL_SetOrigin(pev, pev->origin);
}
void CTriggerPush::Touch(CBaseEntity *pOther)
{
entvars_t *pevToucher = pOther->pev;
switch (pevToucher->movetype)
{
case MOVETYPE_NONE:
case MOVETYPE_PUSH:
case MOVETYPE_NOCLIP:
case MOVETYPE_FOLLOW: return;
}
if (pevToucher->solid != SOLID_NOT && pevToucher->solid != SOLID_BSP)
{
if (FBitSet(pev->spawnflags, SF_TRIG_PUSH_ONCE))
{
pevToucher->velocity = pevToucher->velocity + (pev->speed * pev->movedir);
if (pevToucher->velocity.z > 0)
pevToucher->flags &= ~FL_ONGROUND;
UTIL_Remove(this);
}
else
{
Vector vecPush = (pev->speed * pev->movedir);
if (pevToucher->flags & FL_BASEVELOCITY)
vecPush = vecPush + pevToucher->basevelocity;
pevToucher->basevelocity = vecPush;
pevToucher->flags |= FL_BASEVELOCITY;
}
}
}
void CBaseTrigger::TeleportTouch(CBaseEntity *pOther)
{
entvars_t *pevToucher = pOther->pev;
if (!FBitSet(pevToucher->flags, FL_CLIENT | FL_MONSTER))
return;
if (!UTIL_IsMasterTriggered(m_sMaster, pOther))
return;
if (!(pev->spawnflags & SF_TRIGGER_ALLOWMONSTERS))
{
if (FBitSet(pevToucher->flags, FL_MONSTER))
return;
}
if ((pev->spawnflags & SF_TRIGGER_NOCLIENTS))
{
if (pOther->IsPlayer())
return;
}
edict_t *pentTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(pev->target));
if (FNullEnt(pentTarget))
return;
Vector tmp = VARS(pentTarget)->origin;
if (pOther->IsPlayer())
tmp.z -= pOther->pev->mins.z;
tmp.z++;
pevToucher->flags &= ~FL_ONGROUND;
UTIL_SetOrigin(pevToucher, tmp);
pevToucher->angles = pentTarget->v.angles;
if (pOther->IsPlayer())
pevToucher->v_angle = pentTarget->v.angles;
pevToucher->fixangle = TRUE;
pevToucher->velocity = pevToucher->basevelocity = g_vecZero;
}
class CTriggerTeleport : public CBaseTrigger
{
public:
void Spawn(void);
};
LINK_ENTITY_TO_CLASS(trigger_teleport, CTriggerTeleport);
void CTriggerTeleport::Spawn(void)
{
InitTrigger();
SetTouch(&CBaseTrigger::TeleportTouch);
}
LINK_ENTITY_TO_CLASS(info_teleport_destination, CPointEntity);
class CBuyZone : public CBaseTrigger
{
public:
void Spawn(void);
void EXPORT BuyTouch(CBaseEntity *pOther);
};
LINK_ENTITY_TO_CLASS(func_buyzone, CBuyZone);
void CBuyZone::Spawn(void)
{
InitTrigger();
SetTouch(&CBuyZone::BuyTouch);
if (pev->team > TEAM_CT || pev->team < TEAM_UNASSIGNED)
{
ALERT(at_console, "Bad team number (%i) in func_buyzone\n", pev->team);
pev->team = 0;
}
}
void CBuyZone::BuyTouch(CBaseEntity *pOther)
{
if (!pOther->IsPlayer())
return;
CBasePlayer *pPlayer = (CBasePlayer *)pOther;
if (pev->team == TEAM_UNASSIGNED || pev->team == pPlayer->m_iTeam)
pPlayer->m_signals.Signal(SIGNAL_BUY);
}
class CBombTarget : public CBaseTrigger
{
public:
void Spawn(void);
public:
void EXPORT BombTargetTouch(CBaseEntity *pOther);
void EXPORT BombTargetUse(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
};
LINK_ENTITY_TO_CLASS(func_bomb_target, CBombTarget);
void CBombTarget::Spawn(void)
{
InitTrigger();
SetTouch(&CBombTarget::BombTargetTouch);
SetUse(&CBombTarget::BombTargetUse);
}
void CBombTarget::BombTargetTouch(CBaseEntity *pOther)
{
if (!pOther->IsPlayer())
return;
CBasePlayer *pPlayer = (CBasePlayer *)pOther;
if (pPlayer->m_bHasC4 == true)
{
pPlayer->m_signals.Signal(SIGNAL_BOMB);
pPlayer->m_pentCurBombTarget = ENT(pev);
}
}
void CBombTarget::BombTargetUse(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
{
SUB_UseTargets(NULL, USE_TOGGLE, 0);
}
class CHostageRescue : public CBaseTrigger
{
public:
void Spawn(void);
void EXPORT HostageRescueTouch(CBaseEntity *pOther);
};
LINK_ENTITY_TO_CLASS(func_hostage_rescue, CHostageRescue);
void CHostageRescue::Spawn(void)
{
InitTrigger();
SetTouch(&CHostageRescue::HostageRescueTouch);
}
void CHostageRescue::HostageRescueTouch(CBaseEntity *pOther)
{
if (pOther->IsPlayer())
{
CBasePlayer *pPlayer = (CBasePlayer *)pOther;
pPlayer->m_signals.Signal(SIGNAL_RESCUE);
}
if (FClassnameIs(pOther->pev, "hostage_entity"))
((CHostage *)pOther)->m_bRescueMe = TRUE;
}
class CEscapeZone : public CBaseTrigger
{
public:
void Spawn(void);
void EXPORT EscapeTouch(CBaseEntity *pOther);
};
LINK_ENTITY_TO_CLASS(func_escapezone, CEscapeZone);
void CEscapeZone::Spawn(void)
{
InitTrigger();
SetTouch(&CEscapeZone::EscapeTouch);
}
void CEscapeZone::EscapeTouch(CBaseEntity *pOther)
{
if (!pOther->IsPlayer())
return;
CBasePlayer *pPlayer = (CBasePlayer *)pOther;
if (pPlayer->m_iTeam == TEAM_TERRORIST)
{
pPlayer->m_bEscaped = true;
UTIL_LogPrintf("\"%s<%i><%s><TERRORIST>\" triggered \"Terrorist_Escaped\"\n", STRING(pPlayer->pev->netname), GETPLAYERUSERID(pPlayer->edict()), GETPLAYERAUTHID(pPlayer->edict()));
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
CBasePlayer *client = (CBasePlayer *)UTIL_PlayerByIndex(i);
if (!client)
continue;
if (FNullEnt(client->pev))
continue;
if (client->m_iTeam == pPlayer->m_iTeam)
ClientPrint(client->pev, HUD_PRINTCENTER, "#Terrorist_Escaped");
}
}
else if (pPlayer->m_iTeam == TEAM_CT)
pPlayer->m_signals.Signal(SIGNAL_ESCAPE);
}
class CVIP_SafetyZone : public CBaseTrigger
{
public:
void Spawn(void);
void EXPORT VIP_SafetyTouch(CBaseEntity *pOther);
};
LINK_ENTITY_TO_CLASS(func_vip_safetyzone, CVIP_SafetyZone);
void CVIP_SafetyZone::Spawn(void)
{
InitTrigger();
SetTouch(&CVIP_SafetyZone::VIP_SafetyTouch);
}
void CVIP_SafetyZone::VIP_SafetyTouch(CBaseEntity *pOther)
{
if (!pOther->IsPlayer())
return;
CBasePlayer *pPlayer = (CBasePlayer *)pOther;
pPlayer->m_signals.Signal(SIGNAL_VIPSAFETY);
if (pPlayer->m_bIsVIP == true)
{
UTIL_LogPrintf("\"%s<%i><%s><CT>\" triggered \"Escaped_As_VIP\"\n", STRING(pPlayer->pev->netname), GETPLAYERUSERID(pPlayer->edict()), GETPLAYERAUTHID(pPlayer->edict()));
pPlayer->m_bEscaped = true;
pPlayer->Disappear();
pPlayer->AddAccount(2500);
}
}
class CTriggerSave : public CBaseTrigger
{
public:
void Spawn(void);
void EXPORT SaveTouch(CBaseEntity *pOther);
};
LINK_ENTITY_TO_CLASS(trigger_autosave, CTriggerSave);
void CTriggerSave::Spawn(void)
{
if (g_pGameRules->IsDeathmatch())
{
REMOVE_ENTITY(ENT(pev));
return;
}
InitTrigger();
SetTouch(&CTriggerSave::SaveTouch);
}
void CTriggerSave::SaveTouch(CBaseEntity *pOther)
{
if (!UTIL_IsMasterTriggered(m_sMaster, pOther))
return;
if (!pOther->IsPlayer())
return;
SetTouch(NULL);
UTIL_Remove(this);
SERVER_COMMAND("autosave\n");
}
#define SF_ENDSECTION_USEONLY 0x0001
class CTriggerEndSection : public CBaseTrigger
{
public:
void Spawn(void);
void KeyValue(KeyValueData *pkvd);
public:
void EXPORT EndSectionTouch(CBaseEntity *pOther);
void EXPORT EndSectionUse(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
};
LINK_ENTITY_TO_CLASS(trigger_endsection, CTriggerEndSection);
void CTriggerEndSection::EndSectionUse(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
{
if (pActivator && !pActivator->IsNetClient())
return;
SetUse(NULL);
if (pev->message)
g_engfuncs.pfnEndSection(STRING(pev->message));
UTIL_Remove(this);
}
void CTriggerEndSection::Spawn(void)
{
if (g_pGameRules->IsDeathmatch())
{
REMOVE_ENTITY(ENT(pev));
return;
}
InitTrigger();
SetUse(&CTriggerEndSection::EndSectionUse);
if (!(pev->spawnflags & SF_ENDSECTION_USEONLY))
SetTouch(&CTriggerEndSection::EndSectionTouch);
}
void CTriggerEndSection::EndSectionTouch(CBaseEntity *pOther)
{
if (!pOther->IsNetClient())
return;
SetTouch(NULL);
if (pev->message)
g_engfuncs.pfnEndSection(STRING(pev->message));
UTIL_Remove(this);
}
void CTriggerEndSection::KeyValue(KeyValueData *pkvd)
{
if (FStrEq(pkvd->szKeyName, "section"))
{
pev->message = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CBaseTrigger::KeyValue(pkvd);
}
class CTriggerGravity : public CBaseTrigger
{
public:
void Spawn(void);
void EXPORT GravityTouch(CBaseEntity *pOther);
};
LINK_ENTITY_TO_CLASS(trigger_gravity, CTriggerGravity);
void CTriggerGravity::Spawn(void)
{
InitTrigger();
SetTouch(&CTriggerGravity::GravityTouch);
}
void CTriggerGravity::GravityTouch(CBaseEntity *pOther)
{
if (!pOther->IsPlayer())
return;
pOther->pev->gravity = pev->gravity;
}
class CTriggerChangeTarget : public CBaseDelay
{
public:
void KeyValue(KeyValueData *pkvd);
void Spawn(void);
void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
int ObjectCaps(void) { return CBaseDelay::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
int Save(CSave &save);
int Restore(CRestore &restore);
public:
static TYPEDESCRIPTION m_SaveData[];
private:
int m_iszNewTarget;
};
LINK_ENTITY_TO_CLASS(trigger_changetarget, CTriggerChangeTarget);
TYPEDESCRIPTION CTriggerChangeTarget::m_SaveData[] =
{
DEFINE_FIELD(CTriggerChangeTarget, m_iszNewTarget, FIELD_STRING),
};
IMPLEMENT_SAVERESTORE(CTriggerChangeTarget, CBaseDelay);
void CTriggerChangeTarget::KeyValue(KeyValueData *pkvd)
{
if (FStrEq(pkvd->szKeyName, "m_iszNewTarget"))
{
m_iszNewTarget = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CBaseDelay::KeyValue(pkvd);
}
void CTriggerChangeTarget::Spawn(void)
{
}
void CTriggerChangeTarget::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
{
CBaseEntity *pTarget = UTIL_FindEntityByString(NULL, "targetname", STRING(pev->target));
if (pTarget)
{
pTarget->pev->target = m_iszNewTarget;
CBaseMonster *pMonster = pTarget->MyMonsterPointer();
if (pMonster)
pMonster->m_pGoalEnt = NULL;
}
}
#define SF_CAMERA_PLAYER_POSITION 1
#define SF_CAMERA_PLAYER_TARGET 2
#define SF_CAMERA_PLAYER_TAKECONTROL 4
class CTriggerCamera : public CBaseDelay
{
public:
void Spawn(void);
void KeyValue(KeyValueData *pkvd);
void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
int Save(CSave &save);
int Restore(CRestore &restore);
int ObjectCaps(void) { return CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
public:
void EXPORT FollowTarget(void);
void Move(void);
public:
static TYPEDESCRIPTION m_SaveData[];
public:
EHANDLE m_hPlayer;
EHANDLE m_hTarget;
CBaseEntity *m_pentPath;
int m_sPath;
float m_flWait;
float m_flReturnTime;
float m_flStopTime;
float m_moveDistance;
float m_targetSpeed;
float m_initialSpeed;
float m_acceleration;
float m_deceleration;
int m_state;
};
LINK_ENTITY_TO_CLASS(trigger_camera, CTriggerCamera);
TYPEDESCRIPTION CTriggerCamera::m_SaveData[] =
{
DEFINE_FIELD(CTriggerCamera, m_hPlayer, FIELD_EHANDLE),
DEFINE_FIELD(CTriggerCamera, m_hTarget, FIELD_EHANDLE),
DEFINE_FIELD(CTriggerCamera, m_pentPath, FIELD_CLASSPTR),
DEFINE_FIELD(CTriggerCamera, m_sPath, FIELD_STRING),
DEFINE_FIELD(CTriggerCamera, m_flWait, FIELD_FLOAT),
DEFINE_FIELD(CTriggerCamera, m_flReturnTime, FIELD_TIME),
DEFINE_FIELD(CTriggerCamera, m_flStopTime, FIELD_TIME),
DEFINE_FIELD(CTriggerCamera, m_moveDistance, FIELD_FLOAT),
DEFINE_FIELD(CTriggerCamera, m_targetSpeed, FIELD_FLOAT),
DEFINE_FIELD(CTriggerCamera, m_initialSpeed, FIELD_FLOAT),
DEFINE_FIELD(CTriggerCamera, m_acceleration, FIELD_FLOAT),
DEFINE_FIELD(CTriggerCamera, m_deceleration, FIELD_FLOAT),
DEFINE_FIELD(CTriggerCamera, m_state, FIELD_INTEGER),
};
IMPLEMENT_SAVERESTORE(CTriggerCamera, CBaseDelay);
void CTriggerCamera::Spawn(void)
{
pev->movetype = MOVETYPE_NOCLIP;
pev->solid = SOLID_NOT;
pev->renderamt = 0;
pev->rendermode = kRenderTransTexture;
m_initialSpeed = pev->speed;
if (!m_acceleration)
m_acceleration = 500;
if (!m_deceleration)
m_deceleration = 500;
}
void CTriggerCamera::KeyValue(KeyValueData *pkvd)
{
if (FStrEq(pkvd->szKeyName, "wait"))
{
m_flWait = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "moveto"))
{
m_sPath = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "acceleration"))
{
m_acceleration = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "deceleration"))
{
m_deceleration = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CBaseDelay::KeyValue(pkvd);
}
void CTriggerCamera::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
{
if (!ShouldToggle(useType, m_state))
return;
m_state = !m_state;
if (!m_state)
{
m_flReturnTime = gpGlobals->time;
if (pActivator&&pActivator->IsPlayer())
{
CBasePlayer *pPlayer = (CBasePlayer *)pActivator;
pPlayer->ResetMaxSpeed();
}
return;
}
if (!pActivator || !pActivator->IsPlayer())
pActivator = CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex(1));
m_hPlayer = pActivator;
m_flReturnTime = gpGlobals->time + m_flWait;
pev->speed = m_initialSpeed;
m_targetSpeed = m_initialSpeed;
if (FBitSet(pev->spawnflags, SF_CAMERA_PLAYER_TARGET))
m_hTarget = m_hPlayer;
else
m_hTarget = GetNextTarget();
if (m_hTarget == NULL)
return;
if (pActivator->IsPlayer())
{
CBasePlayer *pPlayer = (CBasePlayer *)pActivator;
g_engfuncs.pfnSetClientMaxspeed(pActivator->edict(), 0.001);
}
if (FBitSet(pev->spawnflags, SF_CAMERA_PLAYER_TAKECONTROL))
((CBasePlayer *)pActivator)->EnableControl(FALSE);
if (m_sPath)
m_pentPath = Instance(FIND_ENTITY_BY_TARGETNAME(NULL, STRING(m_sPath)));
else
m_pentPath = NULL;
m_flStopTime = gpGlobals->time;
if (m_pentPath)
{
if (m_pentPath->pev->speed != 0)
m_targetSpeed = m_pentPath->pev->speed;
m_flStopTime += m_pentPath->GetDelay();
}
if (FBitSet(pev->spawnflags, SF_CAMERA_PLAYER_POSITION))
{
UTIL_SetOrigin(pev, pActivator->pev->origin + pActivator->pev->view_ofs);
pev->angles.x = -pActivator->pev->angles.x;
pev->angles.y = pActivator->pev->angles.y;
pev->angles.z = 0;
pev->velocity = pActivator->pev->velocity;
}
else
pev->velocity = Vector(0, 0, 0);
SET_VIEW(pActivator->edict(), edict());
SET_MODEL(ENT(pev), STRING(pActivator->pev->model));
SetThink(&CTriggerCamera::FollowTarget);
pev->nextthink = gpGlobals->time;
m_moveDistance = 0;
Move();
}
void CTriggerCamera::FollowTarget(void)
{
if (m_hPlayer == NULL)
return;
if (m_hTarget == NULL || m_flReturnTime < gpGlobals->time)
{
if (m_hPlayer->IsAlive())
{
SET_VIEW(m_hPlayer->edict(), m_hPlayer->edict());
((CBasePlayer *)((CBaseEntity *)m_hPlayer))->EnableControl(TRUE);
((CBasePlayer *)((CBaseEntity *)m_hPlayer))->ResetMaxSpeed();
}
SUB_UseTargets(this, USE_TOGGLE, 0);
pev->avelocity = Vector(0, 0, 0);
m_state = 0;
return;
}
Vector vecGoal = UTIL_VecToAngles(m_hTarget->pev->origin - pev->origin);
vecGoal.x = -vecGoal.x;
if (pev->angles.y > 360)
pev->angles.y -= 360;
if (pev->angles.y < 0)
pev->angles.y += 360;
float dx = vecGoal.x - pev->angles.x;
float dy = vecGoal.y - pev->angles.y;
if (dx < -180)
dx += 360;
if (dx > 180)
dx = dx - 360;
if (dy < -180)
dy += 360;
if (dy > 180)
dy = dy - 360;
pev->avelocity.x = dx * 40 * gpGlobals->frametime;
pev->avelocity.y = dy * 40 * gpGlobals->frametime;
if (!(FBitSet(pev->spawnflags, SF_CAMERA_PLAYER_TAKECONTROL)))
{
pev->velocity = pev->velocity * 0.8;
if (pev->velocity.Length() < 10)
pev->velocity = g_vecZero;
}
pev->nextthink = gpGlobals->time;
Move();
}
void CTriggerCamera::Move(void)
{
if (!m_pentPath)
return;
m_moveDistance -= pev->speed * gpGlobals->frametime;
if (m_moveDistance <= 0)
{
if (m_pentPath->pev->message)
{
FireTargets(STRING(m_pentPath->pev->message), this, this, USE_TOGGLE, 0);
if (FBitSet(m_pentPath->pev->spawnflags, SF_CORNER_FIREONCE))
m_pentPath->pev->message = 0;
}
m_pentPath = m_pentPath->GetNextTarget();
if (!m_pentPath)
{
pev->velocity = g_vecZero;
}
else
{
if (m_pentPath->pev->speed)
m_targetSpeed = m_pentPath->pev->speed;
Vector delta = m_pentPath->pev->origin - pev->origin;
m_moveDistance = delta.Length();
pev->movedir = delta.Normalize();
m_flStopTime = gpGlobals->time + m_pentPath->GetDelay();
}
}
if (m_flStopTime > gpGlobals->time)
pev->speed = UTIL_Approach(0, pev->speed, m_deceleration * gpGlobals->frametime);
else
pev->speed = UTIL_Approach(m_targetSpeed, pev->speed, m_acceleration * gpGlobals->frametime);
float fraction = 2 * gpGlobals->frametime;
pev->velocity = ((pev->movedir * pev->speed) * fraction) + (pev->velocity * (1 - fraction));
}
class CWeather : public CBaseTrigger
{
public:
void Spawn(void) { InitTrigger(); }
};
LINK_ENTITY_TO_CLASS(env_snow, CWeather);
LINK_ENTITY_TO_CLASS(func_snow, CWeather);
LINK_ENTITY_TO_CLASS(env_rain, CWeather);
LINK_ENTITY_TO_CLASS(func_rain, CWeather);
void CClientFog::Spawn(void)
{
pev->movetype = MOVETYPE_NOCLIP;
pev->solid = SOLID_NOT;
pev->renderamt = 0;
pev->rendermode = kRenderNormal;
}
void CClientFog::KeyValue(KeyValueData *pkvd)
{
if (FStrEq(pkvd->szKeyName, "density"))
{
m_fDensity = atof(pkvd->szValue);
if (m_fDensity < 0 || m_fDensity > 0.01)
m_fDensity = 0;
pkvd->fHandled = TRUE;
}
else
CBaseEntity::KeyValue(pkvd);
}
LINK_ENTITY_TO_CLASS(env_fog, CClientFog);