Files
HL2Overcharged/game/client/overcharged/c_weapon_cguard.cpp
2025-05-21 21:09:22 +03:00

702 lines
17 KiB
C++

//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============
//
// Purpose: Combine guard effects
//
// $NoKeywords: $
//=============================================================================
#include "cbase.h"
#include "c_ai_basenpc.h"
#include "c_te_particlesystem.h"
#include "iefx.h"
#include "dlight.h"
#include "glow_overlay.h"
#include "fx.h"
#include "fx_sparks.h"
#include "basehlcombatweapon_shared.h"
#include "particlemgr.h"
#include "particle_prototype.h"
#include "particle_util.h"
#include "view_scene.h"
#include "c_tracer.h"
#include "c_weapon__stubs.h"
#include "ClientEffectPrecacheSystem.h"
#include "c_basehlcombatweapon.h"
#define CGUARD_MSG_SHOT 1
#define CGUARD_MSG_SHOT_START 2
class CSTParticle : public TrailParticle
{
public:
float m_speed;
};
#define MAX_SPHERE_DIRS 128
static Vector g_SphereDirs[MAX_SPHERE_DIRS];
static int g_SphereDirIndex = -1;
void InitSphereDirs()
{
if (g_SphereDirIndex >= 0)
return;
g_SphereDirIndex = 0;
for (int i = 0; i < MAX_SPHERE_DIRS; i++)
{
float len = 0;
do
{
g_SphereDirs[i].Random(-100, 100);
len = VectorNormalize(g_SphereDirs[i]);
} while (len < 1);
}
}
inline const Vector &GetNextSphereDir()
{
g_SphereDirIndex = (g_SphereDirIndex + 1) & (MAX_SPHERE_DIRS - 1);
return g_SphereDirs[g_SphereDirIndex];
}
//
// CCombineGuardParticleEffect
//
class CCombineGuardParticleEffect : public CParticleEffect
{
DECLARE_CLASS(CCombineGuardParticleEffect, CParticleEffect);
public:
CCombineGuardParticleEffect(const char *pDebugName, const Vector &origin) :
CParticleEffect(pDebugName)
{
SetSortOrigin(origin);
SetDynamicallyAllocated(true);
}
virtual void SimulateParticles(CParticleSimulateIterator *pIterator)
{
//BaseClass::SimulateParticles(pIterator);
}
void RenderParticles(CParticleRenderIterator *pIterator)
{
//BaseClass::RenderParticles(pIterator);
}
private:
CCombineGuardParticleEffect(const CCombineGuardParticleEffect &); // not defined, not accessible
};
//
// CCombineGuardBallParticle
//
class CCombineGuardBallParticle : public Particle
{
public:
float t;
};
#define BALL_GROW_TIME 0.9f
#define BALL_RELEASE_TIME 0.1f
//
// CCombineGuardBall
//
class CCombineGuardBall : public CCombineGuardParticleEffect
{
DECLARE_CLASS(CCombineGuardBall, CCombineGuardParticleEffect);
public:
CCombineGuardBall(const char *pDebugName, const Vector &origin, float radius, float speed, float delay, int entityIndex, int attachment)
: CCombineGuardParticleEffect(pDebugName, origin), m_radius(radius), m_effectSpeed(1 / speed),
m_entityIndex(entityIndex), m_attachment(attachment)
{
SetSortOrigin(origin);
m_boneOrigin = origin;
PMaterialHandle centerMaterial = GetPMaterial("sprites/strider_blackball");
CCombineGuardBallParticle *pBall = (CCombineGuardBallParticle *)AddParticle(sizeof(CCombineGuardBallParticle), centerMaterial, origin);
if (pBall)
{
pBall->t = -delay;
}
m_clock = 0;
m_dieTime = (BALL_GROW_TIME + BALL_RELEASE_TIME) * m_effectSpeed;
m_vecColor.Init(1, 1, 1);
}
bool SimulateAndRender(Particle *pInParticle, ParticleDraw *pDraw, float &sortKey)
{
CCombineGuardBallParticle *pParticle = (CCombineGuardBallParticle *)pInParticle;
float timeDelta = pDraw->GetTimeDelta();
if (pParticle->t < BALL_GROW_TIME || IsReleased())
{
//Should this particle die?
pParticle->t += timeDelta;
if (pParticle->t >= m_dieTime)
return false;
// not visible yet, but don't kill
if (pParticle->t < 0)
return true;
}
float t = pParticle->t - BALL_GROW_TIME*m_effectSpeed;
float size;
if (t > 0)
{
size = Bias(1, 0.2) * m_radius;
if (IsReleased())
{
if (t > BALL_RELEASE_TIME*m_effectSpeed)
t = BALL_RELEASE_TIME*m_effectSpeed;
t = (BALL_RELEASE_TIME*m_effectSpeed - t) * (1 / BALL_RELEASE_TIME*m_effectSpeed);
size *= t;
}
}
else
{
size = Bias(pParticle->t * (1 / (BALL_GROW_TIME*m_effectSpeed)), 0.2) * m_radius;
}
Vector tPos;
pParticle->m_Pos = m_boneOrigin;
TransformParticle(ParticleMgr()->GetModelView(), pParticle->m_Pos, tPos);
sortKey = (int)tPos.z;
//Render it
RenderParticle_ColorSize(pDraw, tPos, m_vecColor, 1.0, size);
return true;
}
void StartRender()
{
if (m_entityIndex > 0)
{
QAngle angles;
C_BaseEntity *ent = cl_entitylist->GetEnt(m_entityIndex);
if (ent)
{
ent->GetAttachment(m_attachment, m_boneOrigin, angles);
}
}
}
void Update(float dt)
{
m_clock += dt;
SetSortOrigin(m_boneOrigin);
dlight_t *dl = effects->CL_AllocDlight(m_entityIndex);
dl->origin = m_boneOrigin;
dl->color.r = 40;
dl->color.g = 60;
dl->color.b = 250;
dl->color.exponent = 5;
float size = (m_clock > m_dieTime) ? m_dieTime : m_clock;
dl->radius = m_radius * 3 * (size / m_dieTime);
dl->die = gpGlobals->curtime + 0.001;
}
Vector m_boneOrigin;
Vector m_vecColor;
float m_radius;
float m_effectSpeed;
int m_entityIndex;
int m_attachment;
float m_dieTime;
float m_clock;
private:
CCombineGuardBall(const CCombineGuardBall &);
};
//
// Sphere drawing
//
double noise1(double arg)
{
return (arg + random->RandomFloat(-1.5f, 1.5f));
}
static void RandomizeNormal(Vector &vec)
{
vec.x = 2.0f * (noise1(vec.x) - 0.5f);
vec.y = 2.0f * (noise1(vec.y) - 0.5f);
vec.z = 2.0f * (noise1(vec.z) - 0.5f);
}
static void DrawSphere(int stacks, int slices, float radius, Vector &origin)
{
// this sucks and stuff
float x = origin.x;
float y = origin.y;
float z = origin.z;
float stackAngle, sliceAngle;
int stack, slice;
Vector v[4];
float sliced, stacked, sliced1, stacked1, stacks1;
float slicedsin, slicedcos, stackedsin, stackedcos;
float sliced1sin, sliced1cos, stacked1sin, stacked1cos;
float stacks1sin, stacks1cos;
float stacksin, stackcos;
CMatRenderContextPtr pRenderContext(materials);
IMesh *pMesh = pRenderContext->GetDynamicMesh();
CMeshBuilder meshBuilder;
stackAngle = M_PI / (float)stacks;
sliceAngle = 2.0 * M_PI / (float)slices;
for (stack = 1; stack < stacks - 1; stack++)
{
for (slice = 0; slice < slices; slice++)
{
int i, j;
sliced = sliceAngle * slice;
stacked = stackAngle * stack;
sliced1 = sliceAngle * (slice + 1);
stacked1 = stackAngle * (stack + 1);
SinCos(sliced, &slicedsin, &slicedcos);
SinCos(stacked, &stackedsin, &stackedcos);
SinCos(sliced1, &sliced1sin, &sliced1cos);
SinCos(stacked1, &stacked1sin, &stacked1cos);
v[0][0] = -slicedsin * stackedsin;
v[0][1] = slicedcos * stackedsin;
v[0][2] = stackedcos;
v[1][0] = -sliced1sin * stackedsin;
v[1][1] = sliced1cos * stackedsin;
v[1][2] = stackedcos;
v[2][0] = -sliced1sin * stacked1sin;
v[2][1] = sliced1cos * stacked1sin;
v[2][2] = stacked1cos;
v[3][0] = -slicedsin * stacked1sin;
v[3][1] = slicedcos * stacked1sin;
v[3][2] = stacked1cos;
for (i = 0; i < 4; i++)
{
for (j = 0; j < 3; j++)
{
v[i][j] *= radius;
}
v[i][0] += x;
v[i][1] += y;
v[i][2] += z;
}
#if 1
// if( drawWireframe.value )
if (1)
{
meshBuilder.Begin(pMesh, MATERIAL_QUADS, 1);
meshBuilder.Position3fv(v[0].Base());
Vector normal;
normal = v[0] - origin;
VectorNormalize(normal);
RandomizeNormal(normal);
VectorNormalize(normal);
meshBuilder.Normal3fv(normal.Base());
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv(v[1].Base());
normal = v[1] - origin;
VectorNormalize(normal);
RandomizeNormal(normal);
VectorNormalize(normal);
meshBuilder.Normal3fv(normal.Base());
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv(v[2].Base());
normal = v[2] - origin;
VectorNormalize(normal);
RandomizeNormal(normal);
VectorNormalize(normal);
meshBuilder.Normal3fv(normal.Base());
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv(v[3].Base());
normal = v[3] - origin;
VectorNormalize(normal);
RandomizeNormal(normal);
VectorNormalize(normal);
meshBuilder.Normal3fv(normal.Base());
meshBuilder.AdvanceVertex();
meshBuilder.End();
pMesh->Draw();
}
else
{
// DrawIndexedQuad( v, 0, 1, 2, 3 );
}
#endif
}
}
// do the caps
for (slice = 0; slice < slices; slice++)
{
int i, j;
sliced = sliceAngle * slice;
stacked = stackAngle * stack;
sliced1 = sliceAngle * (slice + 1);
stacked1 = stackAngle * (stack + 1);
stacks1 = stackAngle * (stacks - 1);
SinCos(sliced, &slicedsin, &slicedcos);
SinCos(stacked, &stackedsin, &stackedcos);
SinCos(sliced1, &sliced1sin, &sliced1cos);
SinCos(stacked1, &stacked1sin, &stacked1cos);
SinCos(stackAngle, &stacksin, &stackcos);
SinCos(stacks1, &stacks1sin, &stacks1cos);
v[0][0] = 0.0f;
v[0][1] = 0.0f;
v[0][2] = 1.0f;
v[1][0] = -sliced1sin * stacksin;
v[1][1] = sliced1cos * stacksin;
v[1][2] = stackcos;
v[2][0] = -slicedsin * stacksin;
v[2][1] = slicedcos * stacksin;
v[2][2] = stackcos;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
v[i][j] *= radius;
}
v[i][0] += x;
v[i][1] += y;
v[i][2] += z;
}
meshBuilder.Begin(pMesh, MATERIAL_TRIANGLES, 1);
meshBuilder.Position3fv(v[0].Base());
Vector normal;
normal = v[0] - origin;
VectorNormalize(normal);
RandomizeNormal(normal);
VectorNormalize(normal);
meshBuilder.Normal3fv(normal.Base());
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv(v[1].Base());
normal = v[1] - origin;
VectorNormalize(normal);
RandomizeNormal(normal);
VectorNormalize(normal);
meshBuilder.Normal3fv(normal.Base());
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv(v[2].Base());
normal = v[2] - origin;
VectorNormalize(normal);
RandomizeNormal(normal);
VectorNormalize(normal);
meshBuilder.Normal3fv(normal.Base());
meshBuilder.AdvanceVertex();
meshBuilder.End();
pMesh->Draw();
v[0][0] = 0.0f;
v[0][1] = 0.0f;
v[0][2] = -1.0f;
v[1][0] = -sliced1sin * stacks1sin;
v[1][1] = sliced1cos * stacks1sin;
v[1][2] = stacks1cos;
v[2][0] = -slicedsin * stacks1sin;
v[2][1] = slicedcos * stacks1sin;
v[2][2] = stacks1cos;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
v[i][j] *= radius;
}
v[i][0] += x;
v[i][1] += y;
v[i][2] += z;
}
meshBuilder.Begin(pMesh, MATERIAL_TRIANGLES, 1);
meshBuilder.Position3fv(v[0].Base());
normal = v[0] - origin;
VectorNormalize(normal);
RandomizeNormal(normal);
VectorNormalize(normal);
meshBuilder.Normal3fv(normal.Base());
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv(v[2].Base());
normal = v[2] - origin;
VectorNormalize(normal);
RandomizeNormal(normal);
VectorNormalize(normal);
meshBuilder.Normal3fv(normal.Base());
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv(v[1].Base());
normal = v[1] - origin;
VectorNormalize(normal);
RandomizeNormal(normal);
VectorNormalize(normal);
meshBuilder.Normal3fv(normal.Base());
meshBuilder.AdvanceVertex();
meshBuilder.End();
pMesh->Draw();
}
}
class CCombineGuardMuzzleOverlay : public CWarpOverlay
{
public:
virtual bool Update(void)
{
m_flLifetime += gpGlobals->frametime;
if (m_flLifetime < m_flTotalLifetime)
{
return true;
}
return false;
}
virtual void Draw(void)
{
if (m_entityIndex > 0)
{
QAngle angles;
C_BaseEntity *ent = cl_entitylist->GetEnt(m_entityIndex);
if (ent)
{
ent->GetAttachment(m_nAttachment, m_vPos, angles);
}
}
UpdateRefractTexture();
CMatRenderContextPtr pRenderContext(materials);
pRenderContext->Bind(m_pWarpMaterial, NULL);
float maxRadius = 128.0f;
float radius;
float fractionOfLifetime = m_flLifetime / m_flTotalLifetime;
if (fractionOfLifetime < 0.5f)
{
radius = fractionOfLifetime * 2.0f * maxRadius;
}
else
{
radius = (1.0f - fractionOfLifetime) * 2.0f * maxRadius;
}
DrawSphere(8, 8, radius, m_vPos);
}
public:
int m_entityIndex;
int m_nAttachment;
IMaterial *m_pWarpMaterial;
float m_flLifetime;
float m_flTotalLifetime;
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class C_WeaponCguard : public C_BaseHLCombatWeapon
{
DECLARE_CLASS(C_WeaponCguard, C_BaseHLCombatWeapon);
public:
DECLARE_CLIENTCLASS();
DECLARE_PREDICTABLE();
C_WeaponCguard();
~C_WeaponCguard();
void ClientThink(void);
bool m_bEmitStreaks;
CSmartPtr<CSphereTrails> m_pGunTrails;
CSmartPtr<CCombineGuardBall> m_pGunBall;
float m_flTrailTime;
bool EnableSphere;
// model specific
//virtual void ReceiveMessage(const char *msgname, int length, void *data);
virtual void ReceiveMessage(int classID, bf_read &msg);
//private:
//C_WeaponCguard(const C_WeaponCguard &);
};
STUB_WEAPON_CLASS_IMPLEMENT(weapon_cguard, C_WeaponCguard);
IMPLEMENT_CLIENTCLASS_DT(C_WeaponCguard, DT_WeaponCguard, CWeaponCguard)
RecvPropBool(RECVINFO(EnableSphere)),
END_RECV_TABLE()
C_WeaponCguard::C_WeaponCguard(void)
{
m_bEmitStreaks = false;
m_flTrailTime = 0.0f;
m_pGunTrails = NULL;
m_pGunBall = NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Strider class implementation
//-----------------------------------------------------------------------------
C_WeaponCguard::~C_WeaponCguard()
{
}
int count = 0;
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_WeaponCguard::ClientThink(void)
{
if (m_bEmitStreaks)
{
m_pGunBall = NULL;
m_pGunTrails = NULL;
m_bEmitStreaks = false;
}
if (EnableSphere)
{
int attachment = LookupAttachment("muzzle");
m_bEmitStreaks = true;
SetNextClientThink(gpGlobals->curtime + 0.5f);
//m_pGunTrails = new CSphereTrails("C_CombineGuard::ReceiveMessage 1", GetAbsOrigin(), 0, 128, 256, entindex(), attachment);
if (!m_pGunBall)
m_pGunBall = new CCombineGuardBall("C_CombineGuard::ReceiveMessage 2", GetAbsOrigin(), 32, 1, 0, entindex(), attachment);
count++;
m_pGunBall->m_dieTime = 15;
//Make the warp overlay
/*if (CCombineGuardMuzzleOverlay *pOverlay = new CCombineGuardMuzzleOverlay)
{
pOverlay->m_nAttachment = attachment;
pOverlay->m_entityIndex = entindex();
pOverlay->m_vPos = GetAbsOrigin();
pOverlay->m_flLifetime = 0;
pOverlay->m_flTotalLifetime = 2.0f; // seconds
pOverlay->m_pWarpMaterial = materials->FindMaterial("sprites/predator", TEXTURE_GROUP_CLIENT_EFFECTS);
pOverlay->Activate();
}*/
}
/*if (count > 100)
m_pGunBall->m_dieTime*/
//SetNextClientThink(0.0f);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : length -
// *data -
//-----------------------------------------------------------------------------
void C_WeaponCguard::ReceiveMessage(int classID, bf_read &msg) //ReceiveMessage(const char *msgname, int length, void *data)
{
if (classID != GetClientClass()->m_ClassID)
{
// message is for subclass
BaseClass::ReceiveMessage(classID, msg);
return;
}
int messageType = msg.ReadByte();
switch (messageType)
{
case CGUARD_MSG_SHOT_START:
{
int attachment = LookupAttachment("muzzle");
m_bEmitStreaks = true;
SetNextClientThink(gpGlobals->curtime + 0.5f);
//m_pGunTrails = new CSphereTrails("C_CombineGuard::ReceiveMessage 1", GetAbsOrigin(), 0, 128, 256, entindex(), attachment);
m_pGunBall = new CCombineGuardBall("C_CombineGuard::ReceiveMessage 2", GetAbsOrigin(), 32, 1, 0, entindex(), attachment);
//Make the warp overlay
if (CCombineGuardMuzzleOverlay *pOverlay = new CCombineGuardMuzzleOverlay)
{
pOverlay->m_nAttachment = attachment;
pOverlay->m_entityIndex = entindex();
pOverlay->m_vPos = GetAbsOrigin();
pOverlay->m_flLifetime = 0;
pOverlay->m_flTotalLifetime = 2.0f; // seconds
pOverlay->m_pWarpMaterial = materials->FindMaterial("sprites/predator", TEXTURE_GROUP_CLIENT_EFFECTS);
pOverlay->Activate();
}
}
break;
case CGUARD_MSG_SHOT:
{
Vector pos, muzzleDir;
QAngle angle;
GetAttachment(LookupAttachment("muzzle"), pos, angle);
AngleVectors(angle, &muzzleDir);
CSmartPtr<CSimpleEmitter> emitter = CSimpleEmitter::Create("CGUARD_MSG_SHOT");
emitter->SetSortOrigin(pos);
SimpleParticle *pParticle;
for (int i = 0; i < 16; i++)
{
pParticle = (SimpleParticle *)emitter->AddParticle(sizeof(SimpleParticle), emitter->GetPMaterial("particle/particle_smokegrenade"), pos);
pParticle->m_flLifetime = 0.0f;
pParticle->m_flDieTime = 0.5f;
pParticle->m_vecVelocity = muzzleDir;
pParticle->m_vecVelocity[0] += random->RandomFloat(-0.8f, 0.8f);
pParticle->m_vecVelocity[1] += random->RandomFloat(-0.8f, 0.8f);
pParticle->m_vecVelocity[2] += random->RandomFloat(-0.8f, 0.8f);
pParticle->m_vecVelocity *= random->RandomFloat(64, 256);
pParticle->m_uchColor[0] = pParticle->m_uchColor[1] = pParticle->m_uchColor[2] = 64.0f;
pParticle->m_uchStartSize = random->RandomInt(16, 32);
pParticle->m_uchEndSize = pParticle->m_uchStartSize * 2;
pParticle->m_uchStartAlpha = random->RandomInt(32, 64);
pParticle->m_uchEndAlpha = 0;
pParticle->m_flRoll = random->RandomInt(0, 360);
pParticle->m_flRollDelta = random->RandomFloat(-8.0f, 8.0f);
}
}
break;
}
}