halflife-photomode/dlls/effects.cpp

2268 lines
48 KiB
C++
Raw Normal View History

/***
2013-08-30 13:34:05 -07:00
*
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "customentity.h"
#include "effects.h"
#include "weapons.h"
#include "decals.h"
#include "func_break.h"
#include "shake.h"
#define SF_GIBSHOOTER_REPEATABLE 1 // allows a gibshooter to be refired
2013-08-30 13:34:05 -07:00
#define SF_FUNNEL_REVERSE 1 // funnel effect repels particles instead of attracting them.
2013-08-30 13:34:05 -07:00
// Lightning target, just alias landmark
LINK_ENTITY_TO_CLASS(info_target, CPointEntity);
2013-08-30 13:34:05 -07:00
class CBubbling : public CBaseEntity
{
public:
void Spawn() override;
void Precache() override;
bool KeyValue(KeyValueData* pkvd) override;
void EXPORT FizzThink();
void Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value) override;
bool Save(CSave& save) override;
bool Restore(CRestore& restore) override;
int ObjectCaps() override { return CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
static TYPEDESCRIPTION m_SaveData[];
int m_density;
int m_frequency;
int m_bubbleModel;
bool m_state;
2013-08-30 13:34:05 -07:00
};
LINK_ENTITY_TO_CLASS(env_bubbles, CBubbling);
2013-08-30 13:34:05 -07:00
TYPEDESCRIPTION CBubbling::m_SaveData[] =
{
DEFINE_FIELD(CBubbling, m_density, FIELD_INTEGER),
DEFINE_FIELD(CBubbling, m_frequency, FIELD_INTEGER),
DEFINE_FIELD(CBubbling, m_state, FIELD_BOOLEAN),
// Let spawn restore this!
// DEFINE_FIELD( CBubbling, m_bubbleModel, FIELD_INTEGER ),
2013-08-30 13:34:05 -07:00
};
IMPLEMENT_SAVERESTORE(CBubbling, CBaseEntity);
2013-08-30 13:34:05 -07:00
#define SF_BUBBLES_STARTOFF 0x0001
2013-08-30 13:34:05 -07:00
void CBubbling::Spawn()
2013-08-30 13:34:05 -07:00
{
Precache();
SET_MODEL(ENT(pev), STRING(pev->model)); // Set size
2013-08-30 13:34:05 -07:00
pev->solid = SOLID_NOT; // Remove model & collisions
pev->renderamt = 0; // The engine won't draw this model if this is set to 0 and blending is on
2013-08-30 13:34:05 -07:00
pev->rendermode = kRenderTransTexture;
int speed = pev->speed > 0 ? pev->speed : -pev->speed;
// HACKHACK!!! - Speed in rendercolor
pev->rendercolor.x = speed >> 8;
pev->rendercolor.y = speed & 255;
pev->rendercolor.z = (pev->speed < 0) ? 1 : 0;
if ((pev->spawnflags & SF_BUBBLES_STARTOFF) == 0)
2013-08-30 13:34:05 -07:00
{
SetThink(&CBubbling::FizzThink);
2013-08-30 13:34:05 -07:00
pev->nextthink = gpGlobals->time + 2.0;
m_state = true;
2013-08-30 13:34:05 -07:00
}
else
m_state = false;
2013-08-30 13:34:05 -07:00
}
void CBubbling::Precache()
2013-08-30 13:34:05 -07:00
{
m_bubbleModel = PRECACHE_MODEL("sprites/bubble.spr"); // Precache bubble sprite
2013-08-30 13:34:05 -07:00
}
void CBubbling::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value)
2013-08-30 13:34:05 -07:00
{
if (ShouldToggle(useType, m_state))
2013-08-30 13:34:05 -07:00
m_state = !m_state;
if (m_state)
2013-08-30 13:34:05 -07:00
{
SetThink(&CBubbling::FizzThink);
2013-08-30 13:34:05 -07:00
pev->nextthink = gpGlobals->time + 0.1;
}
else
{
SetThink(NULL);
2013-08-30 13:34:05 -07:00
pev->nextthink = 0;
}
}
bool CBubbling::KeyValue(KeyValueData* pkvd)
2013-08-30 13:34:05 -07:00
{
if (FStrEq(pkvd->szKeyName, "density"))
{
m_density = atoi(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "frequency"))
{
m_frequency = atoi(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "current"))
{
pev->speed = atoi(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
return CBaseEntity::KeyValue(pkvd);
2013-08-30 13:34:05 -07:00
}
void CBubbling::FizzThink()
2013-08-30 13:34:05 -07:00
{
MESSAGE_BEGIN(MSG_PAS, SVC_TEMPENTITY, VecBModelOrigin(pev));
WRITE_BYTE(TE_FIZZ);
WRITE_SHORT((short)ENTINDEX(edict()));
WRITE_SHORT((short)m_bubbleModel);
WRITE_BYTE(m_density);
2013-08-30 13:34:05 -07:00
MESSAGE_END();
if (m_frequency > 19)
2013-08-30 13:34:05 -07:00
pev->nextthink = gpGlobals->time + 0.5;
else
pev->nextthink = gpGlobals->time + 2.5 - (0.1 * m_frequency);
}
// --------------------------------------------------
//
2013-08-30 13:34:05 -07:00
// Beams
//
// --------------------------------------------------
LINK_ENTITY_TO_CLASS(beam, CBeam);
2013-08-30 13:34:05 -07:00
void CBeam::Spawn()
2013-08-30 13:34:05 -07:00
{
pev->solid = SOLID_NOT; // Remove model & collisions
Precache();
2013-08-30 13:34:05 -07:00
}
void CBeam::Precache()
2013-08-30 13:34:05 -07:00
{
if (pev->owner)
SetStartEntity(ENTINDEX(pev->owner));
if (pev->aiment)
SetEndEntity(ENTINDEX(pev->aiment));
2013-08-30 13:34:05 -07:00
}
void CBeam::SetStartEntity(int entityIndex)
{
pev->sequence = (entityIndex & 0x0FFF) | (pev->sequence & 0xF000);
pev->owner = g_engfuncs.pfnPEntityOfEntIndex(entityIndex);
2013-08-30 13:34:05 -07:00
}
void CBeam::SetEndEntity(int entityIndex)
{
pev->skin = (entityIndex & 0x0FFF) | (pev->skin & 0xF000);
pev->aiment = g_engfuncs.pfnPEntityOfEntIndex(entityIndex);
2013-08-30 13:34:05 -07:00
}
// These don't take attachments into account
const Vector& CBeam::GetStartPos()
2013-08-30 13:34:05 -07:00
{
if (GetType() == BEAM_ENTS)
2013-08-30 13:34:05 -07:00
{
edict_t* pent = g_engfuncs.pfnPEntityOfEntIndex(GetStartEntity());
2013-08-30 13:34:05 -07:00
return pent->v.origin;
}
return pev->origin;
}
const Vector& CBeam::GetEndPos()
2013-08-30 13:34:05 -07:00
{
int type = GetType();
if (type == BEAM_POINTS || type == BEAM_HOSE)
2013-08-30 13:34:05 -07:00
{
return pev->angles;
}
edict_t* pent = g_engfuncs.pfnPEntityOfEntIndex(GetEndEntity());
if (pent)
2013-08-30 13:34:05 -07:00
return pent->v.origin;
return pev->angles;
}
CBeam* CBeam::BeamCreate(const char* pSpriteName, int width)
2013-08-30 13:34:05 -07:00
{
// Create a new entity with CBeam private data
CBeam* pBeam = GetClassPtr((CBeam*)NULL);
2013-08-30 13:34:05 -07:00
pBeam->pev->classname = MAKE_STRING("beam");
pBeam->BeamInit(pSpriteName, width);
2013-08-30 13:34:05 -07:00
return pBeam;
}
void CBeam::BeamInit(const char* pSpriteName, int width)
2013-08-30 13:34:05 -07:00
{
pev->flags |= FL_CUSTOMENTITY;
SetColor(255, 255, 255);
SetBrightness(255);
SetNoise(0);
SetFrame(0);
SetScrollRate(0);
pev->model = MAKE_STRING(pSpriteName);
SetTexture(PRECACHE_MODEL((char*)pSpriteName));
SetWidth(width);
2013-08-30 13:34:05 -07:00
pev->skin = 0;
pev->sequence = 0;
pev->rendermode = 0;
}
void CBeam::PointsInit(const Vector& start, const Vector& end)
2013-08-30 13:34:05 -07:00
{
SetType(BEAM_POINTS);
SetStartPos(start);
SetEndPos(end);
SetStartAttachment(0);
SetEndAttachment(0);
2013-08-30 13:34:05 -07:00
RelinkBeam();
}
void CBeam::HoseInit(const Vector& start, const Vector& direction)
2013-08-30 13:34:05 -07:00
{
SetType(BEAM_HOSE);
SetStartPos(start);
SetEndPos(direction);
SetStartAttachment(0);
SetEndAttachment(0);
2013-08-30 13:34:05 -07:00
RelinkBeam();
}
void CBeam::PointEntInit(const Vector& start, int endIndex)
2013-08-30 13:34:05 -07:00
{
SetType(BEAM_ENTPOINT);
SetStartPos(start);
SetEndEntity(endIndex);
SetStartAttachment(0);
SetEndAttachment(0);
2013-08-30 13:34:05 -07:00
RelinkBeam();
}
void CBeam::EntsInit(int startIndex, int endIndex)
2013-08-30 13:34:05 -07:00
{
SetType(BEAM_ENTS);
SetStartEntity(startIndex);
SetEndEntity(endIndex);
SetStartAttachment(0);
SetEndAttachment(0);
2013-08-30 13:34:05 -07:00
RelinkBeam();
}
void CBeam::RelinkBeam()
2013-08-30 13:34:05 -07:00
{
const Vector &startPos = GetStartPos(), &endPos = GetEndPos();
pev->mins.x = V_min(startPos.x, endPos.x);
pev->mins.y = V_min(startPos.y, endPos.y);
pev->mins.z = V_min(startPos.z, endPos.z);
pev->maxs.x = V_max(startPos.x, endPos.x);
pev->maxs.y = V_max(startPos.y, endPos.y);
pev->maxs.z = V_max(startPos.z, endPos.z);
2013-08-30 13:34:05 -07:00
pev->mins = pev->mins - pev->origin;
pev->maxs = pev->maxs - pev->origin;
UTIL_SetSize(pev, pev->mins, pev->maxs);
UTIL_SetOrigin(pev, pev->origin);
2013-08-30 13:34:05 -07:00
}
#if 0
void CBeam::SetObjectCollisionBox()
2013-08-30 13:34:05 -07:00
{
const Vector &startPos = GetStartPos(), &endPos = GetEndPos();
2018-09-03 00:01:23 +02:00
pev->absmin.x = V_min( startPos.x, endPos.x );
pev->absmin.y = V_min( startPos.y, endPos.y );
pev->absmin.z = V_min( startPos.z, endPos.z );
pev->absmax.x = V_max( startPos.x, endPos.x );
pev->absmax.y = V_max( startPos.y, endPos.y );
pev->absmax.z = V_max( startPos.z, endPos.z );
2013-08-30 13:34:05 -07:00
}
#endif
void CBeam::TriggerTouch(CBaseEntity* pOther)
2013-08-30 13:34:05 -07:00
{
if ((pOther->pev->flags & (FL_CLIENT | FL_MONSTER)) != 0)
2013-08-30 13:34:05 -07:00
{
if (pev->owner)
2013-08-30 13:34:05 -07:00
{
CBaseEntity* pOwner = CBaseEntity::Instance(pev->owner);
pOwner->Use(pOther, this, USE_TOGGLE, 0);
2013-08-30 13:34:05 -07:00
}
ALERT(at_console, "Firing targets!!!\n");
2013-08-30 13:34:05 -07:00
}
}
CBaseEntity* CBeam::RandomTargetname(const char* szName)
2013-08-30 13:34:05 -07:00
{
int total = 0;
CBaseEntity* pEntity = NULL;
CBaseEntity* pNewEntity = NULL;
while ((pNewEntity = UTIL_FindEntityByTargetname(pNewEntity, szName)) != NULL)
2013-08-30 13:34:05 -07:00
{
total++;
if (RANDOM_LONG(0, total - 1) < 1)
2013-08-30 13:34:05 -07:00
pEntity = pNewEntity;
}
return pEntity;
}
void CBeam::DoSparks(const Vector& start, const Vector& end)
2013-08-30 13:34:05 -07:00
{
if ((pev->spawnflags & (SF_BEAM_SPARKSTART | SF_BEAM_SPARKEND)) != 0)
2013-08-30 13:34:05 -07:00
{
if ((pev->spawnflags & SF_BEAM_SPARKSTART) != 0)
2013-08-30 13:34:05 -07:00
{
UTIL_Sparks(start);
2013-08-30 13:34:05 -07:00
}
if ((pev->spawnflags & SF_BEAM_SPARKEND) != 0)
2013-08-30 13:34:05 -07:00
{
UTIL_Sparks(end);
2013-08-30 13:34:05 -07:00
}
}
}
class CLightning : public CBeam
{
public:
void Spawn() override;
void Precache() override;
bool KeyValue(KeyValueData* pkvd) override;
void Activate() override;
void EXPORT StrikeThink();
void EXPORT DamageThink();
void RandomArea();
void RandomPoint(Vector& vecSrc);
void Zap(const Vector& vecSrc, const Vector& vecDest);
void EXPORT StrikeUse(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value);
void EXPORT ToggleUse(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value);
inline bool ServerSide()
2013-08-30 13:34:05 -07:00
{
if (m_life == 0 && (pev->spawnflags & SF_BEAM_RING) == 0)
2021-11-19 13:45:16 +01:00
return true;
2021-11-19 13:43:33 +01:00
return false;
2013-08-30 13:34:05 -07:00
}
bool Save(CSave& save) override;
bool Restore(CRestore& restore) override;
static TYPEDESCRIPTION m_SaveData[];
2013-08-30 13:34:05 -07:00
void BeamUpdateVars();
2013-08-30 13:34:05 -07:00
bool m_active;
int m_iszStartEntity;
int m_iszEndEntity;
float m_life;
int m_boltWidth;
int m_noiseAmplitude;
int m_brightness;
int m_speed;
float m_restrike;
int m_spriteTexture;
int m_iszSpriteName;
int m_frameStart;
2013-08-30 13:34:05 -07:00
float m_radius;
2013-08-30 13:34:05 -07:00
};
LINK_ENTITY_TO_CLASS(env_lightning, CLightning);
LINK_ENTITY_TO_CLASS(env_beam, CLightning);
2013-08-30 13:34:05 -07:00
// UNDONE: Jay -- This is only a test
#if _DEBUG
class CTripBeam : public CLightning
{
void Spawn() override;
2013-08-30 13:34:05 -07:00
};
LINK_ENTITY_TO_CLASS(trip_beam, CTripBeam);
2013-08-30 13:34:05 -07:00
void CTripBeam::Spawn()
2013-08-30 13:34:05 -07:00
{
CLightning::Spawn();
SetTouch(&CBeam::TriggerTouch);
2013-08-30 13:34:05 -07:00
pev->solid = SOLID_TRIGGER;
RelinkBeam();
}
#endif
TYPEDESCRIPTION CLightning::m_SaveData[] =
{
DEFINE_FIELD(CLightning, m_active, FIELD_BOOLEAN),
DEFINE_FIELD(CLightning, m_iszStartEntity, FIELD_STRING),
DEFINE_FIELD(CLightning, m_iszEndEntity, FIELD_STRING),
DEFINE_FIELD(CLightning, m_life, FIELD_FLOAT),
DEFINE_FIELD(CLightning, m_boltWidth, FIELD_INTEGER),
DEFINE_FIELD(CLightning, m_noiseAmplitude, FIELD_INTEGER),
DEFINE_FIELD(CLightning, m_brightness, FIELD_INTEGER),
DEFINE_FIELD(CLightning, m_speed, FIELD_INTEGER),
DEFINE_FIELD(CLightning, m_restrike, FIELD_FLOAT),
DEFINE_FIELD(CLightning, m_spriteTexture, FIELD_INTEGER),
DEFINE_FIELD(CLightning, m_iszSpriteName, FIELD_STRING),
DEFINE_FIELD(CLightning, m_frameStart, FIELD_INTEGER),
DEFINE_FIELD(CLightning, m_radius, FIELD_FLOAT),
2013-08-30 13:34:05 -07:00
};
IMPLEMENT_SAVERESTORE(CLightning, CBeam);
2013-08-30 13:34:05 -07:00
void CLightning::Spawn()
2013-08-30 13:34:05 -07:00
{
if (FStringNull(m_iszSpriteName))
2013-08-30 13:34:05 -07:00
{
SetThink(&CLightning::SUB_Remove);
2013-08-30 13:34:05 -07:00
return;
}
pev->solid = SOLID_NOT; // Remove model & collisions
Precache();
2013-08-30 13:34:05 -07:00
pev->dmgtime = gpGlobals->time;
if (ServerSide())
2013-08-30 13:34:05 -07:00
{
SetThink(NULL);
if (pev->dmg > 0)
2013-08-30 13:34:05 -07:00
{
SetThink(&CLightning::DamageThink);
2013-08-30 13:34:05 -07:00
pev->nextthink = gpGlobals->time + 0.1;
}
if (!FStringNull(pev->targetname))
2013-08-30 13:34:05 -07:00
{
if ((pev->spawnflags & SF_BEAM_STARTON) == 0)
2013-08-30 13:34:05 -07:00
{
pev->effects = EF_NODRAW;
m_active = false;
2013-08-30 13:34:05 -07:00
pev->nextthink = 0;
}
else
m_active = true;
SetUse(&CLightning::ToggleUse);
2013-08-30 13:34:05 -07:00
}
}
else
{
m_active = false;
if (!FStringNull(pev->targetname))
2013-08-30 13:34:05 -07:00
{
SetUse(&CLightning::StrikeUse);
2013-08-30 13:34:05 -07:00
}
if (FStringNull(pev->targetname) || FBitSet(pev->spawnflags, SF_BEAM_STARTON))
2013-08-30 13:34:05 -07:00
{
SetThink(&CLightning::StrikeThink);
2013-08-30 13:34:05 -07:00
pev->nextthink = gpGlobals->time + 1.0;
}
}
}
void CLightning::Precache()
2013-08-30 13:34:05 -07:00
{
m_spriteTexture = PRECACHE_MODEL((char*)STRING(m_iszSpriteName));
2013-08-30 13:34:05 -07:00
CBeam::Precache();
}
void CLightning::Activate()
2013-08-30 13:34:05 -07:00
{
if (ServerSide())
2013-08-30 13:34:05 -07:00
BeamUpdateVars();
}
bool CLightning::KeyValue(KeyValueData* pkvd)
2013-08-30 13:34:05 -07:00
{
if (FStrEq(pkvd->szKeyName, "LightningStart"))
{
m_iszStartEntity = ALLOC_STRING(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "LightningEnd"))
{
m_iszEndEntity = ALLOC_STRING(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "life"))
{
m_life = atof(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "BoltWidth"))
{
m_boltWidth = atoi(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "NoiseAmplitude"))
{
m_noiseAmplitude = atoi(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "TextureScroll"))
{
m_speed = atoi(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "StrikeTime"))
{
m_restrike = atof(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "texture"))
{
m_iszSpriteName = ALLOC_STRING(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "framestart"))
{
m_frameStart = atoi(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "Radius"))
{
m_radius = atof(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "damage"))
{
pev->dmg = atof(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
return CBeam::KeyValue(pkvd);
2013-08-30 13:34:05 -07:00
}
void CLightning::ToggleUse(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value)
2013-08-30 13:34:05 -07:00
{
if (!ShouldToggle(useType, m_active))
2013-08-30 13:34:05 -07:00
return;
if (m_active)
2013-08-30 13:34:05 -07:00
{
m_active = false;
2013-08-30 13:34:05 -07:00
pev->effects |= EF_NODRAW;
pev->nextthink = 0;
}
else
{
m_active = true;
2013-08-30 13:34:05 -07:00
pev->effects &= ~EF_NODRAW;
DoSparks(GetStartPos(), GetEndPos());
if (pev->dmg > 0)
2013-08-30 13:34:05 -07:00
{
pev->nextthink = gpGlobals->time;
pev->dmgtime = gpGlobals->time;
}
}
}
void CLightning::StrikeUse(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value)
2013-08-30 13:34:05 -07:00
{
if (!ShouldToggle(useType, m_active))
2013-08-30 13:34:05 -07:00
return;
if (m_active)
2013-08-30 13:34:05 -07:00
{
m_active = false;
SetThink(NULL);
2013-08-30 13:34:05 -07:00
}
else
{
SetThink(&CLightning::StrikeThink);
2013-08-30 13:34:05 -07:00
pev->nextthink = gpGlobals->time + 0.1;
}
if (!FBitSet(pev->spawnflags, SF_BEAM_TOGGLE))
SetUse(NULL);
2013-08-30 13:34:05 -07:00
}
bool IsPointEntity(CBaseEntity* pEnt)
2013-08-30 13:34:05 -07:00
{
if (0 == pEnt->pev->modelindex)
return true;
if (FClassnameIs(pEnt->pev, "info_target") || FClassnameIs(pEnt->pev, "info_landmark") || FClassnameIs(pEnt->pev, "path_corner"))
return true;
2013-08-30 13:34:05 -07:00
return false;
2013-08-30 13:34:05 -07:00
}
void CLightning::StrikeThink()
2013-08-30 13:34:05 -07:00
{
if (m_life != 0)
2013-08-30 13:34:05 -07:00
{
if ((pev->spawnflags & SF_BEAM_RANDOM) != 0)
pev->nextthink = gpGlobals->time + m_life + RANDOM_FLOAT(0, m_restrike);
2013-08-30 13:34:05 -07:00
else
pev->nextthink = gpGlobals->time + m_life + m_restrike;
}
m_active = true;
2013-08-30 13:34:05 -07:00
if (FStringNull(m_iszEndEntity))
{
if (FStringNull(m_iszStartEntity))
{
RandomArea();
2013-08-30 13:34:05 -07:00
}
else
{
CBaseEntity* pStart = RandomTargetname(STRING(m_iszStartEntity));
2013-08-30 13:34:05 -07:00
if (pStart != NULL)
RandomPoint(pStart->pev->origin);
2013-08-30 13:34:05 -07:00
else
ALERT(at_console, "env_beam: unknown entity \"%s\"\n", STRING(m_iszStartEntity));
2013-08-30 13:34:05 -07:00
}
return;
}
CBaseEntity* pStart = RandomTargetname(STRING(m_iszStartEntity));
CBaseEntity* pEnd = RandomTargetname(STRING(m_iszEndEntity));
2013-08-30 13:34:05 -07:00
if (pStart != NULL && pEnd != NULL)
2013-08-30 13:34:05 -07:00
{
if (IsPointEntity(pStart) || IsPointEntity(pEnd))
2013-08-30 13:34:05 -07:00
{
if ((pev->spawnflags & SF_BEAM_RING) != 0)
2013-08-30 13:34:05 -07:00
{
// don't work
return;
}
}
MESSAGE_BEGIN(MSG_BROADCAST, SVC_TEMPENTITY);
if (IsPointEntity(pStart) || IsPointEntity(pEnd))
{
if (!IsPointEntity(pEnd)) // One point entity must be in pEnd
2013-08-30 13:34:05 -07:00
{
CBaseEntity* pTemp;
pTemp = pStart;
pStart = pEnd;
pEnd = pTemp;
}
if (!IsPointEntity(pStart)) // One sided
{
WRITE_BYTE(TE_BEAMENTPOINT);
WRITE_SHORT(pStart->entindex());
WRITE_COORD(pEnd->pev->origin.x);
WRITE_COORD(pEnd->pev->origin.y);
WRITE_COORD(pEnd->pev->origin.z);
2013-08-30 13:34:05 -07:00
}
else
{
WRITE_BYTE(TE_BEAMPOINTS);
WRITE_COORD(pStart->pev->origin.x);
WRITE_COORD(pStart->pev->origin.y);
WRITE_COORD(pStart->pev->origin.z);
WRITE_COORD(pEnd->pev->origin.x);
WRITE_COORD(pEnd->pev->origin.y);
WRITE_COORD(pEnd->pev->origin.z);
2013-08-30 13:34:05 -07:00
}
}
else
{
if ((pev->spawnflags & SF_BEAM_RING) != 0)
WRITE_BYTE(TE_BEAMRING);
else
WRITE_BYTE(TE_BEAMENTS);
WRITE_SHORT(pStart->entindex());
WRITE_SHORT(pEnd->entindex());
}
2013-08-30 13:34:05 -07:00
WRITE_SHORT(m_spriteTexture);
WRITE_BYTE(m_frameStart); // framestart
WRITE_BYTE((int)pev->framerate); // framerate
WRITE_BYTE((int)(m_life * 10.0)); // life
WRITE_BYTE(m_boltWidth); // width
WRITE_BYTE(m_noiseAmplitude); // noise
WRITE_BYTE((int)pev->rendercolor.x); // r, g, b
WRITE_BYTE((int)pev->rendercolor.y); // r, g, b
WRITE_BYTE((int)pev->rendercolor.z); // r, g, b
WRITE_BYTE(pev->renderamt); // brightness
WRITE_BYTE(m_speed); // speed
2013-08-30 13:34:05 -07:00
MESSAGE_END();
DoSparks(pStart->pev->origin, pEnd->pev->origin);
if (pev->dmg > 0)
2013-08-30 13:34:05 -07:00
{
TraceResult tr;
UTIL_TraceLine(pStart->pev->origin, pEnd->pev->origin, dont_ignore_monsters, NULL, &tr);
BeamDamageInstant(&tr, pev->dmg);
2013-08-30 13:34:05 -07:00
}
}
}
void CBeam::BeamDamage(TraceResult* ptr)
2013-08-30 13:34:05 -07:00
{
RelinkBeam();
if (ptr->flFraction != 1.0 && ptr->pHit != NULL)
2013-08-30 13:34:05 -07:00
{
CBaseEntity* pHit = CBaseEntity::Instance(ptr->pHit);
if (pHit)
2013-08-30 13:34:05 -07:00
{
ClearMultiDamage();
pHit->TraceAttack(pev, pev->dmg * (gpGlobals->time - pev->dmgtime), (ptr->vecEndPos - pev->origin).Normalize(), ptr, DMG_ENERGYBEAM);
ApplyMultiDamage(pev, pev);
if ((pev->spawnflags & SF_BEAM_DECALS) != 0)
2013-08-30 13:34:05 -07:00
{
if (pHit->IsBSPModel())
UTIL_DecalTrace(ptr, DECAL_BIGSHOT1 + RANDOM_LONG(0, 4));
2013-08-30 13:34:05 -07:00
}
}
}
pev->dmgtime = gpGlobals->time;
}
void CLightning::DamageThink()
2013-08-30 13:34:05 -07:00
{
pev->nextthink = gpGlobals->time + 0.1;
TraceResult tr;
UTIL_TraceLine(GetStartPos(), GetEndPos(), dont_ignore_monsters, NULL, &tr);
BeamDamage(&tr);
2013-08-30 13:34:05 -07:00
}
void CLightning::Zap(const Vector& vecSrc, const Vector& vecDest)
2013-08-30 13:34:05 -07:00
{
#if 1
MESSAGE_BEGIN(MSG_BROADCAST, SVC_TEMPENTITY);
WRITE_BYTE(TE_BEAMPOINTS);
WRITE_COORD(vecSrc.x);
WRITE_COORD(vecSrc.y);
WRITE_COORD(vecSrc.z);
WRITE_COORD(vecDest.x);
WRITE_COORD(vecDest.y);
WRITE_COORD(vecDest.z);
WRITE_SHORT(m_spriteTexture);
WRITE_BYTE(m_frameStart); // framestart
WRITE_BYTE((int)pev->framerate); // framerate
WRITE_BYTE((int)(m_life * 10.0)); // life
WRITE_BYTE(m_boltWidth); // width
WRITE_BYTE(m_noiseAmplitude); // noise
WRITE_BYTE((int)pev->rendercolor.x); // r, g, b
WRITE_BYTE((int)pev->rendercolor.y); // r, g, b
WRITE_BYTE((int)pev->rendercolor.z); // r, g, b
WRITE_BYTE(pev->renderamt); // brightness
WRITE_BYTE(m_speed); // speed
2013-08-30 13:34:05 -07:00
MESSAGE_END();
#else
MESSAGE_BEGIN(MSG_BROADCAST, SVC_TEMPENTITY);
WRITE_BYTE(TE_LIGHTNING);
WRITE_COORD(vecSrc.x);
WRITE_COORD(vecSrc.y);
WRITE_COORD(vecSrc.z);
WRITE_COORD(vecDest.x);
WRITE_COORD(vecDest.y);
WRITE_COORD(vecDest.z);
WRITE_BYTE(10);
WRITE_BYTE(50);
WRITE_BYTE(40);
WRITE_SHORT(m_spriteTexture);
2013-08-30 13:34:05 -07:00
MESSAGE_END();
#endif
DoSparks(vecSrc, vecDest);
2013-08-30 13:34:05 -07:00
}
void CLightning::RandomArea()
2013-08-30 13:34:05 -07:00
{
int iLoops = 0;
for (iLoops = 0; iLoops < 10; iLoops++)
{
Vector vecSrc = pev->origin;
Vector vecDir1 = Vector(RANDOM_FLOAT(-1.0, 1.0), RANDOM_FLOAT(-1.0, 1.0), RANDOM_FLOAT(-1.0, 1.0));
2013-08-30 13:34:05 -07:00
vecDir1 = vecDir1.Normalize();
TraceResult tr1;
UTIL_TraceLine(vecSrc, vecSrc + vecDir1 * m_radius, ignore_monsters, ENT(pev), &tr1);
2013-08-30 13:34:05 -07:00
if (tr1.flFraction == 1.0)
continue;
Vector vecDir2;
do
{
vecDir2 = Vector(RANDOM_FLOAT(-1.0, 1.0), RANDOM_FLOAT(-1.0, 1.0), RANDOM_FLOAT(-1.0, 1.0));
} while (DotProduct(vecDir1, vecDir2) > 0);
2013-08-30 13:34:05 -07:00
vecDir2 = vecDir2.Normalize();
TraceResult tr2;
UTIL_TraceLine(vecSrc, vecSrc + vecDir2 * m_radius, ignore_monsters, ENT(pev), &tr2);
2013-08-30 13:34:05 -07:00
if (tr2.flFraction == 1.0)
continue;
if ((tr1.vecEndPos - tr2.vecEndPos).Length() < m_radius * 0.1)
continue;
UTIL_TraceLine(tr1.vecEndPos, tr2.vecEndPos, ignore_monsters, ENT(pev), &tr2);
2013-08-30 13:34:05 -07:00
if (tr2.flFraction != 1.0)
continue;
Zap(tr1.vecEndPos, tr2.vecEndPos);
2013-08-30 13:34:05 -07:00
break;
}
}
void CLightning::RandomPoint(Vector& vecSrc)
2013-08-30 13:34:05 -07:00
{
int iLoops = 0;
for (iLoops = 0; iLoops < 10; iLoops++)
{
Vector vecDir1 = Vector(RANDOM_FLOAT(-1.0, 1.0), RANDOM_FLOAT(-1.0, 1.0), RANDOM_FLOAT(-1.0, 1.0));
2013-08-30 13:34:05 -07:00
vecDir1 = vecDir1.Normalize();
TraceResult tr1;
UTIL_TraceLine(vecSrc, vecSrc + vecDir1 * m_radius, ignore_monsters, ENT(pev), &tr1);
2013-08-30 13:34:05 -07:00
if ((tr1.vecEndPos - vecSrc).Length() < m_radius * 0.1)
continue;
if (tr1.flFraction == 1.0)
continue;
Zap(vecSrc, tr1.vecEndPos);
2013-08-30 13:34:05 -07:00
break;
}
}
void CLightning::BeamUpdateVars()
2013-08-30 13:34:05 -07:00
{
int beamType;
bool pointStart, pointEnd;
2013-08-30 13:34:05 -07:00
edict_t* pStart = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(m_iszStartEntity));
edict_t* pEnd = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(m_iszEndEntity));
pointStart = IsPointEntity(CBaseEntity::Instance(pStart));
pointEnd = IsPointEntity(CBaseEntity::Instance(pEnd));
2013-08-30 13:34:05 -07:00
pev->skin = 0;
pev->sequence = 0;
pev->rendermode = 0;
pev->flags |= FL_CUSTOMENTITY;
pev->model = m_iszSpriteName;
SetTexture(m_spriteTexture);
2013-08-30 13:34:05 -07:00
beamType = BEAM_ENTS;
if (pointStart || pointEnd)
2013-08-30 13:34:05 -07:00
{
if (!pointStart) // One point entity must be in pStart
2013-08-30 13:34:05 -07:00
{
edict_t* pTemp;
2013-08-30 13:34:05 -07:00
// Swap start & end
pTemp = pStart;
pStart = pEnd;
pEnd = pTemp;
bool swap = pointStart;
2013-08-30 13:34:05 -07:00
pointStart = pointEnd;
pointEnd = swap;
}
if (!pointEnd)
2013-08-30 13:34:05 -07:00
beamType = BEAM_ENTPOINT;
else
beamType = BEAM_POINTS;
}
SetType(beamType);
if (beamType == BEAM_POINTS || beamType == BEAM_ENTPOINT || beamType == BEAM_HOSE)
2013-08-30 13:34:05 -07:00
{
SetStartPos(pStart->v.origin);
if (beamType == BEAM_POINTS || beamType == BEAM_HOSE)
SetEndPos(pEnd->v.origin);
2013-08-30 13:34:05 -07:00
else
SetEndEntity(ENTINDEX(pEnd));
2013-08-30 13:34:05 -07:00
}
else
{
SetStartEntity(ENTINDEX(pStart));
SetEndEntity(ENTINDEX(pEnd));
2013-08-30 13:34:05 -07:00
}
RelinkBeam();
SetWidth(m_boltWidth);
SetNoise(m_noiseAmplitude);
SetFrame(m_frameStart);
SetScrollRate(m_speed);
if ((pev->spawnflags & SF_BEAM_SHADEIN) != 0)
SetFlags(BEAM_FSHADEIN);
else if ((pev->spawnflags & SF_BEAM_SHADEOUT) != 0)
SetFlags(BEAM_FSHADEOUT);
2013-08-30 13:34:05 -07:00
}
LINK_ENTITY_TO_CLASS(env_laser, CLaser);
2013-08-30 13:34:05 -07:00
TYPEDESCRIPTION CLaser::m_SaveData[] =
{
DEFINE_FIELD(CLaser, m_pSprite, FIELD_CLASSPTR),
DEFINE_FIELD(CLaser, m_iszSpriteName, FIELD_STRING),
DEFINE_FIELD(CLaser, m_firePosition, FIELD_POSITION_VECTOR),
2013-08-30 13:34:05 -07:00
};
IMPLEMENT_SAVERESTORE(CLaser, CBeam);
2013-08-30 13:34:05 -07:00
void CLaser::Spawn()
2013-08-30 13:34:05 -07:00
{
if (FStringNull(pev->model))
2013-08-30 13:34:05 -07:00
{
SetThink(&CLaser::SUB_Remove);
2013-08-30 13:34:05 -07:00
return;
}
pev->solid = SOLID_NOT; // Remove model & collisions
Precache();
2013-08-30 13:34:05 -07:00
SetThink(&CLaser::StrikeThink);
2013-08-30 13:34:05 -07:00
pev->flags |= FL_CUSTOMENTITY;
PointsInit(pev->origin, pev->origin);
2013-08-30 13:34:05 -07:00
if (!m_pSprite && !FStringNull(m_iszSpriteName))
m_pSprite = CSprite::SpriteCreate(STRING(m_iszSpriteName), pev->origin, true);
2013-08-30 13:34:05 -07:00
else
m_pSprite = NULL;
if (m_pSprite)
m_pSprite->SetTransparency(kRenderGlow, pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z, pev->renderamt, pev->renderfx);
2013-08-30 13:34:05 -07:00
if (!FStringNull(pev->targetname) && (pev->spawnflags & SF_BEAM_STARTON) == 0)
2013-08-30 13:34:05 -07:00
TurnOff();
else
TurnOn();
}
void CLaser::Precache()
2013-08-30 13:34:05 -07:00
{
pev->modelindex = PRECACHE_MODEL((char*)STRING(pev->model));
if (!FStringNull(m_iszSpriteName))
PRECACHE_MODEL((char*)STRING(m_iszSpriteName));
2013-08-30 13:34:05 -07:00
}
bool CLaser::KeyValue(KeyValueData* pkvd)
2013-08-30 13:34:05 -07:00
{
if (FStrEq(pkvd->szKeyName, "LaserTarget"))
{
pev->message = ALLOC_STRING(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "width"))
{
SetWidth((int)atof(pkvd->szValue));
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "NoiseAmplitude"))
{
SetNoise(atoi(pkvd->szValue));
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "TextureScroll"))
{
SetScrollRate(atoi(pkvd->szValue));
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "texture"))
{
pev->model = ALLOC_STRING(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "EndSprite"))
{
m_iszSpriteName = ALLOC_STRING(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "framestart"))
{
pev->frame = atoi(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "damage"))
{
pev->dmg = atof(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
return CBeam::KeyValue(pkvd);
2013-08-30 13:34:05 -07:00
}
bool CLaser::IsOn()
2013-08-30 13:34:05 -07:00
{
if ((pev->effects & EF_NODRAW) != 0)
return false;
return true;
2013-08-30 13:34:05 -07:00
}
void CLaser::TurnOff()
2013-08-30 13:34:05 -07:00
{
pev->effects |= EF_NODRAW;
pev->nextthink = 0;
if (m_pSprite)
2013-08-30 13:34:05 -07:00
m_pSprite->TurnOff();
}
void CLaser::TurnOn()
2013-08-30 13:34:05 -07:00
{
pev->effects &= ~EF_NODRAW;
if (m_pSprite)
2013-08-30 13:34:05 -07:00
m_pSprite->TurnOn();
pev->dmgtime = gpGlobals->time;
pev->nextthink = gpGlobals->time;
}
void CLaser::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value)
2013-08-30 13:34:05 -07:00
{
bool active = IsOn();
2013-08-30 13:34:05 -07:00
if (!ShouldToggle(useType, active))
2013-08-30 13:34:05 -07:00
return;
if (active)
2013-08-30 13:34:05 -07:00
{
TurnOff();
}
else
{
TurnOn();
}
}
void CLaser::FireAtPoint(TraceResult& tr)
2013-08-30 13:34:05 -07:00
{
SetEndPos(tr.vecEndPos);
if (m_pSprite)
UTIL_SetOrigin(m_pSprite->pev, tr.vecEndPos);
2013-08-30 13:34:05 -07:00
BeamDamage(&tr);
DoSparks(GetStartPos(), tr.vecEndPos);
2013-08-30 13:34:05 -07:00
}
void CLaser::StrikeThink()
2013-08-30 13:34:05 -07:00
{
CBaseEntity* pEnd = RandomTargetname(STRING(pev->message));
2013-08-30 13:34:05 -07:00
if (pEnd)
2013-08-30 13:34:05 -07:00
m_firePosition = pEnd->pev->origin;
TraceResult tr;
UTIL_TraceLine(pev->origin, m_firePosition, dont_ignore_monsters, NULL, &tr);
FireAtPoint(tr);
2013-08-30 13:34:05 -07:00
pev->nextthink = gpGlobals->time + 0.1;
}
class CGlow : public CPointEntity
{
public:
void Spawn() override;
void Think() override;
void Animate(float frames);
bool Save(CSave& save) override;
bool Restore(CRestore& restore) override;
static TYPEDESCRIPTION m_SaveData[];
2013-08-30 13:34:05 -07:00
float m_lastTime;
float m_maxFrame;
2013-08-30 13:34:05 -07:00
};
LINK_ENTITY_TO_CLASS(env_glow, CGlow);
2013-08-30 13:34:05 -07:00
TYPEDESCRIPTION CGlow::m_SaveData[] =
{
DEFINE_FIELD(CGlow, m_lastTime, FIELD_TIME),
DEFINE_FIELD(CGlow, m_maxFrame, FIELD_FLOAT),
2013-08-30 13:34:05 -07:00
};
IMPLEMENT_SAVERESTORE(CGlow, CPointEntity);
2013-08-30 13:34:05 -07:00
void CGlow::Spawn()
2013-08-30 13:34:05 -07:00
{
pev->solid = SOLID_NOT;
pev->movetype = MOVETYPE_NONE;
pev->effects = 0;
pev->frame = 0;
2013-08-30 13:34:05 -07:00
PRECACHE_MODEL((char*)STRING(pev->model));
SET_MODEL(ENT(pev), STRING(pev->model));
2013-08-30 13:34:05 -07:00
m_maxFrame = (float)MODEL_FRAMES(pev->modelindex) - 1;
if (m_maxFrame > 1.0 && pev->framerate != 0)
pev->nextthink = gpGlobals->time + 0.1;
2013-08-30 13:34:05 -07:00
m_lastTime = gpGlobals->time;
}
void CGlow::Think()
2013-08-30 13:34:05 -07:00
{
Animate(pev->framerate * (gpGlobals->time - m_lastTime));
2013-08-30 13:34:05 -07:00
pev->nextthink = gpGlobals->time + 0.1;
m_lastTime = gpGlobals->time;
2013-08-30 13:34:05 -07:00
}
void CGlow::Animate(float frames)
{
if (m_maxFrame > 0)
pev->frame = fmod(pev->frame + frames, m_maxFrame);
2013-08-30 13:34:05 -07:00
}
LINK_ENTITY_TO_CLASS(env_sprite, CSprite);
2013-08-30 13:34:05 -07:00
TYPEDESCRIPTION CSprite::m_SaveData[] =
{
DEFINE_FIELD(CSprite, m_lastTime, FIELD_TIME),
DEFINE_FIELD(CSprite, m_maxFrame, FIELD_FLOAT),
2013-08-30 13:34:05 -07:00
};
IMPLEMENT_SAVERESTORE(CSprite, CPointEntity);
2013-08-30 13:34:05 -07:00
void CSprite::Spawn()
2013-08-30 13:34:05 -07:00
{
pev->solid = SOLID_NOT;
pev->movetype = MOVETYPE_NONE;
pev->effects = 0;
pev->frame = 0;
2013-08-30 13:34:05 -07:00
Precache();
SET_MODEL(ENT(pev), STRING(pev->model));
2013-08-30 13:34:05 -07:00
m_maxFrame = (float)MODEL_FRAMES(pev->modelindex) - 1;
if (!FStringNull(pev->targetname) && (pev->spawnflags & SF_SPRITE_STARTON) == 0)
2013-08-30 13:34:05 -07:00
TurnOff();
else
TurnOn();
2013-08-30 13:34:05 -07:00
// Worldcraft only sets y rotation, copy to Z
if (pev->angles.y != 0 && pev->angles.z == 0)
2013-08-30 13:34:05 -07:00
{
pev->angles.z = pev->angles.y;
pev->angles.y = 0;
}
}
void CSprite::Precache()
2013-08-30 13:34:05 -07:00
{
PRECACHE_MODEL((char*)STRING(pev->model));
2013-08-30 13:34:05 -07:00
// Reset attachment after save/restore
if (pev->aiment)
SetAttachment(pev->aiment, pev->body);
2013-08-30 13:34:05 -07:00
else
{
// Clear attachment
pev->skin = 0;
pev->body = 0;
}
}
void CSprite::SpriteInit(const char* pSpriteName, const Vector& origin)
2013-08-30 13:34:05 -07:00
{
pev->model = MAKE_STRING(pSpriteName);
pev->origin = origin;
Spawn();
}
CSprite* CSprite::SpriteCreate(const char* pSpriteName, const Vector& origin, bool animate)
2013-08-30 13:34:05 -07:00
{
CSprite* pSprite = GetClassPtr((CSprite*)NULL);
pSprite->SpriteInit(pSpriteName, origin);
2013-08-30 13:34:05 -07:00
pSprite->pev->classname = MAKE_STRING("env_sprite");
pSprite->pev->solid = SOLID_NOT;
pSprite->pev->movetype = MOVETYPE_NOCLIP;
if (animate)
2013-08-30 13:34:05 -07:00
pSprite->TurnOn();
return pSprite;
}
void CSprite::AnimateThink()
2013-08-30 13:34:05 -07:00
{
Animate(pev->framerate * (gpGlobals->time - m_lastTime));
2013-08-30 13:34:05 -07:00
pev->nextthink = gpGlobals->time + 0.1;
m_lastTime = gpGlobals->time;
2013-08-30 13:34:05 -07:00
}
void CSprite::AnimateUntilDead()
2013-08-30 13:34:05 -07:00
{
if (gpGlobals->time > pev->dmgtime)
2013-08-30 13:34:05 -07:00
UTIL_Remove(this);
else
{
AnimateThink();
pev->nextthink = gpGlobals->time;
}
}
void CSprite::Expand(float scaleSpeed, float fadeSpeed)
2013-08-30 13:34:05 -07:00
{
pev->speed = scaleSpeed;
pev->health = fadeSpeed;
SetThink(&CSprite::ExpandThink);
2013-08-30 13:34:05 -07:00
pev->nextthink = gpGlobals->time;
m_lastTime = gpGlobals->time;
2013-08-30 13:34:05 -07:00
}
void CSprite::ExpandThink()
2013-08-30 13:34:05 -07:00
{
float frametime = gpGlobals->time - m_lastTime;
pev->scale += pev->speed * frametime;
pev->renderamt -= pev->health * frametime;
if (pev->renderamt <= 0)
2013-08-30 13:34:05 -07:00
{
pev->renderamt = 0;
UTIL_Remove(this);
2013-08-30 13:34:05 -07:00
}
else
{
pev->nextthink = gpGlobals->time + 0.1;
m_lastTime = gpGlobals->time;
2013-08-30 13:34:05 -07:00
}
}
void CSprite::Animate(float frames)
{
2013-08-30 13:34:05 -07:00
pev->frame += frames;
if (pev->frame > m_maxFrame)
2013-08-30 13:34:05 -07:00
{
if ((pev->spawnflags & SF_SPRITE_ONCE) != 0)
2013-08-30 13:34:05 -07:00
{
TurnOff();
}
else
{
if (m_maxFrame > 0)
pev->frame = fmod(pev->frame, m_maxFrame);
2013-08-30 13:34:05 -07:00
}
}
}
void CSprite::TurnOff()
2013-08-30 13:34:05 -07:00
{
pev->effects = EF_NODRAW;
pev->nextthink = 0;
}
void CSprite::TurnOn()
2013-08-30 13:34:05 -07:00
{
pev->effects = 0;
if ((0 != pev->framerate && m_maxFrame > 1.0) || (pev->spawnflags & SF_SPRITE_ONCE) != 0)
2013-08-30 13:34:05 -07:00
{
SetThink(&CSprite::AnimateThink);
2013-08-30 13:34:05 -07:00
pev->nextthink = gpGlobals->time;
m_lastTime = gpGlobals->time;
}
pev->frame = 0;
}
void CSprite::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value)
2013-08-30 13:34:05 -07:00
{
bool on = pev->effects != EF_NODRAW;
if (ShouldToggle(useType, on))
2013-08-30 13:34:05 -07:00
{
if (on)
2013-08-30 13:34:05 -07:00
{
TurnOff();
}
else
{
TurnOn();
}
}
}
class CGibShooter : public CBaseDelay
{
public:
void Spawn() override;
void Precache() override;
bool KeyValue(KeyValueData* pkvd) override;
void EXPORT ShootThink();
void Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value) override;
2013-08-30 13:34:05 -07:00
virtual CGib* CreateGib();
2013-08-30 13:34:05 -07:00
bool Save(CSave& save) override;
bool Restore(CRestore& restore) override;
static TYPEDESCRIPTION m_SaveData[];
2013-08-30 13:34:05 -07:00
int m_iGibs;
2013-08-30 13:34:05 -07:00
int m_iGibCapacity;
int m_iGibMaterial;
int m_iGibModelIndex;
float m_flGibVelocity;
float m_flVariance;
float m_flGibLife;
};
TYPEDESCRIPTION CGibShooter::m_SaveData[] =
{
DEFINE_FIELD(CGibShooter, m_iGibs, FIELD_INTEGER),
DEFINE_FIELD(CGibShooter, m_iGibCapacity, FIELD_INTEGER),
DEFINE_FIELD(CGibShooter, m_iGibMaterial, FIELD_INTEGER),
DEFINE_FIELD(CGibShooter, m_iGibModelIndex, FIELD_INTEGER),
DEFINE_FIELD(CGibShooter, m_flGibVelocity, FIELD_FLOAT),
DEFINE_FIELD(CGibShooter, m_flVariance, FIELD_FLOAT),
DEFINE_FIELD(CGibShooter, m_flGibLife, FIELD_FLOAT),
2013-08-30 13:34:05 -07:00
};
IMPLEMENT_SAVERESTORE(CGibShooter, CBaseDelay);
LINK_ENTITY_TO_CLASS(gibshooter, CGibShooter);
2013-08-30 13:34:05 -07:00
void CGibShooter::Precache()
2013-08-30 13:34:05 -07:00
{
if (g_Language == LANGUAGE_GERMAN)
2013-08-30 13:34:05 -07:00
{
m_iGibModelIndex = PRECACHE_MODEL("models/germanygibs.mdl");
2013-08-30 13:34:05 -07:00
}
else
{
m_iGibModelIndex = PRECACHE_MODEL("models/hgibs.mdl");
2013-08-30 13:34:05 -07:00
}
}
bool CGibShooter::KeyValue(KeyValueData* pkvd)
2013-08-30 13:34:05 -07:00
{
if (FStrEq(pkvd->szKeyName, "m_iGibs"))
{
m_iGibs = m_iGibCapacity = atoi(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "m_flVelocity"))
{
m_flGibVelocity = atof(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "m_flVariance"))
{
m_flVariance = atof(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "m_flGibLife"))
{
m_flGibLife = atof(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
return CBaseDelay::KeyValue(pkvd);
2013-08-30 13:34:05 -07:00
}
void CGibShooter::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value)
2013-08-30 13:34:05 -07:00
{
SetThink(&CGibShooter::ShootThink);
2013-08-30 13:34:05 -07:00
pev->nextthink = gpGlobals->time;
}
void CGibShooter::Spawn()
2013-08-30 13:34:05 -07:00
{
Precache();
pev->solid = SOLID_NOT;
pev->effects = EF_NODRAW;
if (m_flDelay == 0)
2013-08-30 13:34:05 -07:00
{
m_flDelay = 0.1;
}
if (m_flGibLife == 0)
2013-08-30 13:34:05 -07:00
{
m_flGibLife = 25;
}
SetMovedir(pev);
pev->body = MODEL_FRAMES(m_iGibModelIndex);
2013-08-30 13:34:05 -07:00
}
CGib* CGibShooter::CreateGib()
2013-08-30 13:34:05 -07:00
{
if (CVAR_GET_FLOAT("violence_hgibs") == 0)
2013-08-30 13:34:05 -07:00
return NULL;
CGib* pGib = GetClassPtr((CGib*)NULL);
pGib->Spawn("models/hgibs.mdl");
2013-08-30 13:34:05 -07:00
pGib->m_bloodColor = BLOOD_COLOR_RED;
if (pev->body <= 1)
2013-08-30 13:34:05 -07:00
{
ALERT(at_aiconsole, "GibShooter Body is <= 1!\n");
2013-08-30 13:34:05 -07:00
}
pGib->pev->body = RANDOM_LONG(1, pev->body - 1); // avoid throwing random amounts of the 0th gib. (skull).
2013-08-30 13:34:05 -07:00
return pGib;
}
void CGibShooter::ShootThink()
2013-08-30 13:34:05 -07:00
{
pev->nextthink = gpGlobals->time + m_flDelay;
Vector vecShootDir;
vecShootDir = pev->movedir;
vecShootDir = vecShootDir + gpGlobals->v_right * RANDOM_FLOAT(-1, 1) * m_flVariance;
vecShootDir = vecShootDir + gpGlobals->v_forward * RANDOM_FLOAT(-1, 1) * m_flVariance;
vecShootDir = vecShootDir + gpGlobals->v_up * RANDOM_FLOAT(-1, 1) * m_flVariance;
2013-08-30 13:34:05 -07:00
vecShootDir = vecShootDir.Normalize();
CGib* pGib = CreateGib();
if (pGib)
2013-08-30 13:34:05 -07:00
{
pGib->pev->origin = pev->origin;
pGib->pev->velocity = vecShootDir * m_flGibVelocity;
pGib->pev->avelocity.x = RANDOM_FLOAT(100, 200);
pGib->pev->avelocity.y = RANDOM_FLOAT(100, 300);
2013-08-30 13:34:05 -07:00
float thinkTime = pGib->pev->nextthink - gpGlobals->time;
pGib->m_lifeTime = (m_flGibLife * RANDOM_FLOAT(0.95, 1.05)); // +/- 5%
if (pGib->m_lifeTime < thinkTime)
2013-08-30 13:34:05 -07:00
{
pGib->pev->nextthink = gpGlobals->time + pGib->m_lifeTime;
pGib->m_lifeTime = 0;
}
}
if (--m_iGibs <= 0)
2013-08-30 13:34:05 -07:00
{
if ((pev->spawnflags & SF_GIBSHOOTER_REPEATABLE) != 0)
2013-08-30 13:34:05 -07:00
{
m_iGibs = m_iGibCapacity;
SetThink(NULL);
2013-08-30 13:34:05 -07:00
pev->nextthink = gpGlobals->time;
}
else
{
SetThink(&CGibShooter::SUB_Remove);
2013-08-30 13:34:05 -07:00
pev->nextthink = gpGlobals->time;
}
}
}
class CEnvShooter : public CGibShooter
{
void Precache() override;
bool KeyValue(KeyValueData* pkvd) override;
2013-08-30 13:34:05 -07:00
CGib* CreateGib() override;
2013-08-30 13:34:05 -07:00
};
LINK_ENTITY_TO_CLASS(env_shooter, CEnvShooter);
2013-08-30 13:34:05 -07:00
bool CEnvShooter::KeyValue(KeyValueData* pkvd)
2013-08-30 13:34:05 -07:00
{
if (FStrEq(pkvd->szKeyName, "shootmodel"))
{
pev->model = ALLOC_STRING(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "shootsounds"))
{
int iNoise = atoi(pkvd->szValue);
switch (iNoise)
2013-08-30 13:34:05 -07:00
{
case 0:
m_iGibMaterial = matGlass;
break;
case 1:
m_iGibMaterial = matWood;
break;
case 2:
m_iGibMaterial = matMetal;
break;
case 3:
m_iGibMaterial = matFlesh;
break;
case 4:
m_iGibMaterial = matRocks;
break;
2013-08-30 13:34:05 -07:00
default:
case -1:
m_iGibMaterial = matNone;
break;
}
return true;
2013-08-30 13:34:05 -07:00
}
return CGibShooter::KeyValue(pkvd);
2013-08-30 13:34:05 -07:00
}
void CEnvShooter::Precache()
2013-08-30 13:34:05 -07:00
{
m_iGibModelIndex = PRECACHE_MODEL((char*)STRING(pev->model));
CBreakable::MaterialSoundPrecache((Materials)m_iGibMaterial);
2013-08-30 13:34:05 -07:00
}
CGib* CEnvShooter::CreateGib()
2013-08-30 13:34:05 -07:00
{
CGib* pGib = GetClassPtr((CGib*)NULL);
pGib->Spawn(STRING(pev->model));
2013-08-30 13:34:05 -07:00
int bodyPart = 0;
if (pev->body > 1)
bodyPart = RANDOM_LONG(0, pev->body - 1);
2013-08-30 13:34:05 -07:00
pGib->pev->body = bodyPart;
pGib->m_bloodColor = DONT_BLEED;
pGib->m_material = m_iGibMaterial;
pGib->pev->rendermode = pev->rendermode;
pGib->pev->renderamt = pev->renderamt;
pGib->pev->rendercolor = pev->rendercolor;
pGib->pev->renderfx = pev->renderfx;
pGib->pev->scale = pev->scale;
pGib->pev->skin = pev->skin;
return pGib;
}
class CTestEffect : public CBaseDelay
{
public:
void Spawn() override;
void Precache() override;
// void KeyValue( KeyValueData *pkvd ) override;
void EXPORT TestThink();
void Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value) override;
2013-08-30 13:34:05 -07:00
int m_iLoop;
int m_iBeam;
CBeam* m_pBeam[24];
float m_flBeamTime[24];
float m_flStartTime;
2013-08-30 13:34:05 -07:00
};
LINK_ENTITY_TO_CLASS(test_effect, CTestEffect);
2013-08-30 13:34:05 -07:00
void CTestEffect::Spawn()
2013-08-30 13:34:05 -07:00
{
Precache();
2013-08-30 13:34:05 -07:00
}
void CTestEffect::Precache()
2013-08-30 13:34:05 -07:00
{
PRECACHE_MODEL("sprites/lgtning.spr");
2013-08-30 13:34:05 -07:00
}
void CTestEffect::TestThink()
2013-08-30 13:34:05 -07:00
{
int i;
float t = (gpGlobals->time - m_flStartTime);
if (m_iBeam < 24)
{
CBeam* pbeam = CBeam::BeamCreate("sprites/lgtning.spr", 100);
2013-08-30 13:34:05 -07:00
TraceResult tr;
2013-08-30 13:34:05 -07:00
Vector vecSrc = pev->origin;
Vector vecDir = Vector(RANDOM_FLOAT(-1.0, 1.0), RANDOM_FLOAT(-1.0, 1.0), RANDOM_FLOAT(-1.0, 1.0));
2013-08-30 13:34:05 -07:00
vecDir = vecDir.Normalize();
UTIL_TraceLine(vecSrc, vecSrc + vecDir * 128, ignore_monsters, ENT(pev), &tr);
2013-08-30 13:34:05 -07:00
pbeam->PointsInit(vecSrc, tr.vecEndPos);
2013-08-30 13:34:05 -07:00
// pbeam->SetColor( 80, 100, 255 );
pbeam->SetColor(255, 180, 100);
pbeam->SetWidth(100);
pbeam->SetScrollRate(12);
2013-08-30 13:34:05 -07:00
m_flBeamTime[m_iBeam] = gpGlobals->time;
m_pBeam[m_iBeam] = pbeam;
m_iBeam++;
#if 0
Vector vecMid = (vecSrc + tr.vecEndPos) * 0.5;
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
WRITE_BYTE(TE_DLIGHT);
WRITE_COORD(vecMid.x); // X
WRITE_COORD(vecMid.y); // Y
WRITE_COORD(vecMid.z); // Z
WRITE_BYTE( 20 ); // radius * 0.1
WRITE_BYTE( 255 ); // r
WRITE_BYTE( 180 ); // g
WRITE_BYTE( 100 ); // b
WRITE_BYTE( 20 ); // time * 10
WRITE_BYTE( 0 ); // decay * 0.1
MESSAGE_END( );
#endif
}
if (t < 3.0)
{
for (i = 0; i < m_iBeam; i++)
{
t = (gpGlobals->time - m_flBeamTime[i]) / (3 + m_flStartTime - m_flBeamTime[i]);
m_pBeam[i]->SetBrightness(255 * t);
2013-08-30 13:34:05 -07:00
// m_pBeam[i]->SetScrollRate( 20 * t );
}
pev->nextthink = gpGlobals->time + 0.1;
}
else
{
for (i = 0; i < m_iBeam; i++)
{
UTIL_Remove(m_pBeam[i]);
2013-08-30 13:34:05 -07:00
}
m_flStartTime = gpGlobals->time;
m_iBeam = 0;
// pev->nextthink = gpGlobals->time;
SetThink(NULL);
2013-08-30 13:34:05 -07:00
}
}
void CTestEffect::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value)
2013-08-30 13:34:05 -07:00
{
SetThink(&CTestEffect::TestThink);
2013-08-30 13:34:05 -07:00
pev->nextthink = gpGlobals->time + 0.1;
m_flStartTime = gpGlobals->time;
}
// Blood effects
class CBlood : public CPointEntity
{
public:
void Spawn() override;
void Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value) override;
bool KeyValue(KeyValueData* pkvd) override;
2013-08-30 13:34:05 -07:00
inline int Color() { return pev->impulse; }
inline float BloodAmount() { return pev->dmg; }
2013-08-30 13:34:05 -07:00
inline void SetColor(int color) { pev->impulse = color; }
inline void SetBloodAmount(float amount) { pev->dmg = amount; }
Vector Direction();
Vector BloodPosition(CBaseEntity* pActivator);
2013-08-30 13:34:05 -07:00
private:
};
LINK_ENTITY_TO_CLASS(env_blood, CBlood);
2013-08-30 13:34:05 -07:00
#define SF_BLOOD_RANDOM 0x0001
#define SF_BLOOD_STREAM 0x0002
#define SF_BLOOD_PLAYER 0x0004
#define SF_BLOOD_DECAL 0x0008
2013-08-30 13:34:05 -07:00
void CBlood::Spawn()
2013-08-30 13:34:05 -07:00
{
pev->solid = SOLID_NOT;
pev->movetype = MOVETYPE_NONE;
pev->effects = 0;
pev->frame = 0;
SetMovedir(pev);
2013-08-30 13:34:05 -07:00
}
bool CBlood::KeyValue(KeyValueData* pkvd)
2013-08-30 13:34:05 -07:00
{
if (FStrEq(pkvd->szKeyName, "color"))
{
int color = atoi(pkvd->szValue);
switch (color)
2013-08-30 13:34:05 -07:00
{
case 1:
SetColor(BLOOD_COLOR_YELLOW);
2013-08-30 13:34:05 -07:00
break;
default:
SetColor(BLOOD_COLOR_RED);
2013-08-30 13:34:05 -07:00
break;
}
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "amount"))
{
SetBloodAmount(atof(pkvd->szValue));
return true;
2013-08-30 13:34:05 -07:00
}
return CPointEntity::KeyValue(pkvd);
2013-08-30 13:34:05 -07:00
}
Vector CBlood::Direction()
2013-08-30 13:34:05 -07:00
{
if ((pev->spawnflags & SF_BLOOD_RANDOM) != 0)
2013-08-30 13:34:05 -07:00
return UTIL_RandomBloodVector();
2013-08-30 13:34:05 -07:00
return pev->movedir;
}
Vector CBlood::BloodPosition(CBaseEntity* pActivator)
2013-08-30 13:34:05 -07:00
{
if ((pev->spawnflags & SF_BLOOD_PLAYER) != 0)
2013-08-30 13:34:05 -07:00
{
CBaseEntity* pPlayer;
2013-08-30 13:34:05 -07:00
if (pActivator && pActivator->IsPlayer())
2013-08-30 13:34:05 -07:00
{
pPlayer = pActivator;
2013-08-30 13:34:05 -07:00
}
else
pPlayer = UTIL_GetLocalPlayer();
if (pPlayer)
return (pPlayer->pev->origin + pPlayer->pev->view_ofs) + Vector(RANDOM_FLOAT(-10, 10), RANDOM_FLOAT(-10, 10), RANDOM_FLOAT(-10, 10));
2013-08-30 13:34:05 -07:00
}
return pev->origin;
}
void CBlood::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value)
2013-08-30 13:34:05 -07:00
{
if ((pev->spawnflags & SF_BLOOD_STREAM) != 0)
UTIL_BloodStream(BloodPosition(pActivator), Direction(), (Color() == BLOOD_COLOR_RED) ? 70 : Color(), BloodAmount());
2013-08-30 13:34:05 -07:00
else
UTIL_BloodDrips(BloodPosition(pActivator), Direction(), Color(), BloodAmount());
2013-08-30 13:34:05 -07:00
if ((pev->spawnflags & SF_BLOOD_DECAL) != 0)
2013-08-30 13:34:05 -07:00
{
Vector forward = Direction();
Vector start = BloodPosition(pActivator);
2013-08-30 13:34:05 -07:00
TraceResult tr;
UTIL_TraceLine(start, start + forward * BloodAmount() * 2, ignore_monsters, NULL, &tr);
if (tr.flFraction != 1.0)
UTIL_BloodDecalTrace(&tr, Color());
2013-08-30 13:34:05 -07:00
}
}
// Screen shake
class CShake : public CPointEntity
{
public:
void Spawn() override;
void Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value) override;
bool KeyValue(KeyValueData* pkvd) override;
inline float Amplitude() { return pev->scale; }
inline float Frequency() { return pev->dmg_save; }
inline float Duration() { return pev->dmg_take; }
inline float Radius() { return pev->dmg; }
inline void SetAmplitude(float amplitude) { pev->scale = amplitude; }
inline void SetFrequency(float frequency) { pev->dmg_save = frequency; }
inline void SetDuration(float duration) { pev->dmg_take = duration; }
inline void SetRadius(float radius) { pev->dmg = radius; }
2013-08-30 13:34:05 -07:00
private:
};
LINK_ENTITY_TO_CLASS(env_shake, CShake);
2013-08-30 13:34:05 -07:00
// pev->scale is amplitude
// pev->dmg_save is frequency
// pev->dmg_take is duration
// pev->dmg is radius
// radius of 0 means all players
// NOTE: UTIL_ScreenShake() will only shake players who are on the ground
#define SF_SHAKE_EVERYONE 0x0001 // Don't check radius
2013-08-30 13:34:05 -07:00
// UNDONE: These don't work yet
#define SF_SHAKE_DISRUPT 0x0002 // Disrupt controls
#define SF_SHAKE_INAIR 0x0004 // Shake players in air
2013-08-30 13:34:05 -07:00
void CShake::Spawn()
2013-08-30 13:34:05 -07:00
{
pev->solid = SOLID_NOT;
pev->movetype = MOVETYPE_NONE;
pev->effects = 0;
pev->frame = 0;
if ((pev->spawnflags & SF_SHAKE_EVERYONE) != 0)
2013-08-30 13:34:05 -07:00
pev->dmg = 0;
}
bool CShake::KeyValue(KeyValueData* pkvd)
2013-08-30 13:34:05 -07:00
{
if (FStrEq(pkvd->szKeyName, "amplitude"))
{
SetAmplitude(atof(pkvd->szValue));
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "frequency"))
{
SetFrequency(atof(pkvd->szValue));
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "duration"))
{
SetDuration(atof(pkvd->szValue));
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "radius"))
{
SetRadius(atof(pkvd->szValue));
return true;
2013-08-30 13:34:05 -07:00
}
return CPointEntity::KeyValue(pkvd);
2013-08-30 13:34:05 -07:00
}
void CShake::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value)
2013-08-30 13:34:05 -07:00
{
UTIL_ScreenShake(pev->origin, Amplitude(), Frequency(), Duration(), Radius());
2013-08-30 13:34:05 -07:00
}
class CFade : public CPointEntity
{
public:
void Spawn() override;
void Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value) override;
bool KeyValue(KeyValueData* pkvd) override;
2013-08-30 13:34:05 -07:00
inline float Duration() { return pev->dmg_take; }
inline float HoldTime() { return pev->dmg_save; }
inline void SetDuration(float duration) { pev->dmg_take = duration; }
inline void SetHoldTime(float hold) { pev->dmg_save = hold; }
2013-08-30 13:34:05 -07:00
private:
};
LINK_ENTITY_TO_CLASS(env_fade, CFade);
2013-08-30 13:34:05 -07:00
// pev->dmg_take is duration
// pev->dmg_save is hold duration
#define SF_FADE_IN 0x0001 // Fade in, not out
#define SF_FADE_MODULATE 0x0002 // Modulate, don't blend
#define SF_FADE_ONLYONE 0x0004
2013-08-30 13:34:05 -07:00
void CFade::Spawn()
2013-08-30 13:34:05 -07:00
{
pev->solid = SOLID_NOT;
pev->movetype = MOVETYPE_NONE;
pev->effects = 0;
pev->frame = 0;
2013-08-30 13:34:05 -07:00
}
bool CFade::KeyValue(KeyValueData* pkvd)
2013-08-30 13:34:05 -07:00
{
if (FStrEq(pkvd->szKeyName, "duration"))
{
SetDuration(atof(pkvd->szValue));
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "holdtime"))
{
SetHoldTime(atof(pkvd->szValue));
return true;
2013-08-30 13:34:05 -07:00
}
return CPointEntity::KeyValue(pkvd);
2013-08-30 13:34:05 -07:00
}
void CFade::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value)
2013-08-30 13:34:05 -07:00
{
int fadeFlags = 0;
if ((pev->spawnflags & SF_FADE_IN) == 0)
2013-08-30 13:34:05 -07:00
fadeFlags |= FFADE_OUT;
if ((pev->spawnflags & SF_FADE_MODULATE) != 0)
2013-08-30 13:34:05 -07:00
fadeFlags |= FFADE_MODULATE;
if ((pev->spawnflags & SF_FADE_ONLYONE) != 0)
2013-08-30 13:34:05 -07:00
{
if (pActivator->IsNetClient())
2013-08-30 13:34:05 -07:00
{
UTIL_ScreenFade(pActivator, pev->rendercolor, Duration(), HoldTime(), pev->renderamt, fadeFlags);
2013-08-30 13:34:05 -07:00
}
}
else
{
UTIL_ScreenFadeAll(pev->rendercolor, Duration(), HoldTime(), pev->renderamt, fadeFlags);
2013-08-30 13:34:05 -07:00
}
SUB_UseTargets(this, USE_TOGGLE, 0);
2013-08-30 13:34:05 -07:00
}
class CMessage : public CPointEntity
{
public:
void Spawn() override;
void Precache() override;
void Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value) override;
bool KeyValue(KeyValueData* pkvd) override;
2013-08-30 13:34:05 -07:00
private:
};
LINK_ENTITY_TO_CLASS(env_message, CMessage);
2013-08-30 13:34:05 -07:00
void CMessage::Spawn()
2013-08-30 13:34:05 -07:00
{
Precache();
pev->solid = SOLID_NOT;
pev->movetype = MOVETYPE_NONE;
2013-08-30 13:34:05 -07:00
switch (pev->impulse)
2013-08-30 13:34:05 -07:00
{
case 1: // Medium radius
pev->speed = ATTN_STATIC;
break;
case 2: // Large radius
2013-08-30 13:34:05 -07:00
pev->speed = ATTN_NORM;
break;
case 3: //EVERYWHERE
2013-08-30 13:34:05 -07:00
pev->speed = ATTN_NONE;
break;
2013-08-30 13:34:05 -07:00
default:
case 0: // Small radius
pev->speed = ATTN_IDLE;
break;
}
pev->impulse = 0;
// No volume, use normal
if (pev->scale <= 0)
2013-08-30 13:34:05 -07:00
pev->scale = 1.0;
}
void CMessage::Precache()
2013-08-30 13:34:05 -07:00
{
if (!FStringNull(pev->noise))
PRECACHE_SOUND((char*)STRING(pev->noise));
2013-08-30 13:34:05 -07:00
}
bool CMessage::KeyValue(KeyValueData* pkvd)
2013-08-30 13:34:05 -07:00
{
if (FStrEq(pkvd->szKeyName, "messagesound"))
{
pev->noise = ALLOC_STRING(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "messagevolume"))
{
pev->scale = atof(pkvd->szValue) * 0.1;
return true;
2013-08-30 13:34:05 -07:00
}
else if (FStrEq(pkvd->szKeyName, "messageattenuation"))
{
pev->impulse = atoi(pkvd->szValue);
return true;
2013-08-30 13:34:05 -07:00
}
return CPointEntity::KeyValue(pkvd);
2013-08-30 13:34:05 -07:00
}
void CMessage::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value)
2013-08-30 13:34:05 -07:00
{
CBaseEntity* pPlayer = NULL;
2013-08-30 13:34:05 -07:00
if ((pev->spawnflags & SF_MESSAGE_ALL) != 0)
UTIL_ShowMessageAll(STRING(pev->message));
2013-08-30 13:34:05 -07:00
else
{
if (pActivator && pActivator->IsPlayer())
2013-08-30 13:34:05 -07:00
pPlayer = pActivator;
else
{
pPlayer = UTIL_GetLocalPlayer();
2013-08-30 13:34:05 -07:00
}
if (pPlayer)
UTIL_ShowMessage(STRING(pev->message), pPlayer);
2013-08-30 13:34:05 -07:00
}
if (!FStringNull(pev->noise))
2013-08-30 13:34:05 -07:00
{
EMIT_SOUND(edict(), CHAN_BODY, STRING(pev->noise), pev->scale, pev->speed);
2013-08-30 13:34:05 -07:00
}
if ((pev->spawnflags & SF_MESSAGE_ONCE) != 0)
UTIL_Remove(this);
2013-08-30 13:34:05 -07:00
SUB_UseTargets(this, USE_TOGGLE, 0);
2013-08-30 13:34:05 -07:00
}
//=========================================================
// FunnelEffect
//=========================================================
class CEnvFunnel : public CBaseDelay
{
public:
void Spawn() override;
void Precache() override;
void Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value) override;
2013-08-30 13:34:05 -07:00
int m_iSprite; // Don't save, precache
2013-08-30 13:34:05 -07:00
};
void CEnvFunnel::Precache()
2013-08-30 13:34:05 -07:00
{
m_iSprite = PRECACHE_MODEL("sprites/flare6.spr");
2013-08-30 13:34:05 -07:00
}
LINK_ENTITY_TO_CLASS(env_funnel, CEnvFunnel);
2013-08-30 13:34:05 -07:00
void CEnvFunnel::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value)
2013-08-30 13:34:05 -07:00
{
MESSAGE_BEGIN(MSG_BROADCAST, SVC_TEMPENTITY);
WRITE_BYTE(TE_LARGEFUNNEL);
WRITE_COORD(pev->origin.x);
WRITE_COORD(pev->origin.y);
WRITE_COORD(pev->origin.z);
WRITE_SHORT(m_iSprite);
2013-08-30 13:34:05 -07:00
if ((pev->spawnflags & SF_FUNNEL_REVERSE) != 0) // funnel flows in reverse?
{
WRITE_SHORT(1);
}
else
{
WRITE_SHORT(0);
}
2013-08-30 13:34:05 -07:00
MESSAGE_END();
SetThink(&CEnvFunnel::SUB_Remove);
2013-08-30 13:34:05 -07:00
pev->nextthink = gpGlobals->time;
}
void CEnvFunnel::Spawn()
2013-08-30 13:34:05 -07:00
{
Precache();
pev->solid = SOLID_NOT;
pev->effects = EF_NODRAW;
}
//=========================================================
// Beverage Dispenser
// overloaded pev->frags, is now a flag for whether or not a can is stuck in the dispenser.
2013-08-30 13:34:05 -07:00
// overloaded pev->health, is now how many cans remain in the machine.
//=========================================================
class CEnvBeverage : public CBaseDelay
{
public:
void Spawn() override;
void Precache() override;
void Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value) override;
2013-08-30 13:34:05 -07:00
};
void CEnvBeverage::Precache()
2013-08-30 13:34:05 -07:00
{
PRECACHE_MODEL("models/can.mdl");
PRECACHE_SOUND("weapons/g_bounce3.wav");
2013-08-30 13:34:05 -07:00
}
LINK_ENTITY_TO_CLASS(env_beverage, CEnvBeverage);
2013-08-30 13:34:05 -07:00
void CEnvBeverage::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value)
2013-08-30 13:34:05 -07:00
{
if (pev->frags != 0 || pev->health <= 0)
2013-08-30 13:34:05 -07:00
{
// no more cans while one is waiting in the dispenser, or if I'm out of cans.
return;
}
CBaseEntity* pCan = CBaseEntity::Create("item_sodacan", pev->origin, pev->angles, edict());
2013-08-30 13:34:05 -07:00
if (pev->skin == 6)
2013-08-30 13:34:05 -07:00
{
// random
pCan->pev->skin = RANDOM_LONG(0, 5);
2013-08-30 13:34:05 -07:00
}
else
{
pCan->pev->skin = pev->skin;
}
pev->frags = 1;
pev->health--;
//SetThink (SUB_Remove);
//pev->nextthink = gpGlobals->time;
}
void CEnvBeverage::Spawn()
2013-08-30 13:34:05 -07:00
{
Precache();
pev->solid = SOLID_NOT;
pev->effects = EF_NODRAW;
pev->frags = 0;
if (pev->health == 0)
2013-08-30 13:34:05 -07:00
{
pev->health = 10;
}
}
//=========================================================
// Soda can
//=========================================================
class CItemSoda : public CBaseEntity
{
public:
void Spawn() override;
void Precache() override;
void EXPORT CanThink();
void EXPORT CanTouch(CBaseEntity* pOther);
2013-08-30 13:34:05 -07:00
};
void CItemSoda::Precache()
2013-08-30 13:34:05 -07:00
{
}
LINK_ENTITY_TO_CLASS(item_sodacan, CItemSoda);
2013-08-30 13:34:05 -07:00
void CItemSoda::Spawn()
2013-08-30 13:34:05 -07:00
{
Precache();
pev->solid = SOLID_NOT;
pev->movetype = MOVETYPE_TOSS;
SET_MODEL(ENT(pev), "models/can.mdl");
UTIL_SetSize(pev, Vector(0, 0, 0), Vector(0, 0, 0));
SetThink(&CItemSoda::CanThink);
2013-08-30 13:34:05 -07:00
pev->nextthink = gpGlobals->time + 0.5;
}
void CItemSoda::CanThink()
2013-08-30 13:34:05 -07:00
{
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/g_bounce3.wav", 1, ATTN_NORM);
2013-08-30 13:34:05 -07:00
pev->solid = SOLID_TRIGGER;
UTIL_SetSize(pev, Vector(-8, -8, 0), Vector(8, 8, 8));
SetThink(NULL);
SetTouch(&CItemSoda::CanTouch);
2013-08-30 13:34:05 -07:00
}
void CItemSoda::CanTouch(CBaseEntity* pOther)
2013-08-30 13:34:05 -07:00
{
if (!pOther->IsPlayer())
2013-08-30 13:34:05 -07:00
{
return;
}
// spoit sound here
pOther->TakeHealth(1, DMG_GENERIC); // a bit of health.
2013-08-30 13:34:05 -07:00
if (!FNullEnt(pev->owner))
2013-08-30 13:34:05 -07:00
{
// tell the machine the can was taken
pev->owner->v.frags = 0;
}
pev->solid = SOLID_NOT;
pev->movetype = MOVETYPE_NONE;
pev->effects = EF_NODRAW;
SetTouch(NULL);
SetThink(&CItemSoda::SUB_Remove);
2013-08-30 13:34:05 -07:00
pev->nextthink = gpGlobals->time;
}