diff options
Diffstat (limited to 'game/client/hl2')
79 files changed, 20474 insertions, 0 deletions
diff --git a/game/client/hl2/C_Func_Monitor.cpp b/game/client/hl2/C_Func_Monitor.cpp new file mode 100644 index 0000000..17ce78b --- /dev/null +++ b/game/client/hl2/C_Func_Monitor.cpp @@ -0,0 +1,29 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +class C_FuncMonitor : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_FuncMonitor, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + +// C_BaseEntity. +public: + virtual bool ShouldDraw(); +}; + +IMPLEMENT_CLIENTCLASS_DT( C_FuncMonitor, DT_FuncMonitor, CFuncMonitor ) +END_RECV_TABLE() + +bool C_FuncMonitor::ShouldDraw() +{ + return true; +} diff --git a/game/client/hl2/c_antlion_dust.cpp b/game/client/hl2/c_antlion_dust.cpp new file mode 100644 index 0000000..f883cc7 --- /dev/null +++ b/game/client/hl2/c_antlion_dust.cpp @@ -0,0 +1,219 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "fx.h" +#include "particlemgr.h" +#include "particle_prototype.h" +#include "particle_util.h" +#include "c_te_particlesystem.h" +#include "particles_ez.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define DUST_STARTSIZE 16 +#define DUST_ENDSIZE 48 +#define DUST_RADIUS 32.0f +#define DUST_STARTALPHA 0.3f +#define DUST_ENDALPHA 0.0f +#define DUST_LIFETIME 2.0f + +static Vector g_AntlionDustColor( 0.3f, 0.25f, 0.2f ); + +extern IPhysicsSurfaceProps *physprops; + +class CAntlionDustEmitter : public CSimpleEmitter +{ +public: + static CAntlionDustEmitter *Create( const char *debugname ) + { + return new CAntlionDustEmitter( debugname ); + } + + void UpdateVelocity( SimpleParticle *pParticle, float timeDelta ) + { + //FIXME: Incorrect + pParticle->m_vecVelocity *= 0.9f; + } + +private: + CAntlionDustEmitter( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {} + CAntlionDustEmitter( const CAntlionDustEmitter & ); // not defined, not accessible +}; + +//================================================== +// C_TEAntlionDust +//================================================== + +class C_TEAntlionDust: public C_TEParticleSystem +{ +public: + + DECLARE_CLASS( C_TEAntlionDust, C_TEParticleSystem ); + DECLARE_CLIENTCLASS(); + + C_TEAntlionDust(); + virtual ~C_TEAntlionDust(); + +//C_BaseEntity +public: + virtual void PostDataUpdate( DataUpdateType_t updateType ); + virtual bool ShouldDraw() { return true; } + + +//IParticleEffect +public: + virtual void RenderParticles( CParticleRenderIterator *pIterator ); + virtual void SimulateParticles( CParticleSimulateIterator *pIterator ); + +public: + PMaterialHandle m_MaterialHandle; + + Vector m_vecOrigin; + QAngle m_vecAngles; + bool m_bBlockedSpawner; + +protected: + void GetDustColor( Vector &color ); +}; + +// Expose to the particle app. +EXPOSE_PROTOTYPE_EFFECT( AntlionDust, C_TEAntlionDust ); + +IMPLEMENT_CLIENTCLASS_EVENT_DT( C_TEAntlionDust, DT_TEAntlionDust, CTEAntlionDust ) + RecvPropVector(RECVINFO( m_vecOrigin )), + RecvPropVector(RECVINFO( m_vecAngles )), + RecvPropBool(RECVINFO( m_bBlockedSpawner )), +END_RECV_TABLE() + +//================================================== +// C_TEAntlionDust +//================================================== + +C_TEAntlionDust::C_TEAntlionDust() +{ + m_MaterialHandle = INVALID_MATERIAL_HANDLE; + m_vecOrigin.Init(); + m_vecAngles.Init(); + m_bBlockedSpawner = false; +} + +C_TEAntlionDust::~C_TEAntlionDust() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : bNewEntity - whether or not to start a new entity +//----------------------------------------------------------------------------- + +void C_TEAntlionDust::PostDataUpdate( DataUpdateType_t updateType ) +{ + // This style of creating dust emitters is now deprecated; we use the simple particle singleton exclusively. + /* + CSmartPtr<CAntlionDustEmitter> pDustEmitter = CAntlionDustEmitter::Create( "TEAntlionDust" ); + Assert( pDustEmitter ); + if ( pDustEmitter == NULL ) + return; + + pDustEmitter->SetSortOrigin( m_vecOrigin ); + pDustEmitter->SetNearClip( 32, 64 ); + pDustEmitter->GetBinding().SetBBox( m_vecOrigin - Vector( 32, 32, 32 ), m_vecOrigin + Vector( 32, 32, 32 ) ); + */ + + Vector offset; + Vector vecColor; + GetDustColor( vecColor ); + + int iParticleCount = 16; + + if ( m_bBlockedSpawner == true ) + { + iParticleCount = 8; + } + + //Spawn the dust + SimpleParticle particle; + for ( int i = 0; i < iParticleCount; i++ ) + { + //Offset this dust puff's origin + offset[0] = random->RandomFloat( -DUST_RADIUS, DUST_RADIUS ); + offset[1] = random->RandomFloat( -DUST_RADIUS, DUST_RADIUS ); + offset[2] = random->RandomFloat( -16, 8 ); + + offset += m_vecOrigin; + + particle.m_Pos = offset; + particle.m_flDieTime = random->RandomFloat( 0.75f, 1.25f ); + particle.m_flLifetime = 0.0f; + + Vector dir = particle.m_Pos - m_vecOrigin; + particle.m_vecVelocity = dir * random->RandomFloat( 0.5f, 1.0f ); + dir.z = fabs(dir.z); + + float colorRamp = random->RandomFloat( 0.5f, 1.0f ); + Vector color = vecColor*colorRamp; + + color[0] = clamp( color[0], 0.0f, 1.0f ); + color[1] = clamp( color[1], 0.0f, 1.0f ); + color[2] = clamp( color[2], 0.0f, 1.0f ); + + color *= 255; + + particle.m_uchColor[0] = color[0]; + particle.m_uchColor[1] = color[1]; + particle.m_uchColor[2] = color[2]; + + particle.m_uchStartAlpha= random->RandomFloat( 64, 128 ); + particle.m_uchEndAlpha = 0; + + particle.m_uchStartSize = random->RandomInt( 16, 32 ); + particle.m_uchEndSize = particle.m_uchStartSize * 3; + particle.m_flRoll = random->RandomInt( 0, 360 ); + particle.m_flRollDelta = random->RandomFloat( -0.2f, 0.2f ); + + // Though it appears there are two particle handle entries in g_Mat_DustPuff, in fact + // only the one present at index 0 actually draws. Trying to spawn a particle with + // the other material will give you no particle at all. Therefore while instead of this: + // AddSimpleParticle( &particle, g_Mat_DustPuff[random->RandomInt(0,1) ); + // we have to do this: + AddSimpleParticle( &particle, g_Mat_DustPuff[0] ); + } +} + +void GetColorForSurface( trace_t *trace, Vector *color ); + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &color - +//----------------------------------------------------------------------------- +void C_TEAntlionDust::GetDustColor( Vector &color ) +{ + trace_t tr; + UTIL_TraceLine( m_vecOrigin+Vector(0,0,1), m_vecOrigin+Vector(0,0,-32), + MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &tr ); + + if ( tr.fraction < 1.0f ) + { + GetColorForSurface( &tr, &color ); + } + else + { + //Fill in a fallback + color = g_AntlionDustColor; + } +} + +void C_TEAntlionDust::RenderParticles( CParticleRenderIterator *pIterator ) +{ +} + +void C_TEAntlionDust::SimulateParticles( CParticleSimulateIterator *pIterator ) +{ +} + diff --git a/game/client/hl2/c_ar2_explosion.cpp b/game/client/hl2/c_ar2_explosion.cpp new file mode 100644 index 0000000..e60343e --- /dev/null +++ b/game/client/hl2/c_ar2_explosion.cpp @@ -0,0 +1,475 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "particlemgr.h" +#include "particle_prototype.h" +#include "particle_util.h" +#include "surfinfo.h" +#include "baseparticleentity.h" +#include "materialsystem/imaterialsystemhardwareconfig.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// ------------------------------------------------------------------------- // +// Definitions +// ------------------------------------------------------------------------- // + +#define NUM_AR2_EXPLOSION_PARTICLES 70 +#define AR2_DUST_RADIUS 240 // 340 +#define AR2_DUST_LIFETIME 4 +#define AR2_DUST_LIFETIME_DELTA 6 +#define AR2_DUST_SPEED 10000 +#define AR2_DUST_STARTSIZE 8 +#define AR2_DUST_ENDSIZE 32 +#define AR2_DUST_ALPHA 0.5f +#define AR2_DUST_FADE_IN_TIME 0.25f + +static Vector g_AR2DustColor1(0.35, 0.345, 0.33 ); +static Vector g_AR2DustColor2(0.75, 0.75, 0.7); + + +// ------------------------------------------------------------------------- // +// Classes +// ------------------------------------------------------------------------- // + +class C_AR2Explosion : public C_BaseParticleEntity, public IPrototypeAppEffect +{ +public: + DECLARE_CLASS( C_AR2Explosion, C_BaseParticleEntity ); + DECLARE_CLIENTCLASS(); + + C_AR2Explosion(); + ~C_AR2Explosion(); + +private: + + class AR2ExplosionParticle : public StandardParticle_t + { + public: + float m_Dist; + Vector m_Start; + float m_Roll; + float m_RollSpeed; + float m_Dwell; + }; + +// C_BaseEntity. +public: + virtual void OnDataChanged(DataUpdateType_t updateType); + +// IPrototypeAppEffect. +public: + virtual void Start(CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs); + +// IParticleEffect. +public: + virtual void Update(float fTimeDelta); + + virtual void RenderParticles( CParticleRenderIterator *pIterator ); + virtual void SimulateParticles( CParticleSimulateIterator *pIterator ); + + +public: + CParticleMgr *m_pParticleMgr; + PMaterialHandle m_MaterialHandle; + +private: + + char m_szMaterialName[255]; + + C_AR2Explosion( const C_AR2Explosion & ); +}; + +// Expose to the particle app. +EXPOSE_PROTOTYPE_EFFECT(AR2Explosion, C_AR2Explosion); + +IMPLEMENT_CLIENTCLASS_DT(C_AR2Explosion, DT_AR2Explosion, AR2Explosion) + RecvPropString( RECVINFO( m_szMaterialName ) ), +END_RECV_TABLE() + + + +// ------------------------------------------------------------------------- // +// Helpers. +// ------------------------------------------------------------------------- // + +// Given a line segment from vStart to vEnd +// and a list of convex polygons in pSurfInfos and nSurfInfos, +// fill in the list of which polygons the segment intersects. +// Returns the number of intersected surfaces. +static int IntersectSegmentWithSurfInfos( + const Vector &vStart, + const Vector &vEnd, + SurfInfo *pSurfInfos, + const int nSurfInfos, + SurfInfo ** pIntersections, + Vector *pIntersectionPositions, + int nMaxIntersections) +{ + if(nMaxIntersections == 0) + return 0; + + int nIntersections = 0; + for(int i=0; i < nSurfInfos; i++) + { + SurfInfo *pSurf = &pSurfInfos[i]; + + // Does it intersect the plane? + float dot1 = pSurf->m_Plane.DistTo(vStart); + float dot2 = pSurf->m_Plane.DistTo(vEnd); + if((dot1 > 0) != (dot2 > 0)) + { + float t = dot1 / (dot1 - dot2); + Vector vIntersection = vStart + (vEnd - vStart) * t; + + // If the intersection is behind any edge plane, then it's not inside the polygon. + unsigned long iEdge; + for(iEdge=0; iEdge < pSurf->m_nVerts; iEdge++) + { + VPlane edgePlane; + edgePlane.m_Normal = pSurf->m_Plane.m_Normal.Cross(pSurf->m_Verts[iEdge] - pSurf->m_Verts[(iEdge+1)%pSurf->m_nVerts]); + VectorNormalize( edgePlane.m_Normal ); + edgePlane.m_Dist = edgePlane.m_Normal.Dot(pSurf->m_Verts[iEdge]); + + if(edgePlane.DistTo(vIntersection) < 0.0f) + break; + } + + if(iEdge == pSurf->m_nVerts) + { + pIntersections[nIntersections] = pSurf; + pIntersectionPositions[nIntersections] = vIntersection; + ++nIntersections; + if(nIntersections >= nMaxIntersections) + break; + } + } + } + + return nIntersections; +} + + + +// ------------------------------------------------------------------------- // +// C_AR2Explosion +// ------------------------------------------------------------------------- // +C_AR2Explosion::C_AR2Explosion() +{ + m_pParticleMgr = NULL; + m_MaterialHandle = INVALID_MATERIAL_HANDLE; +} + + +C_AR2Explosion::~C_AR2Explosion() +{ +} + + +void C_AR2Explosion::OnDataChanged(DataUpdateType_t updateType) +{ + C_BaseEntity::OnDataChanged(updateType); + + if(updateType == DATA_UPDATE_CREATED) + { + Start(ParticleMgr(), NULL); + } +} + +static ConVar mat_reduceparticles( "mat_reduceparticles", "0" ); + +void C_AR2Explosion::Start(CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs) +{ + m_pParticleMgr = pParticleMgr; + if(!pParticleMgr->AddEffect(&m_ParticleEffect, this)) + return; + + if (!m_szMaterialName[0]) + { + Q_strncpy(m_szMaterialName, "particle/particle_noisesphere", sizeof( m_szMaterialName ) ); + } + + m_MaterialHandle = m_ParticleEffect.FindOrAddMaterial(m_szMaterialName); + + // Precalculate stuff for the particle spawning.. + #define NUM_DUSTEMITTER_SURFINFOS 128 + SurfInfo surfInfos[NUM_DUSTEMITTER_SURFINFOS]; + int nSurfInfos; + + // Center of explosion. + Vector vCenter = GetAbsOrigin(); // HACKHACK.. when the engine bug is fixed, use origin. + + if ( IsXbox() ) + { + m_ParticleEffect.SetBBox( vCenter-Vector(300,300,300), vCenter+Vector(300,300,300) ); + } + + #ifdef PARTICLEPROTOTYPE_APP + float surfSize = 10000; + nSurfInfos = 1; + surfInfos[0].m_Verts[0].Init(-surfSize,-surfSize,0); + surfInfos[0].m_Verts[1].Init(-surfSize,surfSize,0); + surfInfos[0].m_Verts[2].Init(surfSize, surfSize,0); + surfInfos[0].m_Verts[3].Init(surfSize,-surfSize,0); + surfInfos[0].m_nVerts = 4; + surfInfos[0].m_Plane.m_Normal.Init(0,0,1); + surfInfos[0].m_Plane.m_Dist = -3; + #else + { + nSurfInfos = 0; + C_BaseEntity *ent = cl_entitylist->GetEnt( 0 ); + if ( ent ) + { + nSurfInfos = engine->GetIntersectingSurfaces( + ent->GetModel(), + vCenter, + AR2_DUST_RADIUS, + true, + surfInfos, + NUM_DUSTEMITTER_SURFINFOS); + } + } + #endif + + int nParticles = 0; + + int iParticlesToSpawn = NUM_AR2_EXPLOSION_PARTICLES; + + // In DX7, much fewer particles + if ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 ) + { + iParticlesToSpawn *= 0.25; + } + else if ( mat_reduceparticles.GetBool() ) + { + iParticlesToSpawn *= 0.025; + } + + if( nSurfInfos > 0 ) + { + // For nParticles*N, generate a ray and cast it out. If it hits anything, spawn a particle there. + int nTestsPerParticle=3; + for(int i=0; i < iParticlesToSpawn; i++) + { + for(int iTest=0; iTest < nTestsPerParticle; iTest++) + { + Vector randVec = RandomVector(-1,1); + VectorNormalize( randVec ); + Vector startPos = vCenter + randVec * AR2_DUST_RADIUS; + + randVec = RandomVector(-1,1); + VectorNormalize( randVec ); + Vector endPos = vCenter + randVec * AR2_DUST_RADIUS; + + #define MAX_SURFINFO_INTERSECTIONS 4 + SurfInfo *pIntersected[MAX_SURFINFO_INTERSECTIONS]; + Vector vIntersections[MAX_SURFINFO_INTERSECTIONS]; + int nIntersections; + nIntersections = IntersectSegmentWithSurfInfos( + startPos, + endPos, + surfInfos, + nSurfInfos, + pIntersected, + vIntersections, + MAX_SURFINFO_INTERSECTIONS); + + if(nIntersections) + { + int iIntersection = rand() % nIntersections; + + Vector velocity; + //velocity.Init(-1.0f + ((float)rand()/VALVE_RAND_MAX) * 2.0f, -1.0f + ((float)rand()/VALVE_RAND_MAX) * 2.0f, -1.0f + ((float)rand()/VALVE_RAND_MAX) * 2.0f); + //velocity = velocity * FRand(m_MinSpeed, m_MaxSpeed); + Vector direction = (vIntersections[iIntersection] - vCenter ); + float dist = VectorNormalize( direction ); + if(dist > AR2_DUST_RADIUS) + dist = AR2_DUST_RADIUS; + + static float power = 2.0f; + float falloffMul = pow(1.0f - dist / AR2_DUST_RADIUS, power); + + Vector reflection = direction - 2 * DotProduct( direction, pIntersected[iIntersection]->m_Plane.m_Normal ) * pIntersected[iIntersection]->m_Plane.m_Normal; + VectorNormalize( reflection ); + + velocity = reflection * AR2_DUST_SPEED * falloffMul; + // velocity = velocity + (vIntersections[iIntersection] - vCenter) * falloffMul; + + + /* + debugoverlay->AddLineOverlay( vIntersections[iIntersection], + vIntersections[iIntersection] + reflection * 64, + 128, 128, 255, false, 15.0 ); + */ +#if 1 + AR2ExplosionParticle *pParticle = + (AR2ExplosionParticle*)m_ParticleEffect.AddParticle( sizeof(AR2ExplosionParticle), m_MaterialHandle ); + + if(pParticle) + { + pParticle->m_Pos = vIntersections[iIntersection]; + pParticle->m_Start = pParticle->m_Pos; + pParticle->m_Dist = 8.0; + pParticle->m_Velocity = velocity; + // sound == 13031.496062992125984251968503937ips + pParticle->m_Lifetime = -dist / 13031.5f - 0.1; + pParticle->m_Roll = FRand( 0, M_PI * 2 ); + pParticle->m_RollSpeed = FRand( -1, 1 ) * 0.4; + pParticle->m_Dwell = AR2_DUST_LIFETIME + random->RandomFloat( 0, AR2_DUST_LIFETIME_DELTA ); + nParticles++; + break; + } +#endif + } + } + } + } + + // build interior smoke particles + for(int i=nParticles; i < iParticlesToSpawn; i++) + { + Vector randVec = RandomVector(-1,1); + VectorNormalize( randVec ); + Vector endPos = vCenter + randVec * AR2_DUST_RADIUS / 4.0; + + Vector direction = (endPos - vCenter ); + float dist = VectorNormalize( direction ) + random->RandomFloat( 0, AR2_DUST_RADIUS / 4.0 ); + if(dist > AR2_DUST_RADIUS) + dist = AR2_DUST_RADIUS; + + static float power = 2.0f; + float falloffMul = pow(1.0f - dist / (AR2_DUST_RADIUS / 2), power); + + Vector velocity = direction * AR2_DUST_SPEED * falloffMul; + AR2ExplosionParticle *pParticle = + (AR2ExplosionParticle*)m_ParticleEffect.AddParticle( sizeof(AR2ExplosionParticle), m_MaterialHandle ); + + if(pParticle) + { + pParticle->m_Pos = endPos; + pParticle->m_Start = pParticle->m_Pos; + pParticle->m_Dist = 8.0; + pParticle->m_Velocity = velocity; + // sound == 13031.496062992125984251968503937ips + pParticle->m_Lifetime = -dist / 13031.5f - 0.1; + pParticle->m_Roll = FRand( 0, M_PI * 2 ); + pParticle->m_RollSpeed = FRand( -1, 1 ) * 4.0; + pParticle->m_Dwell = 0.5 * (AR2_DUST_LIFETIME + random->RandomFloat( 0, AR2_DUST_LIFETIME_DELTA )); + } + } +} + + +void C_AR2Explosion::Update(float fTimeDelta) +{ + if(!m_pParticleMgr) + return; +} + + +void C_AR2Explosion::SimulateParticles( CParticleSimulateIterator *pIterator ) +{ + float dt = pIterator->GetTimeDelta(); + + AR2ExplosionParticle *pParticle = (AR2ExplosionParticle*)pIterator->GetFirst(); + while ( pParticle ) + { + if (dt > 0.05) + dt = 0.05; // yuck, air resistance function craps out at less then 20fps + + // Update its lifetime. + pParticle->m_Lifetime += dt; // pDraw->GetTimeDelta(); + if(pParticle->m_Lifetime > pParticle->m_Dwell) + { + // faded to nothing.... + pIterator->RemoveParticle( pParticle ); + } + else + { + // Spin the thing + pParticle->m_Roll += pParticle->m_RollSpeed * pIterator->GetTimeDelta(); + + // delayed? + if ( pParticle->m_Lifetime >= 0.0f ) + { + // Move it (this comes after rendering to make it clear that moving the particle here won't change + // its rendering for this frame since m_TransformedPos has already been set). + pParticle->m_Pos = pParticle->m_Pos + pParticle->m_Velocity * dt; + + // keep track of distance traveled + pParticle->m_Dist = pParticle->m_Dist + pParticle->m_Velocity.Length() * dt; + + // Dampen velocity. + float dist = pParticle->m_Velocity.Length() * dt; + float r = dist * dist; + // FIXME: this is a really screwy air-resistance function.... + pParticle->m_Velocity = pParticle->m_Velocity * (100 / (100 + r )); + + // dampen roll + static float dtime; + static float decay; + if (dtime != dt) + { + dtime = dt; + decay = ExponentialDecay( 0.3, 1.0, dtime ); + } + if (fabs(pParticle->m_RollSpeed) > 0.2) + pParticle->m_RollSpeed = pParticle->m_RollSpeed * decay; + } + } + + pParticle = (AR2ExplosionParticle*)pIterator->GetNext(); + } +} + + +void C_AR2Explosion::RenderParticles( CParticleRenderIterator *pIterator ) +{ + const AR2ExplosionParticle *pParticle = (const AR2ExplosionParticle *)pIterator->GetFirst(); + while ( pParticle ) + { + float sortKey = 0; + if ( pParticle->m_Lifetime >= 0.0f ) + { + // Draw. + float lifetimePercent = ( pParticle->m_Lifetime - AR2_DUST_FADE_IN_TIME ) / pParticle->m_Dwell; + + // FIXME: base color should be a dirty version of the material color + Vector color = g_AR2DustColor1 * (1.0 - lifetimePercent) + g_AR2DustColor2 * lifetimePercent; + + Vector tPos; + TransformParticle(m_pParticleMgr->GetModelView(), pParticle->m_Pos, tPos); + sortKey = tPos.z; + + float alpha; + + if ( pParticle->m_Lifetime < AR2_DUST_FADE_IN_TIME ) + { + alpha = AR2_DUST_ALPHA * ( pParticle->m_Lifetime / AR2_DUST_FADE_IN_TIME ); + } + else + { + alpha = AR2_DUST_ALPHA * ( 1.0f - lifetimePercent ); + } + + alpha *= GetAlphaDistanceFade( tPos, IsXbox() ? 100 : 50, IsXbox() ? 200 : 150 ); + + RenderParticle_ColorSizeAngle( + pIterator->GetParticleDraw(), + tPos, + color, + alpha, + pParticle->m_Dist, // size based on how far it's traveled + pParticle->m_Roll); + } + + pParticle = (const AR2ExplosionParticle *)pIterator->GetNext( sortKey ); + } +} + + diff --git a/game/client/hl2/c_barnacle.cpp b/game/client/hl2/c_barnacle.cpp new file mode 100644 index 0000000..344ac0e --- /dev/null +++ b/game/client/hl2/c_barnacle.cpp @@ -0,0 +1,313 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "c_ai_basenpc.h" +#include "engine/ivmodelinfo.h" +#include "rope_physics.h" +#include "materialsystem/imaterialsystem.h" +#include "fx_line.h" +#include "engine/ivdebugoverlay.h" +#include "bone_setup.h" +#include "model_types.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define BARNACLE_TONGUE_POINTS 7 + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_NPC_Barnacle : public C_AI_BaseNPC +{ +public: + + DECLARE_CLASS( C_NPC_Barnacle, C_AI_BaseNPC ); + DECLARE_CLIENTCLASS(); + + C_NPC_Barnacle( void ); + + virtual void GetRenderBounds( Vector &theMins, Vector &theMaxs ) + { + BaseClass::GetRenderBounds( theMins, theMaxs ); + + // Extend our bounding box downwards the length of the tongue + theMins -= Vector( 0, 0, m_flAltitude ); + } + + // Purpose: Initialize absmin & absmax to the appropriate box + virtual void ComputeWorldSpaceSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ) + { + // Extend our bounding box downwards the length of the tongue + CollisionProp()->WorldSpaceAABB( pVecWorldMins, pVecWorldMaxs ); + + // We really care about the tongue tip. The altitude is not really relevant. + VectorMin( *pVecWorldMins, m_vecTip, *pVecWorldMins ); + VectorMax( *pVecWorldMaxs, m_vecTip, *pVecWorldMaxs ); + +// pVecWorldMins->z -= m_flAltitude; + } + + void OnDataChanged( DataUpdateType_t updateType ); + void InitTonguePhysics( void ); + void ClientThink( void ); + void StandardBlendingRules( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], float currentTime, int boneMask ); + + void SetVecTip( const float *pPosition ); + void SetAltitude( float flAltitude ); + + // Purpose: + void ComputeVisualTipPoint( Vector *pTip ); + +protected: + Vector m_vecTipPrevious; + Vector m_vecRoot; + Vector m_vecTip; + Vector m_vecTipDrawOffset; + +private: + // Tongue points + float m_flAltitude; + Vector m_vecTonguePoints[BARNACLE_TONGUE_POINTS]; + CRopePhysics<BARNACLE_TONGUE_POINTS> m_TonguePhysics; + + // Tongue physics delegate + class CBarnaclePhysicsDelegate : public CSimplePhysics::IHelper + { + public: + virtual void GetNodeForces( CSimplePhysics::CNode *pNodes, int iNode, Vector *pAccel ); + virtual void ApplyConstraints( CSimplePhysics::CNode *pNodes, int nNodes ); + + C_NPC_Barnacle *m_pBarnacle; + }; + friend class CBarnaclePhysicsDelegate; + CBarnaclePhysicsDelegate m_PhysicsDelegate; + +private: + C_NPC_Barnacle( const C_NPC_Barnacle & ); // not defined, not accessible +}; + +static void RecvProxy_VecTip( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + ((C_NPC_Barnacle*)pStruct)->SetVecTip( pData->m_Value.m_Vector ); +} + +IMPLEMENT_CLIENTCLASS_DT( C_NPC_Barnacle, DT_Barnacle, CNPC_Barnacle ) + RecvPropFloat( RECVINFO( m_flAltitude ) ), + RecvPropVector( RECVINFO( m_vecRoot ) ), + RecvPropVector( RECVINFO( m_vecTip ), 0, RecvProxy_VecTip ), + RecvPropVector( RECVINFO( m_vecTipDrawOffset ) ), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_NPC_Barnacle::C_NPC_Barnacle( void ) +{ + m_PhysicsDelegate.m_pBarnacle = this; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_NPC_Barnacle::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + if ( updateType == DATA_UPDATE_CREATED ) + { + InitTonguePhysics(); + + // We want to think every frame. + SetNextClientThink( CLIENT_THINK_ALWAYS ); + return; + } +} + + +//----------------------------------------------------------------------------- +// Sets the tongue altitude +//----------------------------------------------------------------------------- +void C_NPC_Barnacle::SetAltitude( float flAltitude ) +{ + m_flAltitude = flAltitude; +} + +void C_NPC_Barnacle::SetVecTip( const float *pPosition ) +{ + Vector vecNewTip; + vecNewTip.Init( pPosition[0], pPosition[1], pPosition[2] ); + if ( vecNewTip != m_vecTip ) + { + m_vecTip = vecNewTip; + CollisionProp()->MarkSurroundingBoundsDirty(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_NPC_Barnacle::InitTonguePhysics( void ) +{ + // Init tongue spline + // First point is at the top + m_TonguePhysics.SetupSimulation( m_flAltitude / (BARNACLE_TONGUE_POINTS-1), &m_PhysicsDelegate ); + m_TonguePhysics.Restart(); + + // Initialize the positions of the nodes. + m_TonguePhysics.GetFirstNode()->m_vPos = m_vecRoot; + m_TonguePhysics.GetFirstNode()->m_vPrevPos = m_TonguePhysics.GetFirstNode()->m_vPos; + float flAltitude = m_flAltitude; + for( int i = 1; i < m_TonguePhysics.NumNodes(); i++ ) + { + flAltitude *= 0.5; + CSimplePhysics::CNode *pNode = m_TonguePhysics.GetNode( i ); + pNode->m_vPos = m_TonguePhysics.GetNode(i-1)->m_vPos - Vector(0,0,flAltitude); + pNode->m_vPrevPos = pNode->m_vPos; + + // Set the length of the node's spring + //m_TonguePhysics.ResetNodeSpringLength( i-1, flAltitude ); + } + + m_vecTipPrevious = m_vecTip; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_NPC_Barnacle::ClientThink( void ) +{ + m_TonguePhysics.Simulate( gpGlobals->frametime ); + + // Set the spring's length to that of the tongue's extension + m_TonguePhysics.ResetSpringLength( m_flAltitude / (BARNACLE_TONGUE_POINTS-1) ); + + // Necessary because ComputeVisualTipPoint depends on m_vecTipPrevious + Vector vecTemp; + ComputeVisualTipPoint( &vecTemp ); + m_vecTipPrevious = vecTemp; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_NPC_Barnacle::StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quaternion q[], float currentTime, int boneMask ) +{ + BaseClass::StandardBlendingRules( hdr, pos, q, currentTime, boneMask ); + + if ( !hdr ) + return; + + int firstBone = Studio_BoneIndexByName( hdr, "Barnacle.tongue1" ); + + Vector vecPrevRight; + GetVectors( NULL, &vecPrevRight, NULL ); + + Vector vecPrev = pos[Studio_BoneIndexByName( hdr, "Barnacle.base" )]; + Vector vecCurr = vec3_origin; + Vector vecForward; + for ( int i = 0; i <= BARNACLE_TONGUE_POINTS; i++ ) + { + // We double up the bones at the last node. + if ( i == BARNACLE_TONGUE_POINTS ) + { + vecCurr = m_TonguePhysics.GetLastNode()->m_vPos; + } + else + { + vecCurr = m_TonguePhysics.GetNode(i)->m_vPos; + } + + //debugoverlay->AddBoxOverlay( vecCurr, -Vector(2,2,2), Vector(2,2,2), vec3_angle, 0,255,0, 128, 0.1 ); + + // Fill out the positions in local space + VectorITransform( vecCurr, EntityToWorldTransform(), pos[firstBone+i] ); + vecCurr = pos[firstBone+i]; + + // Disallow twist in the tongue visually + // Forward vector has to follow the tongue, right + up have to minimize twist from + // the previous bone + + // Fill out the angles + if ( i != BARNACLE_TONGUE_POINTS ) + { + vecForward = (vecCurr - vecPrev); + if ( VectorNormalize( vecForward ) < 1e-3 ) + { + vecForward.Init( 0, 0, 1 ); + } + } + + // Project the previous vecRight into a plane perpendicular to vecForward + // that's the vector closest to what we want... + Vector vecRight, vecUp; + VectorMA( vecPrevRight, -DotProduct( vecPrevRight, vecForward ), vecForward, vecRight ); + VectorNormalize( vecRight ); + CrossProduct( vecForward, vecRight, vecUp ); + + BasisToQuaternion( vecForward, vecRight, vecUp, q[firstBone+i] ); + + vecPrev = vecCurr; + vecPrevRight = vecRight; + } +} + +//=============================================================================================================================== +// BARNACLE TONGUE PHYSICS +//=============================================================================================================================== +#define TONGUE_GRAVITY 0, 0, -1000 +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_NPC_Barnacle::CBarnaclePhysicsDelegate::GetNodeForces( CSimplePhysics::CNode *pNodes, int iNode, Vector *pAccel ) +{ + // Gravity. + pAccel->Init( TONGUE_GRAVITY ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +#define TIP_SNAP_FACTOR 200 +// Todo: this really ought to be SIMD. +void C_NPC_Barnacle::ComputeVisualTipPoint( Vector *pTip ) +{ + float flTipMove = TIP_SNAP_FACTOR * gpGlobals->frametime; + Vector tipIdeal; + VectorAdd(m_vecTip, m_vecTipDrawOffset, tipIdeal); + if ( tipIdeal.DistToSqr( m_vecTipPrevious ) > (flTipMove * flTipMove) ) + { + // Inch the visual tip toward the actual tip + VectorSubtract( tipIdeal, m_vecTipPrevious, *pTip ); + VectorNormalize( *pTip ); + *pTip *= flTipMove; + *pTip += m_vecTipPrevious; + } + else + { + *pTip = tipIdeal; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_NPC_Barnacle::CBarnaclePhysicsDelegate::ApplyConstraints( CSimplePhysics::CNode *pNodes, int nNodes ) +{ + // Startpoint always stays at the root + pNodes[0].m_vPos = m_pBarnacle->m_vecRoot; + + // Endpoint always stays at the tip + m_pBarnacle->ComputeVisualTipPoint( &pNodes[nNodes-1].m_vPos ); +} diff --git a/game/client/hl2/c_barney.cpp b/game/client/hl2/c_barney.cpp new file mode 100644 index 0000000..85d6173 --- /dev/null +++ b/game/client/hl2/c_barney.cpp @@ -0,0 +1,41 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_ai_basenpc.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_Barney : public C_AI_BaseNPC +{ +public: + DECLARE_CLASS( C_Barney, C_AI_BaseNPC ); + DECLARE_CLIENTCLASS(); + + C_Barney(); + virtual ~C_Barney(); + +private: + C_Barney( const C_Barney & ); // not defined, not accessible +}; + +IMPLEMENT_CLIENTCLASS_DT(C_Barney, DT_NPC_Barney, CNPC_Barney) +END_RECV_TABLE() + +C_Barney::C_Barney() +{ +} + + +C_Barney::~C_Barney() +{ +} + + diff --git a/game/client/hl2/c_basehelicopter.cpp b/game/client/hl2/c_basehelicopter.cpp new file mode 100644 index 0000000..abc3728 --- /dev/null +++ b/game/client/hl2/c_basehelicopter.cpp @@ -0,0 +1,91 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "c_basehelicopter.h" +#include "proxyentity.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/imaterialvar.h" +#include "KeyValues.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +IMPLEMENT_CLIENTCLASS_DT( C_BaseHelicopter, DT_BaseHelicopter, CBaseHelicopter ) + RecvPropTime( RECVINFO( m_flStartupTime ) ), +END_RECV_TABLE() + + +C_BaseHelicopter::C_BaseHelicopter() +{ +} + + +//----------------------------------------------------------------------------- +// Chopper blade fade-in time +//----------------------------------------------------------------------------- +#define FADE_IN_TIME 2.0f + + +//----------------------------------------------------------------------------- +// Sets the fade of the blades when the chopper starts up +//----------------------------------------------------------------------------- +class CHeliBladeMaterialProxy : public CEntityMaterialProxy +{ +public: + CHeliBladeMaterialProxy() { m_AlphaVar = NULL; } + virtual ~CHeliBladeMaterialProxy() {} + virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); + virtual void OnBind( C_BaseEntity *pEntity ); + virtual IMaterial *GetMaterial(); + +private: + IMaterialVar *m_AlphaVar; + bool m_bFadeOut; +}; + +bool CHeliBladeMaterialProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) +{ + bool foundVar; + m_AlphaVar = pMaterial->FindVar( "$alpha", &foundVar, false ); + m_bFadeOut = pKeyValues->GetInt( "$fadeout", 0 ) != 0; + return foundVar; +} + +void CHeliBladeMaterialProxy::OnBind( C_BaseEntity *pEnt ) +{ + if (!m_AlphaVar) + return; + + C_BaseHelicopter *pHeli = dynamic_cast<C_BaseHelicopter*>( pEnt ); + if ( pHeli ) + { + float dt = gpGlobals->curtime - pHeli->StartupTime(); + dt /= FADE_IN_TIME; + dt = clamp( dt, 0.0f, 1.0f ); + if ( m_bFadeOut ) + { + dt = 1.0f - dt; + } + + m_AlphaVar->SetFloatValue( dt ); + } + else + { + m_AlphaVar->SetFloatValue( 1.0f ); + } +} + +IMaterial *CHeliBladeMaterialProxy::GetMaterial() +{ + if ( !m_AlphaVar ) + return NULL; + + return m_AlphaVar->GetOwningMaterial(); +} + +EXPOSE_INTERFACE( CHeliBladeMaterialProxy, IMaterialProxy, "HeliBlade" IMATERIAL_PROXY_INTERFACE_VERSION ); + diff --git a/game/client/hl2/c_basehelicopter.h b/game/client/hl2/c_basehelicopter.h new file mode 100644 index 0000000..6ef2d93 --- /dev/null +++ b/game/client/hl2/c_basehelicopter.h @@ -0,0 +1,33 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef C_BASEHELICOPTER_H +#define C_BASEHELICOPTER_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "c_ai_basenpc.h" + + +class C_BaseHelicopter : public C_AI_BaseNPC +{ +public: + DECLARE_CLASS( C_BaseHelicopter, C_AI_BaseNPC ); + DECLARE_CLIENTCLASS(); + + C_BaseHelicopter(); + + float StartupTime() const { return m_flStartupTime; } + +private: + C_BaseHelicopter( const C_BaseHelicopter &other ) {} + float m_flStartupTime; +}; + + +#endif // C_BASEHELICOPTER_H diff --git a/game/client/hl2/c_basehlcombatweapon.cpp b/game/client/hl2/c_basehlcombatweapon.cpp new file mode 100644 index 0000000..bc3e5a3 --- /dev/null +++ b/game/client/hl2/c_basehlcombatweapon.cpp @@ -0,0 +1,21 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "c_basehlcombatweapon.h" +#include "igamemovement.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +IMPLEMENT_CLIENTCLASS_DT( C_HLMachineGun, DT_HLMachineGun, CHLMachineGun ) +END_RECV_TABLE() + +IMPLEMENT_CLIENTCLASS_DT( C_HLSelectFireMachineGun, DT_HLSelectFireMachineGun, CHLSelectFireMachineGun ) +END_RECV_TABLE() + +IMPLEMENT_CLIENTCLASS_DT( C_BaseHLBludgeonWeapon, DT_BaseHLBludgeonWeapon, CBaseHLBludgeonWeapon ) +END_RECV_TABLE()
\ No newline at end of file diff --git a/game/client/hl2/c_basehlcombatweapon.h b/game/client/hl2/c_basehlcombatweapon.h new file mode 100644 index 0000000..72440cc --- /dev/null +++ b/game/client/hl2/c_basehlcombatweapon.h @@ -0,0 +1,36 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "basehlcombatweapon_shared.h" + +#ifndef C_BASEHLCOMBATWEAPON_H +#define C_BASEHLCOMBATWEAPON_H +#ifdef _WIN32 +#pragma once +#endif + +class C_HLMachineGun : public C_BaseHLCombatWeapon +{ +public: + DECLARE_CLASS( C_HLMachineGun, C_BaseHLCombatWeapon ); + DECLARE_CLIENTCLASS(); +}; + +class C_HLSelectFireMachineGun : public C_HLMachineGun +{ +public: + DECLARE_CLASS( C_HLSelectFireMachineGun, C_HLMachineGun ); + DECLARE_CLIENTCLASS(); +}; + +class C_BaseHLBludgeonWeapon : public C_BaseHLCombatWeapon +{ +public: + DECLARE_CLASS( C_BaseHLBludgeonWeapon, C_BaseHLCombatWeapon ); + DECLARE_CLIENTCLASS(); +}; + +#endif // C_BASEHLCOMBATWEAPON_H diff --git a/game/client/hl2/c_basehlplayer.cpp b/game/client/hl2/c_basehlplayer.cpp new file mode 100644 index 0000000..fbc40eb --- /dev/null +++ b/game/client/hl2/c_basehlplayer.cpp @@ -0,0 +1,649 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_basehlplayer.h" +#include "playerandobjectenumerator.h" +#include "engine/ivdebugoverlay.h" +#include "c_ai_basenpc.h" +#include "in_buttons.h" +#include "collisionutils.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// How fast to avoid collisions with center of other object, in units per second +#define AVOID_SPEED 2000.0f +extern ConVar cl_forwardspeed; +extern ConVar cl_backspeed; +extern ConVar cl_sidespeed; + +extern ConVar zoom_sensitivity_ratio; +extern ConVar default_fov; +extern ConVar sensitivity; + +ConVar cl_npc_speedmod_intime( "cl_npc_speedmod_intime", "0.25", FCVAR_CLIENTDLL | FCVAR_ARCHIVE ); +ConVar cl_npc_speedmod_outtime( "cl_npc_speedmod_outtime", "1.5", FCVAR_CLIENTDLL | FCVAR_ARCHIVE ); + +IMPLEMENT_CLIENTCLASS_DT(C_BaseHLPlayer, DT_HL2_Player, CHL2_Player) + RecvPropDataTable( RECVINFO_DT(m_HL2Local),0, &REFERENCE_RECV_TABLE(DT_HL2Local) ), + RecvPropBool( RECVINFO( m_fIsSprinting ) ), +END_RECV_TABLE() + +BEGIN_PREDICTION_DATA( C_BaseHLPlayer ) + DEFINE_PRED_TYPEDESCRIPTION( m_HL2Local, C_HL2PlayerLocalData ), + DEFINE_PRED_FIELD( m_fIsSprinting, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), +END_PREDICTION_DATA() + +//----------------------------------------------------------------------------- +// Purpose: Drops player's primary weapon +//----------------------------------------------------------------------------- +void CC_DropPrimary( void ) +{ + C_BasePlayer *pPlayer = (C_BasePlayer *) C_BasePlayer::GetLocalPlayer(); + + if ( pPlayer == NULL ) + return; + + pPlayer->Weapon_DropPrimary(); +} + +static ConCommand dropprimary("dropprimary", CC_DropPrimary, "dropprimary: Drops the primary weapon of the player."); + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +C_BaseHLPlayer::C_BaseHLPlayer() +{ + AddVar( &m_Local.m_vecPunchAngle, &m_Local.m_iv_vecPunchAngle, LATCH_SIMULATION_VAR ); + AddVar( &m_Local.m_vecPunchAngleVel, &m_Local.m_iv_vecPunchAngleVel, LATCH_SIMULATION_VAR ); + + m_flZoomStart = 0.0f; + m_flZoomEnd = 0.0f; + m_flZoomRate = 0.0f; + m_flZoomStartTime = 0.0f; + m_flSpeedMod = cl_forwardspeed.GetFloat(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : updateType - +//----------------------------------------------------------------------------- +void C_BaseHLPlayer::OnDataChanged( DataUpdateType_t updateType ) +{ + // Make sure we're thinking + if ( updateType == DATA_UPDATE_CREATED ) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } + + BaseClass::OnDataChanged( updateType ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseHLPlayer::Weapon_DropPrimary( void ) +{ + engine->ServerCmd( "DropPrimary" ); +} + +float C_BaseHLPlayer::GetFOV() +{ + //Find our FOV with offset zoom value + float flFOVOffset = BaseClass::GetFOV() + GetZoom(); + + // Clamp FOV in MP + int min_fov = ( gpGlobals->maxClients == 1 ) ? 5 : default_fov.GetInt(); + + // Don't let it go too low + flFOVOffset = MAX( min_fov, flFOVOffset ); + + return flFOVOffset; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : float +//----------------------------------------------------------------------------- +float C_BaseHLPlayer::GetZoom( void ) +{ + float fFOV = m_flZoomEnd; + + //See if we need to lerp the values + if ( ( m_flZoomStart != m_flZoomEnd ) && ( m_flZoomRate > 0.0f ) ) + { + float deltaTime = (float)( gpGlobals->curtime - m_flZoomStartTime ) / m_flZoomRate; + + if ( deltaTime >= 1.0f ) + { + //If we're past the zoom time, just take the new value and stop lerping + fFOV = m_flZoomStart = m_flZoomEnd; + } + else + { + fFOV = SimpleSplineRemapVal( deltaTime, 0.0f, 1.0f, m_flZoomStart, m_flZoomEnd ); + } + } + + return fFOV; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : FOVOffset - +// time - +//----------------------------------------------------------------------------- +void C_BaseHLPlayer::Zoom( float FOVOffset, float time ) +{ + m_flZoomStart = GetZoom(); + m_flZoomEnd = FOVOffset; + m_flZoomRate = time; + m_flZoomStartTime = gpGlobals->curtime; +} + + +//----------------------------------------------------------------------------- +// Purpose: Hack to zero out player's pitch, use value from poseparameter instead +// Input : flags - +// Output : int +//----------------------------------------------------------------------------- +int C_BaseHLPlayer::DrawModel( int flags ) +{ + // Not pitch for player + QAngle saveAngles = GetLocalAngles(); + + QAngle useAngles = saveAngles; + useAngles[ PITCH ] = 0.0f; + + SetLocalAngles( useAngles ); + + int iret = BaseClass::DrawModel( flags ); + + SetLocalAngles( saveAngles ); + + return iret; +} + +//----------------------------------------------------------------------------- +// Purpose: Helper to remove from ladder +//----------------------------------------------------------------------------- +void C_BaseHLPlayer::ExitLadder() +{ + if ( MOVETYPE_LADDER != GetMoveType() ) + return; + + SetMoveType( MOVETYPE_WALK ); + SetMoveCollide( MOVECOLLIDE_DEFAULT ); + // Remove from ladder + m_HL2Local.m_hLadder = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: Determines if a player can be safely moved towards a point +// Input: pos - position to test move to, fVertDist - how far to trace downwards to see if the player would fall, +// radius - how close the player can be to the object, objPos - position of the object to avoid, +// objDir - direction the object is travelling +//----------------------------------------------------------------------------- +bool C_BaseHLPlayer::TestMove( const Vector &pos, float fVertDist, float radius, const Vector &objPos, const Vector &objDir ) +{ + trace_t trUp; + trace_t trOver; + trace_t trDown; + float flHit1, flHit2; + + UTIL_TraceHull( GetAbsOrigin(), pos, GetPlayerMins(), GetPlayerMaxs(), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &trOver ); + if ( trOver.fraction < 1.0f ) + { + // check if the endpos intersects with the direction the object is travelling. if it doesn't, this is a good direction to move. + if ( objDir.IsZero() || + ( IntersectInfiniteRayWithSphere( objPos, objDir, trOver.endpos, radius, &flHit1, &flHit2 ) && + ( ( flHit1 >= 0.0f ) || ( flHit2 >= 0.0f ) ) ) + ) + { + // our first trace failed, so see if we can go farther if we step up. + + // trace up to see if we have enough room. + UTIL_TraceHull( GetAbsOrigin(), GetAbsOrigin() + Vector( 0, 0, m_Local.m_flStepSize ), + GetPlayerMins(), GetPlayerMaxs(), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &trUp ); + + // do a trace from the stepped up height + UTIL_TraceHull( trUp.endpos, pos + Vector( 0, 0, trUp.endpos.z - trUp.startpos.z ), + GetPlayerMins(), GetPlayerMaxs(), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &trOver ); + + if ( trOver.fraction < 1.0f ) + { + // check if the endpos intersects with the direction the object is travelling. if it doesn't, this is a good direction to move. + if ( objDir.IsZero() || + ( IntersectInfiniteRayWithSphere( objPos, objDir, trOver.endpos, radius, &flHit1, &flHit2 ) && ( ( flHit1 >= 0.0f ) || ( flHit2 >= 0.0f ) ) ) ) + { + return false; + } + } + } + } + + // trace down to see if this position is on the ground + UTIL_TraceLine( trOver.endpos, trOver.endpos - Vector( 0, 0, fVertDist ), + MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &trDown ); + + if ( trDown.fraction == 1.0f ) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// Client-side obstacle avoidance +//----------------------------------------------------------------------------- +void C_BaseHLPlayer::PerformClientSideObstacleAvoidance( float flFrameTime, CUserCmd *pCmd ) +{ + // Don't avoid if noclipping or in movetype none + switch ( GetMoveType() ) + { + case MOVETYPE_NOCLIP: + case MOVETYPE_NONE: + case MOVETYPE_OBSERVER: + return; + default: + break; + } + + // Try to steer away from any objects/players we might interpenetrate + Vector size = WorldAlignSize(); + + float radius = 0.7f * sqrt( size.x * size.x + size.y * size.y ); + float curspeed = GetLocalVelocity().Length2D(); + + //int slot = 1; + //engine->Con_NPrintf( slot++, "speed %f\n", curspeed ); + //engine->Con_NPrintf( slot++, "radius %f\n", radius ); + + // If running, use a larger radius + float factor = 1.0f; + + if ( curspeed > 150.0f ) + { + curspeed = MIN( 2048.0f, curspeed ); + factor = ( 1.0f + ( curspeed - 150.0f ) / 150.0f ); + + //engine->Con_NPrintf( slot++, "scaleup (%f) to radius %f\n", factor, radius * factor ); + + radius = radius * factor; + } + + Vector currentdir; + Vector rightdir; + + QAngle vAngles = pCmd->viewangles; + vAngles.x = 0; + + AngleVectors( vAngles, ¤tdir, &rightdir, NULL ); + + bool istryingtomove = false; + bool ismovingforward = false; + if ( fabs( pCmd->forwardmove ) > 0.0f || + fabs( pCmd->sidemove ) > 0.0f ) + { + istryingtomove = true; + if ( pCmd->forwardmove > 1.0f ) + { + ismovingforward = true; + } + } + + if ( istryingtomove == true ) + radius *= 1.3f; + + CPlayerAndObjectEnumerator avoid( radius ); + partition->EnumerateElementsInSphere( PARTITION_CLIENT_SOLID_EDICTS, GetAbsOrigin(), radius, false, &avoid ); + + // Okay, decide how to avoid if there's anything close by + int c = avoid.GetObjectCount(); + if ( c <= 0 ) + return; + + //engine->Con_NPrintf( slot++, "moving %s forward %s\n", istryingtomove ? "true" : "false", ismovingforward ? "true" : "false" ); + + float adjustforwardmove = 0.0f; + float adjustsidemove = 0.0f; + + for ( int i = 0; i < c; i++ ) + { + C_AI_BaseNPC *obj = dynamic_cast< C_AI_BaseNPC *>(avoid.GetObject( i )); + + if( !obj ) + continue; + + Vector vecToObject = obj->GetAbsOrigin() - GetAbsOrigin(); + + float flDist = vecToObject.Length2D(); + + // Figure out a 2D radius for the object + Vector vecWorldMins, vecWorldMaxs; + obj->CollisionProp()->WorldSpaceAABB( &vecWorldMins, &vecWorldMaxs ); + Vector objSize = vecWorldMaxs - vecWorldMins; + + float objectradius = 0.5f * sqrt( objSize.x * objSize.x + objSize.y * objSize.y ); + + //Don't run this code if the NPC is not moving UNLESS we are in stuck inside of them. + if ( !obj->IsMoving() && flDist > objectradius ) + continue; + + if ( flDist > objectradius && obj->IsEffectActive( EF_NODRAW ) ) + { + obj->RemoveEffects( EF_NODRAW ); + } + + Vector vecNPCVelocity; + obj->EstimateAbsVelocity( vecNPCVelocity ); + float flNPCSpeed = VectorNormalize( vecNPCVelocity ); + + Vector vPlayerVel = GetAbsVelocity(); + VectorNormalize( vPlayerVel ); + + float flHit1, flHit2; + Vector vRayDir = vecToObject; + VectorNormalize( vRayDir ); + + float flVelProduct = DotProduct( vecNPCVelocity, vPlayerVel ); + float flDirProduct = DotProduct( vRayDir, vPlayerVel ); + + if ( !IntersectInfiniteRayWithSphere( + GetAbsOrigin(), + vRayDir, + obj->GetAbsOrigin(), + radius, + &flHit1, + &flHit2 ) ) + continue; + + Vector dirToObject = -vecToObject; + VectorNormalize( dirToObject ); + + float fwd = 0; + float rt = 0; + + float sidescale = 2.0f; + float forwardscale = 1.0f; + bool foundResult = false; + + Vector vMoveDir = vecNPCVelocity; + if ( flNPCSpeed > 0.001f ) + { + // This NPC is moving. First try deflecting the player left or right relative to the NPC's velocity. + // Start with whatever side they're on relative to the NPC's velocity. + Vector vecNPCTrajectoryRight = CrossProduct( vecNPCVelocity, Vector( 0, 0, 1) ); + int iDirection = ( vecNPCTrajectoryRight.Dot( dirToObject ) > 0 ) ? 1 : -1; + for ( int nTries = 0; nTries < 2; nTries++ ) + { + Vector vecTryMove = vecNPCTrajectoryRight * iDirection; + VectorNormalize( vecTryMove ); + + Vector vTestPosition = GetAbsOrigin() + vecTryMove * radius * 2; + + if ( TestMove( vTestPosition, size.z * 2, radius * 2, obj->GetAbsOrigin(), vMoveDir ) ) + { + fwd = currentdir.Dot( vecTryMove ); + rt = rightdir.Dot( vecTryMove ); + + //Msg( "PUSH DEFLECT fwd=%f, rt=%f\n", fwd, rt ); + + foundResult = true; + break; + } + else + { + // Try the other direction. + iDirection *= -1; + } + } + } + else + { + // the object isn't moving, so try moving opposite the way it's facing + Vector vecNPCForward; + obj->GetVectors( &vecNPCForward, NULL, NULL ); + + Vector vTestPosition = GetAbsOrigin() - vecNPCForward * radius * 2; + if ( TestMove( vTestPosition, size.z * 2, radius * 2, obj->GetAbsOrigin(), vMoveDir ) ) + { + fwd = currentdir.Dot( -vecNPCForward ); + rt = rightdir.Dot( -vecNPCForward ); + + if ( flDist < objectradius ) + { + obj->AddEffects( EF_NODRAW ); + } + + //Msg( "PUSH AWAY FACE fwd=%f, rt=%f\n", fwd, rt ); + + foundResult = true; + } + } + + if ( !foundResult ) + { + // test if we can move in the direction the object is moving + Vector vTestPosition = GetAbsOrigin() + vMoveDir * radius * 2; + if ( TestMove( vTestPosition, size.z * 2, radius * 2, obj->GetAbsOrigin(), vMoveDir ) ) + { + fwd = currentdir.Dot( vMoveDir ); + rt = rightdir.Dot( vMoveDir ); + + if ( flDist < objectradius ) + { + obj->AddEffects( EF_NODRAW ); + } + + //Msg( "PUSH ALONG fwd=%f, rt=%f\n", fwd, rt ); + + foundResult = true; + } + else + { + // try moving directly away from the object + Vector vTestPosition = GetAbsOrigin() - dirToObject * radius * 2; + if ( TestMove( vTestPosition, size.z * 2, radius * 2, obj->GetAbsOrigin(), vMoveDir ) ) + { + fwd = currentdir.Dot( -dirToObject ); + rt = rightdir.Dot( -dirToObject ); + foundResult = true; + + //Msg( "PUSH AWAY fwd=%f, rt=%f\n", fwd, rt ); + } + } + } + + if ( !foundResult ) + { + // test if we can move through the object + Vector vTestPosition = GetAbsOrigin() - vMoveDir * radius * 2; + fwd = currentdir.Dot( -vMoveDir ); + rt = rightdir.Dot( -vMoveDir ); + + if ( flDist < objectradius ) + { + obj->AddEffects( EF_NODRAW ); + } + + //Msg( "PUSH THROUGH fwd=%f, rt=%f\n", fwd, rt ); + + foundResult = true; + } + + // If running, then do a lot more sideways veer since we're not going to do anything to + // forward velocity + if ( istryingtomove ) + { + sidescale = 6.0f; + } + + if ( flVelProduct > 0.0f && flDirProduct > 0.0f ) + { + sidescale = 0.1f; + } + + float force = 1.0f; + float forward = forwardscale * fwd * force * AVOID_SPEED; + float side = sidescale * rt * force * AVOID_SPEED; + + adjustforwardmove += forward; + adjustsidemove += side; + } + + pCmd->forwardmove += adjustforwardmove; + pCmd->sidemove += adjustsidemove; + + // Clamp the move to within legal limits, preserving direction. This is a little + // complicated because we have different limits for forward, back, and side + + //Msg( "PRECLAMP: forwardmove=%f, sidemove=%f\n", pCmd->forwardmove, pCmd->sidemove ); + + float flForwardScale = 1.0f; + if ( pCmd->forwardmove > fabs( cl_forwardspeed.GetFloat() ) ) + { + flForwardScale = fabs( cl_forwardspeed.GetFloat() ) / pCmd->forwardmove; + } + else if ( pCmd->forwardmove < -fabs( cl_backspeed.GetFloat() ) ) + { + flForwardScale = fabs( cl_backspeed.GetFloat() ) / fabs( pCmd->forwardmove ); + } + + float flSideScale = 1.0f; + if ( fabs( pCmd->sidemove ) > fabs( cl_sidespeed.GetFloat() ) ) + { + flSideScale = fabs( cl_sidespeed.GetFloat() ) / fabs( pCmd->sidemove ); + } + + float flScale = MIN( flForwardScale, flSideScale ); + pCmd->forwardmove *= flScale; + pCmd->sidemove *= flScale; + + //Msg( "POSTCLAMP: forwardmove=%f, sidemove=%f\n", pCmd->forwardmove, pCmd->sidemove ); +} + + +void C_BaseHLPlayer::PerformClientSideNPCSpeedModifiers( float flFrameTime, CUserCmd *pCmd ) +{ + if ( m_hClosestNPC == NULL ) + { + if ( m_flSpeedMod != cl_forwardspeed.GetFloat() ) + { + float flDeltaTime = (m_flSpeedModTime - gpGlobals->curtime); + m_flSpeedMod = RemapValClamped( flDeltaTime, cl_npc_speedmod_outtime.GetFloat(), 0, m_flExitSpeedMod, cl_forwardspeed.GetFloat() ); + } + } + else + { + C_AI_BaseNPC *pNPC = dynamic_cast< C_AI_BaseNPC *>( m_hClosestNPC.Get() ); + + if ( pNPC ) + { + float flDist = (GetAbsOrigin() - pNPC->GetAbsOrigin()).LengthSqr(); + bool bShouldModSpeed = false; + + // Within range? + if ( flDist < pNPC->GetSpeedModifyRadius() ) + { + // Now, only slowdown if we're facing & running parallel to the target's movement + // Facing check first (in 2D) + Vector vecTargetOrigin = pNPC->GetAbsOrigin(); + Vector los = ( vecTargetOrigin - EyePosition() ); + los.z = 0; + VectorNormalize( los ); + Vector facingDir; + AngleVectors( GetAbsAngles(), &facingDir ); + float flDot = DotProduct( los, facingDir ); + if ( flDot > 0.8 ) + { + /* + // Velocity check (abort if the target isn't moving) + Vector vecTargetVelocity; + pNPC->EstimateAbsVelocity( vecTargetVelocity ); + float flSpeed = VectorNormalize(vecTargetVelocity); + Vector vecMyVelocity = GetAbsVelocity(); + VectorNormalize(vecMyVelocity); + if ( flSpeed > 1.0 ) + { + // Velocity roughly parallel? + if ( DotProduct(vecTargetVelocity,vecMyVelocity) > 0.4 ) + { + bShouldModSpeed = true; + } + } + else + { + // NPC's not moving, slow down if we're moving at him + //Msg("Dot: %.2f\n", DotProduct( los, vecMyVelocity ) ); + if ( DotProduct( los, vecMyVelocity ) > 0.8 ) + { + bShouldModSpeed = true; + } + } + */ + + bShouldModSpeed = true; + } + } + + if ( !bShouldModSpeed ) + { + m_hClosestNPC = NULL; + m_flSpeedModTime = gpGlobals->curtime + cl_npc_speedmod_outtime.GetFloat(); + m_flExitSpeedMod = m_flSpeedMod; + return; + } + else + { + if ( m_flSpeedMod != pNPC->GetSpeedModifySpeed() ) + { + float flDeltaTime = (m_flSpeedModTime - gpGlobals->curtime); + m_flSpeedMod = RemapValClamped( flDeltaTime, cl_npc_speedmod_intime.GetFloat(), 0, cl_forwardspeed.GetFloat(), pNPC->GetSpeedModifySpeed() ); + } + } + } + } + + if ( pCmd->forwardmove > 0.0f ) + { + pCmd->forwardmove = clamp( pCmd->forwardmove, -m_flSpeedMod, m_flSpeedMod ); + } + else + { + pCmd->forwardmove = clamp( pCmd->forwardmove, -m_flSpeedMod, m_flSpeedMod ); + } + pCmd->sidemove = clamp( pCmd->sidemove, -m_flSpeedMod, m_flSpeedMod ); + + //Msg( "fwd %f right %f\n", pCmd->forwardmove, pCmd->sidemove ); +} + +//----------------------------------------------------------------------------- +// Purpose: Input handling +//----------------------------------------------------------------------------- +bool C_BaseHLPlayer::CreateMove( float flInputSampleTime, CUserCmd *pCmd ) +{ + bool bResult = BaseClass::CreateMove( flInputSampleTime, pCmd ); + + if ( !IsInAVehicle() ) + { + PerformClientSideObstacleAvoidance( TICK_INTERVAL, pCmd ); + PerformClientSideNPCSpeedModifiers( TICK_INTERVAL, pCmd ); + } + + return bResult; +} + + +//----------------------------------------------------------------------------- +// Purpose: Input handling +//----------------------------------------------------------------------------- +void C_BaseHLPlayer::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed ) +{ + BaseClass::BuildTransformations( hdr, pos, q, cameraTransform, boneMask, boneComputed ); + BuildFirstPersonMeathookTransformations( hdr, pos, q, cameraTransform, boneMask, boneComputed, "ValveBiped.Bip01_Head1" ); +} + diff --git a/game/client/hl2/c_basehlplayer.h b/game/client/hl2/c_basehlplayer.h new file mode 100644 index 0000000..c6507e9 --- /dev/null +++ b/game/client/hl2/c_basehlplayer.h @@ -0,0 +1,81 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// + +#if !defined( C_BASEHLPLAYER_H ) +#define C_BASEHLPLAYER_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "c_baseplayer.h" +#include "c_hl2_playerlocaldata.h" + +class C_BaseHLPlayer : public C_BasePlayer +{ +public: + DECLARE_CLASS( C_BaseHLPlayer, C_BasePlayer ); + DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); + + C_BaseHLPlayer(); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + + void Weapon_DropPrimary( void ); + + float GetFOV(); + void Zoom( float FOVOffset, float time ); + float GetZoom( void ); + bool IsZoomed( void ) { return m_HL2Local.m_bZooming; } + + bool IsSprinting( void ) { return m_HL2Local.m_bitsActiveDevices & bits_SUIT_DEVICE_SPRINT; } + bool IsFlashlightActive( void ) { return m_HL2Local.m_bitsActiveDevices & bits_SUIT_DEVICE_FLASHLIGHT; } + bool IsBreatherActive( void ) { return m_HL2Local.m_bitsActiveDevices & bits_SUIT_DEVICE_BREATHER; } + + virtual int DrawModel( int flags ); + virtual void BuildTransformations( CStudioHdr *hdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed ); + + LadderMove_t *GetLadderMove() { return &m_HL2Local.m_LadderMove; } + virtual void ExitLadder(); + bool IsSprinting() const { return m_fIsSprinting; } + + // Input handling + virtual bool CreateMove( float flInputSampleTime, CUserCmd *pCmd ); + void PerformClientSideObstacleAvoidance( float flFrameTime, CUserCmd *pCmd ); + void PerformClientSideNPCSpeedModifiers( float flFrameTime, CUserCmd *pCmd ); + + bool IsWeaponLowered( void ) { return m_HL2Local.m_bWeaponLowered; } + +public: + + C_HL2PlayerLocalData m_HL2Local; + EHANDLE m_hClosestNPC; + float m_flSpeedModTime; + bool m_fIsSprinting; + +private: + C_BaseHLPlayer( const C_BaseHLPlayer & ); // not defined, not accessible + + bool TestMove( const Vector &pos, float fVertDist, float radius, const Vector &objPos, const Vector &objDir ); + + float m_flZoomStart; + float m_flZoomEnd; + float m_flZoomRate; + float m_flZoomStartTime; + + bool m_bPlayUseDenySound; // Signaled by PlayerUse, but can be unset by HL2 ladder code... + float m_flSpeedMod; + float m_flExitSpeedMod; + + +friend class CHL2GameMovement; +}; + + +#endif diff --git a/game/client/hl2/c_citadel_effects.cpp b/game/client/hl2/c_citadel_effects.cpp new file mode 100644 index 0000000..af43c4b --- /dev/null +++ b/game/client/hl2/c_citadel_effects.cpp @@ -0,0 +1,483 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "particles_simple.h" +#include "citadel_effects_shared.h" +#include "particles_attractor.h" +#include "fx_quad.h" + +class C_CitadelEnergyCore : public C_BaseEntity +{ + DECLARE_CLASS( C_CitadelEnergyCore, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + +public: + void OnDataChanged( DataUpdateType_t updateType ); + RenderGroup_t GetRenderGroup( void ); + + void ClientThink( void ); + void NotifyShouldTransmit( ShouldTransmitState_t state ); + + void UpdateIdle( float percentage ); + void UpdateCharging( float percentage ); + void UpdateDischarging( void ); + +private: + + bool SetupEmitters( void ); + inline float GetStateDurationPercentage( void ); + + float m_flScale; + int m_nState; + float m_flDuration; + float m_flStartTime; + int m_spawnflags; + + CSmartPtr<CSimpleEmitter> m_pSimpleEmitter; + CSmartPtr<CParticleAttractor> m_pAttractorEmitter; +}; + +IMPLEMENT_CLIENTCLASS_DT( C_CitadelEnergyCore, DT_CitadelEnergyCore, CCitadelEnergyCore ) + RecvPropFloat( RECVINFO(m_flScale) ), + RecvPropInt( RECVINFO(m_nState) ), + RecvPropFloat( RECVINFO(m_flDuration) ), + RecvPropFloat( RECVINFO(m_flStartTime) ), + RecvPropInt( RECVINFO(m_spawnflags) ), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +// Output : RenderGroup_t +//----------------------------------------------------------------------------- +RenderGroup_t C_CitadelEnergyCore::GetRenderGroup( void ) +{ + return RENDER_GROUP_TRANSLUCENT_ENTITY; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : updateType - +//----------------------------------------------------------------------------- +void C_CitadelEnergyCore::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + if ( updateType == DATA_UPDATE_CREATED ) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); + SetupEmitters(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_CitadelEnergyCore::SetupEmitters( void ) +{ + // Setup the basic core emitter + if ( m_pSimpleEmitter.IsValid() == false ) + { + m_pSimpleEmitter = CSimpleEmitter::Create( "energycore" ); + + if ( m_pSimpleEmitter.IsValid() == false ) + return false; + } + + // Setup the attractor emitter + if ( m_pAttractorEmitter.IsValid() == false ) + { + m_pAttractorEmitter = CParticleAttractor::Create( GetAbsOrigin(), "energyattractor" ); + + if ( m_pAttractorEmitter.IsValid() == false ) + return false; + } + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : percentage - +//----------------------------------------------------------------------------- +void C_CitadelEnergyCore::UpdateIdle( float percentage ) +{ + // Only do these particles if required + if ( m_spawnflags & SF_ENERGYCORE_NO_PARTICLES ) + return; + + // Must be active + if ( percentage >= 1.0f ) + return; + + // Emitters must be valid + if ( SetupEmitters() == false ) + return; + + // Reset our sort origin + m_pSimpleEmitter->SetSortOrigin( GetAbsOrigin() ); + + SimpleParticle *sParticle; + + // Do the charging particles + m_pAttractorEmitter->SetAttractorOrigin( GetAbsOrigin() ); + + Vector forward, right, up; + AngleVectors( GetAbsAngles(), &forward, &right, &up ); + + Vector offset; + float dist; + + int numParticles = floor( 4.0f * percentage ); + + for ( int i = 0; i < numParticles; i++ ) + { + dist = random->RandomFloat( 4.0f * percentage, 64.0f * percentage ); + + offset = forward * dist; + + dist = RemapValClamped( dist, 4.0f * percentage, 64.0f * percentage, 6.0f, 1.0f ); + offset += right * random->RandomFloat( -4.0f * dist, 4.0f * dist ); + offset += up * random->RandomFloat( -4.0f * dist, 4.0f * dist ); + + offset += GetAbsOrigin(); + + sParticle = (SimpleParticle *) m_pAttractorEmitter->AddParticle( sizeof(SimpleParticle), m_pAttractorEmitter->GetPMaterial( "effects/strider_muzzle" ), offset ); + + if ( sParticle == NULL ) + return; + + sParticle->m_vecVelocity = Vector(0,0,8); + sParticle->m_flDieTime = 0.5f; + sParticle->m_flLifetime = 0.0f; + + sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); + sParticle->m_flRollDelta = 0.0f; + + float alpha = 255 * percentage; + + sParticle->m_uchColor[0] = alpha; + sParticle->m_uchColor[1] = alpha; + sParticle->m_uchColor[2] = alpha; + sParticle->m_uchStartAlpha = alpha; + sParticle->m_uchEndAlpha = 0; + + sParticle->m_uchStartSize = random->RandomFloat( 1, 2 ); + sParticle->m_uchEndSize = 0; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : percentage - +//----------------------------------------------------------------------------- +void C_CitadelEnergyCore::UpdateCharging( float percentage ) +{ + // Emitters must be valid + if ( SetupEmitters() == false ) + return; + + if ( percentage <= 0.0f ) + return; + + // Reset our sort origin + m_pSimpleEmitter->SetSortOrigin( GetAbsOrigin() ); + + float flScale = 4.0f * m_flScale * percentage; + + SimpleParticle *sParticle; + + // Do the core effects + for ( int i = 0; i < 2; i++ ) + { + sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), m_pSimpleEmitter->GetPMaterial( "effects/strider_muzzle" ), GetAbsOrigin() ); + + if ( sParticle == NULL ) + return; + + sParticle->m_vecVelocity = vec3_origin; + sParticle->m_flDieTime = 0.1f; + sParticle->m_flLifetime = 0.0f; + + sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); + sParticle->m_flRollDelta = 0.0f; + + float alpha = 255; + + sParticle->m_uchColor[0] = alpha; + sParticle->m_uchColor[1] = alpha; + sParticle->m_uchColor[2] = alpha; + sParticle->m_uchStartAlpha = alpha; + sParticle->m_uchEndAlpha = 0; + + if ( i < 2 ) + { + sParticle->m_uchStartSize = flScale * (i+1); + sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f; + } + else + { + if ( random->RandomInt( 0, 20 ) == 0 ) + { + sParticle->m_uchStartSize = flScale * (i+1); + sParticle->m_uchEndSize = sParticle->m_uchStartSize * 4.0f; + sParticle->m_flDieTime = 0.25f; + } + else + { + sParticle->m_uchStartSize = flScale * (i+1); + sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f; + } + } + } + + // Only do these particles if required + if ( m_spawnflags & SF_ENERGYCORE_NO_PARTICLES ) + return; + + // Do the charging particles + m_pAttractorEmitter->SetAttractorOrigin( GetAbsOrigin() ); + + Vector forward, right, up; + AngleVectors( GetAbsAngles(), &forward, &right, &up ); + + Vector offset; + float dist; + + int numParticles = floor( 4.0f * percentage ); + + for ( int i = 0; i < numParticles; i++ ) + { + dist = random->RandomFloat( 4.0f * percentage, 64.0f * percentage ); + + offset = forward * dist; + + dist = RemapValClamped( dist, 4.0f * percentage, 64.0f * percentage, 6.0f, 1.0f ); + offset += right * random->RandomFloat( -4.0f * dist, 4.0f * dist ); + offset += up * random->RandomFloat( -4.0f * dist, 4.0f * dist ); + + offset += GetAbsOrigin(); + + sParticle = (SimpleParticle *) m_pAttractorEmitter->AddParticle( sizeof(SimpleParticle), m_pAttractorEmitter->GetPMaterial( "effects/strider_muzzle" ), offset ); + + if ( sParticle == NULL ) + return; + + sParticle->m_vecVelocity = Vector(0,0,8); + sParticle->m_flDieTime = 0.5f; + sParticle->m_flLifetime = 0.0f; + + sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); + sParticle->m_flRollDelta = 0.0f; + + float alpha = 255 * percentage; + + sParticle->m_uchColor[0] = alpha; + sParticle->m_uchColor[1] = alpha; + sParticle->m_uchColor[2] = alpha; + sParticle->m_uchStartAlpha = alpha; + sParticle->m_uchEndAlpha = 0; + + sParticle->m_uchStartSize = random->RandomFloat( 1, 2 ); + sParticle->m_uchEndSize = 0; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : percentage - +//----------------------------------------------------------------------------- +void C_CitadelEnergyCore::UpdateDischarging( void ) +{ + // Emitters must be valid + if ( SetupEmitters() == false ) + return; + + // Reset our sort origin + m_pSimpleEmitter->SetSortOrigin( GetAbsOrigin() ); + + float flScale = 8.0f * m_flScale; + + Vector forward, right, up; + AngleVectors( GetAbsAngles(), &forward, &right, &up ); + + SimpleParticle *sParticle; + + // Base of the core effect + sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), m_pSimpleEmitter->GetPMaterial( "effects/strider_muzzle" ), GetAbsOrigin() ); + + if ( sParticle == NULL ) + return; + + sParticle->m_vecVelocity = forward * 32.0f; + sParticle->m_flDieTime = 0.2f; + sParticle->m_flLifetime = 0.0f; + + sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); + sParticle->m_flRollDelta = 0.0f; + + float alpha = 128; + + sParticle->m_uchColor[0] = alpha; + sParticle->m_uchColor[1] = alpha; + sParticle->m_uchColor[2] = alpha; + sParticle->m_uchStartAlpha = alpha; + sParticle->m_uchEndAlpha = 0; + + sParticle->m_uchStartSize = flScale * 2.0f; + sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f; + + // Make sure we encompass the complete particle here! + m_pSimpleEmitter->SetParticleCullRadius( sParticle->m_uchEndSize ); + + // Do the core effects + for ( int i = 0; i < 2; i++ ) + { + sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), m_pSimpleEmitter->GetPMaterial( "effects/combinemuzzle2" ), GetAbsOrigin() ); + + if ( sParticle == NULL ) + return; + + sParticle->m_vecVelocity = forward * ( 32.0f * (i+1) ); + sParticle->m_flDieTime = 0.2f; + sParticle->m_flLifetime = 0.0f; + + sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); + sParticle->m_flRollDelta = 0.0f; + + float alpha = 100; + + sParticle->m_uchColor[0] = alpha; + sParticle->m_uchColor[1] = alpha; + sParticle->m_uchColor[2] = alpha; + sParticle->m_uchStartAlpha = alpha; + sParticle->m_uchEndAlpha = 0; + + if ( i < 1 ) + { + sParticle->m_uchStartSize = flScale * (i+1); + sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f; + } + else + { + if ( random->RandomInt( 0, 20 ) == 0 ) + { + sParticle->m_uchStartSize = flScale * (i+1); + sParticle->m_uchEndSize = 0.0f; + sParticle->m_flDieTime = 0.25f; + } + else + { + sParticle->m_uchStartSize = flScale * (i+1); + sParticle->m_uchEndSize = 0.0f; + } + } + } + + // Only do these particles if required + if ( m_spawnflags & SF_ENERGYCORE_NO_PARTICLES ) + return; + + // Do the charging particles + m_pAttractorEmitter->SetAttractorOrigin( GetAbsOrigin() ); + + Vector offset; + float dist; + + for ( int i = 0; i < 4; i++ ) + { + dist = random->RandomFloat( 4.0f * m_flScale, 64.0f * m_flScale ); + + offset = forward * dist; + + dist = RemapValClamped( dist, 4.0f * m_flScale, 64.0f * m_flScale, 6.0f, 1.0f ); + offset += right * random->RandomFloat( -2.0f * dist * m_flScale, 2.0f * dist * m_flScale ); + offset += up * random->RandomFloat( -2.0f * dist * m_flScale, 2.0f * dist * m_flScale ); + + offset += GetAbsOrigin(); + + sParticle = (SimpleParticle *) m_pAttractorEmitter->AddParticle( sizeof(SimpleParticle), m_pAttractorEmitter->GetPMaterial( "effects/combinemuzzle2_dark" ), offset ); + + if ( sParticle == NULL ) + return; + + sParticle->m_vecVelocity = Vector(0,0,2); + sParticle->m_flDieTime = 0.5f; + sParticle->m_flLifetime = 0.0f; + + sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); + sParticle->m_flRollDelta = 0.0f; + + float alpha = 255; + + sParticle->m_uchColor[0] = alpha; + sParticle->m_uchColor[1] = alpha; + sParticle->m_uchColor[2] = alpha; + sParticle->m_uchStartAlpha = alpha; + sParticle->m_uchEndAlpha = 0; + + sParticle->m_uchStartSize = 1; + sParticle->m_uchEndSize = 0; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : inline float +//----------------------------------------------------------------------------- +inline float C_CitadelEnergyCore::GetStateDurationPercentage( void ) +{ + if ( m_flDuration == 0 ) + return 0.0f; + + return RemapValClamped( ( gpGlobals->curtime - m_flStartTime ), 0, m_flDuration, 0, 1.0f );; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_CitadelEnergyCore::NotifyShouldTransmit( ShouldTransmitState_t state ) +{ + BaseClass::NotifyShouldTransmit( state ); + + // Turn off + if ( state == SHOULDTRANSMIT_END ) + { + SetNextClientThink( CLIENT_THINK_NEVER ); + } + + // Turn on + if ( state == SHOULDTRANSMIT_START ) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_CitadelEnergyCore::ClientThink( void ) +{ + if ( gpGlobals->frametime <= 0.0f ) + return; + + float flDuration = GetStateDurationPercentage(); + + switch( m_nState ) + { + case ENERGYCORE_STATE_OFF: + UpdateIdle( 1.0f - flDuration ); + break; + + case ENERGYCORE_STATE_CHARGING: + UpdateCharging( flDuration ); + break; + + case ENERGYCORE_STATE_DISCHARGING: + UpdateDischarging( ); + break; + } +} diff --git a/game/client/hl2/c_corpse.cpp b/game/client/hl2/c_corpse.cpp new file mode 100644 index 0000000..fddb07e --- /dev/null +++ b/game/client/hl2/c_corpse.cpp @@ -0,0 +1,66 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Implements C_Corpse +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_corpse.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +IMPLEMENT_CLIENTCLASS_DT(C_Corpse, DT_Corpse, CCorpse) + RecvPropInt(RECVINFO(m_nReferencePlayer)) +END_RECV_TABLE() + + + + +C_Corpse::C_Corpse() +{ + m_nReferencePlayer = 0; +} + + +int C_Corpse::DrawModel( int flags ) +{ + int drawn = 0; + if ( m_nReferencePlayer <= 0 || + m_nReferencePlayer > gpGlobals->maxClients ) + { + return drawn; + }; + + // Make sure m_pstudiohdr is valid for drawing + if ( !GetModelPtr() ) + { + return drawn; + } + + if ( !m_bReadyToDraw ) + return 0; + + // get copy of player + C_BasePlayer *player = dynamic_cast< C_BasePlayer *>( cl_entitylist->GetEnt( m_nReferencePlayer ) ); + if ( player ) + { + Vector zero; + zero.Init(); + + drawn = modelrender->DrawModel( + flags, + this, + MODEL_INSTANCE_INVALID, + m_nReferencePlayer, + GetModel(), + GetAbsOrigin(), + GetAbsAngles(), + m_nSkin, + m_nBody, + m_nHitboxSet ); + } + + return drawn; +} + diff --git a/game/client/hl2/c_corpse.h b/game/client/hl2/c_corpse.h new file mode 100644 index 0000000..1bd4a09 --- /dev/null +++ b/game/client/hl2/c_corpse.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( C_CORPSE_H ) +#define C_CORPSE_H +#ifdef _WIN32 +#pragma once +#endif + +class C_Corpse : public C_BaseAnimating +{ +public: + DECLARE_CLASS( C_Corpse, C_BaseAnimating ); + DECLARE_CLIENTCLASS(); + + C_Corpse( void ); + + virtual int DrawModel( int flags ); + +public: + // The player whom we are copying our data from + int m_nReferencePlayer; + +private: + C_Corpse( const C_Corpse & ); +}; + + +#endif // C_CORPSE_H
\ No newline at end of file diff --git a/game/client/hl2/c_energy_wave.cpp b/game/client/hl2/c_energy_wave.cpp new file mode 100644 index 0000000..31d8b32 --- /dev/null +++ b/game/client/hl2/c_energy_wave.cpp @@ -0,0 +1,416 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client's energy wave +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "materialsystem/imaterialsystem.h" +#include "materialsystem/imesh.h" +#include "energy_wave_effect.h" +#include "mathlib/vmatrix.h" +#include "clienteffectprecachesystem.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +CLIENTEFFECT_REGISTER_BEGIN( PrecacheEnergyWave ) +CLIENTEFFECT_MATERIAL( "effects/energywave/energywave" ) +CLIENTEFFECT_REGISTER_END() + +//----------------------------------------------------------------------------- +// Energy Wave: +//----------------------------------------------------------------------------- + +class C_EnergyWave : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_EnergyWave, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + C_EnergyWave(); + ~C_EnergyWave(); + + void PostDataUpdate( DataUpdateType_t updateType ); + int DrawModel( int flags ); + void ComputePoint( float s, float t, Vector& pt, Vector& normal, float& opacity ); + void DrawWireframeModel( ); + + CEnergyWaveEffect m_EWaveEffect; + + IMaterial* m_pWireframe; + IMaterial* m_pEWaveMat; + +private: + C_EnergyWave( const C_EnergyWave & ); // not defined, not accessible + + void ComputeEWavePoints( Vector* pt, Vector* normal, float* opacity ); + void DrawEWavePoints(Vector* pt, Vector* normal, float* opacity); + +}; + + +EXTERN_RECV_TABLE(DT_BaseEntity); + +IMPLEMENT_CLIENTCLASS_DT(C_EnergyWave, DT_EWaveEffect, CEnergyWave) +END_RECV_TABLE() + + +// ---------------------------------------------------------------------------- +// Functions. +// ---------------------------------------------------------------------------- + +C_EnergyWave::C_EnergyWave() : m_EWaveEffect(NULL, NULL) +{ + m_pWireframe = materials->FindMaterial("shadertest/wireframevertexcolor", TEXTURE_GROUP_OTHER); + m_pEWaveMat = materials->FindMaterial("effects/energywave/energywave", TEXTURE_GROUP_CLIENT_EFFECTS); + m_EWaveEffect.Spawn(); +} + +C_EnergyWave::~C_EnergyWave() +{ +} + +void C_EnergyWave::PostDataUpdate( DataUpdateType_t updateType ) +{ + MarkMessageReceived(); + + // Make sure that origin points to current origin, at least + MoveToLastReceivedPosition(); +} + + + +enum +{ + NUM_SUBDIVISIONS = 21, +}; + + +static void ComputeIndices( int is, int it, int* idx ) +{ + int is0 = (is > 0) ? (is - 1) : is; + int it0 = (it > 0) ? (it - 1) : it; + int is1 = (is < EWAVE_NUM_HORIZONTAL_POINTS - 1) ? is + 1 : is; + int it1 = (it < EWAVE_NUM_HORIZONTAL_POINTS - 1) ? it + 1 : it; + int is2 = is + 2; + int it2 = it + 2; + if (is2 >= EWAVE_NUM_HORIZONTAL_POINTS) + is2 = EWAVE_NUM_HORIZONTAL_POINTS - 1; + if (it2 >= EWAVE_NUM_HORIZONTAL_POINTS) + it2 = EWAVE_NUM_HORIZONTAL_POINTS - 1; + + idx[0] = is0 + it0 * EWAVE_NUM_HORIZONTAL_POINTS; + idx[1] = is + it0 * EWAVE_NUM_HORIZONTAL_POINTS; + idx[2] = is1 + it0 * EWAVE_NUM_HORIZONTAL_POINTS; + idx[3] = is2 + it0 * EWAVE_NUM_HORIZONTAL_POINTS; + + idx[4] = is0 + it * EWAVE_NUM_HORIZONTAL_POINTS; + idx[5] = is + it * EWAVE_NUM_HORIZONTAL_POINTS; + idx[6] = is1 + it * EWAVE_NUM_HORIZONTAL_POINTS; + idx[7] = is2 + it * EWAVE_NUM_HORIZONTAL_POINTS; + + idx[8] = is0 + it1 * EWAVE_NUM_HORIZONTAL_POINTS; + idx[9] = is + it1 * EWAVE_NUM_HORIZONTAL_POINTS; + idx[10] = is1 + it1 * EWAVE_NUM_HORIZONTAL_POINTS; + idx[11] = is2 + it1 * EWAVE_NUM_HORIZONTAL_POINTS; + + idx[12] = is0 + it2 * EWAVE_NUM_HORIZONTAL_POINTS; + idx[13] = is + it2 * EWAVE_NUM_HORIZONTAL_POINTS; + idx[14] = is1 + it2 * EWAVE_NUM_HORIZONTAL_POINTS; + idx[15] = is2 + it2 * EWAVE_NUM_HORIZONTAL_POINTS; +} + +void C_EnergyWave::ComputePoint( float s, float t, Vector& pt, Vector& normal, float& opacity ) +{ + int is = (int)s; + int it = (int)t; + if( is >= EWAVE_NUM_HORIZONTAL_POINTS ) + is -= 1; + + if( it >= EWAVE_NUM_VERTICAL_POINTS ) + it -= 1; + + int idx[16]; + ComputeIndices( is, it, idx ); + + // The patch equation is: + // px = S * M * Gx * M^T * T^T + // py = S * M * Gy * M^T * T^T + // pz = S * M * Gz * M^T * T^T + // where S = [s^3 s^2 s 1], T = [t^3 t^2 t 1] + // M is the patch type matrix, in my case I'm using a catmull-rom + // G is the array of control points. rows have constant t + static VMatrix catmullRom( -0.5, 1.5, -1.5, 0.5, + 1, -2.5, 2, -0.5, + -0.5, 0, 0.5, 0, + 0, 1, 0, 0 ); + + VMatrix controlPointsX, controlPointsY, controlPointsZ, controlPointsO; + + Vector pos; + for (int i = 0; i < 4; ++i) + { + for (int j = 0; j < 4; ++j) + { + const Vector& v = m_EWaveEffect.GetPoint( idx[i * 4 + j] ); + + controlPointsX[j][i] = v.x; + controlPointsY[j][i] = v.y; + controlPointsZ[j][i] = v.z; + + controlPointsO[j][i] = m_EWaveEffect.ComputeOpacity( v, GetAbsOrigin() ); + } + } + + float fs = s - is; + float ft = t - it; + + VMatrix temp, mgm[4]; + MatrixTranspose( catmullRom, temp ); + MatrixMultiply( controlPointsX, temp, mgm[0] ); + MatrixMultiply( controlPointsY, temp, mgm[1] ); + MatrixMultiply( controlPointsZ, temp, mgm[2] ); + MatrixMultiply( controlPointsO, temp, mgm[3] ); + + MatrixMultiply( catmullRom, mgm[0], mgm[0] ); + MatrixMultiply( catmullRom, mgm[1], mgm[1] ); + MatrixMultiply( catmullRom, mgm[2], mgm[2] ); + MatrixMultiply( catmullRom, mgm[3], mgm[3] ); + + Vector4D svec, tvec; + float ft2 = ft * ft; + tvec[0] = ft2 * ft; tvec[1] = ft2; tvec[2] = ft; tvec[3] = 1.0f; + + float fs2 = fs * fs; + svec[0] = fs2 * fs; svec[1] = fs2; svec[2] = fs; svec[3] = 1.0f; + + Vector4D tmp; + Vector4DMultiply( mgm[0], tvec, tmp ); + pt[0] = DotProduct4D( tmp, svec ); + Vector4DMultiply( mgm[1], tvec, tmp ); + pt[1] = DotProduct4D( tmp, svec ); + Vector4DMultiply( mgm[2], tvec, tmp ); + pt[2] = DotProduct4D( tmp, svec ); + + Vector4DMultiply( mgm[3], tvec, tmp ); + opacity = DotProduct4D( tmp, svec ); + + if ((s == 0.0f) || (t == 0.0f) || + (s == (EWAVE_NUM_HORIZONTAL_POINTS-1.0f)) || (t == (EWAVE_NUM_VERTICAL_POINTS-1.0f)) ) + { + opacity = 0.0f; + } + + if ((s <= 0.3) || (t < 0.3)) + { + opacity *= 0.35f; + } + if ((s == (EWAVE_NUM_HORIZONTAL_POINTS-0.7f)) || (t == (EWAVE_NUM_VERTICAL_POINTS-0.7f)) ) + { + opacity *= 0.35f; + } + + if (opacity < 0.0f) + opacity = 0.0f; + else if (opacity > 255.0f) + opacity = 255.0f; + + // Normal computation + Vector4D dsvec, dtvec; + dsvec[0] = 3.0f * fs2; dsvec[1] = 2.0f * fs; dsvec[2] = 1.0f; dsvec[3] = 0.0f; + dtvec[0] = 3.0f * ft2; dtvec[1] = 2.0f * ft; dtvec[2] = 1.0f; dtvec[3] = 0.0f; + + Vector ds, dt; + Vector4DMultiply( mgm[0], tvec, tmp ); + ds[0] = DotProduct4D( tmp, dsvec ); + Vector4DMultiply( mgm[1], tvec, tmp ); + ds[1] = DotProduct4D( tmp, dsvec ); + Vector4DMultiply( mgm[2], tvec, tmp ); + ds[2] = DotProduct4D( tmp, dsvec ); + + Vector4DMultiply( mgm[0], dtvec, tmp ); + dt[0] = DotProduct4D( tmp, svec ); + Vector4DMultiply( mgm[1], dtvec, tmp ); + dt[1] = DotProduct4D( tmp, svec ); + Vector4DMultiply( mgm[2], dtvec, tmp ); + dt[2] = DotProduct4D( tmp, svec ); + + CrossProduct( ds, dt, normal ); + VectorNormalize( normal ); +} + +void C_EnergyWave::DrawWireframeModel( ) +{ + IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL, m_pWireframe ); + + int numLines = (EWAVE_NUM_VERTICAL_POINTS - 1) * EWAVE_NUM_HORIZONTAL_POINTS + + EWAVE_NUM_VERTICAL_POINTS * (EWAVE_NUM_HORIZONTAL_POINTS - 1); + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_LINES, numLines ); + + Vector tmp; + for (int i = 0; i < EWAVE_NUM_VERTICAL_POINTS; ++i) + { + for (int j = 0; j < EWAVE_NUM_HORIZONTAL_POINTS; ++j) + { + if ( i > 0 ) + { + meshBuilder.Position3fv( m_EWaveEffect.GetPoint( j, i ).Base() ); + meshBuilder.Color4ub( 255, 255, 255, 128 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv( m_EWaveEffect.GetPoint( j, i - 1 ).Base() ); + meshBuilder.Color4ub( 255, 255, 255, 128 ); + meshBuilder.AdvanceVertex(); + } + + if (j > 0) + { + meshBuilder.Position3fv( m_EWaveEffect.GetPoint( j, i ).Base() ); + meshBuilder.Color4ub( 255, 255, 255, 128 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv( m_EWaveEffect.GetPoint( j - 1, i ).Base() ); + meshBuilder.Color4ub( 255, 255, 255, 128 ); + meshBuilder.AdvanceVertex(); + } + } + } + + meshBuilder.End(); + pMesh->Draw(); +} + +//----------------------------------------------------------------------------- +// Compute the ewave points using catmull-rom +//----------------------------------------------------------------------------- + +void C_EnergyWave::ComputeEWavePoints( Vector* pt, Vector* normal, float* opacity ) +{ + int i; + for ( i = 0; i < NUM_SUBDIVISIONS; ++i) + { + float t = (EWAVE_NUM_VERTICAL_POINTS -1 ) * (float)i / (float)(NUM_SUBDIVISIONS - 1); + for (int j = 0; j < NUM_SUBDIVISIONS; ++j) + { + float s = (EWAVE_NUM_HORIZONTAL_POINTS-1) * (float)j / (float)(NUM_SUBDIVISIONS - 1); + int idx = i * NUM_SUBDIVISIONS + j; + + ComputePoint( s, t, pt[idx], normal[idx], opacity[idx] ); + } + } +} + +//----------------------------------------------------------------------------- +// Draws the base ewave +//----------------------------------------------------------------------------- + +#define TRANSITION_REGION_WIDTH 0.5f + +void C_EnergyWave::DrawEWavePoints(Vector* pt, Vector* normal, float* opacity) +{ + IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL, m_pEWaveMat ); + + int numTriangles = (NUM_SUBDIVISIONS - 1) * (NUM_SUBDIVISIONS - 1) * 2; + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, numTriangles ); + + float du = 1.0f / (float)(NUM_SUBDIVISIONS - 1); + float dv = du; + + unsigned char color[3]; + color[0] = 255; + color[1] = 255; + color[2] = 255; + + for ( int i = 0; i < NUM_SUBDIVISIONS - 1; ++i) + { + float v = i * dv; + for (int j = 0; j < NUM_SUBDIVISIONS - 1; ++j) + { + int idx = i * NUM_SUBDIVISIONS + j; + float u = j * du; + + meshBuilder.Position3fv( pt[idx].Base() ); + meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx] ); + meshBuilder.Normal3fv( normal[idx].Base() ); + meshBuilder.TexCoord2f( 0, u, v ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv( pt[idx + NUM_SUBDIVISIONS].Base() ); + meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+NUM_SUBDIVISIONS] ); + meshBuilder.Normal3fv( normal[idx + NUM_SUBDIVISIONS].Base() ); + meshBuilder.TexCoord2f( 0, u, v + dv ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv( pt[idx + 1].Base() ); + meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+1] ); + meshBuilder.Normal3fv( normal[idx+1].Base() ); + meshBuilder.TexCoord2f( 0, u + du, v ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv( pt[idx + 1].Base() ); + meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+1] ); + meshBuilder.Normal3fv( normal[idx+1].Base() ); + meshBuilder.TexCoord2f( 0, u + du, v ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv( pt[idx + NUM_SUBDIVISIONS].Base() ); + meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+NUM_SUBDIVISIONS] ); + meshBuilder.Normal3fv( normal[idx + NUM_SUBDIVISIONS].Base() ); + meshBuilder.TexCoord2f( 0, u, v + dv ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv( pt[idx + NUM_SUBDIVISIONS + 1].Base() ); + meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+NUM_SUBDIVISIONS+1] ); + meshBuilder.Normal3fv( normal[idx + NUM_SUBDIVISIONS + 1].Base() ); + meshBuilder.TexCoord2f( 0, u + du, v + dv ); + meshBuilder.AdvanceVertex(); + } + } + + meshBuilder.End(); + pMesh->Draw(); +} + +//----------------------------------------------------------------------------- +// Main draw entry point +//----------------------------------------------------------------------------- + +int C_EnergyWave::DrawModel( int flags ) +{ + if ( !m_bReadyToDraw ) + return 0; + + // NOTE: We've got a stiff spring case here, we need to simulate at + // a fairly fast timestep. A better solution would be to use an + // implicit method, which I'm going to not implement for the moment + + float dt = gpGlobals->frametime; + m_EWaveEffect.SetPosition( GetAbsOrigin(), GetAbsAngles() ); + m_EWaveEffect.Simulate(dt); + + Vector pt[NUM_SUBDIVISIONS * NUM_SUBDIVISIONS]; + Vector normal[NUM_SUBDIVISIONS * NUM_SUBDIVISIONS]; + float opacity[NUM_SUBDIVISIONS * NUM_SUBDIVISIONS]; + + ComputeEWavePoints( pt, normal, opacity ); + + DrawEWavePoints( pt, normal, opacity ); + + return 1; +} + + + + + diff --git a/game/client/hl2/c_env_alyxtemp.cpp b/game/client/hl2/c_env_alyxtemp.cpp new file mode 100644 index 0000000..9e7cd57 --- /dev/null +++ b/game/client/hl2/c_env_alyxtemp.cpp @@ -0,0 +1,486 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "particles_simple.h" +#include "citadel_effects_shared.h" +#include "particles_attractor.h" + +class C_AlyxEmpEffect : public C_BaseEntity +{ + DECLARE_CLASS( C_AlyxEmpEffect, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + +public: + void OnDataChanged( DataUpdateType_t updateType ); + RenderGroup_t GetRenderGroup( void ); + + void ClientThink( void ); + void NotifyShouldTransmit( ShouldTransmitState_t state ); + + void UpdateIdle( float percentage ); + void UpdateCharging( float percentage ); + void UpdateDischarging( void ); + +private: + + bool SetupEmitters( void ); + inline float GetStateDurationPercentage( void ); + + int m_nState; + float m_flDuration; + float m_flStartTime; + TimedEvent m_tParticleSpawn; + + CSmartPtr<CSimpleEmitter> m_pSimpleEmitter; + CSmartPtr<CParticleAttractor> m_pAttractorEmitter; +}; + +IMPLEMENT_CLIENTCLASS_DT( C_AlyxEmpEffect, DT_AlyxEmpEffect, CAlyxEmpEffect ) + RecvPropInt( RECVINFO(m_nState) ), + RecvPropFloat( RECVINFO(m_flDuration) ), + RecvPropFloat( RECVINFO(m_flStartTime) ), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +// Output : RenderGroup_t +//----------------------------------------------------------------------------- +RenderGroup_t C_AlyxEmpEffect::GetRenderGroup( void ) +{ + return RENDER_GROUP_TRANSLUCENT_ENTITY; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : updateType - +//----------------------------------------------------------------------------- +void C_AlyxEmpEffect::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + if ( updateType == DATA_UPDATE_CREATED ) + { + m_tParticleSpawn.Init( 32 ); + SetNextClientThink( CLIENT_THINK_ALWAYS ); + SetupEmitters(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_AlyxEmpEffect::SetupEmitters( void ) +{ + // Setup the basic core emitter + if ( m_pSimpleEmitter.IsValid() == false ) + { + m_pSimpleEmitter = CSimpleEmitter::Create( "energycore" ); + + if ( m_pSimpleEmitter.IsValid() == false ) + return false; + } + + // Setup the attractor emitter + if ( m_pAttractorEmitter.IsValid() == false ) + { + m_pAttractorEmitter = CParticleAttractor::Create( GetAbsOrigin(), "energyattractor" ); + + if ( m_pAttractorEmitter.IsValid() == false ) + return false; + } + + return true; +} + +#define EMP_SCALE 0.5f + +#define EMP_PARTICLES "effects/ar2_altfire1b" + +//----------------------------------------------------------------------------- +// Purpose: +// Input : percentage - +//----------------------------------------------------------------------------- +void C_AlyxEmpEffect::UpdateIdle( float percentage ) +{ +#if 0 + + // Must be active + if ( percentage >= 1.0f ) + return; + + // Emitters must be valid + if ( SetupEmitters() == false ) + return; + + // Reset our sort origin + m_pSimpleEmitter->SetSortOrigin( GetAbsOrigin() ); + + SimpleParticle *sParticle; + + // Do the charging particles + m_pAttractorEmitter->SetAttractorOrigin( GetAbsOrigin() ); + + Vector forward, right, up; + AngleVectors( GetAbsAngles(), &forward, &right, &up ); + + Vector offset; + float dist; + + int numParticles = floor( 4.0f * percentage ); + + float dTime = gpGlobals->frametime; + + while ( m_tParticleSpawn.NextEvent( dTime ) ) + { + for ( int i = 0; i < numParticles; i++ ) + { + dist = random->RandomFloat( 4.0f * EMP_SCALE * percentage, 64.0f * EMP_SCALE * percentage ); + + offset = forward * dist; + + dist = RemapValClamped( dist, 4.0f * EMP_SCALE * percentage, 64.0f * EMP_SCALE * percentage, 6.0f, 1.0f ); + offset += right * random->RandomFloat( -4.0f * EMP_SCALE * dist, 4.0f * EMP_SCALE * dist ); + offset += up * random->RandomFloat( -4.0f * EMP_SCALE * dist, 4.0f * EMP_SCALE * dist ); + + offset += GetAbsOrigin(); + + sParticle = (SimpleParticle *) m_pAttractorEmitter->AddParticle( sizeof(SimpleParticle), m_pAttractorEmitter->GetPMaterial( EMP_PARTICLES ), offset ); + + if ( sParticle == NULL ) + return; + + sParticle->m_vecVelocity = Vector(0,0,8); + sParticle->m_flDieTime = 0.5f; + sParticle->m_flLifetime = 0.0f; + + sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); + sParticle->m_flRollDelta = 0.0f; + + float alpha = 255 * percentage; + + sParticle->m_uchColor[0] = alpha; + sParticle->m_uchColor[1] = alpha; + sParticle->m_uchColor[2] = alpha; + sParticle->m_uchStartAlpha = alpha; + sParticle->m_uchEndAlpha = 0; + + sParticle->m_uchStartSize = random->RandomFloat( 1, 2 ); + sParticle->m_uchEndSize = 0; + } + } + +#endif + +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : percentage - +//----------------------------------------------------------------------------- +void C_AlyxEmpEffect::UpdateCharging( float percentage ) +{ + // Emitters must be valid + if ( SetupEmitters() == false ) + return; + + if ( percentage <= 0.0f ) + return; + + // Reset our sort origin + m_pSimpleEmitter->SetSortOrigin( GetAbsOrigin() ); + + float flScale = 4.0f * EMP_SCALE * percentage; + + SimpleParticle *sParticle; + + float dTime = gpGlobals->frametime; + + while ( m_tParticleSpawn.NextEvent( dTime ) ) + { + // Do the core effects + sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), m_pSimpleEmitter->GetPMaterial( EMP_PARTICLES ), GetAbsOrigin() ); + + if ( sParticle == NULL ) + return; + + sParticle->m_vecVelocity = vec3_origin; + sParticle->m_flDieTime = 0.1f; + sParticle->m_flLifetime = 0.0f; + + sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); + sParticle->m_flRollDelta = 0.0f; + + float alpha = 255 * percentage; + + sParticle->m_uchColor[0] = alpha; + sParticle->m_uchColor[1] = alpha; + sParticle->m_uchColor[2] = alpha; + sParticle->m_uchStartAlpha = alpha; + sParticle->m_uchEndAlpha = 0; + + sParticle->m_uchStartSize = flScale; + sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f; + } + +#if 0 + + // Do the charging particles + m_pAttractorEmitter->SetAttractorOrigin( GetAbsOrigin() ); + + Vector forward, right, up; + AngleVectors( GetAbsAngles(), &forward, &right, &up ); + + Vector offset; + float dist; + + int numParticles = floor( 4.0f * percentage ); + + for ( i = 0; i < numParticles; i++ ) + { + dist = random->RandomFloat( 4.0f * percentage, 64.0f * percentage ); + + offset = forward * dist; + + dist = RemapValClamped( dist, 4.0f * percentage, 64.0f * percentage, 6.0f, 1.0f ); + offset += right * random->RandomFloat( -4.0f * dist, 4.0f * dist ); + offset += up * random->RandomFloat( -4.0f * dist, 4.0f * dist ); + + offset += GetAbsOrigin(); + + sParticle = (SimpleParticle *) m_pAttractorEmitter->AddParticle( sizeof(SimpleParticle), m_pAttractorEmitter->GetPMaterial( EMP_PARTICLES ), offset ); + + if ( sParticle == NULL ) + return; + + sParticle->m_vecVelocity = Vector(0,0,8); + sParticle->m_flDieTime = 0.5f; + sParticle->m_flLifetime = 0.0f; + + sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); + sParticle->m_flRollDelta = 0.0f; + + float alpha = 255 * percentage; + + sParticle->m_uchColor[0] = alpha; + sParticle->m_uchColor[1] = alpha; + sParticle->m_uchColor[2] = alpha; + sParticle->m_uchStartAlpha = alpha; + sParticle->m_uchEndAlpha = 0; + + sParticle->m_uchStartSize = random->RandomFloat( 1, 2 ); + sParticle->m_uchEndSize = 0; + } + +#endif + +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : percentage - +//----------------------------------------------------------------------------- +void C_AlyxEmpEffect::UpdateDischarging( void ) +{ + // Emitters must be valid + if ( SetupEmitters() == false ) + return; + + // Reset our sort origin + m_pSimpleEmitter->SetSortOrigin( GetAbsOrigin() ); + + float flScale = EMP_SCALE * 8.0f; + + Vector forward, right, up; + AngleVectors( GetAbsAngles(), &forward, &right, &up ); + + SimpleParticle *sParticle; + + float dTime = gpGlobals->frametime; + + while ( m_tParticleSpawn.NextEvent( dTime ) ) + { + // Base of the core effect + sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), m_pSimpleEmitter->GetPMaterial( EMP_PARTICLES ), GetAbsOrigin() ); + + if ( sParticle == NULL ) + return; + + sParticle->m_vecVelocity = vec3_origin; + sParticle->m_flDieTime = 0.25f; + sParticle->m_flLifetime = 0.0f; + + sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); + sParticle->m_flRollDelta = 0.0f; + + float alpha = 64; + + sParticle->m_uchColor[0] = alpha; + sParticle->m_uchColor[1] = alpha; + sParticle->m_uchColor[2] = alpha; + sParticle->m_uchStartAlpha = alpha; + sParticle->m_uchEndAlpha = 0; + + sParticle->m_uchStartSize = flScale * 4.0f; + sParticle->m_uchEndSize = 0.0f; + + // Base of the core effect + sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), m_pSimpleEmitter->GetPMaterial( EMP_PARTICLES ), GetAbsOrigin() ); + + if ( sParticle == NULL ) + return; + + sParticle->m_vecVelocity = vec3_origin; + sParticle->m_flDieTime = 0.1f; + sParticle->m_flLifetime = 0.0f; + + sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); + sParticle->m_flRollDelta = 0.0f; + + alpha = 128; + + sParticle->m_uchColor[0] = alpha; + sParticle->m_uchColor[1] = alpha; + sParticle->m_uchColor[2] = alpha; + sParticle->m_uchStartAlpha = alpha; + sParticle->m_uchEndAlpha = 0; + + sParticle->m_uchStartSize = 0.0f; + sParticle->m_uchEndSize = flScale * 2.0f; + + // Make sure we encompass the complete particle here! + m_pSimpleEmitter->SetParticleCullRadius( sParticle->m_uchEndSize ); + + // Do the core effects + sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), m_pSimpleEmitter->GetPMaterial( EMP_PARTICLES ), GetAbsOrigin() ); + + if ( sParticle == NULL ) + return; + + sParticle->m_vecVelocity = RandomVector( -32.0f, 32.0f ); + sParticle->m_flDieTime = 0.2f; + sParticle->m_flLifetime = 0.0f; + + sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); + sParticle->m_flRollDelta = 0.0f; + + alpha = 255; + + sParticle->m_uchColor[0] = alpha; + sParticle->m_uchColor[1] = alpha; + sParticle->m_uchColor[2] = alpha; + sParticle->m_uchStartAlpha = alpha; + sParticle->m_uchEndAlpha = 0; + + sParticle->m_uchStartSize = flScale; + sParticle->m_uchEndSize = 0.0f; + } + +#if 0 + + // Do the charging particles + m_pAttractorEmitter->SetAttractorOrigin( GetAbsOrigin() ); + + Vector offset; + float dist; + + for ( i = 0; i < 4; i++ ) + { + dist = random->RandomFloat( 4.0f, 64.0f ); + + offset = forward * dist; + + dist = RemapValClamped( dist, 4.0f, 64.0f, 6.0f, 1.0f ); + offset += right * random->RandomFloat( -2.0f * dist, 2.0f * dist ); + offset += up * random->RandomFloat( -2.0f * dist, 2.0f * dist ); + + offset += GetAbsOrigin(); + + sParticle = (SimpleParticle *) m_pAttractorEmitter->AddParticle( sizeof(SimpleParticle), m_pAttractorEmitter->GetPMaterial( "effects/combinemuzzle2_dark" ), offset ); + + if ( sParticle == NULL ) + return; + + sParticle->m_vecVelocity = Vector(0,0,2); + sParticle->m_flDieTime = 0.5f; + sParticle->m_flLifetime = 0.0f; + + sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); + sParticle->m_flRollDelta = 0.0f; + + float alpha = 255; + + sParticle->m_uchColor[0] = alpha; + sParticle->m_uchColor[1] = alpha; + sParticle->m_uchColor[2] = alpha; + sParticle->m_uchStartAlpha = alpha; + sParticle->m_uchEndAlpha = 0; + + sParticle->m_uchStartSize = 1; + sParticle->m_uchEndSize = 0; + } + +#endif + +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : inline float +//----------------------------------------------------------------------------- +inline float C_AlyxEmpEffect::GetStateDurationPercentage( void ) +{ + if ( m_flDuration == 0 ) + return 0.0f; + + return RemapValClamped( ( gpGlobals->curtime - m_flStartTime ), 0, m_flDuration, 0, 1.0f );; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_AlyxEmpEffect::NotifyShouldTransmit( ShouldTransmitState_t state ) +{ + BaseClass::NotifyShouldTransmit( state ); + + // Turn off + if ( state == SHOULDTRANSMIT_END ) + { + SetNextClientThink( CLIENT_THINK_NEVER ); + } + + // Turn on + if ( state == SHOULDTRANSMIT_START ) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_AlyxEmpEffect::ClientThink( void ) +{ + if ( gpGlobals->frametime <= 0.0f ) + return; + + float flDuration = GetStateDurationPercentage(); + + switch( m_nState ) + { + case ENERGYCORE_STATE_OFF: + UpdateIdle( 1.0f - flDuration ); + break; + + case ENERGYCORE_STATE_CHARGING: + UpdateCharging( flDuration ); + break; + + case ENERGYCORE_STATE_DISCHARGING: + UpdateDischarging( ); + break; + } +} diff --git a/game/client/hl2/c_env_headcrabcanister.cpp b/game/client/hl2/c_env_headcrabcanister.cpp new file mode 100644 index 0000000..fe92ed2 --- /dev/null +++ b/game/client/hl2/c_env_headcrabcanister.cpp @@ -0,0 +1,97 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "fx_explosion.h" +#include "tempentity.h" +#include "c_tracer.h" +#include "env_headcrabcanister_shared.h" +#include "baseparticleentity.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Headcrab canister Class (Client-side only!) +//----------------------------------------------------------------------------- +class C_EnvHeadcrabCanister : public C_BaseAnimating +{ + DECLARE_CLASS( C_EnvHeadcrabCanister, C_BaseAnimating ); + DECLARE_CLIENTCLASS(); + +public: + //------------------------------------------------------------------------- + // Initialization/Destruction + //------------------------------------------------------------------------- + C_EnvHeadcrabCanister(); + ~C_EnvHeadcrabCanister(); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void ClientThink(); + +private: + C_EnvHeadcrabCanister( const C_EnvHeadcrabCanister & ); + + CEnvHeadcrabCanisterShared m_Shared; + CNetworkVar( bool, m_bLanded ); +}; + + +EXTERN_RECV_TABLE(DT_EnvHeadcrabCanisterShared); + +IMPLEMENT_CLIENTCLASS_DT( C_EnvHeadcrabCanister, DT_EnvHeadcrabCanister, CEnvHeadcrabCanister ) + RecvPropDataTable( RECVINFO_DT( m_Shared ), 0, &REFERENCE_RECV_TABLE(DT_EnvHeadcrabCanisterShared) ), + RecvPropBool( RECVINFO( m_bLanded ) ), +END_RECV_TABLE() + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +C_EnvHeadcrabCanister::C_EnvHeadcrabCanister() +{ +} + + +//----------------------------------------------------------------------------- +// Destructor +//----------------------------------------------------------------------------- +C_EnvHeadcrabCanister::~C_EnvHeadcrabCanister() +{ +} + + +//----------------------------------------------------------------------------- +// On data update +//----------------------------------------------------------------------------- +void C_EnvHeadcrabCanister::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + if ( updateType == DATA_UPDATE_CREATED ) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } + + // Stop client-side simulation on landing + if ( m_bLanded ) + { + SetNextClientThink( CLIENT_THINK_NEVER ); + } +} + + +//----------------------------------------------------------------------------- +// Compute position +//----------------------------------------------------------------------------- +void C_EnvHeadcrabCanister::ClientThink() +{ + Vector vecEndPosition; + QAngle vecEndAngles; + m_Shared.GetPositionAtTime( gpGlobals->curtime, vecEndPosition, vecEndAngles ); + SetAbsOrigin( vecEndPosition ); + SetAbsAngles( vecEndAngles ); +} + diff --git a/game/client/hl2/c_env_starfield.cpp b/game/client/hl2/c_env_starfield.cpp new file mode 100644 index 0000000..632c6f3 --- /dev/null +++ b/game/client/hl2/c_env_starfield.cpp @@ -0,0 +1,132 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "engine/IEngineTrace.h" +#include "fx_sparks.h" +#include "particles_ez.h" +#include "view.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +ConVar cl_starfield_diameter( "cl_starfield_diameter", "128.0", FCVAR_NONE ); +ConVar cl_starfield_distance( "cl_starfield_distance", "256.0", FCVAR_NONE ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_EnvStarfield : public C_BaseEntity +{ + DECLARE_CLASS( C_EnvStarfield, C_BaseEntity ); +public: + DECLARE_CLIENTCLASS(); + + C_EnvStarfield(); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void ClientThink( void ); + +private: + // Emitter + CSmartPtr<CTrailParticles> m_pEmitter; + bool m_bOn; + float m_flDensity; + float m_flNumParticles; + +private: + C_EnvStarfield( const C_EnvStarfield & ); +}; + +IMPLEMENT_CLIENTCLASS_DT( C_EnvStarfield, DT_EnvStarfield, CEnvStarfield ) + RecvPropInt( RECVINFO(m_bOn) ), + RecvPropFloat( RECVINFO(m_flDensity) ), +END_RECV_TABLE() + +// ------------------------------------------------------------------------- // +// C_EnvStarfield +// ------------------------------------------------------------------------- // +C_EnvStarfield::C_EnvStarfield() +{ + m_bOn = false; + m_flDensity = 1.0; + m_flNumParticles = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : updateType - +//----------------------------------------------------------------------------- +void C_EnvStarfield::OnDataChanged( DataUpdateType_t updateType ) +{ + if ( updateType == DATA_UPDATE_CREATED ) + { + m_pEmitter = CTrailParticles::Create( "EnvStarfield" ); + Vector vecCenter = MainViewOrigin() + (MainViewForward() * cl_starfield_distance.GetFloat() ); + m_pEmitter->Setup( (Vector &) vecCenter, + NULL, + 0.0, + 0, + 64, + 0, + 0, + bitsPARTICLE_TRAIL_VELOCITY_DAMPEN | bitsPARTICLE_TRAIL_FADE | bitsPARTICLE_TRAIL_FADE_IN ); + + // Start thinking + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } + + BaseClass::OnDataChanged( updateType ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_EnvStarfield::ClientThink( void ) +{ + if ( !m_bOn || !m_flDensity ) + return; + + PMaterialHandle hParticleMaterial = m_pEmitter->GetPMaterial( "effects/spark_noz" ); + + // Find a start & end point for the particle + // Start particles straight ahead of the client + Vector vecViewOrigin = MainViewOrigin(); + + // Determine the number of particles + m_flNumParticles += 1.0 * (m_flDensity); + int iNumParticles = floor(m_flNumParticles); + m_flNumParticles -= iNumParticles; + + // Add particles + for ( int i = 0; i < iNumParticles; i++ ) + { + float flDiameter = cl_starfield_diameter.GetFloat(); + + Vector vecStart = vecViewOrigin + (MainViewForward() * cl_starfield_distance.GetFloat() ); + Vector vecEnd = vecViewOrigin + (MainViewRight() * RandomFloat(-flDiameter,flDiameter)) + (MainViewUp() * RandomFloat(-flDiameter,flDiameter)); + Vector vecDir = (vecEnd - vecStart); + float flDistance = VectorNormalize( vecDir ); + float flTravelTime = 2.0; + + // Start a random amount along the path + vecStart += vecDir * ( RandomFloat(0.1,0.3) * flDistance ); + + TrailParticle *pParticle = (TrailParticle *) m_pEmitter->AddParticle( sizeof(TrailParticle), hParticleMaterial, vecStart ); + if ( pParticle ) + { + pParticle->m_vecVelocity = vecDir * (flDistance / flTravelTime); + pParticle->m_flDieTime = flTravelTime; + pParticle->m_flLifetime = 0; + pParticle->m_flWidth = RandomFloat( 1, 3 ); + pParticle->m_flLength = RandomFloat( 0.05, 0.4 ); + pParticle->m_color.r = 255; + pParticle->m_color.g = 255; + pParticle->m_color.b = 255; + pParticle->m_color.a = 255; + } + } +}
\ No newline at end of file diff --git a/game/client/hl2/c_extinguisher.cpp b/game/client/hl2/c_extinguisher.cpp new file mode 100644 index 0000000..c5dd042 --- /dev/null +++ b/game/client/hl2/c_extinguisher.cpp @@ -0,0 +1,413 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "particles_simple.h" +#include "baseparticleentity.h" +#include "iefx.h" +#include "decals.h" +#include "beamdraw.h" +#include "hud.h" +#include "clienteffectprecachesystem.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +CLIENTEFFECT_REGISTER_BEGIN( PrecacheExtinguisher ) +CLIENTEFFECT_MATERIAL( "particle/particle_smokegrenade" ) +CLIENTEFFECT_REGISTER_END() + +class C_ExtinguisherJet : public C_BaseEntity +{ +public: + DECLARE_CLIENTCLASS(); + DECLARE_CLASS( C_ExtinguisherJet, C_BaseEntity ); + + C_ExtinguisherJet(); + ~C_ExtinguisherJet(); + + void OnDataChanged( DataUpdateType_t updateType ); + void Update( float fTimeDelta ); + void Start( void ); + int DrawModel( int flags ); + bool ShouldDraw( void ) { return m_bEmit; } + +protected: + + void AddExtinguisherDecal( trace_t &tr ); + + bool m_bEmit; + bool m_bUseMuzzlePoint; + int m_nLength; + int m_nSize; + + PMaterialHandle m_MaterialHandle; + PMaterialHandle m_EmberMaterialHandle; + TimedEvent m_ParticleSpawn; + CSmartPtr<CSimpleEmitter> m_pEmitter; + CSmartPtr<CEmberEffect> m_pEmberEmitter; + +private: + C_ExtinguisherJet( const C_ExtinguisherJet & ); +}; + +//Datatable +IMPLEMENT_CLIENTCLASS_DT( C_ExtinguisherJet, DT_ExtinguisherJet, CExtinguisherJet ) + RecvPropInt(RECVINFO(m_bEmit), 0), + RecvPropInt(RECVINFO(m_bUseMuzzlePoint), 0), + RecvPropInt(RECVINFO(m_nLength), 0), + RecvPropInt(RECVINFO(m_nSize), 0), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ExtinguisherJet::C_ExtinguisherJet( void ) +{ + m_bEmit = false; + + m_pEmitter = NULL; + m_pEmberEmitter = NULL; +} + +C_ExtinguisherJet::~C_ExtinguisherJet( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : bnewentity - +//----------------------------------------------------------------------------- +void C_ExtinguisherJet::OnDataChanged( DataUpdateType_t updateType ) +{ + C_BaseEntity::OnDataChanged(updateType); + + if( updateType == DATA_UPDATE_CREATED ) + { + Start(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ExtinguisherJet::Start( void ) +{ + AddToLeafSystem( RENDER_GROUP_TRANSLUCENT_ENTITY ); + + m_ParticleSpawn.Init( 100 ); //Events per second + + //Create the basic emitter + m_pEmitter = CSimpleEmitter::Create("C_ExtinguisherJet::m_pEmitter"); + + Assert( m_pEmitter.IsValid() ); + if ( m_pEmitter.IsValid() ) + { + m_MaterialHandle = g_Mat_DustPuff[0]; + m_pEmitter->SetSortOrigin( GetAbsOrigin() ); + } + + //Create the "ember" emitter for the smaller flecks + m_pEmberEmitter = CEmberEffect::Create( "C_ExtinguisherJet::m_pEmberEmitter" ); + + Assert( m_pEmberEmitter.IsValid() ); + if ( m_pEmberEmitter.IsValid() ) + { + m_EmberMaterialHandle = g_Mat_DustPuff[0]; + m_pEmberEmitter->SetSortOrigin( GetAbsOrigin() ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ExtinguisherJet::AddExtinguisherDecal( trace_t &tr ) +{ + C_BaseEntity *ent = cl_entitylist->GetEnt( 0 ); + + if ( ent != NULL ) + { + int index = decalsystem->GetDecalIndexForName( "Extinguish" ); + if ( index >= 0 ) + { + Vector endpos; + endpos.Random( -24.0f, 24.0f ); + endpos += tr.endpos; + + effects->DecalShoot( index, 0, ent->GetModel(), ent->GetAbsOrigin(), ent->GetAbsAngles(), endpos, 0, 0 ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : fTimeDelta - +//----------------------------------------------------------------------------- +void C_ExtinguisherJet::Update( float fTimeDelta ) +{ + if ( m_bEmit == false ) + return; + + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + + if ( m_bUseMuzzlePoint ) + { + C_BaseViewModel *vm = player ? player->GetViewModel( 0 ) : NULL; + + if ( vm ) + { + int iAttachment = vm->LookupAttachment( "muzzle" ); + Vector origin; + QAngle angles; + vm->GetAttachment( iAttachment, origin, angles ); + + Assert( !GetMoveParent() ); + SetLocalOrigin( origin ); + SetLocalAngles( angles ); + } + } + + trace_t tr; + Vector shotDir, vRight, vUp; + + AngleVectors( GetAbsAngles(), &shotDir, &vRight, &vUp ); + + //FIXME: Muzzle point is incorrect on the model! + if ( m_bUseMuzzlePoint ) + { + shotDir.Negate(); + } + + Vector endPoint = GetAbsOrigin() + ( shotDir * 150.0f ); + + UTIL_TraceLine( GetAbsOrigin(), endPoint, MASK_SHOT, NULL, COLLISION_GROUP_NONE, &tr ); + + bool hitWall = ( tr.fraction < 1.0f ); + + //Add normal jet + if ( m_pEmitter.IsValid() ) + { + SimpleParticle *pParticle; + + m_pEmitter->SetSortOrigin( GetAbsOrigin() ); + + float tempDelta = fTimeDelta; + + //FIXME: All particles need to be within this loop + while( m_ParticleSpawn.NextEvent( tempDelta ) ) + { + pParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), m_MaterialHandle, GetAbsOrigin() ); + + if ( pParticle ) + { + pParticle->m_flDieTime = 0.2f; + pParticle->m_flLifetime = 0.0f; + + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta= random->RandomFloat( -4.0f, 4.0f ); + + pParticle->m_uchStartSize = 1; + pParticle->m_uchEndSize = random->RandomInt( 32, 48 ); + pParticle->m_uchStartAlpha = random->RandomInt( 128, 164 ); + pParticle->m_uchEndAlpha = 0; + + int cScale = random->RandomInt( 192, 255 ); + pParticle->m_uchColor[0] = cScale; + pParticle->m_uchColor[1] = cScale; + pParticle->m_uchColor[2] = cScale; + + Vector dir; + QAngle ofsAngles; + + ofsAngles.Random( -8.0f, 8.0f ); + ofsAngles += GetAbsAngles(); + + AngleVectors( ofsAngles, &dir ); + + if ( m_bUseMuzzlePoint ) + { + dir.Negate(); + } + + pParticle->m_vecVelocity = dir * random->RandomInt( 400, 800 ); + } + + //Add muzzle effect + pParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), m_MaterialHandle, GetAbsOrigin() ); + + if ( pParticle ) + { + pParticle->m_flDieTime = 0.1f; + pParticle->m_flLifetime = 0.0f; + + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta= random->RandomFloat( -4.0f, 4.0f ); + + pParticle->m_uchStartSize = 1; + pParticle->m_uchEndSize = random->RandomInt( 8, 16 ); + pParticle->m_uchStartAlpha = random->RandomInt( 128, 255 ); + pParticle->m_uchEndAlpha = 0; + + int cScale = random->RandomInt( 192, 255 ); + pParticle->m_uchColor[0] = cScale; + pParticle->m_uchColor[1] = cScale; + pParticle->m_uchColor[2] = cScale; + + Vector dir; + QAngle ofsAngles; + + ofsAngles.Random( -64.0f, 64.0f ); + ofsAngles += GetAbsAngles(); + + AngleVectors( ofsAngles, &dir ); + + if ( m_bUseMuzzlePoint ) + { + dir.Negate(); + } + + pParticle->m_vecVelocity = dir * random->RandomInt( 32, 64 ); + } + + //Add a wall effect if needed + if ( hitWall ) + { + AddExtinguisherDecal( tr ); + + Vector offDir; + + offDir.Random( -16.0f, 16.0f ); + + pParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), m_MaterialHandle, ( tr.endpos + ( tr.plane.normal * 8.0f ) ) + offDir ); + + if ( pParticle ) + { + pParticle->m_flDieTime = 0.4f; + pParticle->m_flLifetime = 0.0f; + + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta= random->RandomFloat( -2.0f, 2.0f ); + + pParticle->m_uchStartSize = random->RandomInt( 8, 16 ); + pParticle->m_uchEndSize = random->RandomInt( 24, 32 ); + pParticle->m_uchStartAlpha = random->RandomInt( 64, 128 ); + pParticle->m_uchEndAlpha = 0; + + int cScale = random->RandomInt( 192, 255 ); + pParticle->m_uchColor[0] = cScale; + pParticle->m_uchColor[1] = cScale; + pParticle->m_uchColor[2] = cScale; + + Vector rDir; + + rDir = tr.plane.normal; + rDir[0] += random->RandomFloat( -0.9f, 0.9f ); + rDir[1] += random->RandomFloat( -0.9f, 0.9f ); + rDir[2] += random->RandomFloat( -0.9f, 0.9f ); + + pParticle->m_vecVelocity = rDir * random->RandomInt( 32, 64 ); + } + } + + //Add small ember-like particles + if ( random->RandomInt( 0, 1 ) == 0 ) + { + m_pEmberEmitter->SetSortOrigin( GetAbsOrigin() ); + + pParticle = (SimpleParticle *) m_pEmberEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[0], GetAbsOrigin() ); + + assert(pParticle); + + if ( pParticle ) + { + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = 1.0f; + + pParticle->m_flRoll = 0; + pParticle->m_flRollDelta = 0; + + pParticle->m_uchColor[0] = 255; + pParticle->m_uchColor[1] = 255; + pParticle->m_uchColor[2] = 255; + pParticle->m_uchStartAlpha = 255; + pParticle->m_uchEndAlpha = 0; + pParticle->m_uchStartSize = 1; + pParticle->m_uchEndSize = 0; + + Vector dir; + QAngle ofsAngles; + + ofsAngles.Random( -8.0f, 8.0f ); + ofsAngles += GetAbsAngles(); + + AngleVectors( ofsAngles, &dir ); + + if ( m_bUseMuzzlePoint ) + { + dir.Negate(); + } + + pParticle->m_vecVelocity = dir * random->RandomInt( 400, 800 ); + } + } + } + } + + // Inner beam + + CBeamSegDraw beamDraw; + CBeamSeg seg; + const int numPoints = 4; + Vector beamPoints[numPoints]; + + beamPoints[0] = GetAbsOrigin(); + + // Create our beam points + int i; + for ( i = 0; i < numPoints; i++ ) + { + beamPoints[i] = GetAbsOrigin() + ( shotDir * (32*i*i) ); + + beamPoints[i] += vRight * sin( gpGlobals->curtime * 4.0f ) * (2.0f*i); + beamPoints[i] += vUp * sin( gpGlobals->curtime * 8.0f ) * (1.0f*i); + beamPoints[i] += shotDir * sin( gpGlobals->curtime * (16.0f*i) ) * (1.0f*i); + } + + IMaterial *pMat = materials->FindMaterial( "particle/particle_smokegrenade", TEXTURE_GROUP_PARTICLE ); + + beamDraw.Start( numPoints, pMat ); + + //Setup and draw those points + for( i = 0; i < numPoints; i++ ) + { + float t = (float) i / (numPoints - 1); + float color = 1.0f * (1.0f - t); + + seg.m_vColor = Vector( color, color, color ); + seg.m_vPos = beamPoints[i]; + seg.m_flTexCoord = (float)i/(float)(numPoints-1) - ((gpGlobals->curtime - (int)gpGlobals->curtime) * 4.0f ); + seg.m_flWidth = 4.0f + ( (64.0f*t) * (fabs( sin( gpGlobals->curtime * 16.0f ) )) ); + seg.m_flAlpha = color; + + beamDraw.NextSeg( &seg ); + } + + beamDraw.End(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flags - +//----------------------------------------------------------------------------- +int C_ExtinguisherJet::DrawModel( int flags ) +{ + if ( m_bEmit == false ) + return 1; + + Update( Helper_GetFrameTime() ); + + return 1; +} diff --git a/game/client/hl2/c_func_tankmortar.cpp b/game/client/hl2/c_func_tankmortar.cpp new file mode 100644 index 0000000..09987aa --- /dev/null +++ b/game/client/hl2/c_func_tankmortar.cpp @@ -0,0 +1,249 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "fx_quad.h" +#include "fx.h" + +class C_MortarShell : public C_BaseEntity +{ +public: + + DECLARE_CLASS( C_MortarShell, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + void OnDataChanged( DataUpdateType_t updateType ); + int DrawModel( int flags ); + + RenderGroup_t GetRenderGroup( void ) { return RENDER_GROUP_TRANSLUCENT_ENTITY; } + +private: + + void AddRisingParticles( float flPerc ); + void AddExplodingParticles( float flPerc ); + + inline float GetStartPerc( void ); + inline float GetEndPerc( void ); + + CSmartPtr<CSimpleEmitter> m_pEmitter; + TimedEvent m_ParticleEvent; + + float m_flLifespan; + float m_flRadius; + float m_flStarttime; + Vector m_vecSurfaceNormal; +}; + +IMPLEMENT_CLIENTCLASS_DT( C_MortarShell, DT_MortarShell, CMortarShell ) + RecvPropFloat( RECVINFO( m_flLifespan ) ), + RecvPropFloat( RECVINFO( m_flRadius ) ), + RecvPropVector( RECVINFO( m_vecSurfaceNormal ) ), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +// Input : updateType - +//----------------------------------------------------------------------------- +void C_MortarShell::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + if ( updateType == DATA_UPDATE_CREATED ) + { + m_flStarttime = gpGlobals->curtime; + AddToLeafSystem( RENDER_GROUP_TRANSLUCENT_ENTITY ); + + m_pEmitter = CSimpleEmitter::Create( "C_EntityDissolve" ); + m_pEmitter->SetSortOrigin( GetAbsOrigin() ); + + m_ParticleEvent.Init( 128 ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flPerc - +//----------------------------------------------------------------------------- +void C_MortarShell::AddRisingParticles( float flPerc ) +{ + SimpleParticle *sParticle; + + Vector offset; + float radius = m_flRadius * 0.25f * flPerc; + + float val = RemapValClamped( gpGlobals->curtime, m_flStarttime, m_flStarttime + m_flLifespan, 0.0f, 1.0f ); + + float flCur = gpGlobals->frametime; + + // Anime ground effects + while ( m_ParticleEvent.NextEvent( flCur ) ) + { + offset.x = random->RandomFloat( -radius, radius ); + offset.y = random->RandomFloat( -radius, radius ); + offset.z = random->RandomFloat( -8.0f, 8.0f ); + + offset += GetAbsOrigin(); + + sParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), m_pEmitter->GetPMaterial( "effects/spark" ), offset ); + + if ( sParticle == NULL ) + return; + + sParticle->m_vecVelocity = Vector( Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( 32.0f, 256.0f ) * Bias( val, 0.25f ) ); + + sParticle->m_uchStartSize = random->RandomFloat( 4, 8 ) * flPerc; + + sParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f ); + + sParticle->m_flLifetime = 0.0f; + + sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); + + float alpha = 255 * flPerc; + + sParticle->m_flRollDelta = Helper_RandomFloat( -8.0f * flPerc, 8.0f * flPerc ); + sParticle->m_uchColor[0] = alpha; + sParticle->m_uchColor[1] = alpha; + sParticle->m_uchColor[2] = alpha; + sParticle->m_uchStartAlpha = alpha; + sParticle->m_uchEndAlpha = 0; + sParticle->m_uchEndSize = 0; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flPerc - +//----------------------------------------------------------------------------- +void C_MortarShell::AddExplodingParticles( float flPerc ) +{ + SimpleParticle *sParticle; + + Vector offset; + float radius = 48.0f * flPerc; + + float flCur = gpGlobals->frametime; + + // Anime ground effects + while ( m_ParticleEvent.NextEvent( flCur ) ) + { + offset.x = random->RandomFloat( -radius, radius ); + offset.y = random->RandomFloat( -radius, radius ); + offset.z = random->RandomFloat( -8.0f, 8.0f ); + + offset += GetAbsOrigin(); + + sParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), m_pEmitter->GetPMaterial( "effects/spark" ), offset ); + + if ( sParticle == NULL ) + return; + + sParticle->m_vecVelocity = RandomVector( -1.0f, 1.0f ) + Vector( 0, 0, 1 ); + sParticle->m_vecVelocity *= ( 750.0f * flPerc ); + + sParticle->m_uchStartSize = random->RandomFloat( 2, 4 ) * flPerc; + + sParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f ); + + sParticle->m_flLifetime = 0.0f; + + sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); + + float alpha = 255 * flPerc; + + sParticle->m_flRollDelta = Helper_RandomFloat( -8.0f * flPerc, 8.0f * flPerc ); + sParticle->m_uchColor[0] = alpha; + sParticle->m_uchColor[1] = alpha; + sParticle->m_uchColor[2] = alpha; + sParticle->m_uchStartAlpha = alpha; + sParticle->m_uchEndAlpha = 0; + sParticle->m_uchEndSize = 0; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : inline float +//----------------------------------------------------------------------------- +inline float C_MortarShell::GetStartPerc( void ) +{ + float val = RemapValClamped( gpGlobals->curtime, m_flStarttime, m_flStarttime + m_flLifespan, 0.0f, 1.0f ); + + return ( Gain( val, 0.2f ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : inline float +//----------------------------------------------------------------------------- +inline float C_MortarShell::GetEndPerc( void ) +{ + float val = RemapValClamped( gpGlobals->curtime, m_flStarttime + m_flLifespan, m_flStarttime + m_flLifespan + 1.0f, 1.0f, 0.0f ); + + return ( Gain( val, 0.75f ) ); +} + +#define ALPHA_MIN 0.0f +#define ALPHA_MAX 1.0f + +#define SCALE_MIN 8 +#define SCALE_MAX 200 + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int C_MortarShell::DrawModel( int flags ) +{ + if ( gpGlobals->frametime <= 0.0f ) + return 0; + + float flPerc; + bool ending; + + // See if we're in the beginning phase + if ( gpGlobals->curtime < ( m_flStarttime + m_flLifespan ) ) + { + flPerc = GetStartPerc(); + ending = false; + } + else + { + flPerc = GetEndPerc(); + ending = true; + } + + float flAlpha = ALPHA_MIN + ( ( ALPHA_MAX - ALPHA_MIN ) * flPerc ); + float flScale = ( ending ) ? m_flRadius : ( (m_flRadius*0.1f)+ ( ( m_flRadius - (m_flRadius*0.1f) ) * flPerc ) ); + + // Do the ground effect + FX_AddQuad( GetAbsOrigin() + ( m_vecSurfaceNormal * 2.0f ), + m_vecSurfaceNormal, + flScale, + flScale, + 1.0f, + flAlpha, + flAlpha, + 1.0f, + 0, + 0, + Vector( 1.0f, 1.0f, 1.0f ), + 0.0001f, + "effects/combinemuzzle2_nocull", + 0 ); + + if ( !ending ) + { + // Add extra effects on startup + AddRisingParticles( flPerc ); + } + else + { + // Add exploding particles after the impact + AddExplodingParticles( flPerc ); + } + + return 1; +} diff --git a/game/client/hl2/c_hl2_playerlocaldata.cpp b/game/client/hl2/c_hl2_playerlocaldata.cpp new file mode 100644 index 0000000..469bd4e --- /dev/null +++ b/game/client/hl2/c_hl2_playerlocaldata.cpp @@ -0,0 +1,52 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_hl2_playerlocaldata.h" +#include "dt_recv.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +BEGIN_RECV_TABLE_NOBASE( C_HL2PlayerLocalData, DT_HL2Local ) + RecvPropFloat( RECVINFO(m_flSuitPower) ), + RecvPropInt( RECVINFO(m_bZooming) ), + RecvPropInt( RECVINFO(m_bitsActiveDevices) ), + RecvPropInt( RECVINFO(m_iSquadMemberCount) ), + RecvPropInt( RECVINFO(m_iSquadMedicCount) ), + RecvPropBool( RECVINFO(m_fSquadInFollowMode) ), + RecvPropBool( RECVINFO(m_bWeaponLowered) ), + RecvPropEHandle( RECVINFO(m_hAutoAimTarget) ), + RecvPropVector( RECVINFO(m_vecAutoAimPoint) ), + RecvPropEHandle( RECVINFO(m_hLadder) ), + RecvPropBool( RECVINFO(m_bDisplayReticle) ), + RecvPropBool( RECVINFO(m_bStickyAutoAim) ), + RecvPropBool( RECVINFO(m_bAutoAimTarget) ), +#ifdef HL2_EPISODIC + RecvPropFloat( RECVINFO(m_flFlashBattery) ), + RecvPropVector( RECVINFO(m_vecLocatorOrigin) ), +#endif +END_RECV_TABLE() + +BEGIN_PREDICTION_DATA_NO_BASE( C_HL2PlayerLocalData ) + DEFINE_PRED_FIELD( m_hLadder, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ), +END_PREDICTION_DATA() + +C_HL2PlayerLocalData::C_HL2PlayerLocalData() +{ + m_flSuitPower = 0.0; + m_bZooming = false; + m_iSquadMemberCount = 0; + m_iSquadMedicCount = 0; + m_fSquadInFollowMode = false; + m_bWeaponLowered = false; + m_hLadder = NULL; +#ifdef HL2_EPISODIC + m_flFlashBattery = 0.0f; + m_vecLocatorOrigin = vec3_origin; +#endif +} + diff --git a/game/client/hl2/c_hl2_playerlocaldata.h b/game/client/hl2/c_hl2_playerlocaldata.h new file mode 100644 index 0000000..8001991 --- /dev/null +++ b/game/client/hl2/c_hl2_playerlocaldata.h @@ -0,0 +1,55 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// + +#if !defined( C_HL2_PLAYERLOCALDATA_H ) +#define C_HL2_PLAYERLOCALDATA_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "dt_recv.h" + +#include "hl2/hl_movedata.h" + +EXTERN_RECV_TABLE( DT_HL2Local ); + + +class C_HL2PlayerLocalData +{ +public: + DECLARE_PREDICTABLE(); + DECLARE_CLASS_NOBASE( C_HL2PlayerLocalData ); + DECLARE_EMBEDDED_NETWORKVAR(); + + C_HL2PlayerLocalData(); + + float m_flSuitPower; + bool m_bZooming; + int m_bitsActiveDevices; + int m_iSquadMemberCount; + int m_iSquadMedicCount; + bool m_fSquadInFollowMode; + bool m_bWeaponLowered; + EHANDLE m_hAutoAimTarget; + Vector m_vecAutoAimPoint; + bool m_bDisplayReticle; + bool m_bStickyAutoAim; + bool m_bAutoAimTarget; +#ifdef HL2_EPISODIC + float m_flFlashBattery; + Vector m_vecLocatorOrigin; +#endif + + // Ladder related data + EHANDLE m_hLadder; + LadderMove_t m_LadderMove; +}; + + +#endif diff --git a/game/client/hl2/c_info_teleporter_countdown.cpp b/game/client/hl2/c_info_teleporter_countdown.cpp new file mode 100644 index 0000000..e99277c --- /dev/null +++ b/game/client/hl2/c_info_teleporter_countdown.cpp @@ -0,0 +1,194 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" + +#include "c_vguiscreen.h" +#include <vgui/IVGui.h> +#include <vgui_controls/Controls.h> +#include <vgui_controls/Label.h> +#include "clientmode_hlnormal.h" +#include "tier1/utllinkedlist.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +//----------------------------------------------------------------------------- +// Amount of time before breen teleports away +//----------------------------------------------------------------------------- +class C_InfoTeleporterCountdown : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_InfoTeleporterCountdown, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + +public: + C_InfoTeleporterCountdown(); + ~C_InfoTeleporterCountdown(); + + virtual bool ShouldDraw() { return false; } + +private: + bool m_bCountdownStarted; + bool m_bDisabled; + float m_flStartTime; + float m_flTimeRemaining; + + friend class CTeleportCountdownScreen; +}; + + +//----------------------------------------------------------------------------- +// Global list of teleporters +//----------------------------------------------------------------------------- +CUtlFixedLinkedList<C_InfoTeleporterCountdown *> g_InfoTeleporterCountdownList; + + +//----------------------------------------------------------------------------- +// Networking +//----------------------------------------------------------------------------- +IMPLEMENT_CLIENTCLASS_DT( C_InfoTeleporterCountdown, DT_InfoTeleporterCountdown, CInfoTeleporterCountdown ) + RecvPropInt( RECVINFO( m_bCountdownStarted ) ), + RecvPropInt( RECVINFO( m_bDisabled ) ), + RecvPropTime( RECVINFO( m_flStartTime ) ), + RecvPropFloat( RECVINFO( m_flTimeRemaining ) ), +END_RECV_TABLE() + + +//----------------------------------------------------------------------------- +// Constructor, destructor +//----------------------------------------------------------------------------- +C_InfoTeleporterCountdown::C_InfoTeleporterCountdown() +{ + g_InfoTeleporterCountdownList.AddToTail( this ); +} + +C_InfoTeleporterCountdown::~C_InfoTeleporterCountdown() +{ + g_InfoTeleporterCountdownList.FindAndRemove( this ); +} + + +//----------------------------------------------------------------------------- +// +// In-game vgui panel which shows the teleporter countdown +// +//----------------------------------------------------------------------------- +class CTeleportCountdownScreen : public CVGuiScreenPanel +{ + DECLARE_CLASS( CTeleportCountdownScreen, CVGuiScreenPanel ); + +public: + CTeleportCountdownScreen( vgui::Panel *parent, const char *panelName ); + + virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); + virtual void OnTick(); + +private: + vgui::Label *m_pTimeRemainingTitleLabel; + vgui::Label *m_pTimeRemainingLabel; + vgui::Label *m_pMalfunctionLabel; +}; + + +//----------------------------------------------------------------------------- +// Standard VGUI panel for objects +//----------------------------------------------------------------------------- +DECLARE_VGUI_SCREEN_FACTORY( CTeleportCountdownScreen, "teleport_countdown_screen" ); + + +//----------------------------------------------------------------------------- +// Constructor: +//----------------------------------------------------------------------------- +CTeleportCountdownScreen::CTeleportCountdownScreen( vgui::Panel *parent, const char *panelName ) + : BaseClass( parent, panelName, g_hVGuiCombineScheme ) +{ +} + + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- +bool CTeleportCountdownScreen::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ) +{ + // Load all of the controls in + if ( !BaseClass::Init(pKeyValues, pInitData) ) + return false; + + // Make sure we get ticked... + vgui::ivgui()->AddTickSignal( GetVPanel() ); + + // Grab ahold of certain well-known controls + // NOTE: it is valid for these controls to not exist! + m_pTimeRemainingTitleLabel = dynamic_cast<vgui::Label*>(FindChildByName( "TimeRemainingTitle" )); + m_pTimeRemainingLabel = dynamic_cast<vgui::Label*>(FindChildByName( "TimeRemaining" )); + m_pMalfunctionLabel = dynamic_cast<vgui::Label*>( FindChildByName( "MalfunctionLabel" ) ); + + return true; +} + + +//----------------------------------------------------------------------------- +// Frame-based update +//----------------------------------------------------------------------------- +void CTeleportCountdownScreen::OnTick() +{ + BaseClass::OnTick(); + + // Find the active info teleporter countdown + C_InfoTeleporterCountdown *pActiveCountdown = NULL; + for ( int i = g_InfoTeleporterCountdownList.Head(); i != g_InfoTeleporterCountdownList.InvalidIndex(); + i = g_InfoTeleporterCountdownList.Next(i) ) + { + if ( g_InfoTeleporterCountdownList[i]->m_bCountdownStarted ) + { + pActiveCountdown = g_InfoTeleporterCountdownList[i]; + break; + } + } + + if ( !GetEntity() || !pActiveCountdown ) + { + m_pTimeRemainingTitleLabel->SetVisible( false ); + m_pTimeRemainingLabel->SetVisible( false ); + m_pMalfunctionLabel->SetVisible( false ); + + return; + } + + // Make the appropriate labels visible + bool bMalfunction = pActiveCountdown->m_bDisabled; + m_pTimeRemainingTitleLabel->SetVisible( !bMalfunction ); + m_pTimeRemainingLabel->SetVisible( !bMalfunction ); + + // This will make it flash + m_pMalfunctionLabel->SetVisible( bMalfunction && (((int)(gpGlobals->curtime) & 0x1) == 0x1) ); + + // Update the time remaining + if ( !bMalfunction ) + { + char buf[32]; + if (m_pTimeRemainingLabel) + { + float dt = gpGlobals->curtime - pActiveCountdown->m_flStartTime; + if ( dt < 0.0f ) + { + dt = 0.0f; + } + + int nTimeRemaining = (int)(pActiveCountdown->m_flTimeRemaining - dt + 0.5f); + if ( nTimeRemaining < 0 ) + { + nTimeRemaining = 0; + } + + Q_snprintf( buf, sizeof( buf ), "%d", nTimeRemaining ); + m_pTimeRemainingLabel->SetText( buf ); + } + } +} + diff --git a/game/client/hl2/c_npc_antlionguard.cpp b/game/client/hl2/c_npc_antlionguard.cpp new file mode 100644 index 0000000..e2c7232 --- /dev/null +++ b/game/client/hl2/c_npc_antlionguard.cpp @@ -0,0 +1,160 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Client side antlion guard. Used to create dlight for the cave guard. +// +//============================================================================= + +#include "cbase.h" +#include "c_ai_basenpc.h" +#include "dlight.h" +#include "iefx.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +#if HL2_EPISODIC +// When enabled, add code to have the antlion bleed profusely as it is badly injured. +#define ANTLIONGUARD_BLOOD_EFFECTS 2 +#endif + + +class C_NPC_AntlionGuard : public C_AI_BaseNPC +{ +public: + C_NPC_AntlionGuard() {} + + DECLARE_CLASS( C_NPC_AntlionGuard, C_AI_BaseNPC ); + DECLARE_CLIENTCLASS(); + DECLARE_DATADESC(); + + virtual void OnDataChanged( DataUpdateType_t type ); + virtual void ClientThink(); + +private: + + bool m_bCavernBreed; + bool m_bInCavern; + dlight_t *m_dlight; + +#if HL2_EPISODIC + unsigned char m_iBleedingLevel; //< the version coming from the server + unsigned char m_iPerformingBleedingLevel; //< the version we're currently performing (for comparison to one above) + CNewParticleEffect *m_pBleedingFX; + + /// update the hemorrhage particle effect + virtual void UpdateBleedingPerformance( void ); +#endif + + C_NPC_AntlionGuard( const C_NPC_AntlionGuard & ); +}; + + +//----------------------------------------------------------------------------- +// Save/restore +//----------------------------------------------------------------------------- +BEGIN_DATADESC( C_NPC_AntlionGuard ) +END_DATADESC() + + +//----------------------------------------------------------------------------- +// Networking +//----------------------------------------------------------------------------- +IMPLEMENT_CLIENTCLASS_DT(C_NPC_AntlionGuard, DT_NPC_AntlionGuard, CNPC_AntlionGuard) + RecvPropBool( RECVINFO( m_bCavernBreed ) ), + RecvPropBool( RECVINFO( m_bInCavern ) ), + +#if ANTLIONGUARD_BLOOD_EFFECTS + RecvPropInt( RECVINFO( m_iBleedingLevel ) ), +#endif +END_RECV_TABLE() + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void C_NPC_AntlionGuard::OnDataChanged( DataUpdateType_t type ) +{ + BaseClass::OnDataChanged( type ); + + if ( (type == DATA_UPDATE_CREATED) && m_bCavernBreed && m_bInCavern ) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } + + +#if HL2_EPISODIC + if (m_iBleedingLevel != m_iPerformingBleedingLevel) + { + UpdateBleedingPerformance(); + } +#endif + +} + +#if HL2_EPISODIC +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void C_NPC_AntlionGuard::UpdateBleedingPerformance() +{ + // get my particles + CParticleProperty * pProp = ParticleProp(); + + // squelch the prior effect if it exists + if (m_pBleedingFX) + { + pProp->StopEmission(m_pBleedingFX); + m_pBleedingFX = NULL; + } + + // kick off a new effect + switch (m_iBleedingLevel) + { + case 1: // light bleeding + { + m_pBleedingFX = pProp->Create( "blood_antlionguard_injured_light", PATTACH_ABSORIGIN_FOLLOW ); + AssertMsg1( m_pBleedingFX, "Particle system couldn't make %s", "blood_antlionguard_injured_light" ); + if ( m_pBleedingFX ) + { + pProp->AddControlPoint( m_pBleedingFX, 1, this, PATTACH_ABSORIGIN_FOLLOW ); + } + } + break; + + case 2: // severe bleeding + { + m_pBleedingFX = pProp->Create( "blood_antlionguard_injured_heavy", PATTACH_ABSORIGIN_FOLLOW ); + AssertMsg1( m_pBleedingFX, "Particle system couldn't make %s", "blood_antlionguard_injured_heavy" ); + if ( m_pBleedingFX ) + { + pProp->AddControlPoint( m_pBleedingFX, 1, this, PATTACH_ABSORIGIN_FOLLOW ); + } + + } + break; + } + + m_iPerformingBleedingLevel = m_iBleedingLevel; +} +#endif + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void C_NPC_AntlionGuard::ClientThink() +{ + // update the dlight. (always done because clienthink only exists for cavernguard) + if (!m_dlight) + { + m_dlight = effects->CL_AllocDlight( index ); + m_dlight->color.r = 220; + m_dlight->color.g = 255; + m_dlight->color.b = 80; + m_dlight->radius = 180; + m_dlight->minlight = 128.0 / 256.0f; + m_dlight->flags = DLIGHT_NO_MODEL_ILLUMINATION; + } + + m_dlight->origin = GetAbsOrigin(); + // dl->die = gpGlobals->curtime + 0.1f; + + BaseClass::ClientThink(); +} diff --git a/game/client/hl2/c_npc_combinegunship.cpp b/game/client/hl2/c_npc_combinegunship.cpp new file mode 100644 index 0000000..b42ca04 --- /dev/null +++ b/game/client/hl2/c_npc_combinegunship.cpp @@ -0,0 +1,476 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "c_basehelicopter.h" +#include "fx_impact.h" +#include "IEffects.h" +#include "simple_keys.h" +#include "fx_envelope.h" +#include "fx_line.h" +#include "iefx.h" +#include "dlight.h" +#include "c_sprite.h" +#include "clienteffectprecachesystem.h" +#include <bitbuf.h> + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define GUNSHIP_MSG_BIG_SHOT 1 +#define GUNSHIP_MSG_STREAKS 2 +#define GUNSHIP_MSG_DEAD 3 + +#define GUNSHIPFX_BIG_SHOT_TIME 3.0f + +CLIENTEFFECT_REGISTER_BEGIN( PrecacheGunshipFX ) +CLIENTEFFECT_MATERIAL( "sprites/bluelaser1" ) +CLIENTEFFECT_REGISTER_END() + +//----------------------------------------------------------------------------- +// Big belly shot FX +//----------------------------------------------------------------------------- + +class C_GunshipFX : public C_EnvelopeFX +{ +public: + typedef C_EnvelopeFX BaseClass; + + C_GunshipFX(); + void Update( C_BaseEntity *pOwner, const Vector &targetPos ); + + // Returns the bounds relative to the origin (render bounds) + virtual void GetRenderBounds( Vector& mins, Vector& maxs ) + { + ClearBounds( mins, maxs ); + AddPointToBounds( m_worldPosition, mins, maxs ); + AddPointToBounds( m_targetPosition, mins, maxs ); + mins -= GetRenderOrigin(); + maxs -= GetRenderOrigin(); + } + + virtual int DrawModel( int flags ); + + C_BaseEntity *m_pOwner; + Vector m_targetPosition; + Vector m_beamEndPosition; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_GunshipFX::C_GunshipFX( void ) +{ + m_pOwner = NULL; +} + +enum +{ + GUNSHIPFX_WARP_SCALE = 0, + GUNSHIPFX_DARKNESS, + GUNSHIPFX_FLARE_COLOR, + GUNSHIPFX_FLARE_SIZE, + + GUNSHIPFX_NARROW_BEAM_COLOR, + GUNSHIPFX_NARROW_BEAM_SIZE, + + GUNSHIPFX_WIDE_BEAM_COLOR, + GUNSHIPFX_WIDE_BEAM_SIZE, + + GUNSHIPFX_AFTERGLOW_COLOR, + + GUNSHIPFX_WIDE_BEAM_LENGTH, + + // must be last + GUNSHIPFX_PARAMETERS, +}; + +class CGunshipFXEnvelope +{ +public: + CGunshipFXEnvelope(); + + void AddKey( int parameterIndex, const CSimpleKeyInterp &key ) + { + Assert( parameterIndex >= 0 && parameterIndex < GUNSHIPFX_PARAMETERS ); + + if ( parameterIndex >= 0 && parameterIndex < GUNSHIPFX_PARAMETERS ) + { + m_parameters[parameterIndex].Insert( key ); + } + + } + + CSimpleKeyList m_parameters[GUNSHIPFX_PARAMETERS]; +}; + +// NOTE: Beam widths are half-widths or radii, so this is a beam that represents a cylinder with 2" radius +const float NARROW_BEAM_WIDTH = 32; +const float WIDE_BEAM_WIDTH = 2; +const float FLARE_SIZE = 128; +const float DARK_SIZE = 16; +const float AFTERGLOW_SIZE = 64; + +CGunshipFXEnvelope::CGunshipFXEnvelope() +{ + // Glow flare + AddKey( GUNSHIPFX_FLARE_COLOR, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0 ) ); + AddKey( GUNSHIPFX_FLARE_COLOR, CSimpleKeyInterp( 0.5, KEY_SPLINE, 1 ) ); + AddKey( GUNSHIPFX_FLARE_COLOR, CSimpleKeyInterp( 2.9, KEY_LINEAR, 1 ) ); + AddKey( GUNSHIPFX_FLARE_COLOR, CSimpleKeyInterp( 3.2, KEY_DECELERATE, 0 ) ); + + AddKey( GUNSHIPFX_FLARE_SIZE, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0 ) ); + AddKey( GUNSHIPFX_FLARE_SIZE, CSimpleKeyInterp( 2.9, KEY_ACCELERATE, 1 ) ); + AddKey( GUNSHIPFX_FLARE_SIZE, CSimpleKeyInterp( 5.0, KEY_LINEAR, 1 ) ); + + // Ground beam + AddKey( GUNSHIPFX_NARROW_BEAM_COLOR, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0.0 ) ); + AddKey( GUNSHIPFX_NARROW_BEAM_COLOR, CSimpleKeyInterp( 2.5, KEY_SPLINE, 1.0 ) ); + AddKey( GUNSHIPFX_NARROW_BEAM_COLOR, CSimpleKeyInterp( 3.0, KEY_LINEAR, 1 ) ); + AddKey( GUNSHIPFX_NARROW_BEAM_COLOR, CSimpleKeyInterp( 3.2, KEY_ACCELERATE, 0 ) ); + + AddKey( GUNSHIPFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0 ) ); + AddKey( GUNSHIPFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 2.5, KEY_SPLINE, 0.25 ) ); + AddKey( GUNSHIPFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 2.8, KEY_ACCELERATE, 1 ) ); + AddKey( GUNSHIPFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 3.0, KEY_ACCELERATE, 4 ) ); + AddKey( GUNSHIPFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 3.2, KEY_DECELERATE, 0 ) ); + + // Glow color on the ship + AddKey( GUNSHIPFX_AFTERGLOW_COLOR, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0 ) ); + AddKey( GUNSHIPFX_AFTERGLOW_COLOR, CSimpleKeyInterp( 3.0, KEY_LINEAR, 1 ) ); + AddKey( GUNSHIPFX_AFTERGLOW_COLOR, CSimpleKeyInterp( 5.0, KEY_SPLINE, 0 ) ); +} + +CGunshipFXEnvelope g_GunshipCannonEnvelope; + +static void ScaleColor( color32 &out, const color32 &in, float scale ) +{ + out.r = (byte)(int)((float)in.r * scale); + out.g = (byte)(int)((float)in.g * scale); + out.b = (byte)(int)((float)in.b * scale); + out.a = (byte)(int)((float)in.a * scale); +} + +static void DrawSpriteTangentSpace( const Vector &vecOrigin, float flWidth, float flHeight, color32 color ) +{ + unsigned char pColor[4] = { color.r, color.g, color.b, color.a }; + + // Generate half-widths + flWidth *= 0.5f; + flHeight *= 0.5f; + + // Compute direction vectors for the sprite + Vector fwd, right( 1, 0, 0 ), up( 0, 1, 0 ); + VectorSubtract( CurrentViewOrigin(), vecOrigin, fwd ); + float flDist = VectorNormalize( fwd ); + if (flDist >= 1e-3) + { + CrossProduct( CurrentViewUp(), fwd, right ); + flDist = VectorNormalize( right ); + if (flDist >= 1e-3) + { + CrossProduct( fwd, right, up ); + } + else + { + // In this case, fwd == g_vecVUp, it's right above or + // below us in screen space + CrossProduct( fwd, CurrentViewRight(), up ); + VectorNormalize( up ); + CrossProduct( up, fwd, right ); + } + } + + Vector left = -right; + Vector down = -up; + Vector back = -fwd; + + CMatRenderContextPtr pRenderContext( materials ); + + CMeshBuilder meshBuilder; + Vector point; + IMesh* pMesh = pRenderContext->GetDynamicMesh( ); + + meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); + + meshBuilder.Color4ubv (pColor); + meshBuilder.TexCoord2f (0, 0, 1); + VectorMA (vecOrigin, -flHeight, up, point); + VectorMA (point, -flWidth, right, point); + meshBuilder.TangentS3fv( left.Base() ); + meshBuilder.TangentT3fv( down.Base() ); + meshBuilder.Normal3fv( back.Base() ); + meshBuilder.Position3fv (point.Base()); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ubv (pColor); + meshBuilder.TexCoord2f (0, 0, 0); + VectorMA (vecOrigin, flHeight, up, point); + VectorMA (point, -flWidth, right, point); + meshBuilder.TangentS3fv( left.Base() ); + meshBuilder.TangentT3fv( down.Base() ); + meshBuilder.Normal3fv( back.Base() ); + meshBuilder.Position3fv (point.Base()); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ubv (pColor); + meshBuilder.TexCoord2f (0, 1, 0); + VectorMA (vecOrigin, flHeight, up, point); + VectorMA (point, flWidth, right, point); + meshBuilder.TangentS3fv( left.Base() ); + meshBuilder.TangentT3fv( down.Base() ); + meshBuilder.Normal3fv( back.Base() ); + meshBuilder.Position3fv (point.Base()); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ubv (pColor); + meshBuilder.TexCoord2f (0, 1, 1); + VectorMA (vecOrigin, -flHeight, up, point); + VectorMA (point, flWidth, right, point); + meshBuilder.TangentS3fv( left.Base() ); + meshBuilder.TangentT3fv( down.Base() ); + meshBuilder.Normal3fv( back.Base() ); + meshBuilder.Position3fv (point.Base()); + meshBuilder.AdvanceVertex(); + + meshBuilder.End(); + pMesh->Draw(); +} + + +void Gunship_DrawSprite( const Vector &vecOrigin, float size, const color32 &color, bool glow ) +{ + if ( glow ) + { + pixelvis_queryparams_t params; + params.Init( vecOrigin ); + if ( PixelVisibility_FractionVisible( params, NULL ) <= 0.0f ) + return; + } + + DrawSpriteTangentSpace( vecOrigin, size, size, color ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : int - +//----------------------------------------------------------------------------- +int C_GunshipFX::DrawModel( int ) +{ + static color32 white = {255,255,255,255}; + Vector params[GUNSHIPFX_PARAMETERS]; + bool hasParam[GUNSHIPFX_PARAMETERS]; + + if ( !m_active ) + return 1; + + C_BaseEntity *ent = cl_entitylist->GetEnt( m_entityIndex ); + if ( ent ) + { + QAngle angles; + ent->GetAttachment( m_attachment, m_worldPosition, angles ); + } + + Vector test; + m_t += gpGlobals->frametime; + if ( m_tMax > 0 ) + { + m_t = clamp( m_t, 0, m_tMax ); + m_beamEndPosition = m_worldPosition; + } + float t = m_t; + + bool hasAny = false; + memset( hasParam, 0, sizeof(hasParam) ); + for ( int i = 0; i < GUNSHIPFX_PARAMETERS; i++ ) + { + hasParam[i] = g_GunshipCannonEnvelope.m_parameters[i].Interp( params[i], t ); + hasAny = hasAny || hasParam[i]; + } + + // draw the narrow beam + if ( hasParam[GUNSHIPFX_NARROW_BEAM_COLOR] && hasParam[GUNSHIPFX_NARROW_BEAM_SIZE] ) + { + IMaterial *pMat = materials->FindMaterial( "sprites/bluelaser1", TEXTURE_GROUP_CLIENT_EFFECTS ); + float width = NARROW_BEAM_WIDTH * params[GUNSHIPFX_NARROW_BEAM_SIZE].x; + color32 color; + float bright = params[GUNSHIPFX_NARROW_BEAM_COLOR].x; + ScaleColor( color, white, bright ); + + //Gunship_DrawLine( m_beamEndPosition, m_targetPosition, width, pMat, color ); + FX_DrawLine( m_beamEndPosition, m_targetPosition, width, pMat, color ); + } + + // glowy blue flare sprite + if ( hasParam[GUNSHIPFX_FLARE_COLOR] && hasParam[GUNSHIPFX_FLARE_SIZE] ) + { + IMaterial *pMat = materials->FindMaterial( "effects/blueblackflash", TEXTURE_GROUP_CLIENT_EFFECTS ); + float size = FLARE_SIZE * params[GUNSHIPFX_FLARE_SIZE].x; + color32 color; + float bright = params[GUNSHIPFX_FLARE_COLOR].x; + ScaleColor( color, white, bright ); + color.a = (int)(255 * params[GUNSHIPFX_DARKNESS].x); + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->Bind( pMat, (IClientRenderable*)this ); + Gunship_DrawSprite( m_worldPosition, size, color, true ); + } + + if ( hasParam[GUNSHIPFX_AFTERGLOW_COLOR] ) + { + // Muzzle effect + dlight_t *dl = effects->CL_AllocDlight( m_entityIndex ); + dl->origin = m_worldPosition; + dl->color.r = 40*params[GUNSHIPFX_AFTERGLOW_COLOR].x; + dl->color.g = 60*params[GUNSHIPFX_AFTERGLOW_COLOR].x; + dl->color.b = 255*params[GUNSHIPFX_AFTERGLOW_COLOR].x; + dl->color.exponent = 5; + dl->radius = 128.0f; + dl->die = gpGlobals->curtime + 0.001; + } + + if ( m_t >= 4.0 && !hasAny ) + { + EffectShutdown(); + } + + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pOwner - +// &targetPos - +//----------------------------------------------------------------------------- +void C_GunshipFX::Update( C_BaseEntity *pOwner, const Vector &targetPos ) +{ + BaseClass::Update(); + + m_pOwner = pOwner; + + if ( m_active ) + { + m_targetPosition = targetPos; + } +} + +//----------------------------------------------------------------------------- +// Gunship +//----------------------------------------------------------------------------- + +class C_CombineGunship : public C_BaseHelicopter +{ + DECLARE_CLASS( C_CombineGunship, C_BaseHelicopter ); +public: + DECLARE_CLIENTCLASS(); + + C_CombineGunship( void ) {} + + virtual ~C_CombineGunship( void ) + { + m_cannonFX.EffectShutdown(); + } + + C_GunshipFX m_cannonFX; + Vector m_vecHitPos; + + //----------------------------------------------------------------------------- + // Purpose: + // Input : length - + // *data - + // Output : void + //----------------------------------------------------------------------------- + void ReceiveMessage( int classID, bf_read &msg ) + { + if ( classID != GetClientClass()->m_ClassID ) + { + // message is for subclass + BaseClass::ReceiveMessage( classID, msg ); + return; + } + + int messageType = msg.ReadByte(); + switch( messageType ) + { + case GUNSHIP_MSG_STREAKS: + { + Vector pos; + msg.ReadBitVec3Coord( pos ); + m_cannonFX.SetRenderOrigin( pos ); + m_cannonFX.EffectInit( entindex(), LookupAttachment( "BellyGun" ) ); + m_cannonFX.LimitTime( GUNSHIPFX_BIG_SHOT_TIME ); + } + break; + + case GUNSHIP_MSG_BIG_SHOT: + { + Vector tmp; + msg.ReadBitVec3Coord( tmp ); + m_cannonFX.SetTime( GUNSHIPFX_BIG_SHOT_TIME ); + m_cannonFX.LimitTime( 0 ); + } + break; + + case GUNSHIP_MSG_DEAD: + { + m_cannonFX.EffectShutdown(); + } + break; + } + } + + void OnDataChanged( DataUpdateType_t updateType ) + { + BaseClass::OnDataChanged( updateType ); + + m_cannonFX.Update( this, m_vecHitPos ); + } + + virtual RenderGroup_t GetRenderGroup() + { + if ( hl2_episodic.GetBool() == true ) + { + return RENDER_GROUP_TWOPASS; + } + else + { + return BaseClass::GetRenderGroup(); + } + } + +private: + C_CombineGunship( const C_CombineGunship & ) {} +}; + +IMPLEMENT_CLIENTCLASS_DT( C_CombineGunship, DT_CombineGunship, CNPC_CombineGunship ) + RecvPropVector(RECVINFO(m_vecHitPos)), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: Handle gunship impacts +//----------------------------------------------------------------------------- +void ImpactGunshipCallback( const CEffectData &data ) +{ + trace_t tr; + Vector vecOrigin, vecStart, vecShotDir; + int iMaterial, iDamageType, iHitbox; + short nSurfaceProp; + C_BaseEntity *pEntity = ParseImpactData( data, &vecOrigin, &vecStart, &vecShotDir, nSurfaceProp, iMaterial, iDamageType, iHitbox ); + + if ( !pEntity ) + return; + + // If we hit, perform our custom effects and play the sound + if ( Impact( vecOrigin, vecStart, iMaterial, iDamageType, iHitbox, pEntity, tr ) ) + { + // Check for custom effects based on the Decal index + PerformCustomEffects( vecOrigin, tr, vecShotDir, iMaterial, 3 ); + } + + PlayImpactSound( pEntity, tr, vecOrigin, nSurfaceProp ); +} + +DECLARE_CLIENT_EFFECT( "ImpactGunship", ImpactGunshipCallback ); + diff --git a/game/client/hl2/c_npc_hydra.cpp b/game/client/hl2/c_npc_hydra.cpp new file mode 100644 index 0000000..271c775 --- /dev/null +++ b/game/client/hl2/c_npc_hydra.cpp @@ -0,0 +1,386 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "bone_setup.h" +#include "c_ai_basenpc.h" +#include "engine/ivdebugoverlay.h" +#include "tier0/vprof.h" +#include "soundinfo.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_NPC_Hydra : public C_AI_BaseNPC +{ +public: + DECLARE_CLASS( C_NPC_Hydra, C_AI_BaseNPC ); + DECLARE_CLIENTCLASS(); + DECLARE_INTERPOLATION(); + + C_NPC_Hydra(); + virtual ~C_NPC_Hydra(); + + // model specific + virtual void OnLatchInterpolatedVariables( int flags ); + virtual bool SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ); + virtual void StandardBlendingRules( Vector pos[], Quaternion q[], float currentTime, int boneMask ); + + void CalcBoneChain( Vector pos[], const Vector chain[] ); + void CalcBoneAngles( const Vector pos[], Quaternion q[] ); + + virtual bool GetSoundSpatialization( SpatializationInfo_t& info ); + + virtual void ResetLatched(); + +#define CHAIN_LINKS 32 + + bool m_bNewChain; + int m_fLatchFlags; + Vector m_vecChain[CHAIN_LINKS]; + + Vector m_vecHeadDir; + CInterpolatedVar< Vector > m_iv_vecHeadDir; + + //Vector m_vecInterpHeadDir; + + float m_flRelaxedLength; + + Vector *m_vecPos; // current animation + CInterpolatedVar< Vector > *m_iv_vecPos; + + int m_numHydraBones; + float *m_boneLength; + + float m_maxPossibleLength; + +private: + C_NPC_Hydra( const C_NPC_Hydra & ); // not defined, not accessible +}; + +IMPLEMENT_CLIENTCLASS_DT(C_NPC_Hydra, DT_NPC_Hydra, CNPC_Hydra) + RecvPropVector ( RECVINFO( m_vecChain[0] ) ), + RecvPropVector ( RECVINFO( m_vecChain[1] ) ), + RecvPropVector ( RECVINFO( m_vecChain[2] ) ), + RecvPropVector ( RECVINFO( m_vecChain[3] ) ), + RecvPropVector ( RECVINFO( m_vecChain[4] ) ), + RecvPropVector ( RECVINFO( m_vecChain[5] ) ), + RecvPropVector ( RECVINFO( m_vecChain[6] ) ), + RecvPropVector ( RECVINFO( m_vecChain[7] ) ), + RecvPropVector ( RECVINFO( m_vecChain[8] ) ), + RecvPropVector ( RECVINFO( m_vecChain[9] ) ), + RecvPropVector ( RECVINFO( m_vecChain[10] ) ), + RecvPropVector ( RECVINFO( m_vecChain[11] ) ), + RecvPropVector ( RECVINFO( m_vecChain[12] ) ), + RecvPropVector ( RECVINFO( m_vecChain[13] ) ), + RecvPropVector ( RECVINFO( m_vecChain[14] ) ), + RecvPropVector ( RECVINFO( m_vecChain[15] ) ), + RecvPropVector ( RECVINFO( m_vecChain[16] ) ), + RecvPropVector ( RECVINFO( m_vecChain[17] ) ), + RecvPropVector ( RECVINFO( m_vecChain[18] ) ), + RecvPropVector ( RECVINFO( m_vecChain[19] ) ), + RecvPropVector ( RECVINFO( m_vecChain[20] ) ), + RecvPropVector ( RECVINFO( m_vecChain[21] ) ), + RecvPropVector ( RECVINFO( m_vecChain[22] ) ), + RecvPropVector ( RECVINFO( m_vecChain[23] ) ), + RecvPropVector ( RECVINFO( m_vecChain[24] ) ), + RecvPropVector ( RECVINFO( m_vecChain[25] ) ), + RecvPropVector ( RECVINFO( m_vecChain[26] ) ), + RecvPropVector ( RECVINFO( m_vecChain[27] ) ), + RecvPropVector ( RECVINFO( m_vecChain[28] ) ), + RecvPropVector ( RECVINFO( m_vecChain[29] ) ), + RecvPropVector ( RECVINFO( m_vecChain[30] ) ), + RecvPropVector ( RECVINFO( m_vecChain[31] ) ), + RecvPropVector ( RECVINFO( m_vecHeadDir ) ), + RecvPropFloat ( RECVINFO( m_flRelaxedLength ) ), +END_RECV_TABLE() + +C_NPC_Hydra::C_NPC_Hydra() : m_iv_vecHeadDir( "C_NPC_Hydra::m_iv_vecHeadDir" ) +{ + AddVar( &m_vecHeadDir, &m_iv_vecHeadDir, LATCH_ANIMATION_VAR ); + + m_numHydraBones = 0; + m_boneLength = NULL; + m_maxPossibleLength = 1; + m_vecPos = NULL; + m_iv_vecPos = NULL; +} + + +C_NPC_Hydra::~C_NPC_Hydra() +{ + delete m_boneLength; + delete m_vecPos; + delete[] m_iv_vecPos; + m_iv_vecPos = NULL; +} + +void C_NPC_Hydra::OnLatchInterpolatedVariables( int flags ) +{ + m_bNewChain = true; + m_fLatchFlags = flags; + + BaseClass::OnLatchInterpolatedVariables( flags ); +} + +void C_NPC_Hydra::ResetLatched() +{ + for (int i = 0; i < m_numHydraBones; i++) + { + m_iv_vecPos[i].Reset(); + } + + BaseClass::ResetLatched(); +} + +bool C_NPC_Hydra::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ) +{ + return BaseClass::SetupBones( pBoneToWorldOut, nMaxBones, boneMask, currentTime ); +} + + +void C_NPC_Hydra::StandardBlendingRules( Vector pos[], Quaternion q[], float currentTime, int boneMask ) +{ + VPROF( "C_NPC_Hydra::StandardBlendingRules" ); + + studiohdr_t *hdr = GetModelPtr(); + if ( !hdr ) + { + return; + } + + int i; + + // check for changing model memory requirements + bool bNewlyInited = false; + if (m_numHydraBones != hdr->numbones) + { + m_numHydraBones = hdr->numbones; + + // build root animation + float poseparam[MAXSTUDIOPOSEPARAM]; + for (i = 0; i < hdr->GetNumPoseParameters(); i++) + { + poseparam[i] = 0; + } + CalcPose( hdr, NULL, pos, q, 0.0f, 0.0f, poseparam, BONE_USED_BY_ANYTHING ); + + // allocate arrays + if (m_boneLength) + { + delete[] m_boneLength; + } + m_boneLength = new float [m_numHydraBones]; + + if (m_vecPos) + { + delete[] m_vecPos; + } + m_vecPos = new Vector [m_numHydraBones]; + + if (m_iv_vecPos) + { + delete m_iv_vecPos; + } + m_iv_vecPos = new CInterpolatedVar< Vector >[m_numHydraBones]; + for ( i = 0; i < m_numHydraBones; i++ ) + { + m_iv_vecPos[ i ].Setup( &m_vecPos[ i ], LATCH_SIMULATION_VAR | EXCLUDE_AUTO_LATCH | EXCLUDE_AUTO_INTERPOLATE ); + } + + // calc models bone lengths + m_maxPossibleLength = 0; + for (i = 0; i < m_numHydraBones-1; i++) + { + m_boneLength[i] = (pos[i+1] - pos[i]).Length(); + m_maxPossibleLength += m_boneLength[i]; + } + m_boneLength[i] = 0.0f; + + bNewlyInited = true; + } + + // calc new bone setup if networked. + if (m_bNewChain) + { + CalcBoneChain( m_vecPos, m_vecChain ); + for (i = 0; i < m_numHydraBones; i++) + { + // debugoverlay->AddLineOverlay( m_vecPos[i], m_vecPos[i<m_numHydraBones-1?i+1:m_numHydraBones-1], 0, 255, 0, false, 0.1 ); + m_vecPos[i] = m_vecPos[i] - GetAbsOrigin(); + + if ( m_fLatchFlags & LATCH_SIMULATION_VAR ) + { + m_iv_vecPos[i].NoteChanged( currentTime, true ); + } + } + m_bNewChain = false; + } + + // if just allocated, initialize bones + if (bNewlyInited) + { + + for (i = 0; i < m_numHydraBones; i++) + { + m_iv_vecPos[i].Reset(); + } + } + + for (i = 0; i < m_numHydraBones; i++) + { + m_iv_vecPos[i].Interpolate( currentTime ); + pos[ i ] = m_vecPos[ i ]; + } + + // calculate bone angles + CalcBoneAngles( pos, q ); + + // rotate the last bone of the hydra 90 degrees since it's oriented differently than the others + Quaternion qTmp; + AngleQuaternion( QAngle( 0, -90, 0) , qTmp ); + QuaternionMult( q[m_numHydraBones - 1], qTmp, q[m_numHydraBones - 1] ); +} + + + +//----------------------------------------------------------------------------- +// Purpose: Fits skeleton of hydra to the variable segment length "chain" array +// Adjusts overall hydra so that "m_flRelaxedLength" of texture fits over +// the actual length of the chain +//----------------------------------------------------------------------------- + +void C_NPC_Hydra::CalcBoneChain( Vector pos[], const Vector chain[] ) +{ + int i, j; + + // Find the dist chain link that's not zero length + i = CHAIN_LINKS-1; + while (i > 0) + { + if ((chain[i] - chain[i-1]).LengthSqr() > 0.0) + { + break; + } + i--; + } + + // initialize the last bone to the last bone + j = m_numHydraBones - 1; + + // clamp length + float totalLength = 0; + for (int k = i; k > 0; k--) + { + // debugoverlay->AddLineOverlay( chain[k], chain[k-1], 255, 255, 255, false, 0 ); + totalLength += (chain[k] - chain[k-1]).Length(); + } + totalLength = clamp( totalLength, 1.0, m_maxPossibleLength ); + float scale = m_flRelaxedLength / totalLength; + + // starting from the head, fit the hydra skeleton onto the chain spline + float dist = -16; + while (j >= 0 && i > 0) + { + // debugoverlay->AddLineOverlay( chain[i], chain[i-1], 255, 255, 255, false, 0 ); + float dt = (chain[i] - chain[i-1]).Length() * scale; + float dx = dt; + while (j >= 0 && dist + dt >= m_boneLength[j]) + { + float s = (dx - (dt - (m_boneLength[j] - dist))) / dx; + + if (s < 0 || s > 1.) + s = 0; + // pos[j] = chain[i] * (1 - s) + chain[i-1] * s; + Catmull_Rom_Spline( chain[(i<CHAIN_LINKS-1)?i+1:CHAIN_LINKS-1], chain[i], chain[(i>0)?i-1:0], chain[(i>1)?i-2:0], s, pos[j] ); + // debugoverlay->AddLineOverlay( pos[j], chain[i], 0, 255, 0, false, 0 ); + // debugoverlay->AddLineOverlay( pos[j], chain[i-1], 0, 255, 0, false, 0 ); + + dt = dt - (m_boneLength[j] - dist); + j--; + dist = 0; + } + dist += dt; + i--; + } + + while (j >= 0) + { + pos[j] = chain[0]; + j--; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Minimize the amount of twist between bone segments +//----------------------------------------------------------------------------- + +void C_NPC_Hydra::CalcBoneAngles( const Vector pos[], Quaternion q[] ) +{ + int i; + matrix3x4_t bonematrix; + + for (i = m_numHydraBones - 1; i >= 0; i--) + { + Vector forward; + Vector left2; + + if (i != m_numHydraBones - 1) + { + QuaternionMatrix( q[i+1], bonematrix ); + MatrixGetColumn( bonematrix, 1, left2 ); + + forward = (pos[i+1] - pos[i]) /* + (pos[i] - pos[i-1])*/; + float length = VectorNormalize( forward ); + if (length == 0.0) + { + q[i] = q[i+1]; + continue; + } + } + else + { + forward = m_vecHeadDir; + VectorNormalize( forward ); + + VectorMatrix( forward, bonematrix ); + MatrixGetColumn( bonematrix, 1, left2 ); + } + + Vector up = CrossProduct( forward, left2 ); + VectorNormalize( up ); + + Vector left = CrossProduct( up, forward ); + + MatrixSetColumn( forward, 0, bonematrix ); + MatrixSetColumn( left, 1, bonematrix ); + MatrixSetColumn( up, 2, bonematrix ); + + // MatrixQuaternion( bonematrix, q[i] ); + QAngle angles; + MatrixAngles( bonematrix, angles ); + AngleQuaternion( angles, q[i] ); + } +} + +bool C_NPC_Hydra::GetSoundSpatialization( SpatializationInfo_t& info ) +{ + bool bret = BaseClass::GetSoundSpatialization( info ); + // Default things it's audible, put it at a better spot? + if ( bret ) + { + // TODO: Note, this is where you could override the sound position and orientation and use + // an attachment points position as the sound source + // You might have to issue C_BaseAnimating::AllowBoneAccess( true, false ); to allow + // bone setup during sound spatialization if you run into asserts... + } + + return bret; +} + diff --git a/game/client/hl2/c_npc_manhack.cpp b/game/client/hl2/c_npc_manhack.cpp new file mode 100644 index 0000000..a804fcf --- /dev/null +++ b/game/client/hl2/c_npc_manhack.cpp @@ -0,0 +1,182 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "c_ai_basenpc.h" +#include "soundenvelope.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +class C_NPC_Manhack : public C_AI_BaseNPC +{ +public: + C_NPC_Manhack() {} + + DECLARE_CLASS( C_NPC_Manhack, C_AI_BaseNPC ); + DECLARE_CLIENTCLASS(); + DECLARE_DATADESC(); + + // Purpose: Start the manhack's engine sound. + virtual void OnDataChanged( DataUpdateType_t type ); + virtual void UpdateOnRemove( void ); + virtual void OnRestore(); + +private: + C_NPC_Manhack( const C_NPC_Manhack & ); + + // Purpose: Start + stop the manhack's engine sound. + void SoundInit( void ); + void SoundShutdown( void ); + + CSoundPatch *m_pEngineSound1; + CSoundPatch *m_pEngineSound2; + CSoundPatch *m_pBladeSound; + + int m_nEnginePitch1; + int m_nEnginePitch2; + float m_flEnginePitch1Time; + float m_flEnginePitch2Time; +}; + + +//----------------------------------------------------------------------------- +// Save/restore +//----------------------------------------------------------------------------- +BEGIN_DATADESC( C_NPC_Manhack ) + +// DEFINE_SOUNDPATCH( m_pEngineSound1 ), +// DEFINE_SOUNDPATCH( m_pEngineSound2 ), +// DEFINE_SOUNDPATCH( m_pBladeSound ), + +// DEFINE_FIELD( m_nEnginePitch1, FIELD_INTEGER ), +// DEFINE_FIELD( m_nEnginePitch2, FIELD_INTEGER ), +// DEFINE_FIELD( m_flEnginePitch1Time, FIELD_FLOAT ), +// DEFINE_FIELD( m_flEnginePitch2Time, FIELD_FLOAT ), + +END_DATADESC() + + +//----------------------------------------------------------------------------- +// Networking +//----------------------------------------------------------------------------- +IMPLEMENT_CLIENTCLASS_DT(C_NPC_Manhack, DT_NPC_Manhack, CNPC_Manhack) + RecvPropIntWithMinusOneFlag(RECVINFO(m_nEnginePitch1)), + RecvPropFloat(RECVINFO(m_flEnginePitch1Time)), + RecvPropIntWithMinusOneFlag(RECVINFO(m_nEnginePitch2)), + RecvPropFloat(RECVINFO(m_flEnginePitch2Time)), +END_RECV_TABLE() + + + +//----------------------------------------------------------------------------- +// Purpose: Start the manhack's engine sound. +//----------------------------------------------------------------------------- +void C_NPC_Manhack::OnDataChanged( DataUpdateType_t type ) +{ + BaseClass::OnDataChanged( type ); + + if (( m_nEnginePitch1 < 0 ) || ( m_nEnginePitch2 < 0 ) ) + { + SoundShutdown(); + } + else + { + SoundInit(); + if ( m_pEngineSound1 && m_pEngineSound2 ) + { + float dt = ( m_flEnginePitch1Time >= gpGlobals->curtime ) ? m_flEnginePitch1Time - gpGlobals->curtime : 0.0f; + CSoundEnvelopeController::GetController().SoundChangePitch( m_pEngineSound1, m_nEnginePitch1, dt ); + dt = ( m_flEnginePitch2Time >= gpGlobals->curtime ) ? m_flEnginePitch2Time - gpGlobals->curtime : 0.0f; + CSoundEnvelopeController::GetController().SoundChangePitch( m_pEngineSound2, m_nEnginePitch2, dt ); + } + } +} + + +//----------------------------------------------------------------------------- +// Restore +//----------------------------------------------------------------------------- +void C_NPC_Manhack::OnRestore() +{ + BaseClass::OnRestore(); + SoundInit(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Start the manhack's engine sound. +//----------------------------------------------------------------------------- +void C_NPC_Manhack::UpdateOnRemove( void ) +{ + BaseClass::UpdateOnRemove(); + SoundShutdown(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Start the manhack's engine sound. +//----------------------------------------------------------------------------- +void C_NPC_Manhack::SoundInit( void ) +{ + if (( m_nEnginePitch1 < 0 ) || ( m_nEnginePitch2 < 0 ) ) + return; + + // play an engine start sound!! + CPASAttenuationFilter filter( this ); + + // Bring up the engine looping sound. + if( !m_pEngineSound1 ) + { + m_pEngineSound1 = CSoundEnvelopeController::GetController().SoundCreate( filter, entindex(), "NPC_Manhack.EngineSound1" ); + CSoundEnvelopeController::GetController().Play( m_pEngineSound1, 0.0, m_nEnginePitch1 ); + CSoundEnvelopeController::GetController().SoundChangeVolume( m_pEngineSound1, 0.7, 2.0 ); + } + + if( !m_pEngineSound2 ) + { + m_pEngineSound2 = CSoundEnvelopeController::GetController().SoundCreate( filter, entindex(), "NPC_Manhack.EngineSound2" ); + CSoundEnvelopeController::GetController().Play( m_pEngineSound2, 0.0, m_nEnginePitch2 ); + CSoundEnvelopeController::GetController().SoundChangeVolume( m_pEngineSound2, 0.7, 2.0 ); + } + + if( !m_pBladeSound ) + { + m_pBladeSound = CSoundEnvelopeController::GetController().SoundCreate( filter, entindex(), "NPC_Manhack.BladeSound" ); + CSoundEnvelopeController::GetController().Play( m_pBladeSound, 0.0, m_nEnginePitch1 ); + CSoundEnvelopeController::GetController().SoundChangeVolume( m_pBladeSound, 0.7, 2.0 ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_NPC_Manhack::SoundShutdown(void) +{ + // Kill the engine! + if ( m_pEngineSound1 ) + { + CSoundEnvelopeController::GetController().SoundDestroy( m_pEngineSound1 ); + m_pEngineSound1 = NULL; + } + + // Kill the engine! + if ( m_pEngineSound2 ) + { + CSoundEnvelopeController::GetController().SoundDestroy( m_pEngineSound2 ); + m_pEngineSound2 = NULL; + } + + // Kill the blade! + if ( m_pBladeSound ) + { + CSoundEnvelopeController::GetController().SoundDestroy( m_pBladeSound ); + m_pBladeSound = NULL; + } +} + diff --git a/game/client/hl2/c_npc_rollermine.cpp b/game/client/hl2/c_npc_rollermine.cpp new file mode 100644 index 0000000..a8b7ed0 --- /dev/null +++ b/game/client/hl2/c_npc_rollermine.cpp @@ -0,0 +1,174 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "c_ai_basenpc.h" +#include "iviewrender_beams.h" +#include "beam_shared.h" +#include "materialsystem/imaterial.h" +#include "model_types.h" +#include "clienteffectprecachesystem.h" +#include "beamdraw.h" + +class C_RollerMine : public C_AI_BaseNPC +{ + DECLARE_CLASS( C_RollerMine, C_AI_BaseNPC ); +public: + DECLARE_CLIENTCLASS(); + + C_RollerMine( void ) {} + + int DrawModel( int flags ); + + RenderGroup_t GetRenderGroup( void ) + { + if ( m_bIsOpen ) + return RENDER_GROUP_TRANSLUCENT_ENTITY; + else + return RENDER_GROUP_OPAQUE_ENTITY; + } + +private: + C_RollerMine( const C_RollerMine & ) {} + + bool m_bIsOpen; + float m_flActiveTime; + bool m_bHackedByAlyx; + bool m_bPowerDown; +}; + +IMPLEMENT_CLIENTCLASS_DT( C_RollerMine, DT_RollerMine, CNPC_RollerMine ) + RecvPropInt( RECVINFO( m_bIsOpen ) ), + RecvPropFloat( RECVINFO( m_flActiveTime ) ), + RecvPropInt( RECVINFO( m_bHackedByAlyx ) ), + RecvPropInt( RECVINFO( m_bPowerDown ) ), +END_RECV_TABLE() + +#define NUM_ATTACHMENTS 11 + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flags - +// Output : int +//----------------------------------------------------------------------------- +int C_RollerMine::DrawModel( int flags ) +{ + if ( m_bIsOpen && m_flActiveTime <= gpGlobals->curtime ) + { + float scale = random->RandomFloat( 4.0f, 6.0f ); + + if ( gpGlobals->frametime != 0 ) + { + // Inner beams + BeamInfo_t beamInfo; + + beamInfo.m_vecStart = GetAbsOrigin(); + Vector offset = RandomVector( -6*scale, 2*scale ); + + offset += Vector(2,2,2) * scale; + beamInfo.m_vecEnd = GetAbsOrigin() + offset; + + beamInfo.m_pStartEnt= cl_entitylist->GetEnt( BEAMENT_ENTITY( entindex() ) ); + beamInfo.m_pEndEnt = beamInfo.m_pStartEnt; + beamInfo.m_nStartAttachment = random->RandomInt( 0, NUM_ATTACHMENTS ); + beamInfo.m_nEndAttachment = random->RandomInt( 0, NUM_ATTACHMENTS ); + + // Ensure we're not the same point + if ( beamInfo.m_nStartAttachment == beamInfo.m_nEndAttachment ) + { + int nextStep = ( random->RandomInt( 0, 1 ) ) ? 1 : -1; + + beamInfo.m_nEndAttachment = ( beamInfo.m_nStartAttachment + nextStep ) % NUM_ATTACHMENTS; + } + + beamInfo.m_nType = TE_BEAMTESLA; + beamInfo.m_pszModelName = "sprites/lgtning.vmt"; + beamInfo.m_flHaloScale = 0.0f; + beamInfo.m_flLife = 0.1f; + beamInfo.m_flWidth = random->RandomFloat( 2.0f, 4.0f ); + beamInfo.m_flEndWidth = random->RandomFloat( 0.0f, 1.0f ); + beamInfo.m_flFadeLength = 0.0f; + beamInfo.m_flAmplitude = random->RandomFloat( 16, 32 ); + beamInfo.m_flBrightness = 255.0; + beamInfo.m_flSpeed = 0.0; + beamInfo.m_nStartFrame = 0.0; + beamInfo.m_flFrameRate = 1.0f; + + if ( m_bPowerDown ) + { + beamInfo.m_flRed = 255.0f;; + beamInfo.m_flGreen = 64.0f; + beamInfo.m_flBlue = 64.0f; + } + else if ( m_bHackedByAlyx ) + { + beamInfo.m_flRed = 240.0f;; + beamInfo.m_flGreen = 200.0f; + beamInfo.m_flBlue = 80.0f; + } + else + { + beamInfo.m_flRed = 255.0f;; + beamInfo.m_flGreen = 255.0f; + beamInfo.m_flBlue = 255.0f; + } + + beamInfo.m_nSegments = 4; + beamInfo.m_bRenderable = true; + beamInfo.m_nFlags = 0; + + beams->CreateBeamEntPoint( beamInfo ); + + // Draw the halo + float color[3]; + + if ( m_bHackedByAlyx ) + { + color[0] = 0.25f; + color[1] = 0.05f; + color[2] = 0.0f; + } + else + { + color[0] = color[1] = color[2] = 0.15f; + } + + IMaterial *pMaterial = materials->FindMaterial( "effects/rollerglow", NULL, false ); + + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->Bind( pMaterial ); + DrawHalo( pMaterial, GetAbsOrigin(), random->RandomFloat( 6.0f*scale, 6.5f*scale ), color ); + + if ( m_bPowerDown ) + { + color[0] = random->RandomFloat( 0.80f, 1.00f ); + color[1] = random->RandomFloat( 0.10f, 0.25f ); + color[2] = 0.0f; + } + else if ( m_bHackedByAlyx ) + { + color[0] = random->RandomFloat( 0.25f, 0.75f ); + color[1] = random->RandomFloat( 0.10f, 0.25f ); + color[2] = 0.0f; + } + else + { + color[0] = color[1] = color[2] = random->RandomFloat( 0.25f, 0.5f ); + } + + Vector attachOrigin; + QAngle attachAngles; + + GetAttachment( beamInfo.m_nEndAttachment, attachOrigin, attachAngles ); + DrawHalo( pMaterial, attachOrigin, random->RandomFloat( 1.0f*scale, 1.5f*scale ), color ); + + GetAttachment( beamInfo.m_nStartAttachment, attachOrigin, attachAngles ); + DrawHalo( pMaterial, attachOrigin, random->RandomFloat( 1.0f*scale, 1.5f*scale ), color ); + } + } + + return BaseClass::DrawModel( flags ); +}
\ No newline at end of file diff --git a/game/client/hl2/c_plasma_beam_node.cpp b/game/client/hl2/c_plasma_beam_node.cpp new file mode 100644 index 0000000..68cbc70 --- /dev/null +++ b/game/client/hl2/c_plasma_beam_node.cpp @@ -0,0 +1,279 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "particles_simple.h" +#include "c_tracer.h" +#include "particle_collision.h" +#include "view.h" +#include "clienteffectprecachesystem.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define PLASMASPARK_LIFETIME 0.5 +#define SPRAYS_PER_THINK 12 + +CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectPlasmaBeam ) +CLIENTEFFECT_MATERIAL( "sprites/plasmaember" ) +CLIENTEFFECT_REGISTER_END() + +class C_PlasmaBeamNode; + +//################################################################## +// +// > CPlasmaSpray +// +//################################################################## +class CPlasmaSpray : public CSimpleEmitter +{ +public: + CPlasmaSpray( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {} + + static CSmartPtr<CPlasmaSpray> Create( const char *pDebugName ); + void Think( void ); + void UpdateVelocity( SimpleParticle *pParticle, float timeDelta ); + virtual void RenderParticles( CParticleRenderIterator *pIterator ); + virtual void SimulateParticles( CParticleSimulateIterator *pIterator ); + EHANDLE m_pOwner; + CParticleCollision m_ParticleCollision; + +private: + CPlasmaSpray( const CPlasmaSpray & ); +}; + +//################################################################## +// +// PlasmaBeamNode - generates plasma spray +// +//################################################################## +class C_PlasmaBeamNode : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_PlasmaBeamNode, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + C_PlasmaBeamNode(); + ~C_PlasmaBeamNode(void); + +public: + void ClientThink(void); + void AddEntity( void ); + void OnDataChanged(DataUpdateType_t updateType); + bool ShouldDraw(); + bool m_bSprayOn; + CSmartPtr<CPlasmaSpray> m_pFirePlasmaSpray; +}; + +//################################################################## +// +// > CPlasmaSpray +// +//################################################################## + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pParticle - +// timeDelta - +// Output : float +//----------------------------------------------------------------------------- +CSmartPtr<CPlasmaSpray> CPlasmaSpray::Create( const char *pDebugName ) +{ + CPlasmaSpray *pRet = new CPlasmaSpray( pDebugName ); + return pRet; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : fTimeDelta - +// Output : Vector +//----------------------------------------------------------------------------- +void CPlasmaSpray::UpdateVelocity( SimpleParticle *pParticle, float timeDelta ) +{ + Vector vGravity = Vector(0,0,-1000); + float flFrametime = gpGlobals->frametime; + vGravity = flFrametime * vGravity; + pParticle->m_vecVelocity += vGravity; +} + + +void CPlasmaSpray::SimulateParticles( CParticleSimulateIterator *pIterator ) +{ + float timeDelta = pIterator->GetTimeDelta(); + + SimpleParticle *pParticle = (SimpleParticle*)pIterator->GetFirst(); + while ( pParticle ) + { + //Should this particle die? + pParticle->m_flLifetime += timeDelta; + + C_PlasmaBeamNode* pNode = (C_PlasmaBeamNode*)((C_BaseEntity*)m_pOwner); + if ( pParticle->m_flLifetime >= pParticle->m_flDieTime ) + { + pIterator->RemoveParticle( pParticle ); + } + // If owner is gone or spray off remove me + else if (pNode == NULL || !pNode->m_bSprayOn) + { + pIterator->RemoveParticle( pParticle ); + } + + //Simulate the movement with collision + trace_t trace; + m_ParticleCollision.MoveParticle( pParticle->m_Pos, pParticle->m_vecVelocity, NULL, timeDelta, &trace ); + + pParticle = (SimpleParticle*)pIterator->GetNext(); + } +} + + +void CPlasmaSpray::RenderParticles( CParticleRenderIterator *pIterator ) +{ + const SimpleParticle *pParticle = (const SimpleParticle *)pIterator->GetFirst(); + while ( pParticle ) + { + float scale = random->RandomFloat( 0.02, 0.08 ); + + // NOTE: We need to do everything in screen space + Vector delta; + Vector start; + TransformParticle(ParticleMgr()->GetModelView(), pParticle->m_Pos, start); + float sortKey = start.z; + + Vector3DMultiply( CurrentWorldToViewMatrix(), pParticle->m_vecVelocity, delta ); + + delta[0] *= scale; + delta[1] *= scale; + delta[2] *= scale; + + // See c_tracer.* for this method + Tracer_Draw( pIterator->GetParticleDraw(), start, delta, random->RandomInt( 2, 8 ), 0 ); + + pParticle = (const SimpleParticle *)pIterator->GetNext( sortKey ); + } +} + + +//################################################################## +// +// PlasmaBeamNode - generates plasma spray +// +//################################################################## + +//------------------------------------------------------------------------------ +// Purpose : +// Input : +// Output : +//------------------------------------------------------------------------------ +C_PlasmaBeamNode::C_PlasmaBeamNode(void) +{ + m_bSprayOn = false; + m_pFirePlasmaSpray = CPlasmaSpray::Create( "C_PlasmaBeamNode" ); +} + +//------------------------------------------------------------------------------ +// Purpose : +// Input : +// Output : +//------------------------------------------------------------------------------ +C_PlasmaBeamNode::~C_PlasmaBeamNode(void) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PlasmaBeamNode::AddEntity( void ) +{ + m_pFirePlasmaSpray->SetSortOrigin( GetAbsOrigin() ); +} + +//------------------------------------------------------------------------------ +// Purpose : +// Input : +// Output : +//------------------------------------------------------------------------------ +void C_PlasmaBeamNode::OnDataChanged(DataUpdateType_t updateType) +{ + if (updateType == DATA_UPDATE_CREATED) + { + Vector vMoveDir = GetAbsVelocity(); + float flVel = VectorNormalize(vMoveDir); + m_pFirePlasmaSpray->m_ParticleCollision.Setup( GetAbsOrigin(), &vMoveDir, 0.3, + flVel-50, flVel+50, 800, 0.5 ); + SetNextClientThink(gpGlobals->curtime + 0.01); + } + C_BaseEntity::OnDataChanged(updateType); +} + +//------------------------------------------------------------------------------ +// Purpose : +// Input : +// Output : +//------------------------------------------------------------------------------ +bool C_PlasmaBeamNode::ShouldDraw() +{ + return false; +} + +//------------------------------------------------------------------------------ +// Purpose : +// Input : +// Output : +//------------------------------------------------------------------------------ +void C_PlasmaBeamNode::ClientThink(void) +{ + if (!m_bSprayOn) + { + return; + } + + trace_t trace; + Vector vEndTrace = GetAbsOrigin() + (0.3*GetAbsVelocity()); + UTIL_TraceLine( GetAbsOrigin(), vEndTrace, MASK_SHOT, NULL, COLLISION_GROUP_NONE, &trace ); + if ( trace.fraction != 1.0f || trace.startsolid) + { + m_bSprayOn = false; + return; + } + + PMaterialHandle handle = m_pFirePlasmaSpray->GetPMaterial( "sprites/plasmaember" ); + for (int i=0;i<SPRAYS_PER_THINK;i++) + { + SimpleParticle *sParticle; + + //Make a new particle + if ( random->RandomInt( 0, 2 ) == 0 ) + { + float ranx = random->RandomFloat( -28.0f, 28.0f ); + float rany = random->RandomFloat( -28.0f, 28.0f ); + float ranz = random->RandomFloat( -28.0f, 28.0f ); + + Vector vNewPos = GetAbsOrigin(); + Vector vAdd = Vector(GetAbsAngles().x,GetAbsAngles().y,GetAbsAngles().z)*random->RandomFloat(-60,120); + vNewPos += vAdd; + + sParticle = (SimpleParticle *) m_pFirePlasmaSpray->AddParticle( sizeof(SimpleParticle), handle, vNewPos ); + + sParticle->m_flLifetime = 0.0f; + sParticle->m_flDieTime = PLASMASPARK_LIFETIME; + + sParticle->m_vecVelocity = GetAbsVelocity(); + sParticle->m_vecVelocity.x += ranx; + sParticle->m_vecVelocity.y += rany; + sParticle->m_vecVelocity.z += ranz; + m_pFirePlasmaSpray->m_pOwner = this; + } + } + + SetNextClientThink(gpGlobals->curtime + 0.05); +} + +IMPLEMENT_CLIENTCLASS_DT(C_PlasmaBeamNode, DT_PlasmaBeamNode, CPlasmaBeamNode ) + RecvPropVector (RECVINFO(m_vecVelocity), 0, RecvProxy_LocalVelocity), + RecvPropInt (RECVINFO(m_bSprayOn)), +END_RECV_TABLE() diff --git a/game/client/hl2/c_prop_combine_ball.cpp b/game/client/hl2/c_prop_combine_ball.cpp new file mode 100644 index 0000000..2e31806 --- /dev/null +++ b/game/client/hl2/c_prop_combine_ball.cpp @@ -0,0 +1,340 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "c_prop_combine_ball.h" +#include "materialsystem/imaterial.h" +#include "model_types.h" +#include "c_physicsprop.h" +#include "c_te_effect_dispatch.h" +#include "fx_quad.h" +#include "fx.h" +#include "clienteffectprecachesystem.h" +#include "view.h" +#include "view_scene.h" +#include "beamdraw.h" + +// Precache our effects +CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectCombineBall ) +CLIENTEFFECT_MATERIAL( "effects/ar2_altfire1" ) +CLIENTEFFECT_MATERIAL( "effects/ar2_altfire1b" ) +CLIENTEFFECT_MATERIAL( "effects/combinemuzzle1_nocull" ) +CLIENTEFFECT_MATERIAL( "effects/combinemuzzle2_nocull" ) +CLIENTEFFECT_MATERIAL( "effects/combinemuzzle1" ) +CLIENTEFFECT_MATERIAL( "effects/ar2_altfire1" ) +CLIENTEFFECT_MATERIAL( "effects/ar2_altfire1b" ) +CLIENTEFFECT_REGISTER_END() + +IMPLEMENT_CLIENTCLASS_DT( C_PropCombineBall, DT_PropCombineBall, CPropCombineBall ) + RecvPropBool( RECVINFO( m_bEmit ) ), + RecvPropFloat( RECVINFO( m_flRadius ) ), + RecvPropBool( RECVINFO( m_bHeld ) ), + RecvPropBool( RECVINFO( m_bLaunched ) ), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PropCombineBall::C_PropCombineBall( void ) +{ + m_pFlickerMaterial = NULL; + m_pBodyMaterial = NULL; + m_pBlurMaterial = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : updateType - +//----------------------------------------------------------------------------- +void C_PropCombineBall::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + if ( updateType == DATA_UPDATE_CREATED ) + { + m_vecLastOrigin = GetAbsOrigin(); + InitMaterials(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : RenderGroup_t +//----------------------------------------------------------------------------- +RenderGroup_t C_PropCombineBall::GetRenderGroup( void ) +{ + return RENDER_GROUP_TRANSLUCENT_ENTITY; +} + +//----------------------------------------------------------------------------- +// Purpose: Cache the material handles +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool C_PropCombineBall::InitMaterials( void ) +{ + // Motion blur + if ( m_pBlurMaterial == NULL ) + { + m_pBlurMaterial = materials->FindMaterial( "effects/ar2_altfire1b", NULL, false ); + + if ( m_pBlurMaterial == NULL ) + return false; + } + + // Main body of the ball + if ( m_pBodyMaterial == NULL ) + { + m_pBodyMaterial = materials->FindMaterial( "effects/ar2_altfire1", NULL, false ); + + if ( m_pBodyMaterial == NULL ) + return false; + } + + // Flicker material + if ( m_pFlickerMaterial == NULL ) + { + m_pFlickerMaterial = materials->FindMaterial( "effects/combinemuzzle1", NULL, false ); + + if ( m_pFlickerMaterial == NULL ) + return false; + } + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PropCombineBall::DrawMotionBlur( void ) +{ + float color[3]; + + Vector vecDir = GetAbsOrigin() - m_vecLastOrigin; + float speed = VectorNormalize( vecDir ); + + speed = clamp( speed, 0, 32 ); + + float stepSize = MIN( ( speed * 0.5f ), 4.0f ); + + Vector spawnPos = GetAbsOrigin(); + Vector spawnStep = -vecDir * stepSize; + + float base = RemapValClamped( speed, 4, 32, 0.0f, 1.0f ); + + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->Bind( m_pBlurMaterial ); + + // Draw the motion blurred trail + for ( int i = 0; i < 8; i++ ) + { + spawnPos += spawnStep; + + color[0] = color[1] = color[2] = base * ( 1.0f - ( (float) i / 12.0f ) ); + + DrawHalo( m_pBlurMaterial, spawnPos, m_flRadius, color ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PropCombineBall::DrawFlicker( void ) +{ + float rand1 = random->RandomFloat( 0.2f, 0.3f ); + float rand2 = random->RandomFloat( 1.5f, 2.5f ); + + if ( gpGlobals->frametime == 0.0f ) + { + rand1 = 0.2f; + rand2 = 1.5f; + } + + float color[3]; + color[0] = color[1] = color[2] = rand1; + + // Draw the flickering glow + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->Bind( m_pFlickerMaterial ); + DrawHalo( m_pFlickerMaterial, GetAbsOrigin(), m_flRadius * rand2, color ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pMaterial - +// source - +// color - +//----------------------------------------------------------------------------- +void DrawHaloOriented( const Vector& source, float scale, float const *color, float roll ) +{ + Vector point, screen; + + CMatRenderContextPtr pRenderContext( materials ); + IMesh* pMesh = pRenderContext->GetDynamicMesh(); + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); + + // Transform source into screen space + ScreenTransform( source, screen ); + + Vector right, up; + float sr, cr; + + SinCos( roll, &sr, &cr ); + + for ( int i = 0; i < 3; i++ ) + { + right[i] = CurrentViewRight()[i] * cr + CurrentViewUp()[i] * sr; + up[i] = CurrentViewRight()[i] * -sr + CurrentViewUp()[i] * cr; + } + + meshBuilder.Color3fv (color); + meshBuilder.TexCoord2f (0, 0, 1); + VectorMA (source, -scale, up, point); + VectorMA (point, -scale, right, point); + meshBuilder.Position3fv (point.Base()); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color3fv (color); + meshBuilder.TexCoord2f (0, 0, 0); + VectorMA (source, scale, up, point); + VectorMA (point, -scale, right, point); + meshBuilder.Position3fv (point.Base()); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color3fv (color); + meshBuilder.TexCoord2f (0, 1, 0); + VectorMA (source, scale, up, point); + VectorMA (point, scale, right, point); + meshBuilder.Position3fv (point.Base()); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color3fv (color); + meshBuilder.TexCoord2f (0, 1, 1); + VectorMA (source, -scale, up, point); + VectorMA (point, scale, right, point); + meshBuilder.Position3fv (point.Base()); + meshBuilder.AdvanceVertex(); + + meshBuilder.End(); + pMesh->Draw(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flags - +// Output : int +//----------------------------------------------------------------------------- +int C_PropCombineBall::DrawModel( int flags ) +{ + if ( !m_bEmit ) + return 0; + + // Make sure our materials are cached + if ( !InitMaterials() ) + { + //NOTENOTE: This means that a material was not found for the combine ball, so it may not render! + AssertOnce( 0 ); + return 0; + } + + // Draw the flickering overlay + DrawFlicker(); + + // Draw the motion blur from movement + if ( m_bHeld || m_bLaunched ) + { + DrawMotionBlur(); + } + + // Draw the model if we're being held + if ( m_bHeld ) + { + QAngle angles; + VectorAngles( -CurrentViewForward(), angles ); + + // Always orient towards the camera! + SetAbsAngles( angles ); + + BaseClass::DrawModel( flags ); + } + else + { + float color[3]; + color[0] = color[1] = color[2] = 1.0f; + + float sinOffs = 1.0f * sin( gpGlobals->curtime * 25 ); + + float roll = SpawnTime(); + + // Draw the main ball body + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->Bind( m_pBodyMaterial, (C_BaseEntity*) this ); + DrawHaloOriented( GetAbsOrigin(), m_flRadius + sinOffs, color, roll ); + } + + m_vecLastOrigin = GetAbsOrigin(); + + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &data - +//----------------------------------------------------------------------------- +void CombineBallImpactCallback( const CEffectData &data ) +{ + // Quick flash + FX_AddQuad( data.m_vOrigin, + data.m_vNormal, + data.m_flRadius * 10.0f, + 0, + 0.75f, + 1.0f, + 0.0f, + 0.4f, + random->RandomInt( 0, 360 ), + 0, + Vector( 1.0f, 1.0f, 1.0f ), + 0.25f, + "effects/combinemuzzle1_nocull", + (FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) ); + + // Lingering burn + FX_AddQuad( data.m_vOrigin, + data.m_vNormal, + data.m_flRadius * 2.0f, + data.m_flRadius * 4.0f, + 0.75f, + 1.0f, + 0.0f, + 0.4f, + random->RandomInt( 0, 360 ), + 0, + Vector( 1.0f, 1.0f, 1.0f ), + 0.5f, + "effects/combinemuzzle2_nocull", + (FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) ); + + // Throw sparks + FX_ElectricSpark( data.m_vOrigin, 2, 1, &data.m_vNormal ); +} + +DECLARE_CLIENT_EFFECT( "cball_bounce", CombineBallImpactCallback ); + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &data - +//----------------------------------------------------------------------------- +void CombineBallExplosionCallback( const CEffectData &data ) +{ + Vector normal(0,0,1); + + // Throw sparks + FX_ElectricSpark( data.m_vOrigin, 4, 1, &normal ); +} + +DECLARE_CLIENT_EFFECT( "cball_explode", CombineBallExplosionCallback );
\ No newline at end of file diff --git a/game/client/hl2/c_prop_combine_ball.h b/game/client/hl2/c_prop_combine_ball.h new file mode 100644 index 0000000..04e8e47 --- /dev/null +++ b/game/client/hl2/c_prop_combine_ball.h @@ -0,0 +1,45 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef CPROPCOMBINEBALL_H_ +#define CPROPCOMBINEBALL_H_ + +#ifdef _WIN32 +#pragma once +#endif + +class C_PropCombineBall : public C_BaseAnimating +{ + DECLARE_CLASS( C_PropCombineBall, C_BaseAnimating ); + DECLARE_CLIENTCLASS(); +public: + + C_PropCombineBall( void ); + + virtual RenderGroup_t GetRenderGroup( void ); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual int DrawModel( int flags ); + +protected: + + void DrawMotionBlur( void ); + void DrawFlicker( void ); + virtual bool InitMaterials( void ); + + Vector m_vecLastOrigin; + bool m_bEmit; + float m_flRadius; + bool m_bHeld; + bool m_bLaunched; + + IMaterial *m_pFlickerMaterial; + IMaterial *m_pBodyMaterial; + IMaterial *m_pBlurMaterial; +}; + + +#endif
\ No newline at end of file diff --git a/game/client/hl2/c_rotorwash.cpp b/game/client/hl2/c_rotorwash.cpp new file mode 100644 index 0000000..439f18a --- /dev/null +++ b/game/client/hl2/c_rotorwash.cpp @@ -0,0 +1,306 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "particlemgr.h" +#include "particle_prototype.h" +#include "particle_util.h" +#include "c_te_particlesystem.h" +#include "fx.h" +#include "fx_quad.h" +#include "clienteffectprecachesystem.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// ============================================== +// Rotorwash particle emitter +// ============================================== + +#ifndef _XBOX + +class WashEmitter : public CSimpleEmitter +{ +public: + + WashEmitter( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {} + + static WashEmitter *Create( const char *pDebugName ) + { + return new WashEmitter( pDebugName ); + } + + void UpdateVelocity( SimpleParticle *pParticle, float timeDelta ) + { + // Float up when lifetime is half gone. + pParticle->m_vecVelocity[ 2 ] += 64 * timeDelta; + + // FIXME: optimize this.... + pParticle->m_vecVelocity *= ExponentialDecay( 0.8, 0.05, timeDelta ); + } + + virtual float UpdateRoll( SimpleParticle *pParticle, float timeDelta ) + { + pParticle->m_flRoll += pParticle->m_flRollDelta * timeDelta; + + pParticle->m_flRollDelta += pParticle->m_flRollDelta * ( timeDelta * -2.0f ); + + //Cap the minimum roll + if ( fabs( pParticle->m_flRollDelta ) < 0.5f ) + { + pParticle->m_flRollDelta = ( pParticle->m_flRollDelta > 0.0f ) ? 0.5f : -0.5f; + } + + return pParticle->m_flRoll; + } + + virtual float UpdateAlpha( const SimpleParticle *pParticle ) + { + return ( ((float)pParticle->m_uchStartAlpha/255.0f) * sin( M_PI * (pParticle->m_flLifetime / pParticle->m_flDieTime) ) ); + } + +private: + WashEmitter( const WashEmitter & ); +}; + +#endif // !_XBOX + +// ============================================== +// Rotorwash entity +// ============================================== + +#define ROTORWASH_THINK_INTERVAL 0.1f + +class C_RotorWashEmitter : public C_BaseEntity +{ +public: + + DECLARE_CLASS( C_RotorWashEmitter, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + C_RotorWashEmitter( void ); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void ClientThink( void ); + +protected: + + float m_flAltitude; + + PMaterialHandle m_hWaterMaterial[2]; + +#ifndef _XBOX + void InitSpawner( void ); + CSmartPtr<WashEmitter> m_pSimple; +#endif // !XBOX +}; + +IMPLEMENT_CLIENTCLASS_DT( C_RotorWashEmitter, DT_RotorWashEmitter, CRotorWashEmitter) + RecvPropFloat(RECVINFO(m_flAltitude)), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_RotorWashEmitter::C_RotorWashEmitter( void ) +{ +#ifndef _XBOX + m_pSimple = NULL; + m_hWaterMaterial[0] = NULL; + m_hWaterMaterial[1] = NULL; +#endif // !_XBOX +} + +#ifndef _XBOX +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_RotorWashEmitter::InitSpawner( void ) +{ + if ( m_pSimple.IsValid() ) + return; + + m_pSimple = WashEmitter::Create( "wash" ); + m_pSimple->SetNearClip( 128, 256 ); +} +#endif // !XBOX + +//----------------------------------------------------------------------------- +// Purpose: +// Input : updateType - +//----------------------------------------------------------------------------- +void C_RotorWashEmitter::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + if ( updateType == DATA_UPDATE_CREATED ) + { + SetNextClientThink( gpGlobals->curtime + ROTORWASH_THINK_INTERVAL ); + +#ifndef _XBOX + InitSpawner(); +#endif // !XBOX + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_RotorWashEmitter::ClientThink( void ) +{ + SetNextClientThink( gpGlobals->curtime + ROTORWASH_THINK_INTERVAL ); + + trace_t tr; + UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin()+(Vector(0, 0, -1024)), (MASK_SOLID_BRUSHONLY|CONTENTS_WATER|CONTENTS_SLIME), NULL, COLLISION_GROUP_NONE, &tr ); + + if ( /*!m_bIgnoreSolid && */(tr.fraction == 1.0f || tr.startsolid || tr.allsolid) ) + return; + + // If we hit the skybox, don't do it either + if ( tr.surface.flags & SURF_SKY ) + return; + + float heightScale = RemapValClamped( tr.fraction * 1024, 512, 1024, 1.0f, 0.0f ); + + Vector vecDustColor; + + if ( tr.contents & CONTENTS_WATER ) + { + vecDustColor.x = 0.8f; + vecDustColor.y = 0.8f; + vecDustColor.z = 0.75f; + } + else if ( tr.contents & CONTENTS_SLIME ) + { + vecDustColor.x = 0.6f; + vecDustColor.y = 0.5f; + vecDustColor.z = 0.15f; + } + else + { + vecDustColor.x = 0.35f; + vecDustColor.y = 0.3f; + vecDustColor.z = 0.25f; + } + +#ifndef _XBOX + + InitSpawner(); + + if ( m_pSimple.IsValid() == false ) + return; + + m_pSimple->SetSortOrigin( GetAbsOrigin() ); + + PMaterialHandle *hMaterial; + + // Cache and set our material based on the surface we're over (ie. water) + if ( tr.contents & (CONTENTS_WATER|CONTENTS_SLIME) ) + { + if ( m_hWaterMaterial[0] == NULL ) + { + m_hWaterMaterial[0] = m_pSimple->GetPMaterial("effects/splash1"); + m_hWaterMaterial[1] = m_pSimple->GetPMaterial("effects/splash2"); + } + hMaterial = m_hWaterMaterial; + } + else + { + hMaterial = g_Mat_DustPuff; + } + +#endif // !XBOX + + // If we're above water, make ripples + if ( tr.contents & (CONTENTS_WATER|CONTENTS_SLIME) ) + { + float flScale = random->RandomFloat( 7.5f, 8.5f ); + + Vector color = Vector( 0.8f, 0.8f, 0.75f ); + Vector startPos = tr.endpos + Vector(0,0,8); + Vector endPos = tr.endpos + Vector(0,0,-64); + + if ( tr.fraction < 1.0f ) + { + //Add a ripple quad to the surface + FX_AddQuad( tr.endpos + ( tr.plane.normal * 0.5f ), + tr.plane.normal, + 64.0f * flScale, + 128.0f * flScale, + 0.8f, + 0.75f * heightScale, + 0.0f, + 0.75f, + random->RandomFloat( 0, 360 ), + random->RandomFloat( -2.0f, 2.0f ), + vecDustColor, + 0.2f, + "effects/splashwake3", + (FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) ); + } + } + +#ifndef _XBOX + int numRingSprites = 32; + float yaw = random->RandomFloat( 0, 2*M_PI ); // Randomly placed on the unit circle + float yawIncr = (2*M_PI) / numRingSprites; + Vector vecForward; + Vector offset; + SimpleParticle *pParticle; + + // Draw the rings + for ( int i = 0; i < numRingSprites; i++ ) + { + // Get our x,y on the unit circle + SinCos( yaw, &vecForward.y, &vecForward.x ); + + // Increment ahead + yaw += yawIncr; + + // @NOTE toml (3-28-07): broke out following expression because vc2005 optimizer was screwing up in presence of SinCos inline assembly. Would also + // go away if offset were referenced below as in the AddLineOverlay() + //offset = ( RandomVector( -4.0f, 4.0f ) + tr.endpos ) + ( vecForward * 128.0f ); + + offset = vecForward * 128.0f; + offset += tr.endpos + RandomVector( -4.0f, 4.0f ); + + + pParticle = (SimpleParticle *) m_pSimple->AddParticle( sizeof(SimpleParticle), hMaterial[random->RandomInt(0,1)], offset ); + + if ( pParticle != NULL ) + { + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = random->RandomFloat( 0.25f, 1.0f ); + + pParticle->m_vecVelocity = vecForward * random->RandomFloat( 1000, 1500 ); + + #if __EXPLOSION_DEBUG + debugoverlay->AddLineOverlay( m_vecOrigin, m_vecOrigin + pParticle->m_vecVelocity, 255, 0, 0, false, 3 ); + #endif + + if ( tr.contents & CONTENTS_SLIME ) + { + vecDustColor.x = random->RandomFloat( 0.4f, 0.6f ); + vecDustColor.y = random->RandomFloat( 0.3f, 0.5f ); + vecDustColor.z = random->RandomFloat( 0.1f, 0.2f ); + } + + pParticle->m_uchColor[0] = vecDustColor.x * 255.0f; + pParticle->m_uchColor[1] = vecDustColor.y * 255.0f; + pParticle->m_uchColor[2] = vecDustColor.z * 255.0f; + + pParticle->m_uchStartSize = random->RandomInt( 16, 64 ); + pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4; + + pParticle->m_uchStartAlpha = random->RandomFloat( 16, 32 ) * heightScale; + pParticle->m_uchEndAlpha = 0; + + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = random->RandomFloat( -16.0f, 16.0f ); + } + } +#endif // !XBOX +} diff --git a/game/client/hl2/c_script_intro.cpp b/game/client/hl2/c_script_intro.cpp new file mode 100644 index 0000000..eb97cb4 --- /dev/null +++ b/game/client/hl2/c_script_intro.cpp @@ -0,0 +1,327 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// +#include "cbase.h" +#include "shareddefs.h" +#include "materialsystem/imesh.h" +#include "view.h" +#include "iviewrender.h" +#include "view_shared.h" +#include "viewrender.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +extern IntroData_t *g_pIntroData; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_ScriptIntro : public C_BaseEntity +{ + DECLARE_CLASS( C_ScriptIntro, C_BaseEntity ); +public: + DECLARE_CLIENTCLASS(); + + C_ScriptIntro( void ); + ~C_ScriptIntro( void ); + void PostDataUpdate( DataUpdateType_t updateType ); + void ClientThink( void ); + void CalculateFOV( void ); + void CalculateAlpha( void ); + +public: + int m_iNextFOV; + int m_iFOV; + int m_iPrevFOV; + int m_iStartFOV; + float m_flNextFOVBlendTime; + float m_flFOVBlendStartTime; + bool m_bAlternateFOV; + + // Our intro data block + IntroData_t m_IntroData; + +private: + Vector m_vecCameraView; + QAngle m_vecCameraViewAngles; + int m_iBlendMode; + int m_iNextBlendMode; + float m_flNextBlendTime; + float m_flBlendStartTime; + bool m_bActive; + EHANDLE m_hCameraEntity; + + // Fades + float m_flFadeColor[3]; // Server's desired fade color + float m_flFadeAlpha; // Server's desired fade alpha + float m_flPrevServerFadeAlpha; // Previous server's desired fade alpha + float m_flFadeDuration; // Time it should take to reach the server's new fade alpha + float m_flFadeTimeStartedAt; // Time at which we last recieved a new desired fade alpha + float m_flFadeAlphaStartedAt; // Alpha at which we last received a new desired fade alpha +}; + +IMPLEMENT_CLIENTCLASS_DT( C_ScriptIntro, DT_ScriptIntro, CScriptIntro ) + RecvPropVector( RECVINFO( m_vecCameraView ) ), + RecvPropVector( RECVINFO( m_vecCameraViewAngles ) ), + RecvPropInt( RECVINFO( m_iBlendMode ) ), + RecvPropInt( RECVINFO( m_iNextBlendMode ) ), + RecvPropFloat( RECVINFO( m_flNextBlendTime ) ), + RecvPropFloat( RECVINFO( m_flBlendStartTime ) ), + RecvPropBool( RECVINFO( m_bActive ) ), + + // Fov & fov blends + RecvPropInt( RECVINFO( m_iFOV ) ), + RecvPropInt( RECVINFO( m_iNextFOV ) ), + RecvPropInt( RECVINFO( m_iStartFOV ) ), + RecvPropFloat( RECVINFO( m_flNextFOVBlendTime ) ), + RecvPropFloat( RECVINFO( m_flFOVBlendStartTime ) ), + RecvPropBool( RECVINFO( m_bAlternateFOV ) ), + + // Fades + RecvPropFloat( RECVINFO( m_flFadeAlpha ) ), + RecvPropArray( RecvPropFloat( RECVINFO( m_flFadeColor[0] ) ), m_flFadeColor ), + RecvPropFloat( RECVINFO( m_flFadeDuration ) ), + RecvPropEHandle(RECVINFO(m_hCameraEntity)), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ScriptIntro::C_ScriptIntro( void ) +{ + m_bActive = false; + m_vecCameraView = vec3_origin; + m_vecCameraViewAngles = vec3_angle; + m_iBlendMode = 0; + m_iNextBlendMode = 0; + m_flNextBlendTime = 0; + m_flBlendStartTime = 0; + m_IntroData.m_playerViewFOV = 0; + m_flFadeAlpha = 0; + m_flPrevServerFadeAlpha = 0; + m_flFadeDuration = 0; + m_flFadeTimeStartedAt = 0; + m_flFadeAlphaStartedAt = 0; + m_hCameraEntity = NULL; + m_iPrevFOV = 0; + m_iStartFOV = 0; + + g_pIntroData = NULL; + + // Setup fade colors + m_IntroData.m_flCurrentFadeColor[0] = m_flFadeColor[0]; + m_IntroData.m_flCurrentFadeColor[1] = m_flFadeColor[1]; + m_IntroData.m_flCurrentFadeColor[2] = m_flFadeColor[2]; + m_IntroData.m_flCurrentFadeColor[3] = m_flFadeAlpha; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ScriptIntro::~C_ScriptIntro( void ) +{ + g_pIntroData = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ScriptIntro::PostDataUpdate( DataUpdateType_t updateType ) +{ + BaseClass::PostDataUpdate( updateType ); + + SetNextClientThink( CLIENT_THINK_ALWAYS ); + + // Fill out the intro data + m_IntroData.m_vecCameraView = m_vecCameraView; + m_IntroData.m_vecCameraViewAngles = m_vecCameraViewAngles; + m_IntroData.m_Passes.SetCount( 0 ); + + // Find/Create our first pass + IntroDataBlendPass_t *pass1; + if ( m_IntroData.m_Passes.Count() == 0 ) + { + pass1 = &m_IntroData.m_Passes[m_IntroData.m_Passes.AddToTail()]; + } + else + { + pass1 = &m_IntroData.m_Passes[0]; + } + Assert(pass1); + pass1->m_BlendMode = m_iBlendMode; + pass1->m_Alpha = 1.0f; + + if ( m_vecCameraView == vec3_origin ) + { + m_IntroData.m_bDrawPrimary = false; + } + else + { + m_IntroData.m_bDrawPrimary = true; + } + + // If we're currently blending to a new mode, set the second pass + if ( m_flNextBlendTime > gpGlobals->curtime ) + { + IntroDataBlendPass_t *pass2; + if ( m_IntroData.m_Passes.Count() < 2 ) + { + pass2 = &m_IntroData.m_Passes[m_IntroData.m_Passes.AddToTail()]; + + //Msg("STARTED BLEND: Mode %d to %d.\n", m_IntroData.m_Passes[0].m_BlendMode, m_iNextBlendMode ); + } + else + { + pass2 = &m_IntroData.m_Passes[1]; + + Assert( pass2->m_BlendMode == m_iNextBlendMode ); + } + Assert(pass2); + pass2->m_BlendMode = m_iNextBlendMode; + pass2->m_Alpha = 0.0f; + } + else if ( m_IntroData.m_Passes.Count() == 2 ) + { + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + if ( !player ) + return; + + //Msg("FINISHED BLEND.\n"); + m_IntroData.m_Passes.Remove(1); + } + + // Set the introdata our data chunk + if ( m_bActive ) + { + g_pIntroData = &m_IntroData; + } + else if ( g_pIntroData == &m_IntroData ) + { + g_pIntroData = NULL; + } + + // Update the fade color + m_IntroData.m_flCurrentFadeColor[0] = m_flFadeColor[0]; + m_IntroData.m_flCurrentFadeColor[1] = m_flFadeColor[1]; + m_IntroData.m_flCurrentFadeColor[2] = m_flFadeColor[2]; + + // Started fading? + if ( m_flFadeAlpha != m_flPrevServerFadeAlpha ) + { + m_flFadeTimeStartedAt = gpGlobals->curtime; + m_flFadeAlphaStartedAt = m_IntroData.m_flCurrentFadeColor[3]; + m_flPrevServerFadeAlpha = m_flFadeAlpha; + + if ( !m_flFadeDuration ) + { + m_flFadeDuration = 0.01; + } + + //Msg("STARTING NEW FADE: alpha %.2f, duration %.2f.\n", m_flFadeAlpha, m_flFadeDuration ); + } + + if ( m_iPrevFOV != m_iFOV ) + { + m_IntroData.m_playerViewFOV = m_iFOV; + m_iPrevFOV = m_iFOV; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ScriptIntro::ClientThink( void ) +{ + Assert( m_IntroData.m_Passes.Count() <= 2 ); + + if ( m_hCameraEntity ) + { + m_IntroData.m_vecCameraView = m_hCameraEntity->GetAbsOrigin(); + m_IntroData.m_vecCameraViewAngles = m_hCameraEntity->GetAbsAngles(); + } + + CalculateFOV(); + CalculateAlpha(); + + // Calculate the blend levels of each pass + float flPerc = 1.0; + if ( (m_flNextBlendTime - m_flBlendStartTime) != 0 ) + { + flPerc = clamp( (gpGlobals->curtime - m_flBlendStartTime) / (m_flNextBlendTime - m_flBlendStartTime), 0, 1 ); + } + + // Detect when we're finished blending + if ( flPerc >= 1.0 ) + { + if ( m_IntroData.m_Passes.Count() == 2 ) + { + // We're done blending + m_IntroData.m_Passes[0].m_BlendMode = m_IntroData.m_Passes[1].m_BlendMode; + m_IntroData.m_Passes[0].m_Alpha = 1.0; + m_IntroData.m_Passes.Remove(1); + + //Msg("FINISHED BLEND.\n"); + } + else + { + m_IntroData.m_Passes[0].m_Alpha = 1.0f; + } + return; + } + + /* + if ( m_flNextBlendTime >= gpGlobals->curtime ) + { + Msg("INTRO BLENDING: Blending from mode %d to %d.\n", m_IntroData.m_Passes[0].m_BlendMode, m_IntroData.m_Passes[1].m_BlendMode ); + Msg(" curtime %.2f StartedAt %.2f FinishAt: %.2f\n", gpGlobals->curtime, m_flBlendStartTime, m_flNextBlendTime ); + Msg(" Perc: %.2f\n", flPerc ); + } + */ + + if ( m_IntroData.m_Passes.Count() == 2 ) + { + m_IntroData.m_Passes[0].m_Alpha = 1.0 - flPerc; + m_IntroData.m_Passes[1].m_Alpha = flPerc; + } + else + { + m_IntroData.m_Passes[0].m_Alpha = 1.0 - flPerc; + } +} + +extern float ScriptInfo_CalculateFOV( float flFOVBlendStartTime, float flNextFOVBlendTime, int nFOV, int nNextFOV, bool bSplineRamp ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ScriptIntro::CalculateFOV( void ) +{ + // We're past our blending time so we're at our target + if ( m_flNextFOVBlendTime >= gpGlobals->curtime ) + { + // Calculate where we're at + m_IntroData.m_playerViewFOV = ScriptInfo_CalculateFOV( m_flFOVBlendStartTime, m_flNextFOVBlendTime, m_iStartFOV, m_iNextFOV, m_bAlternateFOV ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_ScriptIntro::CalculateAlpha( void ) +{ + // Fill out the fade alpha + float flNewAlpha = RemapValClamped( gpGlobals->curtime, m_flFadeTimeStartedAt, m_flFadeTimeStartedAt + m_flFadeDuration, m_flFadeAlphaStartedAt, m_flFadeAlpha ); + /* + if ( m_IntroData.m_flCurrentFadeColor[3] != flNewAlpha ) + { + Msg("INTRO FADING: curtime %.2f StartedAt %.2f Duration: %.2f\n", gpGlobals->curtime, m_flFadeTimeStartedAt, m_flFadeDuration ); + Msg(" TimePassed %.2f Alpha: %.2f\n", RemapValClamped( gpGlobals->curtime, m_flFadeTimeStartedAt, m_flFadeTimeStartedAt + m_flFadeDuration, 0.0, 1.0 ), m_IntroData.m_flCurrentFadeColor[3] ); + } + */ + + m_IntroData.m_flCurrentFadeColor[3] = flNewAlpha; +} + diff --git a/game/client/hl2/c_strider.cpp b/game/client/hl2/c_strider.cpp new file mode 100644 index 0000000..3ea3f73 --- /dev/null +++ b/game/client/hl2/c_strider.cpp @@ -0,0 +1,1048 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_ai_basenpc.h" +#include "c_te_particlesystem.h" +#include "fx.h" +#include "fx_sparks.h" +#include "c_tracer.h" +#include "clientsideeffects.h" +#include "iefx.h" +#include "dlight.h" +#include "bone_setup.h" +#include "c_rope.h" +#include "fx_line.h" +#include "c_sprite.h" +#include "view.h" +#include "view_scene.h" +#include "materialsystem/imaterialvar.h" +#include "simple_keys.h" +#include "fx_envelope.h" +#include "iclientvehicle.h" +#include "engine/ivdebugoverlay.h" +#include "particles_localspace.h" +#include "dlight.h" +#include "iefx.h" +#include "c_te_effect_dispatch.h" +#include "tier0/vprof.h" +#include "clienteffectprecachesystem.h" +#include <bitbuf.h> +#include "fx_water.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define STRIDER_MSG_BIG_SHOT 1 +#define STRIDER_MSG_STREAKS 2 +#define STRIDER_MSG_DEAD 3 + +#define STOMP_IK_SLOT 11 +const int NUM_STRIDER_IK_TARGETS = 6; + +const float STRIDERFX_BIG_SHOT_TIME = 1.25f; +const float STRIDERFX_END_ALL_TIME = 4.0f; + +class C_StriderFX : public C_EnvelopeFX +{ +public: + typedef C_EnvelopeFX BaseClass; + + C_StriderFX(); + ~C_StriderFX() + { + EffectShutdown(); + } + + + void Update( C_BaseEntity *pOwner, const Vector &targetPos ); + + // Returns the bounds relative to the origin (render bounds) + virtual void GetRenderBounds( Vector& mins, Vector& maxs ) + { + ClearBounds( mins, maxs ); + AddPointToBounds( m_worldPosition, mins, maxs ); + AddPointToBounds( m_targetPosition, mins, maxs ); + mins -= GetRenderOrigin(); + maxs -= GetRenderOrigin(); + } + + virtual void EffectInit( int entityIndex, int attachment ) + { + m_limitHitTime = 0; + BaseClass::EffectInit( entityIndex, attachment ); + } + virtual void EffectShutdown( void ) + { + m_limitHitTime = 0; + BaseClass::EffectShutdown(); + } + + virtual int DrawModel( int flags ); + virtual void LimitTime( float tmax ) + { + float dt = tmax - m_t; + if ( dt < 0 ) + { + dt = 0; + } + m_limitHitTime = gpGlobals->curtime + dt; + BaseClass::LimitTime( tmax ); + } + + C_BaseEntity *m_pOwner; + Vector m_targetPosition; + Vector m_beamEndPosition; + pixelvis_handle_t m_queryHandleGun; + pixelvis_handle_t m_queryHandleBeamEnd; + float m_limitHitTime; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_Strider : public C_AI_BaseNPC +{ + DECLARE_CLASS( C_Strider, C_AI_BaseNPC ); +public: + DECLARE_CLIENTCLASS(); + DECLARE_INTERPOLATION(); + + + C_Strider(); + virtual ~C_Strider(); + + // model specific + virtual void ReceiveMessage( int classID, bf_read &msg ); + virtual void CalculateIKLocks( float currentTime ) + { + // NOTE: All strider IK is solved on the server, enable this to do it client-side + //BaseClass::CalculateIKLocks( currentTime ); + if ( m_pIk && m_pIk->m_target.Count() ) + { + Assert(m_pIk->m_target.Count() > STOMP_IK_SLOT); + // HACKHACK: Hardcoded 11??? Not a cleaner way to do this + CIKTarget &target = m_pIk->m_target[STOMP_IK_SLOT]; + target.SetPos( m_vecHitPos ); + // target.latched.pos = m_vecHitPos; + + for ( int i = 0; i < NUM_STRIDER_IK_TARGETS; i++ ) + { + CIKTarget &target = m_pIk->m_target[i]; + target.SetPos( m_vecIKTarget[i] ); +#if 0 + debugoverlay->AddBoxOverlay( m_vecIKTarget[i], Vector( -2, -2, -2 ), Vector( 2, 2, 2), QAngle( 0, 0, 0 ), (int)255*m_pIk->m_target[i].est.latched, 0, 0, 0, 0 ); +#endif + } + } + } + + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void GetRenderBounds( Vector& theMins, Vector& theMaxs ); + virtual void ClientThink(); + +private: + C_Strider( const C_Strider & ); + C_StriderFX m_cannonFX; + Vector m_vecHitPos; + Vector m_vecIKTarget[NUM_STRIDER_IK_TARGETS]; + CInterpolatedVar< Vector > m_iv_vecHitPos; + CInterpolatedVarArray< Vector, NUM_STRIDER_IK_TARGETS > m_iv_vecIKTarget; + Vector m_vecRenderMins; + Vector m_vecRenderMaxs; + + float m_flNextRopeCutTime; +}; + +IMPLEMENT_CLIENTCLASS_DT(C_Strider, DT_NPC_Strider, CNPC_Strider) + RecvPropVector(RECVINFO(m_vecHitPos)), + RecvPropVector(RECVINFO(m_vecIKTarget[0])), + RecvPropVector(RECVINFO(m_vecIKTarget[1])), + RecvPropVector(RECVINFO(m_vecIKTarget[2])), + RecvPropVector(RECVINFO(m_vecIKTarget[3])), + RecvPropVector(RECVINFO(m_vecIKTarget[4])), + RecvPropVector(RECVINFO(m_vecIKTarget[5])), +END_RECV_TABLE() + +C_StriderFX::C_StriderFX() +{ + m_pOwner = NULL; + m_active = false; +} + +void C_StriderFX::Update( C_BaseEntity *pOwner, const Vector &targetPos ) +{ + BaseClass::Update(); + + m_pOwner = pOwner; + + if ( m_active ) + { + m_targetPosition = targetPos; + } +} + +// --on gun +// warpy sprite bit +// darkening sprite +// glowy blue flare sprite +// bubble warpy sprite +// after glow sprite + +// --on line of sight +// narrow beam +// wide beam + +// --on impact point +// sparkly white bits +// sparkly white streaks +// pale blue particle steam + +enum +{ + STRIDERFX_WARP_SCALE = 0, + STRIDERFX_DARKNESS, + STRIDERFX_FLARE_COLOR, + STRIDERFX_FLARE_SIZE, + STRIDERFX_BUBBLE_SIZE, + STRIDERFX_BUBBLE_REFRACT, + + STRIDERFX_NARROW_BEAM_COLOR, + STRIDERFX_NARROW_BEAM_SIZE, + + STRIDERFX_WIDE_BEAM_COLOR, + STRIDERFX_WIDE_BEAM_SIZE, + + STRIDERFX_AFTERGLOW_COLOR, + + STRIDERFX_WIDE_BEAM_LENGTH, + + STRIDERFX_SPARK_COUNT, + STRIDERFX_STREAK_COUNT, + STRIDERFX_STEAM_COUNT, + + + // must be last + STRIDERFX_PARAMETERS, +}; + +class CStriderFXEnvelope +{ +public: + CStriderFXEnvelope(); + + void AddKey( int parameterIndex, const CSimpleKeyInterp &key ) + { + Assert( parameterIndex >= 0 && parameterIndex < STRIDERFX_PARAMETERS ); + + if ( parameterIndex >= 0 && parameterIndex < STRIDERFX_PARAMETERS ) + { + m_parameters[parameterIndex].Insert( key ); + } + + } + + CSimpleKeyList m_parameters[STRIDERFX_PARAMETERS]; +}; + +// NOTE: Beam widths are half-widths or radii, so this is a beam that represents a cylinder with 2" radius +const float NARROW_BEAM_WIDTH = 2; +const float WIDE_BEAM_WIDTH = 16; +const float FLARE_SIZE = 128; +const float DARK_SIZE = 64; +const float AFTERGLOW_SIZE = 64; + +const float WARP_SIZE = 512; +const float WARP_REFRACT = 0.075f; +const float WARP_BUBBLE_SIZE = 256; +const float WARP_BUBBLE_REFRACT = 1.0f; + +CStriderFXEnvelope::CStriderFXEnvelope() +{ + AddKey( STRIDERFX_WARP_SCALE, CSimpleKeyInterp( 0, KEY_LINEAR, 0 ) ); + AddKey( STRIDERFX_WARP_SCALE, CSimpleKeyInterp( 1.25, KEY_ACCELERATE, 1 ) ); + AddKey( STRIDERFX_WARP_SCALE, CSimpleKeyInterp( 1.25, KEY_LINEAR, 1 ) ); + AddKey( STRIDERFX_WARP_SCALE, CSimpleKeyInterp( 1.3, KEY_LINEAR, 0 ) ); + + AddKey( STRIDERFX_DARKNESS, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0 ) ); + AddKey( STRIDERFX_DARKNESS, CSimpleKeyInterp( 0.5, KEY_SPLINE, 1 ) ); + AddKey( STRIDERFX_DARKNESS, CSimpleKeyInterp( 1.0, KEY_LINEAR, 1 ) ); + AddKey( STRIDERFX_DARKNESS, CSimpleKeyInterp( 1.25, KEY_SPLINE, 0 ) ); + AddKey( STRIDERFX_DARKNESS, CSimpleKeyInterp( 2.0, KEY_SPLINE, 0 ) ); + + AddKey( STRIDERFX_FLARE_COLOR, CSimpleKeyInterp( 0, KEY_LINEAR, 0 ) ); + AddKey( STRIDERFX_FLARE_COLOR, CSimpleKeyInterp( 0.5, KEY_LINEAR, 0 ) ); + AddKey( STRIDERFX_FLARE_COLOR, CSimpleKeyInterp( 1.25, KEY_ACCELERATE, 1 ) ); + AddKey( STRIDERFX_FLARE_COLOR, CSimpleKeyInterp( 1.5, KEY_LINEAR, 1 ) ); + AddKey( STRIDERFX_FLARE_COLOR, CSimpleKeyInterp( 2.0, KEY_SPLINE, 0 ) ); + + AddKey( STRIDERFX_FLARE_SIZE, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0 ) ); + AddKey( STRIDERFX_FLARE_SIZE, CSimpleKeyInterp( 1.0, KEY_LINEAR, 1 ) ); + AddKey( STRIDERFX_FLARE_SIZE, CSimpleKeyInterp( 2.0, KEY_LINEAR, 1 ) ); + + AddKey( STRIDERFX_BUBBLE_SIZE, CSimpleKeyInterp( 1.3, KEY_LINEAR, 0.5 ) ); + AddKey( STRIDERFX_BUBBLE_SIZE, CSimpleKeyInterp( 2.0, KEY_DECELERATE, 2 ) ); + + AddKey( STRIDERFX_BUBBLE_REFRACT, CSimpleKeyInterp( 1.3, KEY_LINEAR, 1 ) ); + AddKey( STRIDERFX_BUBBLE_REFRACT, CSimpleKeyInterp( 2.0, KEY_LINEAR, 0 ) ); + + AddKey( STRIDERFX_NARROW_BEAM_COLOR, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0 ) ); + AddKey( STRIDERFX_NARROW_BEAM_COLOR, CSimpleKeyInterp( 1.25, KEY_ACCELERATE, 1.0 ) ); + AddKey( STRIDERFX_NARROW_BEAM_COLOR, CSimpleKeyInterp( 1.5, KEY_SPLINE, 0 ) ); + + AddKey( STRIDERFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0 ) ); + AddKey( STRIDERFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 0.5, KEY_ACCELERATE, 1 ) ); + AddKey( STRIDERFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 1.25, KEY_LINEAR, 1 ) ); + AddKey( STRIDERFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 1.5, KEY_DECELERATE, 2 ) ); + + AddKey( STRIDERFX_WIDE_BEAM_COLOR, CSimpleKeyInterp( 1.25, KEY_LINEAR, 0 ) ); + AddKey( STRIDERFX_WIDE_BEAM_COLOR, CSimpleKeyInterp( 1.5, KEY_SPLINE, 1 ) ); + AddKey( STRIDERFX_WIDE_BEAM_COLOR, CSimpleKeyInterp( 1.75, KEY_LINEAR, 1 ) ); + AddKey( STRIDERFX_WIDE_BEAM_COLOR, CSimpleKeyInterp( 2.1, KEY_SPLINE, 0 ) ); + + AddKey( STRIDERFX_WIDE_BEAM_SIZE, CSimpleKeyInterp( 1.25, KEY_LINEAR, 1 ) ); + AddKey( STRIDERFX_WIDE_BEAM_SIZE, CSimpleKeyInterp( 2.1, KEY_LINEAR, 1 ) ); + + AddKey( STRIDERFX_AFTERGLOW_COLOR, CSimpleKeyInterp( 1.0, KEY_LINEAR, 0 ) ); + AddKey( STRIDERFX_AFTERGLOW_COLOR, CSimpleKeyInterp( 1.25, KEY_SPLINE, 1 ) ); + AddKey( STRIDERFX_AFTERGLOW_COLOR, CSimpleKeyInterp( 3.0, KEY_LINEAR, 1 ) ); + AddKey( STRIDERFX_AFTERGLOW_COLOR, CSimpleKeyInterp( 3.5, KEY_ACCELERATE, 0 ) ); + + AddKey( STRIDERFX_WIDE_BEAM_LENGTH, CSimpleKeyInterp( 1.25, KEY_LINEAR, 1.0 ) ); + AddKey( STRIDERFX_WIDE_BEAM_LENGTH, CSimpleKeyInterp( 1.5, KEY_ACCELERATE, 0.0 ) ); + AddKey( STRIDERFX_WIDE_BEAM_LENGTH, CSimpleKeyInterp( 2.1, KEY_LINEAR, 0 ) ); + + //AddKey( STRIDERFX_SPARK_COUNT, + //AddKey( STRIDERFX_STREAK_COUNT, + //AddKey( STRIDERFX_STEAM_COUNT, +} + +CStriderFXEnvelope g_StriderCannonEnvelope; + +void ScaleColor( color32 &out, const color32 &in, float scale ) +{ + out.r = (byte)(int)((float)in.r * scale); + out.g = (byte)(int)((float)in.g * scale); + out.b = (byte)(int)((float)in.b * scale); + out.a = (byte)(int)((float)in.a * scale); +} + +void DrawSpriteTangentSpace( const Vector &vecOrigin, float flWidth, float flHeight, color32 color ) +{ + unsigned char pColor[4] = { color.r, color.g, color.b, color.a }; + + // Generate half-widths + flWidth *= 0.5f; + flHeight *= 0.5f; + + // Compute direction vectors for the sprite + Vector fwd, right( 1, 0, 0 ), up( 0, 1, 0 ); + VectorSubtract( CurrentViewOrigin(), vecOrigin, fwd ); + float flDist = VectorNormalize( fwd ); + if (flDist >= 1e-3) + { + CrossProduct( CurrentViewUp(), fwd, right ); + flDist = VectorNormalize( right ); + if (flDist >= 1e-3) + { + CrossProduct( fwd, right, up ); + } + else + { + // In this case, fwd == g_vecVUp, it's right above or + // below us in screen space + CrossProduct( fwd, CurrentViewRight(), up ); + VectorNormalize( up ); + CrossProduct( up, fwd, right ); + } + } + + Vector left = -right; + Vector down = -up; + Vector back = -fwd; + + CMeshBuilder meshBuilder; + Vector point; + CMatRenderContextPtr pRenderContext( materials ); + IMesh* pMesh = pRenderContext->GetDynamicMesh( ); + + meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); + + meshBuilder.Color4ubv (pColor); + meshBuilder.TexCoord2f (0, 0, 1); + VectorMA (vecOrigin, -flHeight, up, point); + VectorMA (point, -flWidth, right, point); + meshBuilder.TangentS3fv( left.Base() ); + meshBuilder.TangentT3fv( down.Base() ); + meshBuilder.Normal3fv( back.Base() ); + meshBuilder.Position3fv (point.Base()); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ubv (pColor); + meshBuilder.TexCoord2f (0, 0, 0); + VectorMA (vecOrigin, flHeight, up, point); + VectorMA (point, -flWidth, right, point); + meshBuilder.TangentS3fv( left.Base() ); + meshBuilder.TangentT3fv( down.Base() ); + meshBuilder.Normal3fv( back.Base() ); + meshBuilder.Position3fv (point.Base()); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ubv (pColor); + meshBuilder.TexCoord2f (0, 1, 0); + VectorMA (vecOrigin, flHeight, up, point); + VectorMA (point, flWidth, right, point); + meshBuilder.TangentS3fv( left.Base() ); + meshBuilder.TangentT3fv( down.Base() ); + meshBuilder.Normal3fv( back.Base() ); + meshBuilder.Position3fv (point.Base()); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ubv (pColor); + meshBuilder.TexCoord2f (0, 1, 1); + VectorMA (vecOrigin, -flHeight, up, point); + VectorMA (point, flWidth, right, point); + meshBuilder.TangentS3fv( left.Base() ); + meshBuilder.TangentT3fv( down.Base() ); + meshBuilder.Normal3fv( back.Base() ); + meshBuilder.Position3fv (point.Base()); + meshBuilder.AdvanceVertex(); + + meshBuilder.End(); + pMesh->Draw(); +} + + +void Strider_DrawSprite( const Vector &vecOrigin, float size, const color32 &color ) +{ + DrawSpriteTangentSpace( vecOrigin, size, size, color ); +} + + +void Strider_DrawLine( const Vector &start, const Vector &end, float width, IMaterial *pMaterial, const color32 &color ) +{ + FX_DrawLineFade( start, end, width, pMaterial, color, 8.0f ); +} + +int C_StriderFX::DrawModel( int ) +{ + static color32 white = {255,255,255,255}; + Vector params[STRIDERFX_PARAMETERS]; + bool hasParam[STRIDERFX_PARAMETERS]; + + if ( !m_active ) + return 1; + + C_BaseEntity *ent = cl_entitylist->GetEnt( m_entityIndex ); + if ( ent ) + { + QAngle angles; + ent->GetAttachment( m_attachment, m_worldPosition, angles ); + } + + // This forces time to drive from the main clock instead of being integrated per-draw below + // that way the effect moves on even when culled for visibility + if ( m_limitHitTime > 0 && m_tMax > 0 ) + { + float dt = m_limitHitTime - gpGlobals->curtime; + if ( dt < 0 ) + { + dt = 0; + } + // if the clock needs to move, update it. + if ( m_tMax - dt > m_t ) + { + m_t = m_tMax - dt; + m_beamEndPosition = m_worldPosition; + } + } + else + { + // don't have enough info to derive the time, integrate current frame time + m_t += gpGlobals->frametime; + if ( m_tMax > 0 ) + { + m_t = clamp( m_t, 0, m_tMax ); + m_beamEndPosition = m_worldPosition; + } + } + float t = m_t; + + bool hasAny = false; + memset( hasParam, 0, sizeof(hasParam) ); + for ( int i = 0; i < STRIDERFX_PARAMETERS; i++ ) + { + hasParam[i] = g_StriderCannonEnvelope.m_parameters[i].Interp( params[i], t ); + hasAny = hasAny || hasParam[i]; + } + + pixelvis_queryparams_t gunParams; + gunParams.Init(m_worldPosition, 4.0f); + float gunFractionVisible = PixelVisibility_FractionVisible( gunParams, &m_queryHandleGun ); + bool gunVisible = gunFractionVisible > 0.0f ? true : false; + + // draw the narrow beam + if ( hasParam[STRIDERFX_NARROW_BEAM_COLOR] && hasParam[STRIDERFX_NARROW_BEAM_SIZE] ) + { + IMaterial *pMat = materials->FindMaterial( "sprites/bluelaser1", TEXTURE_GROUP_CLIENT_EFFECTS ); + float width = NARROW_BEAM_WIDTH * params[STRIDERFX_NARROW_BEAM_SIZE].x; + color32 color; + float bright = params[STRIDERFX_NARROW_BEAM_COLOR].x; + ScaleColor( color, white, bright ); + + Strider_DrawLine( m_beamEndPosition, m_targetPosition, width, pMat, color ); + } + + // draw the wide beam + if ( hasParam[STRIDERFX_WIDE_BEAM_COLOR] && hasParam[STRIDERFX_WIDE_BEAM_SIZE] ) + { + IMaterial *pMat = materials->FindMaterial( "effects/blueblacklargebeam", TEXTURE_GROUP_CLIENT_EFFECTS ); + float width = WIDE_BEAM_WIDTH * params[STRIDERFX_WIDE_BEAM_SIZE].x; + color32 color; + float bright = params[STRIDERFX_WIDE_BEAM_COLOR].x; + ScaleColor( color, white, bright ); + Vector wideBeamEnd = m_beamEndPosition; + if ( hasParam[STRIDERFX_WIDE_BEAM_LENGTH] ) + { + float amt = params[STRIDERFX_WIDE_BEAM_LENGTH].x; + wideBeamEnd = m_beamEndPosition * amt + m_targetPosition * (1-amt); + } + + Strider_DrawLine( wideBeamEnd, m_targetPosition, width, pMat, color ); + } + +// after glow sprite + bool updated = false; + CMatRenderContextPtr pRenderContext( materials ); +// warpy sprite bit + if ( hasParam[STRIDERFX_WARP_SCALE] && !hasParam[STRIDERFX_BUBBLE_SIZE] && gunVisible ) + { + if ( !updated ) + { + updated = true; + pRenderContext->Flush(); + UpdateRefractTexture(); + } + + IMaterial *pMat = materials->FindMaterial( "effects/strider_pinch_dudv", TEXTURE_GROUP_CLIENT_EFFECTS ); + float size = WARP_SIZE; + float refract = params[STRIDERFX_WARP_SCALE].x * WARP_REFRACT * gunFractionVisible; + + pRenderContext->Bind( pMat, (IClientRenderable*)this ); + IMaterialVar *pVar = pMat->FindVar( "$refractamount", NULL ); + pVar->SetFloatValue( refract ); + Strider_DrawSprite( m_worldPosition, size, white ); + } +// darkening sprite +// glowy blue flare sprite + if ( hasParam[STRIDERFX_FLARE_COLOR] && hasParam[STRIDERFX_FLARE_SIZE] && hasParam[STRIDERFX_DARKNESS] && gunVisible ) + { + IMaterial *pMat = materials->FindMaterial( "effects/blueblackflash", TEXTURE_GROUP_CLIENT_EFFECTS ); + float size = FLARE_SIZE * params[STRIDERFX_FLARE_SIZE].x; + color32 color; + float bright = params[STRIDERFX_FLARE_COLOR].x * gunFractionVisible; + ScaleColor( color, white, bright ); + color.a = (int)(255 * params[STRIDERFX_DARKNESS].x); + pRenderContext->Bind( pMat, (IClientRenderable*)this ); + Strider_DrawSprite( m_worldPosition, size, color ); + } +// bubble warpy sprite + if ( hasParam[STRIDERFX_BUBBLE_SIZE] ) + { + Vector wideBeamEnd = m_beamEndPosition; + if ( hasParam[STRIDERFX_WIDE_BEAM_LENGTH] ) + { + float amt = params[STRIDERFX_WIDE_BEAM_LENGTH].x; + wideBeamEnd = m_beamEndPosition * amt + m_targetPosition * (1-amt); + } + pixelvis_queryparams_t endParams; + endParams.Init(wideBeamEnd, 4.0f, 0.001f); + float endFractionVisible = PixelVisibility_FractionVisible( endParams, &m_queryHandleBeamEnd ); + bool endVisible = endFractionVisible > 0.0f ? true : false; + + if ( endVisible ) + { + if ( !updated ) + { + updated = true; + pRenderContext->Flush(); + UpdateRefractTexture(); + } + IMaterial *pMat = materials->FindMaterial( "effects/strider_bulge_dudv", TEXTURE_GROUP_CLIENT_EFFECTS ); + float refract = endFractionVisible * WARP_BUBBLE_REFRACT * params[STRIDERFX_BUBBLE_REFRACT].x; + float size = WARP_BUBBLE_SIZE * params[STRIDERFX_BUBBLE_SIZE].x; + IMaterialVar *pVar = pMat->FindVar( "$refractamount", NULL ); + pVar->SetFloatValue( refract ); + + pRenderContext->Bind( pMat, (IClientRenderable*)this ); + Strider_DrawSprite( wideBeamEnd, size, white ); + } + } + else + { + // call this to have the check ready on the first frame + pixelvis_queryparams_t endParams; + endParams.Init(m_beamEndPosition, 4.0f, 0.001f); + PixelVisibility_FractionVisible( endParams, &m_queryHandleBeamEnd ); + } + if ( hasParam[STRIDERFX_AFTERGLOW_COLOR] && gunVisible ) + { + IMaterial *pMat = materials->FindMaterial( "effects/blueblackflash", TEXTURE_GROUP_CLIENT_EFFECTS ); + float size = AFTERGLOW_SIZE;// * params[STRIDERFX_FLARE_SIZE].x; + color32 color; + float bright = params[STRIDERFX_AFTERGLOW_COLOR].x * gunFractionVisible; + ScaleColor( color, white, bright ); + + pRenderContext->Bind( pMat, (IClientRenderable*)this ); + Strider_DrawSprite( m_worldPosition, size, color ); + + dlight_t *dl = effects->CL_AllocDlight( m_entityIndex ); + dl->origin = m_worldPosition; + dl->color.r = 40; + dl->color.g = 60; + dl->color.b = 255; + dl->color.exponent = 5; + dl->radius = bright * 128; + dl->die = gpGlobals->curtime + 0.001; + } + + if ( m_t >= STRIDERFX_END_ALL_TIME && !hasAny ) + { + EffectShutdown(); + } + return 1; +} + + + + +//----------------------------------------------------------------------------- +// Purpose: Strider class implementation +//----------------------------------------------------------------------------- +C_Strider::C_Strider() : + m_iv_vecHitPos("C_Strider::m_iv_vecHitPos"), + m_iv_vecIKTarget("C_Strider::m_iv_vecIKTarget") +{ + AddVar( &m_vecHitPos, &m_iv_vecHitPos, LATCH_ANIMATION_VAR ); + + memset(m_vecIKTarget, 0, sizeof(m_vecIKTarget)); + AddVar( &m_vecIKTarget, &m_iv_vecIKTarget, LATCH_ANIMATION_VAR ); + + m_flNextRopeCutTime = 0; +} + +C_Strider::~C_Strider() +{ +} + +void C_Strider::ReceiveMessage( int classID, bf_read &msg ) +{ + if ( classID != GetClientClass()->m_ClassID ) + { + // message is for subclass + BaseClass::ReceiveMessage( classID, msg ); + return; + } + + int messageType = msg.ReadByte(); + switch( messageType ) + { + case STRIDER_MSG_STREAKS: + { + Vector pos; + msg.ReadBitVec3Coord( pos ); + m_cannonFX.SetRenderOrigin( pos ); + m_cannonFX.EffectInit( entindex(), LookupAttachment( "BigGun" ) ); + m_cannonFX.LimitTime( STRIDERFX_BIG_SHOT_TIME ); + } + break; + + case STRIDER_MSG_BIG_SHOT: + { + Vector tmp; + msg.ReadBitVec3Coord( tmp ); + m_cannonFX.SetTime( STRIDERFX_BIG_SHOT_TIME ); + m_cannonFX.LimitTime( STRIDERFX_END_ALL_TIME ); + } + break; + + case STRIDER_MSG_DEAD: + { + m_cannonFX.EffectShutdown(); + } + break; + } +} + + +void C_Strider::OnDataChanged( DataUpdateType_t updateType ) +{ + if ( updateType == DATA_UPDATE_CREATED ) + { + // We need to have our render bounds defined or shadow creation won't work correctly + ClientThink(); + ClientThinkList()->SetNextClientThink( GetClientHandle(), CLIENT_THINK_ALWAYS ); + } + + BaseClass::OnDataChanged( updateType ); + + m_cannonFX.Update( this, m_vecHitPos ); +} + +//----------------------------------------------------------------------------- +// Purpose: Recompute my rendering box +//----------------------------------------------------------------------------- +void C_Strider::ClientThink() +{ + // The reason why this is here, as opposed to in SetObjectCollisionBox, + // is because of IK. The code below recomputes bones so as to get at the hitboxes, + // which causes IK to trigger, which causes raycasts against the other entities to occur, + // which is illegal to do while in the Relink phase. + + ComputeEntitySpaceHitboxSurroundingBox( &m_vecRenderMins, &m_vecRenderMaxs ); + // UNDONE: Disabled this until we can get closer to a final map and tune +#if 0 + // Cut ropes. + if ( gpGlobals->curtime >= m_flNextRopeCutTime ) + { + // Blow the bbox out a little. + Vector vExtendedMins = vecMins - Vector( 50, 50, 50 ); + Vector vExtendedMaxs = vecMaxs + Vector( 50, 50, 50 ); + + C_RopeKeyframe *ropes[512]; + int nRopes = C_RopeKeyframe::GetRopesIntersectingAABB( ropes, ARRAYSIZE( ropes ), GetAbsOrigin() + vExtendedMins, GetAbsOrigin() + vExtendedMaxs ); + for ( int i=0; i < nRopes; i++ ) + { + C_RopeKeyframe *pRope = ropes[i]; + + if ( pRope->GetEndEntity() ) + { + Vector vPos; + if ( pRope->GetEndPointPos( 1, vPos ) ) + { + // Detach the endpoint. + pRope->SetEndEntity( NULL ); + + // Make some spark effect here.. + g_pEffects->Sparks( vPos ); + } + } + } + + m_flNextRopeCutTime = gpGlobals->curtime + 0.5; + } +#endif + + // True argument because the origin may have stayed the same, but the size is expected to always change + g_pClientShadowMgr->AddToDirtyShadowList( this, true ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Recompute my rendering box +//----------------------------------------------------------------------------- +void C_Strider::GetRenderBounds( Vector& theMins, Vector& theMaxs ) +{ + theMins = m_vecRenderMins; + theMaxs = m_vecRenderMaxs; +} + + +//----------------------------------------------------------------------------- +// Strider muzzle flashes +//----------------------------------------------------------------------------- +void MuzzleFlash_Strider( ClientEntityHandle_t hEntity, int attachmentIndex ) +{ + VPROF_BUDGET( "MuzzleFlash_Strider", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); + + // If the client hasn't seen this entity yet, bail. + matrix3x4_t matAttachment; + if ( !FX_GetAttachmentTransform( hEntity, attachmentIndex, matAttachment ) ) + return; + + CSmartPtr<CLocalSpaceEmitter> pSimple = CLocalSpaceEmitter::Create( "MuzzleFlash_Strider", hEntity, attachmentIndex ); + + SimpleParticle *pParticle; + Vector forward(1,0,0), offset; //NOTENOTE: All coords are in local space + + float flScale = random->RandomFloat( 3.0f, 4.0f ); + + float burstSpeed = random->RandomFloat( 400.0f, 600.0f ); + +#define FRONT_LENGTH 12 + + // Front flash + for ( int i = 1; i < FRONT_LENGTH; i++ ) + { + offset = (forward * (i*2.0f*flScale)); + + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( VarArgs( "effects/combinemuzzle%d", random->RandomInt(1,2) ) ), offset ); + + if ( pParticle == NULL ) + return; + + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = 0.1f; + + pParticle->m_vecVelocity = forward * burstSpeed; + + pParticle->m_uchColor[0] = 255; + pParticle->m_uchColor[1] = 255; + pParticle->m_uchColor[2] = 255; + + pParticle->m_uchStartAlpha = 255.0f; + pParticle->m_uchEndAlpha = 0; + + pParticle->m_uchStartSize = ( (random->RandomFloat( 6.0f, 8.0f ) * (FRONT_LENGTH-(i))/(FRONT_LENGTH*0.75f)) * flScale ); + pParticle->m_uchEndSize = pParticle->m_uchStartSize; + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = 0.0f; + } + + Vector right(0,1,0), up(0,0,1); + Vector dir = right - up; + +#define SIDE_LENGTH 8 + + burstSpeed = random->RandomFloat( 400.0f, 600.0f ); + + // Diagonal flash + for ( int i = 1; i < SIDE_LENGTH; i++ ) + { + offset = (dir * (i*flScale)); + + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( VarArgs( "effects/combinemuzzle%d", random->RandomInt(1,2) ) ), offset ); + + if ( pParticle == NULL ) + return; + + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = 0.2f; + + pParticle->m_vecVelocity = dir * burstSpeed * 0.25f; + + pParticle->m_uchColor[0] = 255; + pParticle->m_uchColor[1] = 255; + pParticle->m_uchColor[2] = 255; + + pParticle->m_uchStartAlpha = 255; + pParticle->m_uchEndAlpha = 0; + + pParticle->m_uchStartSize = ( (random->RandomFloat( 2.0f, 4.0f ) * (SIDE_LENGTH-(i))/(SIDE_LENGTH*0.5f)) * flScale ); + pParticle->m_uchEndSize = pParticle->m_uchStartSize; + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = 0.0f; + } + + dir = right + up; + burstSpeed = random->RandomFloat( 400.0f, 600.0f ); + + // Diagonal flash + for ( int i = 1; i < SIDE_LENGTH; i++ ) + { + offset = (-dir * (i*flScale)); + + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( VarArgs( "effects/combinemuzzle%d", random->RandomInt(1,2) ) ), offset ); + + if ( pParticle == NULL ) + return; + + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = 0.2f; + + pParticle->m_vecVelocity = dir * -burstSpeed * 0.25f; + + pParticle->m_uchColor[0] = 255; + pParticle->m_uchColor[1] = 255; + pParticle->m_uchColor[2] = 255; + + pParticle->m_uchStartAlpha = 255; + pParticle->m_uchEndAlpha = 0; + + pParticle->m_uchStartSize = ( (random->RandomFloat( 2.0f, 4.0f ) * (SIDE_LENGTH-(i))/(SIDE_LENGTH*0.5f)) * flScale ); + pParticle->m_uchEndSize = pParticle->m_uchStartSize; + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = 0.0f; + } + + dir = up; + burstSpeed = random->RandomFloat( 400.0f, 600.0f ); + + // Top flash + for ( int i = 1; i < SIDE_LENGTH; i++ ) + { + offset = (dir * (i*flScale)); + + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( VarArgs( "effects/combinemuzzle%d", random->RandomInt(1,2) ) ), offset ); + + if ( pParticle == NULL ) + return; + + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = 0.2f; + + pParticle->m_vecVelocity = dir * burstSpeed * 0.25f; + + pParticle->m_uchColor[0] = 255; + pParticle->m_uchColor[1] = 255; + pParticle->m_uchColor[2] = 255; + + pParticle->m_uchStartAlpha = 255; + pParticle->m_uchEndAlpha = 0; + + pParticle->m_uchStartSize = ( (random->RandomFloat( 2.0f, 4.0f ) * (SIDE_LENGTH-(i))/(SIDE_LENGTH*0.5f)) * flScale ); + pParticle->m_uchEndSize = pParticle->m_uchStartSize; + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = 0.0f; + } + + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "effects/strider_muzzle" ), vec3_origin ); + + if ( pParticle == NULL ) + return; + + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = random->RandomFloat( 0.3f, 0.4f ); + + pParticle->m_vecVelocity.Init(); + + pParticle->m_uchColor[0] = 255; + pParticle->m_uchColor[1] = 255; + pParticle->m_uchColor[2] = 255; + + pParticle->m_uchStartAlpha = 255; + pParticle->m_uchEndAlpha = 0; + + pParticle->m_uchStartSize = flScale * random->RandomFloat( 12.0f, 16.0f ); + pParticle->m_uchEndSize = 0.0f; + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = 0.0f; + + Vector origin; + MatrixGetColumn( matAttachment, 3, &origin ); + + int entityIndex = ClientEntityList().HandleToEntIndex( hEntity ); + if ( entityIndex >= 0 ) + { + dlight_t *el = effects->CL_AllocElight( LIGHT_INDEX_MUZZLEFLASH + entityIndex ); + + el->origin = origin; + + el->color.r = 64; + el->color.g = 128; + el->color.b = 255; + el->color.exponent = 5; + + el->radius = random->RandomInt( 100, 150 ); + el->decay = el->radius / 0.05f; + el->die = gpGlobals->curtime + 0.1f; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &data - +//----------------------------------------------------------------------------- +void StriderMuzzleFlashCallback( const CEffectData &data ) +{ + MuzzleFlash_Strider( data.m_hEntity, data.m_nAttachmentIndex ); +} + +DECLARE_CLIENT_EFFECT( "StriderMuzzleFlash", StriderMuzzleFlashCallback ); + +#define BLOOD_MIN_SPEED 64.0f*2.0f +#define BLOOD_MAX_SPEED 256.0f*8.0f + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &origin - +// &normal - +// scale - +//----------------------------------------------------------------------------- +void StriderBlood( const Vector &origin, const Vector &normal, float scale ) +{ + VPROF_BUDGET( "StriderBlood", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); + + //Find area ambient light color and use it to tint smoke + Vector worldLight = WorldGetLightForPoint( origin, true ); + Vector tint; + float luminosity; + UTIL_GetNormalizedColorTintAndLuminosity( worldLight, &tint, &luminosity ); + + // We only take a portion of the tint + tint = (tint * 0.25f)+(Vector(0.75f,0.75f,0.75f)); + + // Rescale to a character range + luminosity = MAX( 200, luminosity*255 ); + + CSmartPtr<CSplashParticle> pSimple = CSplashParticle::Create( "splish" ); + pSimple->SetSortOrigin( origin ); + + int i; + float flScale = scale / 8.0f; + + PMaterialHandle hMaterial = ParticleMgr()->GetPMaterial( "effects/slime1" ); + + float length = 0.2f; + Vector vForward, vRight, vUp; + Vector offDir; + + TrailParticle *tParticle; + + CSmartPtr<CTrailParticles> sparkEmitter = CTrailParticles::Create( "splash" ); + + if ( !sparkEmitter ) + return; + + sparkEmitter->SetSortOrigin( origin ); + sparkEmitter->m_ParticleCollision.SetGravity( 600.0f ); + sparkEmitter->SetFlag( bitsPARTICLE_TRAIL_VELOCITY_DAMPEN ); + sparkEmitter->SetVelocityDampen( 2.0f ); + + //Dump out drops + Vector offset; + for ( i = 0; i < 64; i++ ) + { + offset = origin; + offset[0] += random->RandomFloat( -8.0f, 8.0f ) * flScale; + offset[1] += random->RandomFloat( -8.0f, 8.0f ) * flScale; + offset[2] += random->RandomFloat( -8.0f, 8.0f ) * flScale; + + tParticle = (TrailParticle *) sparkEmitter->AddParticle( sizeof(TrailParticle), hMaterial, offset ); + + if ( tParticle == NULL ) + break; + + tParticle->m_flLifetime = 0.0f; + tParticle->m_flDieTime = 1.0f; + + offDir = normal + RandomVector( -1.0f, 1.0f ); + + tParticle->m_vecVelocity = offDir * random->RandomFloat( BLOOD_MIN_SPEED * flScale * 2.0f, BLOOD_MAX_SPEED * flScale * 2.0f ); + tParticle->m_vecVelocity[2] += random->RandomFloat( 8.0f, 32.0f ) * flScale; + + tParticle->m_flWidth = random->RandomFloat( 20.0f, 26.0f ) * flScale; + tParticle->m_flLength = random->RandomFloat( length*0.5f, length ) * flScale; + + int nColor = random->RandomInt( luminosity*0.75f, luminosity ); + tParticle->m_color.r = nColor * tint.x; + tParticle->m_color.g = nColor * tint.y; + tParticle->m_color.b = nColor * tint.z; + tParticle->m_color.a = 255; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &data - +//----------------------------------------------------------------------------- +void StriderBloodCallback( const CEffectData &data ) +{ + StriderBlood( data.m_vOrigin, data.m_vNormal, data.m_flScale ); +} + +DECLARE_CLIENT_EFFECT( "StriderBlood", StriderBloodCallback ); + diff --git a/game/client/hl2/c_te_concussiveexplosion.cpp b/game/client/hl2/c_te_concussiveexplosion.cpp new file mode 100644 index 0000000..530d5d5 --- /dev/null +++ b/game/client/hl2/c_te_concussiveexplosion.cpp @@ -0,0 +1,110 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// +#include "cbase.h" +#include "c_te_particlesystem.h" +#include "fx.h" +#include "ragdollexplosionenumerator.h" +#include "tier1/KeyValues.h" +#include "toolframework_client.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: Concussive explosion entity +//----------------------------------------------------------------------------- +class C_TEConcussiveExplosion : public C_TEParticleSystem +{ +public: + DECLARE_CLASS( C_TEConcussiveExplosion, C_TEParticleSystem ); + DECLARE_CLIENTCLASS(); + + virtual void PostDataUpdate( DataUpdateType_t updateType ); + + void AffectRagdolls( void ); + + Vector m_vecNormal; + float m_flScale; + int m_nRadius; + int m_nMagnitude; +}; + + +//----------------------------------------------------------------------------- +// Networking +//----------------------------------------------------------------------------- +IMPLEMENT_CLIENTCLASS_EVENT_DT( C_TEConcussiveExplosion, DT_TEConcussiveExplosion, CTEConcussiveExplosion ) + RecvPropVector( RECVINFO(m_vecNormal)), + RecvPropFloat( RECVINFO(m_flScale)), + RecvPropInt( RECVINFO(m_nRadius)), + RecvPropInt( RECVINFO(m_nMagnitude)), +END_RECV_TABLE() + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_TEConcussiveExplosion::AffectRagdolls( void ) +{ + if ( ( m_nRadius == 0 ) || ( m_nMagnitude == 0 ) ) + return; + + CRagdollExplosionEnumerator ragdollEnum( m_vecOrigin, m_nRadius, m_nMagnitude ); + partition->EnumerateElementsInSphere( PARTITION_CLIENT_RESPONSIVE_EDICTS, m_vecOrigin, m_nRadius, false, &ragdollEnum ); +} + + +//----------------------------------------------------------------------------- +// Recording +//----------------------------------------------------------------------------- +static inline void RecordConcussiveExplosion( const Vector& start, const Vector &vecDirection ) +{ + if ( !ToolsEnabled() ) + return; + + if ( clienttools->IsInRecordingMode() ) + { + KeyValues *msg = new KeyValues( "TempEntity" ); + + msg->SetInt( "te", TE_CONCUSSIVE_EXPLOSION ); + msg->SetString( "name", "TE_ConcussiveExplosion" ); + msg->SetFloat( "time", gpGlobals->curtime ); + msg->SetFloat( "originx", start.x ); + msg->SetFloat( "originy", start.y ); + msg->SetFloat( "originz", start.z ); + msg->SetFloat( "directionx", vecDirection.x ); + msg->SetFloat( "directiony", vecDirection.y ); + msg->SetFloat( "directionz", vecDirection.z ); + + ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); + msg->deleteThis(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_TEConcussiveExplosion::PostDataUpdate( DataUpdateType_t updateType ) +{ + AffectRagdolls(); + + FX_ConcussiveExplosion( m_vecOrigin, m_vecNormal ); + RecordConcussiveExplosion( m_vecOrigin, m_vecNormal ); +} + +void TE_ConcussiveExplosion( IRecipientFilter& filter, float delay, KeyValues *pKeyValues ) +{ + Vector vecOrigin, vecDirection; + vecOrigin.x = pKeyValues->GetFloat( "originx" ); + vecOrigin.y = pKeyValues->GetFloat( "originy" ); + vecOrigin.z = pKeyValues->GetFloat( "originz" ); + vecDirection.x = pKeyValues->GetFloat( "directionx" ); + vecDirection.y = pKeyValues->GetFloat( "directiony" ); + vecDirection.z = pKeyValues->GetFloat( "directionz" ); + FX_ConcussiveExplosion( vecOrigin, vecDirection ); +}
\ No newline at end of file diff --git a/game/client/hl2/c_te_flare.cpp b/game/client/hl2/c_te_flare.cpp new file mode 100644 index 0000000..5e00ea5 --- /dev/null +++ b/game/client/hl2/c_te_flare.cpp @@ -0,0 +1,414 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Flare effects +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "clienteffectprecachesystem.h" +#include "particles_simple.h" +#include "iefx.h" +#include "dlight.h" +#include "view.h" +#include "fx.h" +#include "clientsideeffects.h" +#include "c_pixel_visibility.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//Precahce the effects +CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectFlares ) +CLIENTEFFECT_MATERIAL( "effects/redflare" ) +CLIENTEFFECT_MATERIAL( "effects/yellowflare" ) +CLIENTEFFECT_MATERIAL( "effects/yellowflare_noz" ) +CLIENTEFFECT_REGISTER_END() + +class C_Flare : public C_BaseCombatCharacter, CSimpleEmitter +{ +public: + DECLARE_CLASS( C_Flare, C_BaseCombatCharacter ); + DECLARE_CLIENTCLASS(); + + C_Flare(); + + void OnDataChanged( DataUpdateType_t updateType ); + void Update( float timeDelta ); + void NotifyDestroyParticle( Particle* pParticle ); + void NotifyShouldTransmit( ShouldTransmitState_t state ); + void RestoreResources( void ); + + float m_flTimeBurnOut; + float m_flScale; + bool m_bLight; + bool m_bSmoke; + bool m_bPropFlare; + pixelvis_handle_t m_queryHandle; + + +private: + C_Flare( const C_Flare & ); + TimedEvent m_teSmokeSpawn; + + int m_iAttachment; + + SimpleParticle *m_pParticle[2]; +}; + +IMPLEMENT_CLIENTCLASS_DT( C_Flare, DT_Flare, CFlare ) + RecvPropFloat( RECVINFO( m_flTimeBurnOut ) ), + RecvPropFloat( RECVINFO( m_flScale ) ), + RecvPropInt( RECVINFO( m_bLight ) ), + RecvPropInt( RECVINFO( m_bSmoke ) ), + RecvPropInt( RECVINFO( m_bPropFlare ) ), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +C_Flare::C_Flare() : CSimpleEmitter( "C_Flare" ) +{ + m_pParticle[0] = NULL; + m_pParticle[1] = NULL; + m_flTimeBurnOut = 0.0f; + + m_bLight = true; + m_bSmoke = true; + m_bPropFlare = false; + + SetDynamicallyAllocated( false ); + m_queryHandle = 0; + + m_iAttachment = -1; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : state - +//----------------------------------------------------------------------------- +void C_Flare::NotifyShouldTransmit( ShouldTransmitState_t state ) +{ + if ( state == SHOULDTRANSMIT_END ) + { + AddEffects( EF_NODRAW ); + } + else if ( state == SHOULDTRANSMIT_START ) + { + RemoveEffects( EF_NODRAW ); + } + + BaseClass::NotifyShouldTransmit( state ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : bool - +//----------------------------------------------------------------------------- +void C_Flare::OnDataChanged( DataUpdateType_t updateType ) +{ + if ( updateType == DATA_UPDATE_CREATED ) + { + SetSortOrigin( GetAbsOrigin() ); + if ( m_bSmoke ) + { + m_teSmokeSpawn.Init( 8 ); + } + } + + BaseClass::OnDataChanged( updateType ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_Flare::RestoreResources( void ) +{ + if ( m_pParticle[0] == NULL ) + { + m_pParticle[0] = (SimpleParticle *) AddParticle( sizeof( SimpleParticle ), GetPMaterial( "effects/redflare" ), GetAbsOrigin() ); + + if ( m_pParticle[0] != NULL ) + { + m_pParticle[0]->m_uchColor[0] = m_pParticle[0]->m_uchColor[1] = m_pParticle[0]->m_uchColor[2] = 0; + m_pParticle[0]->m_flRoll = random->RandomInt( 0, 360 ); + m_pParticle[0]->m_flRollDelta = random->RandomFloat( 1.0f, 4.0f ); + m_pParticle[0]->m_flLifetime = 0.0f; + m_pParticle[0]->m_flDieTime = 10.0f; + } + else + { + Assert(0); + } + } + + if ( m_pParticle[1] == NULL ) + { + m_pParticle[1] = (SimpleParticle *) AddParticle( sizeof( SimpleParticle ), GetPMaterial( "effects/yellowflare_noz" ), GetAbsOrigin() ); + + if ( m_pParticle[1] != NULL ) + { + m_pParticle[1]->m_uchColor[0] = m_pParticle[1]->m_uchColor[1] = m_pParticle[1]->m_uchColor[2] = 0; + m_pParticle[1]->m_flRoll = random->RandomInt( 0, 360 ); + m_pParticle[1]->m_flRollDelta = random->RandomFloat( 1.0f, 4.0f ); + m_pParticle[1]->m_flLifetime = 0.0f; + m_pParticle[1]->m_flDieTime = 10.0f; + } + else + { + Assert(0); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pParticle - +//----------------------------------------------------------------------------- +void C_Flare::NotifyDestroyParticle( Particle* pParticle ) +{ + if ( pParticle == m_pParticle[0] ) + { + m_pParticle[0] = NULL; + } + + if ( pParticle == m_pParticle[1] ) + { + m_pParticle[1] = NULL; + } + + CSimpleEmitter::NotifyDestroyParticle( pParticle ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : timeDelta - +//----------------------------------------------------------------------------- +void C_Flare::Update( float timeDelta ) +{ + if ( !IsVisible() ) + return; + + CSimpleEmitter::Update( timeDelta ); + + //Make sure our stored resources are up to date + RestoreResources(); + + //Don't do this if the console is down + if ( timeDelta <= 0.0f ) + return; + + //Check for LOS + pixelvis_queryparams_t params; + params.Init(GetAbsOrigin()); + params.proxySize = 8.0f; // Inches + + float visible = PixelVisibility_FractionVisible( params, &m_queryHandle ); + + float fColor; +#ifdef HL2_CLIENT_DLL + float baseScale = m_flScale; +#else + // NOTE!!! This is bigger by a factor of 1.2 to deal with fixing a bug from HL2. See dlight_t.h + float baseScale = m_flScale * 1.2f; +#endif + + //Account for fading out + if ( ( m_flTimeBurnOut != -1.0f ) && ( ( m_flTimeBurnOut - gpGlobals->curtime ) <= 10.0f ) ) + { + baseScale *= ( ( m_flTimeBurnOut - gpGlobals->curtime ) / 10.0f ); + } + + bool bVisible = (baseScale < 0.01f || visible == 0.0f) ? false : true; + //Clamp the scale if vanished + if ( !bVisible ) + { + if ( m_pParticle[0] != NULL ) + { + m_pParticle[0]->m_flDieTime = gpGlobals->curtime; + m_pParticle[0]->m_uchStartSize = m_pParticle[0]->m_uchEndSize = 0; + m_pParticle[0]->m_uchColor[0] = 0; + m_pParticle[0]->m_uchColor[1] = 0; + m_pParticle[0]->m_uchColor[2] = 0; + } + + if ( m_pParticle[1] != NULL ) + { + m_pParticle[1]->m_flDieTime = gpGlobals->curtime; + m_pParticle[1]->m_uchStartSize = m_pParticle[1]->m_uchEndSize = 0; + m_pParticle[1]->m_uchColor[0] = 0; + m_pParticle[1]->m_uchColor[1] = 0; + m_pParticle[1]->m_uchColor[2] = 0; + } + } + + if ( baseScale < 0.01f ) + return; + // + // Dynamic light + // + + if ( m_bLight ) + { + dlight_t *dl= effects->CL_AllocDlight( index ); + + + + if ( m_bPropFlare == false ) + { + dl->origin = GetAbsOrigin(); + dl->color.r = 255; + dl->die = gpGlobals->curtime + 0.1f; + + dl->radius = baseScale * random->RandomFloat( 110.0f, 128.0f ); + dl->color.g = dl->color.b = random->RandomInt( 32, 64 ); + } + else + { + if ( m_iAttachment == -1 ) + { + m_iAttachment = LookupAttachment( "fuse" ); + } + + if ( m_iAttachment != -1 ) + { + Vector effect_origin; + QAngle effect_angles; + + GetAttachment( m_iAttachment, effect_origin, effect_angles ); + + //Raise the light a little bit away from the flare so it lights it up better. + dl->origin = effect_origin + Vector( 0, 0, 4 ); + dl->color.r = 255; + dl->die = gpGlobals->curtime + 0.1f; + + dl->radius = baseScale * random->RandomFloat( 245.0f, 256.0f ); + dl->color.g = dl->color.b = random->RandomInt( 95, 128 ); + + dlight_t *el= effects->CL_AllocElight( index ); + + el->origin = effect_origin; + el->color.r = 255; + el->color.g = dl->color.b = random->RandomInt( 95, 128 ); + el->radius = baseScale * random->RandomFloat( 260.0f, 290.0f ); + el->die = gpGlobals->curtime + 0.1f; + } + } + } + + // + // Smoke + // + + float dt = timeDelta; + + if ( m_bSmoke ) + { + while ( m_teSmokeSpawn.NextEvent( dt ) ) + { + Vector smokeOrg = GetAbsOrigin(); + + Vector flareScreenDir = ( smokeOrg - MainViewOrigin() ); + VectorNormalize( flareScreenDir ); + + smokeOrg = smokeOrg + ( flareScreenDir * 2.0f ); + smokeOrg[2] += baseScale * 4.0f; + + SimpleParticle *sParticle = (SimpleParticle *) AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[1], smokeOrg ); + + if ( sParticle == NULL ) + return; + + sParticle->m_flLifetime = 0.0f; + sParticle->m_flDieTime = 1.0f; + + sParticle->m_vecVelocity = Vector( random->RandomFloat( -16.0f, 16.0f ), random->RandomFloat( -16.0f, 16.0f ), random->RandomFloat( 8.0f, 16.0f ) + 32.0f ); + + if ( m_bPropFlare ) + { + sParticle->m_uchColor[0] = 255; + sParticle->m_uchColor[1] = 100; + sParticle->m_uchColor[2] = 100; + } + else + { + sParticle->m_uchColor[0] = 255; + sParticle->m_uchColor[1] = 48; + sParticle->m_uchColor[2] = 48; + } + + sParticle->m_uchStartAlpha = random->RandomInt( 64, 90 ); + sParticle->m_uchEndAlpha = 0; + sParticle->m_uchStartSize = random->RandomInt( 2, 4 ); + sParticle->m_uchEndSize = sParticle->m_uchStartSize * 8.0f; + sParticle->m_flRoll = random->RandomInt( 0, 2*M_PI ); + sParticle->m_flRollDelta = random->RandomFloat( -(M_PI/6.0f), M_PI/6.0f ); + } + } + + if ( !bVisible ) + return; + + // + // Outer glow + // + + Vector offset; + + //Cause the base of the effect to shake + offset.Random( -0.5f * baseScale, 0.5f * baseScale ); + offset += GetAbsOrigin(); + + if ( m_pParticle[0] != NULL ) + { + m_pParticle[0]->m_Pos = offset; + m_pParticle[0]->m_flLifetime = 0.0f; + m_pParticle[0]->m_flDieTime = 2.0f; + + m_pParticle[0]->m_vecVelocity.Init(); + + fColor = random->RandomInt( 100.0f, 128.0f ) * visible; + + m_pParticle[0]->m_uchColor[0] = fColor; + m_pParticle[0]->m_uchColor[1] = fColor; + m_pParticle[0]->m_uchColor[2] = fColor; + m_pParticle[0]->m_uchStartAlpha = fColor; + m_pParticle[0]->m_uchEndAlpha = fColor; + m_pParticle[0]->m_uchStartSize = baseScale * (float) random->RandomInt( 32, 48 ); + m_pParticle[0]->m_uchEndSize = m_pParticle[0]->m_uchStartSize; + m_pParticle[0]->m_flRollDelta = 0.0f; + + if ( random->RandomInt( 0, 4 ) == 3 ) + { + m_pParticle[0]->m_flRoll += random->RandomInt( 2, 8 ); + } + } + + // + // Inner core + // + + //Cause the base of the effect to shake + offset.Random( -1.0f * baseScale, 1.0f * baseScale ); + offset += GetAbsOrigin(); + + if ( m_pParticle[1] != NULL ) + { + m_pParticle[1]->m_Pos = offset; + m_pParticle[1]->m_flLifetime = 0.0f; + m_pParticle[1]->m_flDieTime = 2.0f; + + m_pParticle[1]->m_vecVelocity.Init(); + + fColor = 255 * visible; + + m_pParticle[1]->m_uchColor[0] = fColor; + m_pParticle[1]->m_uchColor[1] = fColor; + m_pParticle[1]->m_uchColor[2] = fColor; + m_pParticle[1]->m_uchStartAlpha = fColor; + m_pParticle[1]->m_uchEndAlpha = fColor; + m_pParticle[1]->m_uchStartSize = baseScale * (float) random->RandomInt( 2, 4 ); + m_pParticle[1]->m_uchEndSize = m_pParticle[0]->m_uchStartSize; + m_pParticle[1]->m_flRoll = random->RandomInt( 0, 360 ); + } +} diff --git a/game/client/hl2/c_thumper_dust.cpp b/game/client/hl2/c_thumper_dust.cpp new file mode 100644 index 0000000..ade7b30 --- /dev/null +++ b/game/client/hl2/c_thumper_dust.cpp @@ -0,0 +1,170 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "particlemgr.h" +#include "particle_prototype.h" +#include "particle_util.h" +#include "c_te_particlesystem.h" +#include "fx.h" +#include "fx_quad.h" +#include "c_te_effect_dispatch.h" +#include "view.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define THUMPER_DUST_LIFETIME 2.0f +#define THUMPER_MAX_PARTICLES 24 + + +extern IPhysicsSurfaceProps *physprops; + + +class ThumperDustEmitter : public CSimpleEmitter +{ +public: + + ThumperDustEmitter( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {} + + static ThumperDustEmitter *Create( const char *pDebugName ) + { + return new ThumperDustEmitter( pDebugName ); + } + + void UpdateVelocity( SimpleParticle *pParticle, float timeDelta ) + { + // Float up when lifetime is half gone. + pParticle->m_vecVelocity[2] -= ( 8.0f * timeDelta ); + + + // FIXME: optimize this.... + pParticle->m_vecVelocity *= ExponentialDecay( 0.9, 0.03, timeDelta ); + } + + virtual float UpdateRoll( SimpleParticle *pParticle, float timeDelta ) + { + pParticle->m_flRoll += pParticle->m_flRollDelta * timeDelta; + + pParticle->m_flRollDelta += pParticle->m_flRollDelta * ( timeDelta * -4.0f ); + + //Cap the minimum roll + if ( fabs( pParticle->m_flRollDelta ) < 0.25f ) + { + pParticle->m_flRollDelta = ( pParticle->m_flRollDelta > 0.0f ) ? 0.25f : -0.25f; + } + + return pParticle->m_flRoll; + } + + virtual float UpdateAlpha( const SimpleParticle *pParticle ) + { + return (pParticle->m_uchStartAlpha/255.0f) + ( (float)(pParticle->m_uchEndAlpha/255.0f) - (float)(pParticle->m_uchStartAlpha/255.0f) ) * (pParticle->m_flLifetime / pParticle->m_flDieTime); + } + +private: + ThumperDustEmitter( const ThumperDustEmitter & ); +}; + +//----------------------------------------------------------------------------- +// Purpose: +// Input : bNewEntity - whether or not to start a new entity +//----------------------------------------------------------------------------- + +void FX_ThumperDust( const CEffectData &data ) +{ + Vector vecDustColor; + vecDustColor.x = 0.85f; + vecDustColor.y = 0.75f; + vecDustColor.z = 0.52f; + + CSmartPtr<ThumperDustEmitter> pSimple = ThumperDustEmitter::Create( "thumperdust" ); + + C_BaseEntity *pEnt = C_BaseEntity::Instance( data.m_hEntity ); + if ( pEnt ) + { + Vector vWorldMins, vWorldMaxs; + float scale = pEnt->CollisionProp()->BoundingRadius(); + vWorldMins[0] = data.m_vOrigin[0] - scale; + vWorldMins[1] = data.m_vOrigin[1] - scale; + vWorldMins[2] = data.m_vOrigin[2] - scale; + vWorldMaxs[0] = data.m_vOrigin[0] + scale; + vWorldMaxs[1] = data.m_vOrigin[1] + scale; + vWorldMaxs[2] = data.m_vOrigin[2] + scale; + pSimple->GetBinding().SetBBox( vWorldMins, vWorldMaxs, true ); + } + + pSimple->SetSortOrigin( data.m_vOrigin ); + pSimple->SetNearClip( 32, 64 ); + + SimpleParticle *pParticle = NULL; + + Vector offset; + + //int numPuffs = IsXbox() ? THUMPER_MAX_PARTICLES/2 : THUMPER_MAX_PARTICLES; + int numPuffs = THUMPER_MAX_PARTICLES; + + float flYaw = 0; + float flIncr = (2*M_PI) / (float) numPuffs; // Radians + Vector forward; + Vector vecColor; + int i = 0; + + float flScale = MIN( data.m_flScale, 255 ); + + // Setup the color for these particles + engine->ComputeLighting( data.m_vOrigin, NULL, true, vecColor ); + VectorLerp( vecColor, vecDustColor, 0.5, vecColor ); + vecColor *= 255; + + for ( i = 0; i < numPuffs; i++ ) + { + flYaw += flIncr; + SinCos( flYaw, &forward.y, &forward.x ); + forward.z = 0.0f; + + offset = ( RandomVector( -4.0f, 4.0f ) + data.m_vOrigin ) + ( forward * 128.0f ); + + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[random->RandomInt(0,1)], offset ); + if ( pParticle != NULL ) + { + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = 1.5f; + + Vector dir = (offset - data.m_vOrigin); + float length = dir.Length(); + VectorNormalize( dir ); + + pParticle->m_vecVelocity = dir * ( length * 2.0f ); + pParticle->m_vecVelocity[2] = data.m_flScale / 3; + + pParticle->m_uchColor[0] = vecColor[0]; + pParticle->m_uchColor[1] = vecColor[1]; + pParticle->m_uchColor[2] = vecColor[2]; + + pParticle->m_uchStartAlpha = random->RandomInt( 64, 96 ); + pParticle->m_uchEndAlpha = 0; + + pParticle->m_uchStartSize = flScale * 0.25f; + pParticle->m_uchEndSize = flScale * 0.5f; + + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = random->RandomFloat( -6.0f, 6.0f ); + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &data - +//----------------------------------------------------------------------------- +void ThumperDustCallback( const CEffectData &data ) +{ + FX_ThumperDust( data ); +} + +DECLARE_CLIENT_EFFECT( "ThumperDust", ThumperDustCallback );
\ No newline at end of file diff --git a/game/client/hl2/c_vehicle_airboat.cpp b/game/client/hl2/c_vehicle_airboat.cpp new file mode 100644 index 0000000..1672037 --- /dev/null +++ b/game/client/hl2/c_vehicle_airboat.cpp @@ -0,0 +1,931 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client side implementation of the airboat. +// +// - Dampens motion of driver's view to reduce nausea. +// - Autocenters driver's view after a period of inactivity. +// - Controls headlights. +// - Controls curve parameters for pitch/roll blending. +// +//=============================================================================// + +#include "cbase.h" +#include "c_prop_vehicle.h" +#include "datacache/imdlcache.h" +#include "flashlighteffect.h" +#include "movevars_shared.h" +#include "ammodef.h" +#include "SpriteTrail.h" +#include "beamdraw.h" +#include "enginesprite.h" +#include "fx_quad.h" +#include "fx.h" +#include "fx_water.h" +#include "engine/ivdebugoverlay.h" +#include "view.h" +#include "clienteffectprecachesystem.h" +#include "c_basehlplayer.h" +#include "vgui_controls/Controls.h" +#include "vgui/ISurface.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +ConVar r_AirboatViewBlendTo( "r_AirboatViewBlendTo", "1", FCVAR_CHEAT ); +ConVar r_AirboatViewBlendToScale( "r_AirboatViewBlendToScale", "0.03", FCVAR_CHEAT ); +ConVar r_AirboatViewBlendToTime( "r_AirboatViewBlendToTime", "1.5", FCVAR_CHEAT ); + +ConVar cl_draw_airboat_wake( "cl_draw_airboat_wake", "1", FCVAR_CHEAT ); + +// Curve parameters for pitch/roll blending. +// NOTE: Must restart (or create a new airboat) after changing these cvars! +ConVar r_AirboatRollCurveZero( "r_AirboatRollCurveZero", "90.0", FCVAR_CHEAT ); // Roll less than this is clamped to zero. +ConVar r_AirboatRollCurveLinear( "r_AirboatRollCurveLinear", "120.0", FCVAR_CHEAT ); // Roll greater than this is mapped directly. + // Spline in between. + +ConVar r_AirboatPitchCurveZero( "r_AirboatPitchCurveZero", "25.0", FCVAR_CHEAT ); // Pitch less than this is clamped to zero. +ConVar r_AirboatPitchCurveLinear( "r_AirboatPitchCurveLinear", "60.0", FCVAR_CHEAT ); // Pitch greater than this is mapped directly. + // Spline in between. + +ConVar airboat_joy_response_move( "airboat_joy_response_move", "1" ); // Quadratic steering response + + +#define AIRBOAT_DELTA_LENGTH_MAX 12.0f // 1 foot +#define AIRBOAT_FRAMETIME_MIN 1e-6 + +#define HEADLIGHT_DISTANCE 1000 + +#define MAX_WAKE_POINTS 16 +#define WAKE_POINT_MASK (MAX_WAKE_POINTS-1) + +#define WAKE_LIFETIME 0.5f + +//============================================================================= +// +// Client-side Airboat Class +// +class C_PropAirboat : public C_PropVehicleDriveable +{ + DECLARE_CLASS( C_PropAirboat, C_PropVehicleDriveable ); + +public: + + DECLARE_CLIENTCLASS(); + DECLARE_INTERPOLATION(); + DECLARE_DATADESC(); + + C_PropAirboat(); + ~C_PropAirboat(); + +public: + + // C_BaseEntity + virtual void Simulate(); + + // IClientVehicle + virtual void UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd ); + virtual void OnEnteredVehicle( C_BasePlayer *pPlayer ); + virtual int GetPrimaryAmmoType() const; + virtual int GetPrimaryAmmoClip() const; + virtual bool PrimaryAmmoUsesClips() const; + virtual int GetPrimaryAmmoCount() const; + virtual int GetJoystickResponseCurve() const; + + int DrawModel( int flags ); + + // Draws crosshair in the forward direction of the boat + void DrawHudElements( ); + +private: + + void DrawPropWake( Vector origin, float speed ); + void DrawPontoonSplash( Vector position, Vector direction, float speed ); + void DrawPontoonWake( Vector startPos, Vector wakeDir, float wakeLength, float speed); + + void DampenEyePosition( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles ); + void DampenForwardMotion( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles, float flFrameTime ); + void DampenUpMotion( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles, float flFrameTime ); + void ComputePDControllerCoefficients( float *pCoefficientsOut, float flFrequency, float flDampening, float flDeltaTime ); + + void UpdateHeadlight( void ); + void UpdateWake( void ); + int DrawWake( void ); + void DrawSegment( const BeamSeg_t &beamSeg, const Vector &vNormal ); + + TrailPoint_t *GetTrailPoint( int n ) + { + int nIndex = (n + m_nFirstStep) & WAKE_POINT_MASK; + return &m_vecSteps[nIndex]; + } + +private: + + Vector m_vecLastEyePos; + Vector m_vecLastEyeTarget; + Vector m_vecEyeSpeed; + Vector m_vecTargetSpeed; + + float m_flViewAngleDeltaTime; + + bool m_bHeadlightIsOn; + int m_nAmmoCount; + CHeadlightEffect *m_pHeadlight; + + int m_nExactWaterLevel; + + TrailPoint_t m_vecSteps[MAX_WAKE_POINTS]; + int m_nFirstStep; + int m_nStepCount; + float m_flUpdateTime; + + TimedEvent m_SplashTime; + CMeshBuilder m_Mesh; + + Vector m_vecPhysVelocity; +}; + +IMPLEMENT_CLIENTCLASS_DT( C_PropAirboat, DT_PropAirboat, CPropAirboat ) + RecvPropBool( RECVINFO( m_bHeadlightIsOn ) ), + RecvPropInt( RECVINFO( m_nAmmoCount ) ), + RecvPropInt( RECVINFO( m_nExactWaterLevel ) ), + RecvPropInt( RECVINFO( m_nWaterLevel ) ), + RecvPropVector( RECVINFO( m_vecPhysVelocity ) ), +END_RECV_TABLE() + + +BEGIN_DATADESC( C_PropAirboat ) + DEFINE_FIELD( m_vecLastEyePos, FIELD_POSITION_VECTOR ), + DEFINE_FIELD( m_vecLastEyeTarget, FIELD_POSITION_VECTOR ), + DEFINE_FIELD( m_vecEyeSpeed, FIELD_VECTOR ), + DEFINE_FIELD( m_vecTargetSpeed, FIELD_VECTOR ), + //DEFINE_FIELD( m_flViewAngleDeltaTime, FIELD_FLOAT ), +END_DATADESC() + + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +C_PropAirboat::C_PropAirboat() +{ + m_vecEyeSpeed.Init(); + m_flViewAngleDeltaTime = 0.0f; + m_pHeadlight = NULL; + + m_ViewSmoothingData.flPitchCurveZero = r_AirboatPitchCurveZero.GetFloat(); + m_ViewSmoothingData.flPitchCurveLinear = r_AirboatPitchCurveLinear.GetFloat(); + m_ViewSmoothingData.flRollCurveZero = r_AirboatRollCurveZero.GetFloat(); + m_ViewSmoothingData.flRollCurveLinear = r_AirboatRollCurveLinear.GetFloat(); + + m_ViewSmoothingData.rollLockData.flLockInterval = 1.5; + m_ViewSmoothingData.rollLockData.flUnlockBlendInterval = 1.0; + + m_ViewSmoothingData.pitchLockData.flLockInterval = 1.5; + m_ViewSmoothingData.pitchLockData.flUnlockBlendInterval = 1.0; + + m_nFirstStep = 0; + m_nStepCount = 0; + m_SplashTime.Init( 60 ); +} + +//----------------------------------------------------------------------------- +// Purpose: Deconstructor +//----------------------------------------------------------------------------- +C_PropAirboat::~C_PropAirboat() +{ + if (m_pHeadlight) + { + delete m_pHeadlight; + } +} + + +//----------------------------------------------------------------------------- +// Draws the ammo for the airboat +//----------------------------------------------------------------------------- +int C_PropAirboat::GetPrimaryAmmoType() const +{ + if ( m_nAmmoCount < 0 ) + return -1; + + int nAmmoType = GetAmmoDef()->Index( "AirboatGun" ); + return nAmmoType; +} + +int C_PropAirboat::GetPrimaryAmmoCount() const +{ + return m_nAmmoCount; +} + +bool C_PropAirboat::PrimaryAmmoUsesClips() const +{ + return false; +} + +int C_PropAirboat::GetPrimaryAmmoClip() const +{ + return -1; +} + +//----------------------------------------------------------------------------- +// The airboat prefers a more peppy response curve for joystick control. +//----------------------------------------------------------------------------- +int C_PropAirboat::GetJoystickResponseCurve() const +{ + return airboat_joy_response_move.GetInt(); +} + +//----------------------------------------------------------------------------- +// Draws crosshair in the forward direction of the boat +//----------------------------------------------------------------------------- +void C_PropAirboat::DrawHudElements( ) +{ + BaseClass::DrawHudElements(); + + MDLCACHE_CRITICAL_SECTION(); + + CHudTexture *pIcon = gHUD.GetIcon( IsX360() ? "crosshair_default" : "plushair" ); + if ( pIcon != NULL ) + { + float x, y; + Vector screen; + + int vx, vy, vw, vh; + vgui::surface()->GetFullscreenViewport( vx, vy, vw, vh ); + float screenWidth = vw; + float screenHeight = vh; + + x = screenWidth/2; + y = screenHeight/2; + + int eyeAttachmentIndex = LookupAttachment( "vehicle_driver_eyes" ); + Vector vehicleEyeOrigin; + QAngle vehicleEyeAngles; + GetAttachment( eyeAttachmentIndex, vehicleEyeOrigin, vehicleEyeAngles ); + + // Only worry about yaw. + vehicleEyeAngles.x = vehicleEyeAngles.z = 0.0f; + + Vector vecForward; + AngleVectors( vehicleEyeAngles, &vecForward ); + VectorMA( vehicleEyeOrigin, 100.0f, vecForward, vehicleEyeOrigin ); + + ScreenTransform( vehicleEyeOrigin, screen ); + x += 0.5 * screen[0] * screenWidth + 0.5; + y -= 0.5 * screen[1] * screenHeight + 0.5; + + x -= pIcon->Width() / 2; + y -= pIcon->Height() / 2; + + pIcon->DrawSelf( x, y, gHUD.m_clrNormal ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Blend view angles. +//----------------------------------------------------------------------------- +void C_PropAirboat::UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd ) +{ + if ( r_AirboatViewBlendTo.GetInt() ) + { + // + // Autocenter the view after a period of no mouse movement while throttling. + // + bool bResetViewAngleTime = false; + + if ( ( pCmd->mousedx != 0 || pCmd->mousedy != 0 ) || ( fabsf( m_flThrottle ) < 0.01f ) ) + { + if ( IsX360() ) + { + // Only reset this if there isn't an autoaim target! + C_BaseHLPlayer *pLocalHLPlayer = (C_BaseHLPlayer *)pLocalPlayer; + if ( pLocalHLPlayer ) + { + // Get the autoaim target. + CBaseEntity *pTarget = pLocalHLPlayer->m_HL2Local.m_hAutoAimTarget.Get(); + + if( !pTarget ) + { + bResetViewAngleTime = true; + } + } + } + else + { + bResetViewAngleTime = true; + } + } + + if( bResetViewAngleTime ) + { + m_flViewAngleDeltaTime = 0.0f; + } + else + { + m_flViewAngleDeltaTime += gpGlobals->frametime; + } + + if ( m_flViewAngleDeltaTime > r_AirboatViewBlendToTime.GetFloat() ) + { + // Blend the view angles. + int eyeAttachmentIndex = LookupAttachment( "vehicle_driver_eyes" ); + Vector vehicleEyeOrigin; + QAngle vehicleEyeAngles; + GetAttachmentLocal( eyeAttachmentIndex, vehicleEyeOrigin, vehicleEyeAngles ); + + QAngle outAngles; + InterpolateAngles( pCmd->viewangles, vehicleEyeAngles, outAngles, r_AirboatViewBlendToScale.GetFloat() ); + pCmd->viewangles = outAngles; + } + } + + BaseClass::UpdateViewAngles( pLocalPlayer, pCmd ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PropAirboat::DampenEyePosition( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles ) +{ + // Get the frametime. (Check to see if enough time has passed to warrent dampening). + float flFrameTime = gpGlobals->frametime; + if ( flFrameTime < AIRBOAT_FRAMETIME_MIN ) + { + vecVehicleEyePos = m_vecLastEyePos; + DampenUpMotion( vecVehicleEyePos, vecVehicleEyeAngles, 0.0f ); + return; + } + + // Keep static the sideways motion. + + // Dampen forward/backward motion. + DampenForwardMotion( vecVehicleEyePos, vecVehicleEyeAngles, flFrameTime ); + + // Blend up/down motion. + DampenUpMotion( vecVehicleEyePos, vecVehicleEyeAngles, flFrameTime ); +} + + +//----------------------------------------------------------------------------- +// Use the controller as follows: +// speed += ( pCoefficientsOut[0] * ( targetPos - currentPos ) + pCoefficientsOut[1] * ( targetSpeed - currentSpeed ) ) * flDeltaTime; +//----------------------------------------------------------------------------- +void C_PropAirboat::ComputePDControllerCoefficients( float *pCoefficientsOut, + float flFrequency, float flDampening, + float flDeltaTime ) +{ + float flKs = 9.0f * flFrequency * flFrequency; + float flKd = 4.5f * flFrequency * flDampening; + + float flScale = 1.0f / ( 1.0f + flKd * flDeltaTime + flKs * flDeltaTime * flDeltaTime ); + + pCoefficientsOut[0] = flKs * flScale; + pCoefficientsOut[1] = ( flKd + flKs * flDeltaTime ) * flScale; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PropAirboat::DampenForwardMotion( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles, float flFrameTime ) +{ + // vecVehicleEyePos = real eye position this frame + + // m_vecLastEyePos = eye position last frame + // m_vecEyeSpeed = eye speed last frame + // vecPredEyePos = predicted eye position this frame (assuming no acceleration - it will get that from the pd controller). + // vecPredEyeSpeed = predicted eye speed + Vector vecPredEyePos = m_vecLastEyePos + m_vecEyeSpeed * flFrameTime; + Vector vecPredEyeSpeed = m_vecEyeSpeed; + + // m_vecLastEyeTarget = real eye position last frame (used for speed calculation). + // Calculate the approximate speed based on the current vehicle eye position and the eye position last frame. + Vector vecVehicleEyeSpeed = ( vecVehicleEyePos - m_vecLastEyeTarget ) / flFrameTime; + m_vecLastEyeTarget = vecVehicleEyePos; + if (vecVehicleEyeSpeed.Length() == 0.0) + { + return; + } + + // Calculate the delta between the predicted eye position and speed and the current eye position and speed. + Vector vecDeltaSpeed = vecVehicleEyeSpeed - vecPredEyeSpeed; + Vector vecDeltaPos = vecVehicleEyePos - vecPredEyePos; + + // Forward vector. + Vector vecForward; + AngleVectors( vecVehicleEyeAngles, &vecForward ); + + float flDeltaLength = vecDeltaPos.Length(); + if ( flDeltaLength > AIRBOAT_DELTA_LENGTH_MAX ) + { + // Clamp. + float flDelta = flDeltaLength - AIRBOAT_DELTA_LENGTH_MAX; + if ( flDelta > 40.0f ) + { + // This part is a bit of a hack to get rid of large deltas (at level load, etc.). + m_vecLastEyePos = vecVehicleEyePos; + m_vecEyeSpeed = vecVehicleEyeSpeed; + } + else + { + // Position clamp. + float flRatio = AIRBOAT_DELTA_LENGTH_MAX / flDeltaLength; + vecDeltaPos *= flRatio; + Vector vecForwardOffset = vecForward * ( vecForward.Dot( vecDeltaPos ) ); + vecVehicleEyePos -= vecForwardOffset; + m_vecLastEyePos = vecVehicleEyePos; + + // Speed clamp. + vecDeltaSpeed *= flRatio; + float flCoefficients[2]; + ComputePDControllerCoefficients( flCoefficients, r_AirboatViewDampenFreq.GetFloat(), r_AirboatViewDampenDamp.GetFloat(), flFrameTime ); + m_vecEyeSpeed += ( ( flCoefficients[0] * vecDeltaPos + flCoefficients[1] * vecDeltaSpeed ) * flFrameTime ); + } + } + else + { + // Generate an updated (dampening) speed for use in next frames position prediction. + float flCoefficients[2]; + ComputePDControllerCoefficients( flCoefficients, r_AirboatViewDampenFreq.GetFloat(), r_AirboatViewDampenDamp.GetFloat(), flFrameTime ); + m_vecEyeSpeed += ( ( flCoefficients[0] * vecDeltaPos + flCoefficients[1] * vecDeltaSpeed ) * flFrameTime ); + + // Save off data for next frame. + m_vecLastEyePos = vecPredEyePos; + + // Move eye forward/backward. + Vector vecForwardOffset = vecForward * ( vecForward.Dot( vecDeltaPos ) ); + vecVehicleEyePos -= vecForwardOffset; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PropAirboat::DampenUpMotion( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles, float flFrameTime ) +{ + // Get up vector. + Vector vecUp; + AngleVectors( vecVehicleEyeAngles, NULL, NULL, &vecUp ); + vecUp.z = clamp( vecUp.z, 0.0f, vecUp.z ); + vecVehicleEyePos.z += r_AirboatViewZHeight.GetFloat() * vecUp.z; + + // NOTE: Should probably use some damped equation here. +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PropAirboat::OnEnteredVehicle( C_BasePlayer *pPlayer ) +{ + int eyeAttachmentIndex = LookupAttachment( "vehicle_driver_eyes" ); + Vector vehicleEyeOrigin; + QAngle vehicleEyeAngles; + GetAttachment( eyeAttachmentIndex, vehicleEyeOrigin, vehicleEyeAngles ); + + m_vecLastEyeTarget = vehicleEyeOrigin; + m_vecLastEyePos = vehicleEyeOrigin; + m_vecEyeSpeed = vec3_origin; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PropAirboat::Simulate() +{ + UpdateHeadlight(); + UpdateWake(); + + BaseClass::Simulate(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Creates, destroys, and updates the headlight effect as needed. +//----------------------------------------------------------------------------- +void C_PropAirboat::UpdateHeadlight() +{ + if (m_bHeadlightIsOn) + { + if (!m_pHeadlight) + { + // Turned on the headlight; create it. + m_pHeadlight = new CHeadlightEffect(); + + if (!m_pHeadlight) + return; + + m_pHeadlight->TurnOn(); + } + + // The headlight is emitted from an attachment point so that it can move + // as we turn the handlebars. + int nHeadlightIndex = LookupAttachment( "vehicle_headlight" ); + + Vector vecLightPos; + QAngle angLightDir; + GetAttachment(nHeadlightIndex, vecLightPos, angLightDir); + + Vector vecLightDir, vecLightRight, vecLightUp; + AngleVectors( angLightDir, &vecLightDir, &vecLightRight, &vecLightUp ); + + // Update the light with the new position and direction. + m_pHeadlight->UpdateLight( vecLightPos, vecLightDir, vecLightRight, vecLightUp, HEADLIGHT_DISTANCE ); + } + else if (m_pHeadlight) + { + // Turned off the headlight; delete it. + delete m_pHeadlight; + m_pHeadlight = NULL; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PropAirboat::UpdateWake( void ) +{ + if ( gpGlobals->frametime <= 0.0f ) + return; + + // Can't update too quickly + if ( m_flUpdateTime > gpGlobals->curtime ) + return; + + Vector screenPos = GetRenderOrigin(); + screenPos.z = m_nExactWaterLevel; + + TrailPoint_t *pLast = m_nStepCount ? GetTrailPoint( m_nStepCount-1 ) : NULL; + if ( ( pLast == NULL ) || ( pLast->m_vecScreenPos.DistToSqr( screenPos ) > 4.0f ) ) + { + // If we're over our limit, steal the last point and put it up front + if ( m_nStepCount >= MAX_WAKE_POINTS ) + { + --m_nStepCount; + ++m_nFirstStep; + } + + // Save off its screen position, not its world position + TrailPoint_t *pNewPoint = GetTrailPoint( m_nStepCount ); + pNewPoint->m_vecScreenPos = screenPos + Vector( 0, 0, 2 ); + pNewPoint->m_flDieTime = gpGlobals->curtime + WAKE_LIFETIME; + pNewPoint->m_flWidthVariance = random->RandomFloat( -16, 16 ); + + if ( pLast ) + { + pNewPoint->m_flTexCoord = pLast->m_flTexCoord + pLast->m_vecScreenPos.DistTo( screenPos ); + pNewPoint->m_flTexCoord = fmod( pNewPoint->m_flTexCoord, 1 ); + } + else + { + pNewPoint->m_flTexCoord = 0.0f; + } + + ++m_nStepCount; + } + + // Don't update again for a bit + m_flUpdateTime = gpGlobals->curtime + ( 0.5f / (float) MAX_WAKE_POINTS ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &beamSeg - +//----------------------------------------------------------------------------- +void C_PropAirboat::DrawSegment( const BeamSeg_t &beamSeg, const Vector &vNormal ) +{ + // Build the endpoints. + Vector vPoint1, vPoint2; + VectorMA( beamSeg.m_vPos, beamSeg.m_flWidth*0.5f, vNormal, vPoint1 ); + VectorMA( beamSeg.m_vPos, -beamSeg.m_flWidth*0.5f, vNormal, vPoint2 ); + + // Specify the points. + m_Mesh.Position3fv( vPoint1.Base() ); + m_Mesh.Color4f( VectorExpand( beamSeg.m_vColor ), beamSeg.m_flAlpha ); + m_Mesh.TexCoord2f( 0, 0, beamSeg.m_flTexCoord ); + m_Mesh.TexCoord2f( 1, 0, beamSeg.m_flTexCoord ); + m_Mesh.AdvanceVertex(); + + m_Mesh.Position3fv( vPoint2.Base() ); + m_Mesh.Color4f( VectorExpand( beamSeg.m_vColor ), beamSeg.m_flAlpha ); + m_Mesh.TexCoord2f( 0, 1, beamSeg.m_flTexCoord ); + m_Mesh.TexCoord2f( 1, 1, beamSeg.m_flTexCoord ); + m_Mesh.AdvanceVertex(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : position - +//----------------------------------------------------------------------------- +void C_PropAirboat::DrawPontoonSplash( Vector origin, Vector direction, float speed ) +{ + Vector offset; + + CSmartPtr<CSplashParticle> pSimple = CSplashParticle::Create( "splish" ); + pSimple->SetSortOrigin( origin ); + + SimpleParticle *pParticle; + + Vector color = Vector( 0.8f, 0.8f, 0.75f ); + float colorRamp; + + float flScale = RemapVal( speed, 64, 256, 0.75f, 1.0f ); + + PMaterialHandle hMaterial; + + float tempDelta = gpGlobals->frametime; + + while( m_SplashTime.NextEvent( tempDelta ) ) + { + if ( random->RandomInt( 0, 1 ) ) + { + hMaterial = ParticleMgr()->GetPMaterial( "effects/splash1" ); + } + else + { + hMaterial = ParticleMgr()->GetPMaterial( "effects/splash2" ); + } + + offset = RandomVector( -8.0f * flScale, 8.0f * flScale ); + offset[2] = 0.0f; + offset += origin; + + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, offset ); + + if ( pParticle == NULL ) + continue; + + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = 0.25f; + + pParticle->m_vecVelocity.Random( -0.4f, 0.4f ); + pParticle->m_vecVelocity += (direction*5.0f+Vector(0,0,1)); + + VectorNormalize( pParticle->m_vecVelocity ); + + pParticle->m_vecVelocity *= speed + random->RandomFloat( -128.0f, 128.0f ); + + colorRamp = random->RandomFloat( 0.75f, 1.25f ); + + pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f; + pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f; + pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f; + + pParticle->m_uchStartSize = random->RandomFloat( 8, 16 ) * flScale; + pParticle->m_uchEndSize = pParticle->m_uchStartSize * 2; + + pParticle->m_uchStartAlpha = 255; + pParticle->m_uchEndAlpha = 0; + + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = random->RandomFloat( -4.0f, 4.0f ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : Vector startPos - +// wakeDir - +// wakeLength - +//----------------------------------------------------------------------------- +void C_PropAirboat::DrawPontoonWake( Vector startPos, Vector wakeDir, float wakeLength, float speed ) +{ +#define WAKE_STEPS 6 + + Vector wakeStep = wakeDir * ( wakeLength / (float) WAKE_STEPS ); + Vector origin; + float scale; + + IMaterial *pMaterial = materials->FindMaterial( "effects/splashwake1", NULL, false ); + CMatRenderContextPtr pRenderContext( materials ); + IMesh* pMesh = pRenderContext->GetDynamicMesh( 0, 0, 0, pMaterial ); + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_QUADS, WAKE_STEPS ); + + for ( int i = 0; i < WAKE_STEPS; i++ ) + { + origin = startPos + ( wakeStep * i ); + origin[0] += random->RandomFloat( -4.0f, 4.0f ); + origin[1] += random->RandomFloat( -4.0f, 4.0f ); + origin[2] = m_nExactWaterLevel + 2.0f; + + float scaleRange = RemapVal( i, 0, WAKE_STEPS-1, 32, 64 ); + scale = scaleRange + ( 8.0f * sin( gpGlobals->curtime * 5 * i ) ); + + float alpha = RemapValClamped( speed, 128, 600, 0.05f, 0.25f ); + float color[4] = { 1.0f, 1.0f, 1.0f, alpha }; + + // Needs to be time based so it'll freeze when the game is frozen + float yaw = random->RandomFloat( 0, 360 ); + + Vector rRight = ( Vector(1,0,0) * cos( DEG2RAD( yaw ) ) ) - ( Vector(0,1,0) * sin( DEG2RAD( yaw ) ) ); + Vector rUp = ( Vector(1,0,0) * cos( DEG2RAD( yaw+90.0f ) ) ) - ( Vector(0,1,0) * sin( DEG2RAD( yaw+90.0f ) ) ); + + Vector point; + meshBuilder.Color4fv (color); + meshBuilder.TexCoord2f (0, 0, 1); + VectorMA (origin, -scale, rRight, point); + VectorMA (point, -scale, rUp, point); + meshBuilder.Position3fv (point.Base()); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4fv (color); + meshBuilder.TexCoord2f (0, 0, 0); + VectorMA (origin, scale, rRight, point); + VectorMA (point, -scale, rUp, point); + meshBuilder.Position3fv (point.Base()); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4fv (color); + meshBuilder.TexCoord2f (0, 1, 0); + VectorMA (origin, scale, rRight, point); + VectorMA (point, scale, rUp, point); + meshBuilder.Position3fv (point.Base()); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4fv (color); + meshBuilder.TexCoord2f (0, 1, 1); + VectorMA (origin, -scale, rRight, point); + VectorMA (point, scale, rUp, point); + meshBuilder.Position3fv (point.Base()); + meshBuilder.AdvanceVertex(); + } + + meshBuilder.End(); + pMesh->Draw(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int +//----------------------------------------------------------------------------- +int C_PropAirboat::DrawWake( void ) +{ + if ( cl_draw_airboat_wake.GetBool() == false ) + return 0; + + // Make sure we're in water... + if ( GetWaterLevel() == 0 ) + return 0; + + //FIXME: For now, we don't draw slime this way + if ( GetWaterLevel() == 2 ) + return 0; + + bool bDriven = ( GetPassenger( VEHICLE_ROLE_DRIVER ) != NULL ); + + Vector vehicleDir = m_vecPhysVelocity; + float vehicleSpeed = VectorNormalize( vehicleDir ); + + Vector vecPontoonFrontLeft; + Vector vecPontoonFrontRight; + Vector vecPontoonRearLeft; + Vector vecPontoonRearRight; + Vector vecSplashPoint; + + QAngle fooAngles; + + //FIXME: This lookup should be cached off + // Get all attachments + GetAttachment( LookupAttachment( "raytrace_fl" ), vecPontoonFrontLeft, fooAngles ); + GetAttachment( LookupAttachment( "raytrace_fr" ), vecPontoonFrontRight, fooAngles ); + GetAttachment( LookupAttachment( "raytrace_rl" ), vecPontoonRearLeft, fooAngles ); + GetAttachment( LookupAttachment( "raytrace_rr" ), vecPontoonRearRight, fooAngles ); + GetAttachment( LookupAttachment( "splash_pt" ), vecSplashPoint, fooAngles ); + + // Find the direction of the pontoons + Vector vecLeftWakeDir = ( vecPontoonRearLeft - vecPontoonFrontLeft ); + Vector vecRightWakeDir = ( vecPontoonRearRight - vecPontoonFrontRight ); + + // Find the pontoon's size + float flWakeLeftLength = VectorNormalize( vecLeftWakeDir ); + float flWakeRightLength = VectorNormalize( vecRightWakeDir ); + + vecPontoonFrontLeft.z = m_nExactWaterLevel; + vecPontoonFrontRight.z = m_nExactWaterLevel; + + if ( bDriven && vehicleSpeed > 128.0f ) + { + DrawPontoonWake( vecPontoonFrontLeft, vecLeftWakeDir, flWakeLeftLength, vehicleSpeed ); + DrawPontoonWake( vecPontoonFrontRight, vecRightWakeDir, flWakeRightLength, vehicleSpeed ); + + Vector vecSplashDir; + Vector vForward; + GetVectors( &vForward, NULL, NULL ); + + if ( m_vecPhysVelocity.x < -64.0f ) + { + vecSplashDir = vecLeftWakeDir - vForward; + VectorNormalize( vecSplashDir ); + + // Don't do this if we're going backwards + if ( m_vecPhysVelocity.y > 0.0f ) + { + DrawPontoonSplash( vecPontoonFrontLeft + ( vecLeftWakeDir * 1.0f ), vecSplashDir, m_vecPhysVelocity.y ); + } + } + else if ( m_vecPhysVelocity.x > 64.0f ) + { + vecSplashDir = vecRightWakeDir + vForward; + VectorNormalize( vecSplashDir ); + + // Don't do this if we're going backwards + if ( m_vecPhysVelocity.y > 0.0f ) + { + DrawPontoonSplash( vecPontoonFrontRight + ( vecRightWakeDir * 1.0f ), vecSplashDir, m_vecPhysVelocity.y ); + } + } + } + + // Must have at least one point + if ( m_nStepCount <= 1 ) + return 1; + + IMaterial *pMaterial = materials->FindMaterial( "effects/splashwake4", 0); + + //Bind the material + CMatRenderContextPtr pRenderContext( materials ); + IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial ); + + m_Mesh.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, (m_nStepCount-1) * 2 ); + + TrailPoint_t *pLast = GetTrailPoint( m_nStepCount - 1 ); + + TrailPoint_t currentPoint; + currentPoint.m_flDieTime = gpGlobals->curtime + 0.5f; + currentPoint.m_vecScreenPos = GetAbsOrigin(); + currentPoint.m_vecScreenPos[2] = m_nExactWaterLevel + 16; + currentPoint.m_flTexCoord = pLast->m_flTexCoord + currentPoint.m_vecScreenPos.DistTo(pLast->m_vecScreenPos); + currentPoint.m_flTexCoord = fmod( currentPoint.m_flTexCoord, 1 ); + currentPoint.m_flWidthVariance = 0.0f; + + TrailPoint_t *pPrevPoint = NULL; + + Vector segDir, normal; + + for ( int i = 0; i <= m_nStepCount; ++i ) + { + // This makes it so that we're always drawing to the current location + TrailPoint_t *pPoint = (i != m_nStepCount) ? GetTrailPoint(i) : ¤tPoint; + + float flLifePerc = RemapValClamped( ( pPoint->m_flDieTime - gpGlobals->curtime ), 0, WAKE_LIFETIME, 0.0f, 1.0f ); + + BeamSeg_t curSeg; + curSeg.m_vColor.x = curSeg.m_vColor.y = curSeg.m_vColor.z = 1.0f; + + float flAlphaFade = flLifePerc; + float alpha = RemapValClamped( fabs( m_vecPhysVelocity.y ), 128, 600, 0.0f, 1.0f ); + + curSeg.m_flAlpha = 0.25f; + curSeg.m_flAlpha *= flAlphaFade * alpha; + + curSeg.m_vPos = pPoint->m_vecScreenPos; + + float widthBase = SimpleSplineRemapVal( fabs( m_vecPhysVelocity.y ), 128, 600, 32, 48 ); + + curSeg.m_flWidth = Lerp( flLifePerc, widthBase*6, widthBase ); + curSeg.m_flWidth += pPoint->m_flWidthVariance; + + if ( curSeg.m_flWidth < 0.0f ) + { + curSeg.m_flWidth = 0.0f; + } + + curSeg.m_flTexCoord = pPoint->m_flTexCoord; + + if ( pPrevPoint != NULL ) + { + segDir = ( pPrevPoint->m_vecScreenPos - pPoint->m_vecScreenPos ); + VectorNormalize( segDir ); + + normal = CrossProduct( segDir, Vector( 0, 0, -1 ) ); + + DrawSegment( curSeg, normal ); + } + + pPrevPoint = pPoint; + } + + m_Mesh.End(); + pMesh->Draw(); + + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flags - +// Output : int +//----------------------------------------------------------------------------- +int C_PropAirboat::DrawModel( int flags ) +{ + if ( BaseClass::DrawModel( flags ) == false ) + return 0; + + if ( !m_bReadyToDraw ) + return 0; + + return DrawWake(); +} diff --git a/game/client/hl2/c_vehicle_cannon.cpp b/game/client/hl2/c_vehicle_cannon.cpp new file mode 100644 index 0000000..74e49ce --- /dev/null +++ b/game/client/hl2/c_vehicle_cannon.cpp @@ -0,0 +1,187 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include <vgui_controls/Controls.h> +#include <Color.h> +#include "c_vehicle_crane.h" +#include "view.h" +#include "vehicle_viewblend_shared.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +int ScreenTransform( const Vector& point, Vector& screen ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_PropCannon : public C_BaseAnimating, public IClientVehicle +{ + + DECLARE_CLASS( C_PropCannon, C_BaseAnimating ); + +public: + + DECLARE_CLIENTCLASS(); + DECLARE_DATADESC(); + + C_PropCannon(); + + void PreDataUpdate( DataUpdateType_t updateType ); + +public: + + // IClientVehicle overrides. + virtual void GetVehicleViewPosition( int nRole, Vector *pOrigin, QAngle *pAngles, float *pFOV = NULL ); + virtual void GetVehicleFOV( float &flFOV ) { flFOV = 0.0f; } + virtual void DrawHudElements(); + virtual bool IsPassengerUsingStandardWeapons( int nRole = VEHICLE_ROLE_DRIVER ) { return false; } + virtual void UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd ) {} + virtual C_BaseCombatCharacter *GetPassenger( int nRole ); + virtual int GetPassengerRole( C_BaseCombatCharacter *pPassenger ); + virtual void GetVehicleClipPlanes( float &flZNear, float &flZFar ) const; + virtual int GetPrimaryAmmoType() const { return -1; } + virtual int GetPrimaryAmmoCount() const { return -1; } + virtual int GetPrimaryAmmoClip() const { return -1; } + virtual bool PrimaryAmmoUsesClips() const { return false; } + virtual int GetJoystickResponseCurve() const { return 0; } + +public: + + // C_BaseEntity overrides. + virtual IClientVehicle* GetClientVehicle() { return this; } + virtual C_BaseEntity *GetVehicleEnt() { return this; } + virtual void SetupMove( C_BasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move ) {} + virtual void ProcessMovement( C_BasePlayer *pPlayer, CMoveData *pMoveData ) {} + virtual void FinishMove( C_BasePlayer *player, CUserCmd *ucmd, CMoveData *move ) {} + virtual bool IsPredicted() const { return false; } + virtual void ItemPostFrame( C_BasePlayer *pPlayer ) {} + virtual bool IsSelfAnimating() { return false; }; + virtual void GetRenderBounds( Vector& theMins, Vector& theMaxs ); + +private: + + CHandle<C_BasePlayer> m_hPlayer; + CHandle<C_BasePlayer> m_hPrevPlayer; + + bool m_bEnterAnimOn; + bool m_bExitAnimOn; + Vector m_vecEyeExitEndpoint; + + Vector m_vecOldShadowDir; + + ViewSmoothingData_t m_ViewSmoothingData; +}; + + +IMPLEMENT_CLIENTCLASS_DT(C_PropCannon, DT_PropCannon, CPropCannon) + RecvPropEHandle( RECVINFO(m_hPlayer) ), + RecvPropBool( RECVINFO( m_bEnterAnimOn ) ), + RecvPropBool( RECVINFO( m_bExitAnimOn ) ), + RecvPropVector( RECVINFO( m_vecEyeExitEndpoint ) ), +END_RECV_TABLE() + + +BEGIN_DATADESC( C_PropCannon ) + DEFINE_EMBEDDED( m_ViewSmoothingData ), +END_DATADESC() + + +#define ROLL_CURVE_ZERO 5 // roll less than this is clamped to zero +#define ROLL_CURVE_LINEAR 45 // roll greater than this is copied out + +#define PITCH_CURVE_ZERO 10 // pitch less than this is clamped to zero +#define PITCH_CURVE_LINEAR 45 // pitch greater than this is copied out + // spline in between + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PropCannon::C_PropCannon( void ) +{ + memset( &m_ViewSmoothingData, 0, sizeof( m_ViewSmoothingData ) ); + m_ViewSmoothingData.pVehicle = this; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : updateType - +//----------------------------------------------------------------------------- +void C_PropCannon::PreDataUpdate( DataUpdateType_t updateType ) +{ + BaseClass::PreDataUpdate( updateType ); + + m_hPrevPlayer = m_hPlayer; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_BaseCombatCharacter *C_PropCannon::GetPassenger( int nRole ) +{ + if ( nRole == VEHICLE_ROLE_DRIVER ) + return m_hPlayer.Get(); + + return NULL; +} + +//----------------------------------------------------------------------------- +// Returns the role of the passenger +//----------------------------------------------------------------------------- +int C_PropCannon::GetPassengerRole( C_BaseCombatCharacter *pPassenger ) +{ + if ( m_hPlayer.Get() == pPassenger ) + return VEHICLE_ROLE_DRIVER; + + return VEHICLE_ROLE_NONE; +} + +//----------------------------------------------------------------------------- +// Purpose: Modify the player view/camera while in a vehicle +//----------------------------------------------------------------------------- +void C_PropCannon::GetVehicleViewPosition( int nRole, Vector *pAbsOrigin, QAngle *pAbsAngles, float *pFOV /*=NULL*/ ) +{ + SharedVehicleViewSmoothing( m_hPlayer, + pAbsOrigin, pAbsAngles, + m_bEnterAnimOn, m_bExitAnimOn, + m_vecEyeExitEndpoint, + &m_ViewSmoothingData, + pFOV ); +} + + +//----------------------------------------------------------------------------- +// Futzes with the clip planes +//----------------------------------------------------------------------------- +void C_PropCannon::GetVehicleClipPlanes( float &flZNear, float &flZFar ) const +{ + // FIXME: Need something a better long-term, this fixes the buggy. + flZNear = 6; +} + + +//----------------------------------------------------------------------------- +// Renders hud elements +//----------------------------------------------------------------------------- +void C_PropCannon::DrawHudElements( ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : theMins - +// theMaxs - +//----------------------------------------------------------------------------- +void C_PropCannon::GetRenderBounds( Vector &theMins, Vector &theMaxs ) +{ + // This is kind of hacky:( Add 660.0 to the y coordinate of the bounding box to + // allow for the full extension of the crane arm. + BaseClass::GetRenderBounds( theMins, theMaxs ); + theMaxs.y += 660.0f; +} + diff --git a/game/client/hl2/c_vehicle_crane.cpp b/game/client/hl2/c_vehicle_crane.cpp new file mode 100644 index 0000000..933bef8 --- /dev/null +++ b/game/client/hl2/c_vehicle_crane.cpp @@ -0,0 +1,151 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include <vgui_controls/Controls.h> +#include <Color.h> +#include "c_vehicle_crane.h" +#include "view.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +int ScreenTransform( const Vector& point, Vector& screen ); + +IMPLEMENT_CLIENTCLASS_DT(C_PropCrane, DT_PropCrane, CPropCrane) + RecvPropEHandle( RECVINFO(m_hPlayer) ), + RecvPropBool( RECVINFO(m_bMagnetOn) ), + RecvPropBool( RECVINFO( m_bEnterAnimOn ) ), + RecvPropBool( RECVINFO( m_bExitAnimOn ) ), + RecvPropVector( RECVINFO( m_vecEyeExitEndpoint ) ), +END_RECV_TABLE() + + +BEGIN_DATADESC( C_PropCrane ) + DEFINE_EMBEDDED( m_ViewSmoothingData ), +END_DATADESC() + + +#define ROLL_CURVE_ZERO 5 // roll less than this is clamped to zero +#define ROLL_CURVE_LINEAR 45 // roll greater than this is copied out + +#define PITCH_CURVE_ZERO 10 // pitch less than this is clamped to zero +#define PITCH_CURVE_LINEAR 45 // pitch greater than this is copied out + // spline in between + +#define CRANE_FOV 75 + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PropCrane::C_PropCrane( void ) +{ + memset( &m_ViewSmoothingData, 0, sizeof( m_ViewSmoothingData ) ); + m_ViewSmoothingData.pVehicle = this; + m_ViewSmoothingData.flFOV = CRANE_FOV; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : updateType - +//----------------------------------------------------------------------------- +void C_PropCrane::PreDataUpdate( DataUpdateType_t updateType ) +{ + BaseClass::PreDataUpdate( updateType ); + + m_hPrevPlayer = m_hPlayer; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PropCrane::PostDataUpdate( DataUpdateType_t updateType ) +{ + BaseClass::PostDataUpdate( updateType ); + + // Store off the old shadow direction + if ( m_hPlayer && !m_hPrevPlayer ) + { + m_vecOldShadowDir = g_pClientShadowMgr->GetShadowDirection(); + //Vector vecDown = m_vecOldShadowDir - Vector(0,0,0.5); + //VectorNormalize( vecDown ); + Vector vecDown = Vector(0,0,-1); + g_pClientShadowMgr->SetShadowDirection( vecDown ); + } + else if ( !m_hPlayer && m_hPrevPlayer ) + { + g_pClientShadowMgr->SetShadowDirection( m_vecOldShadowDir ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_BaseCombatCharacter *C_PropCrane::GetPassenger( int nRole ) +{ + if ( nRole == VEHICLE_ROLE_DRIVER ) + return m_hPlayer.Get(); + + return NULL; +} + +//----------------------------------------------------------------------------- +// Returns the role of the passenger +//----------------------------------------------------------------------------- +int C_PropCrane::GetPassengerRole( C_BaseCombatCharacter *pPassenger ) +{ + if ( m_hPlayer.Get() == pPassenger ) + return VEHICLE_ROLE_DRIVER; + + return VEHICLE_ROLE_NONE; +} + +//----------------------------------------------------------------------------- +// Purpose: Modify the player view/camera while in a vehicle +//----------------------------------------------------------------------------- +void C_PropCrane::GetVehicleViewPosition( int nRole, Vector *pAbsOrigin, QAngle *pAbsAngles, float *pFOV /*=NULL*/ ) +{ + SharedVehicleViewSmoothing( m_hPlayer, + pAbsOrigin, pAbsAngles, + m_bEnterAnimOn, m_bExitAnimOn, + m_vecEyeExitEndpoint, + &m_ViewSmoothingData, + pFOV ); +} + + +//----------------------------------------------------------------------------- +// Futzes with the clip planes +//----------------------------------------------------------------------------- +void C_PropCrane::GetVehicleClipPlanes( float &flZNear, float &flZFar ) const +{ + // FIXME: Need something a better long-term, this fixes the buggy. + flZNear = 6; +} + + +//----------------------------------------------------------------------------- +// Renders hud elements +//----------------------------------------------------------------------------- +void C_PropCrane::DrawHudElements( ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : theMins - +// theMaxs - +//----------------------------------------------------------------------------- +void C_PropCrane::GetRenderBounds( Vector &theMins, Vector &theMaxs ) +{ + // This is kind of hacky:( Add 660.0 to the y coordinate of the bounding box to + // allow for the full extension of the crane arm. + BaseClass::GetRenderBounds( theMins, theMaxs ); + theMaxs.y += 660.0f; +} + diff --git a/game/client/hl2/c_vehicle_crane.h b/game/client/hl2/c_vehicle_crane.h new file mode 100644 index 0000000..81ca6d1 --- /dev/null +++ b/game/client/hl2/c_vehicle_crane.h @@ -0,0 +1,80 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "iclientvehicle.h" +#include "vehicle_viewblend_shared.h" + +#ifndef C_VEHICLE_CRANE_H +#define C_VEHICLE_CRANE_H +#pragma once + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_PropCrane : public C_BaseAnimating, public IClientVehicle +{ + + DECLARE_CLASS( C_PropCrane, C_BaseAnimating ); + +public: + + DECLARE_CLIENTCLASS(); + DECLARE_DATADESC(); + + C_PropCrane(); + + void PreDataUpdate( DataUpdateType_t updateType ); + void PostDataUpdate( DataUpdateType_t updateType ); + + bool IsMagnetOn( void ) { return m_bMagnetOn; } + +public: + + // IClientVehicle overrides. + virtual void GetVehicleViewPosition( int nRole, Vector *pOrigin, QAngle *pAngles, float *pFOV =NULL ); + virtual void GetVehicleFOV( float &flFOV ) { flFOV = 0.0f; } + virtual void DrawHudElements(); + virtual bool IsPassengerUsingStandardWeapons( int nRole = VEHICLE_ROLE_DRIVER ) { return false; } + virtual void UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd ) {} + virtual C_BaseCombatCharacter* GetPassenger( int nRole ); + virtual int GetPassengerRole( C_BaseCombatCharacter *pPassenger ); + virtual void GetVehicleClipPlanes( float &flZNear, float &flZFar ) const; + virtual int GetPrimaryAmmoType() const { return -1; } + virtual int GetPrimaryAmmoCount() const { return -1; } + virtual int GetPrimaryAmmoClip() const { return -1; } + virtual bool PrimaryAmmoUsesClips() const { return false; } + virtual int GetJoystickResponseCurve() const { return 0; } + +public: + + // C_BaseEntity overrides. + virtual IClientVehicle* GetClientVehicle() { return this; } + virtual C_BaseEntity *GetVehicleEnt() { return this; } + virtual void SetupMove( C_BasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move ) {} + virtual void ProcessMovement( C_BasePlayer *pPlayer, CMoveData *pMoveData ) {} + virtual void FinishMove( C_BasePlayer *player, CUserCmd *ucmd, CMoveData *move ) {} + virtual bool IsPredicted() const { return false; } + virtual void ItemPostFrame( C_BasePlayer *pPlayer ) {} + virtual bool IsSelfAnimating() { return false; }; + virtual void GetRenderBounds( Vector& theMins, Vector& theMaxs ); + +private: + + CHandle<C_BasePlayer> m_hPlayer; + CHandle<C_BasePlayer> m_hPrevPlayer; + + bool m_bEnterAnimOn; + bool m_bExitAnimOn; + Vector m_vecEyeExitEndpoint; + + bool m_bMagnetOn; + + Vector m_vecOldShadowDir; + + ViewSmoothingData_t m_ViewSmoothingData; +}; + +#endif // C_VEHICLE_CRANE_H diff --git a/game/client/hl2/c_vehicle_prisoner_pod.cpp b/game/client/hl2/c_vehicle_prisoner_pod.cpp new file mode 100644 index 0000000..1b78bdd --- /dev/null +++ b/game/client/hl2/c_vehicle_prisoner_pod.cpp @@ -0,0 +1,237 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "hud.h" +#include "c_physicsprop.h" +#include "iclientvehicle.h" +#include <vgui_controls/Controls.h> +#include <Color.h> +#include "vehicle_viewblend_shared.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +extern float RemapAngleRange( float startInterval, float endInterval, float value ); + + +#define ROLL_CURVE_ZERO 5 // roll less than this is clamped to zero +#define ROLL_CURVE_LINEAR 45 // roll greater than this is copied out + +#define PITCH_CURVE_ZERO 10 // pitch less than this is clamped to zero +#define PITCH_CURVE_LINEAR 45 // pitch greater than this is copied out + // spline in between + +#define POD_VIEW_FOV 90 +#define POD_VIEW_YAW_MIN -60 +#define POD_VIEW_YAW_MAX 60 +#define POD_VIEW_PITCH_MIN -90 +#define POD_VIEW_PITCH_MAX 38 // Don't let players look down and see that the pod is empty + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_PropVehiclePrisonerPod : public C_PhysicsProp, public IClientVehicle +{ + DECLARE_CLASS( C_PropVehiclePrisonerPod, C_PhysicsProp ); + +public: + + DECLARE_CLIENTCLASS(); + DECLARE_DATADESC(); + + C_PropVehiclePrisonerPod(); + + void PreDataUpdate( DataUpdateType_t updateType ); + void PostDataUpdate( DataUpdateType_t updateType ); + +public: + + // IClientVehicle overrides. + virtual void GetVehicleViewPosition( int nRole, Vector *pOrigin, QAngle *pAngles, float *pFOV = NULL ); + virtual void GetVehicleFOV( float &flFOV ) + { + flFOV = m_flFOV; + } + virtual void DrawHudElements(); + virtual bool IsPassengerUsingStandardWeapons( int nRole = VEHICLE_ROLE_DRIVER ) { return false; } + virtual void UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd ); + virtual C_BaseCombatCharacter* GetPassenger( int nRole ); + virtual int GetPassengerRole( C_BaseCombatCharacter *pEnt ); + virtual void GetVehicleClipPlanes( float &flZNear, float &flZFar ) const; + virtual int GetPrimaryAmmoType() const { return -1; } + virtual int GetPrimaryAmmoCount() const { return -1; } + virtual int GetPrimaryAmmoClip() const { return -1; } + virtual bool PrimaryAmmoUsesClips() const { return false; } + virtual int GetJoystickResponseCurve() const { return 0; } + +public: + + // C_BaseEntity overrides. + virtual IClientVehicle* GetClientVehicle() { return this; } + virtual C_BaseEntity *GetVehicleEnt() { return this; } + virtual void SetupMove( C_BasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move ) {} + virtual void ProcessMovement( C_BasePlayer *pPlayer, CMoveData *pMoveData ) {} + virtual void FinishMove( C_BasePlayer *player, CUserCmd *ucmd, CMoveData *move ) {} + virtual bool IsPredicted() const { return false; } + virtual void ItemPostFrame( C_BasePlayer *pPlayer ) {} + virtual bool IsSelfAnimating() { return false; }; + +private: + + CHandle<C_BasePlayer> m_hPlayer; + CHandle<C_BasePlayer> m_hPrevPlayer; + + bool m_bEnterAnimOn; + bool m_bExitAnimOn; + Vector m_vecEyeExitEndpoint; + float m_flFOV; // The current FOV (changes during entry/exit anims). + + ViewSmoothingData_t m_ViewSmoothingData; +}; + + +IMPLEMENT_CLIENTCLASS_DT(C_PropVehiclePrisonerPod, DT_PropVehiclePrisonerPod, CPropVehiclePrisonerPod) + RecvPropEHandle( RECVINFO(m_hPlayer) ), + RecvPropBool( RECVINFO( m_bEnterAnimOn ) ), + RecvPropBool( RECVINFO( m_bExitAnimOn ) ), + RecvPropVector( RECVINFO( m_vecEyeExitEndpoint ) ), +END_RECV_TABLE() + + +BEGIN_DATADESC( C_PropVehiclePrisonerPod ) + DEFINE_EMBEDDED( m_ViewSmoothingData ), +END_DATADESC() + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_PropVehiclePrisonerPod::C_PropVehiclePrisonerPod( void ) +{ + memset( &m_ViewSmoothingData, 0, sizeof( m_ViewSmoothingData ) ); + + m_ViewSmoothingData.pVehicle = this; + m_ViewSmoothingData.bClampEyeAngles = true; + m_ViewSmoothingData.flPitchCurveZero = PITCH_CURVE_ZERO; + m_ViewSmoothingData.flPitchCurveLinear = PITCH_CURVE_LINEAR; + m_ViewSmoothingData.flRollCurveZero = ROLL_CURVE_ZERO; + m_ViewSmoothingData.flRollCurveLinear = ROLL_CURVE_LINEAR; + m_ViewSmoothingData.flFOV = POD_VIEW_FOV; + + m_flFOV = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : updateType - +//----------------------------------------------------------------------------- +void C_PropVehiclePrisonerPod::PreDataUpdate( DataUpdateType_t updateType ) +{ + BaseClass::PreDataUpdate( updateType ); + + m_hPrevPlayer = m_hPlayer; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PropVehiclePrisonerPod::PostDataUpdate( DataUpdateType_t updateType ) +{ + BaseClass::PostDataUpdate( updateType ); + + if ( !m_hPlayer && m_hPrevPlayer ) + { + // They have just exited the vehicle. + // Sometimes we never reach the end of our exit anim, such as if the + // animation doesn't have fadeout 0 specified in the QC, so we fail to + // catch it in VehicleViewSmoothing. Catch it here instead. + m_ViewSmoothingData.bWasRunningAnim = false; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_BaseCombatCharacter *C_PropVehiclePrisonerPod::GetPassenger( int nRole ) +{ + if ( nRole == VEHICLE_ROLE_DRIVER ) + return m_hPlayer.Get(); + + return NULL; +} + + +//----------------------------------------------------------------------------- +// Returns the role of the passenger +//----------------------------------------------------------------------------- +int C_PropVehiclePrisonerPod::GetPassengerRole( C_BaseCombatCharacter *pPassenger ) +{ + if ( m_hPlayer.Get() == pPassenger ) + return VEHICLE_ROLE_DRIVER; + + return VEHICLE_ROLE_NONE; +} + + +//----------------------------------------------------------------------------- +// Purpose: Modify the player view/camera while in a vehicle +//----------------------------------------------------------------------------- +void C_PropVehiclePrisonerPod::GetVehicleViewPosition( int nRole, Vector *pAbsOrigin, QAngle *pAbsAngles, float *pFOV /*=NULL*/ ) +{ + SharedVehicleViewSmoothing( m_hPlayer, + pAbsOrigin, pAbsAngles, + m_bEnterAnimOn, m_bExitAnimOn, + m_vecEyeExitEndpoint, + &m_ViewSmoothingData, + pFOV ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pLocalPlayer - +// pCmd - +//----------------------------------------------------------------------------- +void C_PropVehiclePrisonerPod::UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd ) +{ + int eyeAttachmentIndex = LookupAttachment( "vehicle_driver_eyes" ); + Vector vehicleEyeOrigin; + QAngle vehicleEyeAngles; + GetAttachmentLocal( eyeAttachmentIndex, vehicleEyeOrigin, vehicleEyeAngles ); + + // Limit the yaw. + float flAngleDiff = AngleDiff( pCmd->viewangles.y, vehicleEyeAngles.y ); + flAngleDiff = clamp( flAngleDiff, POD_VIEW_YAW_MIN, POD_VIEW_YAW_MAX ); + pCmd->viewangles.y = vehicleEyeAngles.y + flAngleDiff; + + // Limit the pitch -- don't let them look down into the empty pod! + flAngleDiff = AngleDiff( pCmd->viewangles.x, vehicleEyeAngles.x ); + flAngleDiff = clamp( flAngleDiff, POD_VIEW_PITCH_MIN, POD_VIEW_PITCH_MAX ); + pCmd->viewangles.x = vehicleEyeAngles.x + flAngleDiff; +} + + +//----------------------------------------------------------------------------- +// Futzes with the clip planes +//----------------------------------------------------------------------------- +void C_PropVehiclePrisonerPod::GetVehicleClipPlanes( float &flZNear, float &flZFar ) const +{ + // Pod doesn't need to adjust the clip planes. + //flZNear = 6; +} + + +//----------------------------------------------------------------------------- +// Renders hud elements +//----------------------------------------------------------------------------- +void C_PropVehiclePrisonerPod::DrawHudElements( ) +{ +} + + diff --git a/game/client/hl2/c_waterbullet.cpp b/game/client/hl2/c_waterbullet.cpp new file mode 100644 index 0000000..c758069 --- /dev/null +++ b/game/client/hl2/c_waterbullet.cpp @@ -0,0 +1,121 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "particles_simple.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +class C_WaterBullet : public C_BaseAnimating +{ +public: + + DECLARE_CLIENTCLASS(); + DECLARE_CLASS( C_WaterBullet, C_BaseAnimating ); + + C_WaterBullet( void ) {}; + ~C_WaterBullet( void ) {}; + + void OnDataChanged( DataUpdateType_t updateType ) + { + BaseClass::OnDataChanged( updateType ); + + if ( updateType == DATA_UPDATE_CREATED ) + { + m_pEmitter = CSimpleEmitter::Create( "FX_Bubble" ); + m_pEmitter->SetSortOrigin( GetAbsOrigin() ); + + m_vecLastOrigin = GetAbsOrigin(); + } + } + +#define BUBBLES_PER_INCH 0.2 + + void AddEntity( void ) + { + Vector direction = GetAbsOrigin() - m_vecLastOrigin; + float flDist = VectorNormalize( direction ); + + int numBubbles = (int) ( flDist * BUBBLES_PER_INCH ); + + if ( numBubbles < 1 ) + numBubbles = 1; + + // Make bubbles + SimpleParticle *sParticle; + + Vector offset; + + for ( int i = 0; i < numBubbles; i++ ) + { + offset = m_vecLastOrigin + ( direction * ( flDist / numBubbles ) * i ) + RandomVector( -2.5f, 2.5f ); + + sParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), m_pEmitter->GetPMaterial( "effects/bubble" ), offset ); + + if ( sParticle ) + { + sParticle->m_flLifetime = 0.0f; + sParticle->m_flDieTime = random->RandomFloat( 0.75f, 1.25f ); + + sParticle->m_flRoll = 0; + sParticle->m_flRollDelta = 0; + + unsigned char color = random->RandomInt( 128, 255 ); + + sParticle->m_uchColor[0] = color; + sParticle->m_uchColor[1] = color; + sParticle->m_uchColor[2] = color; + sParticle->m_uchStartAlpha = 255; + sParticle->m_uchEndAlpha = 0; + sParticle->m_uchStartSize = random->RandomInt( 1, 2 ); + sParticle->m_uchEndSize = sParticle->m_uchStartSize; + + sParticle->m_vecVelocity = ( direction * 64.0f ) + Vector( 0, 0, 32 ); + } + + sParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), m_pEmitter->GetPMaterial( "effects/splash2" ), offset ); + + if ( sParticle ) + { + sParticle->m_flLifetime = 0.0f; + sParticle->m_flDieTime = 0.2f; + + sParticle->m_flRoll = random->RandomInt( 0, 360 ); + sParticle->m_flRollDelta = random->RandomInt( -4, 4 ); + + unsigned char color = random->RandomInt( 200, 255 ); + + sParticle->m_uchColor[0] = color; + sParticle->m_uchColor[1] = color; + sParticle->m_uchColor[2] = color; + sParticle->m_uchStartAlpha = 128; + sParticle->m_uchEndAlpha = 0; + sParticle->m_uchStartSize = 2; + sParticle->m_uchEndSize = sParticle->m_uchStartSize * 4; + + sParticle->m_vecVelocity = ( direction * 64.0f ) + Vector( 0, 0, 32 ); + } + } + + // Save our last position + m_vecLastOrigin = GetAbsOrigin(); + + BaseClass::AddEntity(); + } + + bool ShouldDraw( void ) { return true; } + +private: + C_WaterBullet( const C_WaterBullet & ); + + CSmartPtr<CSimpleEmitter> m_pEmitter; + + Vector m_vecLastOrigin; +}; + +IMPLEMENT_CLIENTCLASS_DT( C_WaterBullet, DT_WaterBullet, CWaterBullet ) +END_RECV_TABLE() diff --git a/game/client/hl2/c_weapon__stubs_hl2.cpp b/game/client/hl2/c_weapon__stubs_hl2.cpp new file mode 100644 index 0000000..68693bf --- /dev/null +++ b/game/client/hl2/c_weapon__stubs_hl2.cpp @@ -0,0 +1,47 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "c_weapon__stubs.h" +#include "basehlcombatweapon_shared.h" +#include "c_basehlcombatweapon.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +STUB_WEAPON_CLASS( cycler_weapon, WeaponCycler, C_BaseCombatWeapon ); + +STUB_WEAPON_CLASS( weapon_binoculars, WeaponBinoculars, C_BaseHLCombatWeapon ); +STUB_WEAPON_CLASS( weapon_bugbait, WeaponBugBait, C_BaseHLCombatWeapon ); +STUB_WEAPON_CLASS( weapon_flaregun, Flaregun, C_BaseHLCombatWeapon ); +STUB_WEAPON_CLASS( weapon_annabelle, WeaponAnnabelle, C_BaseHLCombatWeapon ); +STUB_WEAPON_CLASS( weapon_gauss, WeaponGaussGun, C_BaseHLCombatWeapon ); +STUB_WEAPON_CLASS( weapon_cubemap, WeaponCubemap, C_BaseCombatWeapon ); +STUB_WEAPON_CLASS( weapon_alyxgun, WeaponAlyxGun, C_HLSelectFireMachineGun ); +STUB_WEAPON_CLASS( weapon_citizenpackage, WeaponCitizenPackage, C_BaseHLCombatWeapon ); +STUB_WEAPON_CLASS( weapon_citizensuitcase, WeaponCitizenSuitcase, C_WeaponCitizenPackage ); + +#ifndef HL2MP +STUB_WEAPON_CLASS( weapon_ar2, WeaponAR2, C_HLMachineGun ); +STUB_WEAPON_CLASS( weapon_frag, WeaponFrag, C_BaseHLCombatWeapon ); +STUB_WEAPON_CLASS( weapon_rpg, WeaponRPG, C_BaseHLCombatWeapon ); +STUB_WEAPON_CLASS( weapon_pistol, WeaponPistol, C_BaseHLCombatWeapon ); +STUB_WEAPON_CLASS( weapon_shotgun, WeaponShotgun, C_BaseHLCombatWeapon ); +STUB_WEAPON_CLASS( weapon_smg1, WeaponSMG1, C_HLSelectFireMachineGun ); +STUB_WEAPON_CLASS( weapon_357, Weapon357, C_BaseHLCombatWeapon ); +STUB_WEAPON_CLASS( weapon_crossbow, WeaponCrossbow, C_BaseHLCombatWeapon ); +STUB_WEAPON_CLASS( weapon_slam, Weapon_SLAM, C_BaseHLCombatWeapon ); +STUB_WEAPON_CLASS( weapon_crowbar, WeaponCrowbar, C_BaseHLBludgeonWeapon ); +#ifdef HL2_EPISODIC +STUB_WEAPON_CLASS( weapon_hopwire, WeaponHopwire, C_BaseHLCombatWeapon ); +//STUB_WEAPON_CLASS( weapon_proto1, WeaponProto1, C_BaseHLCombatWeapon ); +#endif +#ifdef HL2_LOSTCOAST +STUB_WEAPON_CLASS( weapon_oldmanharpoon, WeaponOldManHarpoon, C_WeaponCitizenPackage ); +#endif +#endif + + diff --git a/game/client/hl2/c_weapon_crossbow.cpp b/game/client/hl2/c_weapon_crossbow.cpp new file mode 100644 index 0000000..a486041 --- /dev/null +++ b/game/client/hl2/c_weapon_crossbow.cpp @@ -0,0 +1,159 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "model_types.h" +#include "clienteffectprecachesystem.h" +#include "fx.h" +#include "c_te_effect_dispatch.h" +#include "beamdraw.h" + +CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectCrossbow ) +CLIENTEFFECT_MATERIAL( "effects/muzzleflash1" ) +CLIENTEFFECT_REGISTER_END() + +// +// Crossbow bolt +// + +class C_CrossbowBolt : public C_BaseCombatCharacter +{ + DECLARE_CLASS( C_CrossbowBolt, C_BaseCombatCharacter ); + DECLARE_CLIENTCLASS(); +public: + + C_CrossbowBolt( void ); + + virtual RenderGroup_t GetRenderGroup( void ) + { + // We want to draw translucent bits as well as our main model + return RENDER_GROUP_TWOPASS; + } + + virtual void ClientThink( void ); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual int DrawModel( int flags ); + +private: + + C_CrossbowBolt( const C_CrossbowBolt & ); // not defined, not accessible + + Vector m_vecLastOrigin; + bool m_bUpdated; +}; + +IMPLEMENT_CLIENTCLASS_DT( C_CrossbowBolt, DT_CrossbowBolt, CCrossbowBolt ) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_CrossbowBolt::C_CrossbowBolt( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : updateType - +//----------------------------------------------------------------------------- +void C_CrossbowBolt::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + if ( updateType == DATA_UPDATE_CREATED ) + { + m_bUpdated = false; + m_vecLastOrigin = GetAbsOrigin(); + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flags - +// Output : int +//----------------------------------------------------------------------------- +int C_CrossbowBolt::DrawModel( int flags ) +{ + // See if we're drawing the motion blur + if ( flags & STUDIO_TRANSPARENCY ) + { + float color[3]; + IMaterial *pBlurMaterial = materials->FindMaterial( "effects/muzzleflash1", NULL, false ); + + Vector vecDir = GetAbsOrigin() - m_vecLastOrigin; + float speed = VectorNormalize( vecDir ); + + speed = clamp( speed, 0, 32 ); + + if ( speed > 0 ) + { + float stepSize = MIN( ( speed * 0.5f ), 4.0f ); + + Vector spawnPos = GetAbsOrigin() + ( vecDir * 24.0f ); + Vector spawnStep = -vecDir * stepSize; + + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->Bind( pBlurMaterial ); + + float alpha; + + // Draw the motion blurred trail + for ( int i = 0; i < 20; i++ ) + { + spawnPos += spawnStep; + + alpha = RemapValClamped( i, 5, 11, 0.25f, 0.05f ); + + color[0] = color[1] = color[2] = alpha; + + DrawHalo( pBlurMaterial, spawnPos, 3.0f, color ); + } + } + + if ( gpGlobals->frametime > 0.0f && !m_bUpdated) + { + m_bUpdated = true; + m_vecLastOrigin = GetAbsOrigin(); + } + + return 1; + } + + // Draw the normal portion + return BaseClass::DrawModel( flags ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_CrossbowBolt::ClientThink( void ) +{ + m_bUpdated = false; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &data - +//----------------------------------------------------------------------------- +void CrosshairLoadCallback( const CEffectData &data ) +{ + IClientRenderable *pRenderable = data.GetRenderable( ); + if ( !pRenderable ) + return; + + Vector position; + QAngle angles; + + // If we found the attachment, emit sparks there + if ( pRenderable->GetAttachment( data.m_nAttachmentIndex, position, angles ) ) + { + FX_ElectricSpark( position, 1.0f, 1.0f, NULL ); + } +} + +DECLARE_CLIENT_EFFECT( "CrossbowLoad", CrosshairLoadCallback ); diff --git a/game/client/hl2/c_weapon_gravitygun.cpp b/game/client/hl2/c_weapon_gravitygun.cpp new file mode 100644 index 0000000..a328584 --- /dev/null +++ b/game/client/hl2/c_weapon_gravitygun.cpp @@ -0,0 +1,166 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#include "cbase.h" +#include "hud.h" +#include "in_buttons.h" +#include "beamdraw.h" +#include "c_weapon__stubs.h" +#include "clienteffectprecachesystem.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectGravityGun ) +CLIENTEFFECT_MATERIAL( "sprites/physbeam" ) +CLIENTEFFECT_REGISTER_END() + +class C_BeamQuadratic : public CDefaultClientRenderable +{ +public: + C_BeamQuadratic(); + void Update( C_BaseEntity *pOwner ); + + // IClientRenderable + virtual const Vector& GetRenderOrigin( void ) { return m_worldPosition; } + virtual const QAngle& GetRenderAngles( void ) { return vec3_angle; } + virtual bool ShouldDraw( void ) { return true; } + virtual bool IsTransparent( void ) { return true; } + virtual bool ShouldReceiveProjectedTextures( int flags ) { return false; } + virtual int DrawModel( int flags ); + + // Returns the bounds relative to the origin (render bounds) + virtual void GetRenderBounds( Vector& mins, Vector& maxs ) + { + // bogus. But it should draw if you can see the end point + mins.Init(-32,-32,-32); + maxs.Init(32,32,32); + } + + C_BaseEntity *m_pOwner; + Vector m_targetPosition; + Vector m_worldPosition; + int m_active; + int m_glueTouching; + int m_viewModelIndex; +}; + + +class C_WeaponGravityGun : public C_BaseCombatWeapon +{ + DECLARE_CLASS( C_WeaponGravityGun, C_BaseCombatWeapon ); +public: + C_WeaponGravityGun() {} + + DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); + + int KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ) + { + if ( gHUD.m_iKeyBits & IN_ATTACK ) + { + switch ( keynum ) + { + case MOUSE_WHEEL_UP: + gHUD.m_iKeyBits |= IN_WEAPON1; + return 0; + + case MOUSE_WHEEL_DOWN: + gHUD.m_iKeyBits |= IN_WEAPON2; + return 0; + } + } + + // Allow engine to process + return BaseClass::KeyInput( down, keynum, pszCurrentBinding ); + } + + void OnDataChanged( DataUpdateType_t updateType ) + { + BaseClass::OnDataChanged( updateType ); + m_beam.Update( this ); + } + +private: + C_WeaponGravityGun( const C_WeaponGravityGun & ); + + C_BeamQuadratic m_beam; +}; + +STUB_WEAPON_CLASS_IMPLEMENT( weapon_physgun, C_WeaponGravityGun ); + +IMPLEMENT_CLIENTCLASS_DT( C_WeaponGravityGun, DT_WeaponGravityGun, CWeaponGravityGun ) + RecvPropVector( RECVINFO_NAME(m_beam.m_targetPosition,m_targetPosition) ), + RecvPropVector( RECVINFO_NAME(m_beam.m_worldPosition, m_worldPosition) ), + RecvPropInt( RECVINFO_NAME(m_beam.m_active, m_active) ), + RecvPropInt( RECVINFO_NAME(m_beam.m_glueTouching, m_glueTouching) ), + RecvPropInt( RECVINFO_NAME(m_beam.m_viewModelIndex, m_viewModelIndex) ), +END_RECV_TABLE() + + +C_BeamQuadratic::C_BeamQuadratic() +{ + m_pOwner = NULL; +} + +void C_BeamQuadratic::Update( C_BaseEntity *pOwner ) +{ + m_pOwner = pOwner; + if ( m_active ) + { + if ( m_hRenderHandle == INVALID_CLIENT_RENDER_HANDLE ) + { + ClientLeafSystem()->AddRenderable( this, RENDER_GROUP_TRANSLUCENT_ENTITY ); + } + else + { + ClientLeafSystem()->RenderableChanged( m_hRenderHandle ); + } + } + else if ( !m_active && m_hRenderHandle != INVALID_CLIENT_RENDER_HANDLE ) + { + ClientLeafSystem()->RemoveRenderable( m_hRenderHandle ); + } +} + + +int C_BeamQuadratic::DrawModel( int ) +{ + Vector points[3]; + QAngle tmpAngle; + + if ( !m_active ) + return 0; + + C_BaseEntity *pEnt = cl_entitylist->GetEnt( m_viewModelIndex ); + if ( !pEnt ) + return 0; + pEnt->GetAttachment( 1, points[0], tmpAngle ); + + points[1] = 0.5 * (m_targetPosition + points[0]); + + // a little noise 11t & 13t should be somewhat non-periodic looking + //points[1].z += 4*sin( gpGlobals->curtime*11 ) + 5*cos( gpGlobals->curtime*13 ); + points[2] = m_worldPosition; + + IMaterial *pMat = materials->FindMaterial( "sprites/physbeam", TEXTURE_GROUP_CLIENT_EFFECTS ); + Vector color; + if ( m_glueTouching ) + { + color.Init(1,0,0); + } + else + { + color.Init(1,1,1); + } + + float scrollOffset = gpGlobals->curtime - (int)gpGlobals->curtime; + materials->Bind( pMat ); + DrawBeamQuadratic( points[0], points[1], points[2], 13, color, scrollOffset ); + return 1; +} + diff --git a/game/client/hl2/c_weapon_physcannon.cpp b/game/client/hl2/c_weapon_physcannon.cpp new file mode 100644 index 0000000..5dff9a2 --- /dev/null +++ b/game/client/hl2/c_weapon_physcannon.cpp @@ -0,0 +1,442 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "c_weapon__stubs.h" +#include "c_basehlcombatweapon.h" +#include "fx.h" +#include "particles_localspace.h" +#include "view.h" +#include "particles_attractor.h" + +class C_WeaponPhysCannon: public C_BaseHLCombatWeapon +{ + DECLARE_CLASS( C_WeaponPhysCannon, C_BaseHLCombatWeapon ); +public: + C_WeaponPhysCannon( void ); + + DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual int DrawModel( int flags ); + virtual void ClientThink( void ); + + virtual bool ShouldUseLargeViewModelVROverride() OVERRIDE { return true; } + +private: + + bool SetupEmitter( void ); + + bool m_bIsCurrentlyUpgrading; + float m_flTimeForceView; + float m_flTimeIgnoreForceView; + bool m_bWasUpgraded; + + CSmartPtr<CLocalSpaceEmitter> m_pLocalEmitter; + CSmartPtr<CSimpleEmitter> m_pEmitter; + CSmartPtr<CParticleAttractor> m_pAttractor; +}; + +STUB_WEAPON_CLASS_IMPLEMENT( weapon_physcannon, C_WeaponPhysCannon ); + +IMPLEMENT_CLIENTCLASS_DT( C_WeaponPhysCannon, DT_WeaponPhysCannon, CWeaponPhysCannon ) + RecvPropBool( RECVINFO( m_bIsCurrentlyUpgrading ) ), + RecvPropFloat( RECVINFO( m_flTimeForceView) ), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +C_WeaponPhysCannon::C_WeaponPhysCannon( void ) +{ + m_bWasUpgraded = false; + m_flTimeIgnoreForceView = -1; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void C_WeaponPhysCannon::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + SetNextClientThink( CLIENT_THINK_ALWAYS ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool C_WeaponPhysCannon::SetupEmitter( void ) +{ + if ( !m_pLocalEmitter.IsValid() ) + { + m_pLocalEmitter = CLocalSpaceEmitter::Create( "physpowerup", GetRefEHandle(), LookupAttachment( "core" ) ); + + if ( m_pLocalEmitter.IsValid() == false ) + return false; + } + + if ( !m_pAttractor.IsValid() ) + { + m_pAttractor = CParticleAttractor::Create( vec3_origin, "physpowerup_att" ); + + if ( m_pAttractor.IsValid() == false ) + return false; + } + + if ( !m_pEmitter.IsValid() ) + { + m_pEmitter = CSimpleEmitter::Create( "physpowerup_glow" ); + + if ( m_pEmitter.IsValid() == false ) + return false; + } + + return true; +} + +//----------------------------------------------------------------------------- +// Sorts the components of a vector +//----------------------------------------------------------------------------- +static inline void SortAbsVectorComponents( const Vector& src, int* pVecIdx ) +{ + Vector absVec( fabs(src[0]), fabs(src[1]), fabs(src[2]) ); + + int maxIdx = (absVec[0] > absVec[1]) ? 0 : 1; + if (absVec[2] > absVec[maxIdx]) + { + maxIdx = 2; + } + + // always choose something right-handed.... + switch( maxIdx ) + { + case 0: + pVecIdx[0] = 1; + pVecIdx[1] = 2; + pVecIdx[2] = 0; + break; + case 1: + pVecIdx[0] = 2; + pVecIdx[1] = 0; + pVecIdx[2] = 1; + break; + case 2: + pVecIdx[0] = 0; + pVecIdx[1] = 1; + pVecIdx[2] = 2; + break; + } +} + +//----------------------------------------------------------------------------- +// Compute the bounding box's center, size, and basis +//----------------------------------------------------------------------------- +void ComputeRenderInfo( mstudiobbox_t *pHitBox, const matrix3x4_t &hitboxToWorld, + Vector *pVecAbsOrigin, Vector *pXVec, Vector *pYVec ) +{ + // Compute the center of the hitbox in worldspace + Vector vecHitboxCenter; + VectorAdd( pHitBox->bbmin, pHitBox->bbmax, vecHitboxCenter ); + vecHitboxCenter *= 0.5f; + VectorTransform( vecHitboxCenter, hitboxToWorld, *pVecAbsOrigin ); + + // Get the object's basis + Vector vec[3]; + MatrixGetColumn( hitboxToWorld, 0, vec[0] ); + MatrixGetColumn( hitboxToWorld, 1, vec[1] ); + MatrixGetColumn( hitboxToWorld, 2, vec[2] ); +// vec[1] *= -1.0f; + + Vector vecViewDir; + VectorSubtract( CurrentViewOrigin(), *pVecAbsOrigin, vecViewDir ); + VectorNormalize( vecViewDir ); + + // Project the shadow casting direction into the space of the hitbox + Vector localViewDir; + localViewDir[0] = DotProduct( vec[0], vecViewDir ); + localViewDir[1] = DotProduct( vec[1], vecViewDir ); + localViewDir[2] = DotProduct( vec[2], vecViewDir ); + + // Figure out which vector has the largest component perpendicular + // to the view direction... + // Sort by how perpendicular it is + int vecIdx[3]; + SortAbsVectorComponents( localViewDir, vecIdx ); + + // Here's our hitbox basis vectors; namely the ones that are + // most perpendicular to the view direction + *pXVec = vec[vecIdx[0]]; + *pYVec = vec[vecIdx[1]]; + + // Project them into a plane perpendicular to the view direction + *pXVec -= vecViewDir * DotProduct( vecViewDir, *pXVec ); + *pYVec -= vecViewDir * DotProduct( vecViewDir, *pYVec ); + VectorNormalize( *pXVec ); + VectorNormalize( *pYVec ); + + // Compute the hitbox size + Vector boxSize; + VectorSubtract( pHitBox->bbmax, pHitBox->bbmin, boxSize ); + + // We project the two longest sides into the vectors perpendicular + // to the projection direction, then add in the projection of the perp direction + Vector2D size( boxSize[vecIdx[0]], boxSize[vecIdx[1]] ); + size.x *= fabs( DotProduct( vec[vecIdx[0]], *pXVec ) ); + size.y *= fabs( DotProduct( vec[vecIdx[1]], *pYVec ) ); + + // Add the third component into x and y + size.x += boxSize[vecIdx[2]] * fabs( DotProduct( vec[vecIdx[2]], *pXVec ) ); + size.y += boxSize[vecIdx[2]] * fabs( DotProduct( vec[vecIdx[2]], *pYVec ) ); + + // Bloat a bit, since the shadow wants to extend outside the model a bit + size *= 2.0f; + + // Clamp the minimum size + Vector2DMax( size, Vector2D(10.0f, 10.0f), size ); + + // Factor the size into the xvec + yvec + (*pXVec) *= size.x * 0.5f; + (*pYVec) *= size.y * 0.5f; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flags - +// Output : int +//----------------------------------------------------------------------------- +int C_WeaponPhysCannon::DrawModel( int flags ) +{ + // If we're not ugrading, don't do anything special + if ( m_bIsCurrentlyUpgrading == false && m_bWasUpgraded == false ) + return BaseClass::DrawModel( flags ); + + if ( gpGlobals->frametime == 0 ) + return BaseClass::DrawModel( flags ); + + if ( !m_bReadyToDraw ) + return 0; + + m_bWasUpgraded = true; + + // Create the particle emitter if it's not already + if ( SetupEmitter() ) + { + // Add the power-up particles + + // See if we should draw + if ( m_bReadyToDraw == false ) + return 0; + + C_BaseAnimating *pAnimating = GetBaseAnimating(); + if (!pAnimating) + return 0; + + matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; + if ( !pAnimating->HitboxToWorldTransforms( hitboxbones ) ) + return 0; + + studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() ); + if (!pStudioHdr) + return false; + + mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() ); + if ( !set ) + return false; + + int i; + + float fadePerc = 1.0f; + + if ( m_bIsCurrentlyUpgrading ) + { + Vector vecSkew = vec3_origin; + + // Skew the particles in front or in back of their targets + vecSkew = CurrentViewForward() * 4.0f; + + float spriteScale = 1.0f; + spriteScale = clamp( spriteScale, 0.75f, 1.0f ); + + SimpleParticle *sParticle; + + for ( i = 0; i < set->numhitboxes; ++i ) + { + Vector vecAbsOrigin, xvec, yvec; + mstudiobbox_t *pBox = set->pHitbox(i); + ComputeRenderInfo( pBox, *hitboxbones[pBox->bone], &vecAbsOrigin, &xvec, &yvec ); + + Vector offset; + Vector xDir, yDir; + + xDir = xvec; + float xScale = VectorNormalize( xDir ) * 0.75f; + + yDir = yvec; + float yScale = VectorNormalize( yDir ) * 0.75f; + + int numParticles = clamp( 4.0f * fadePerc, 1, 3 ); + + for ( int j = 0; j < numParticles; j++ ) + { + offset = xDir * Helper_RandomFloat( -xScale*0.5f, xScale*0.5f ) + yDir * Helper_RandomFloat( -yScale*0.5f, yScale*0.5f ); + offset += vecSkew; + + sParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), m_pEmitter->GetPMaterial( "effects/combinemuzzle1" ), vecAbsOrigin + offset ); + + if ( sParticle == NULL ) + return 1; + + sParticle->m_vecVelocity = vec3_origin; + sParticle->m_uchStartSize = 16.0f * spriteScale; + sParticle->m_flDieTime = 0.2f; + sParticle->m_flLifetime = 0.0f; + + sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); + sParticle->m_flRollDelta = Helper_RandomFloat( -2.0f, 2.0f ); + + float alpha = 40; + + sParticle->m_uchColor[0] = alpha; + sParticle->m_uchColor[1] = alpha; + sParticle->m_uchColor[2] = alpha; + sParticle->m_uchStartAlpha = alpha; + sParticle->m_uchEndAlpha = 0; + sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2; + } + } + } + } + + int attachment = LookupAttachment( "core" ); + Vector coreOrigin; + QAngle coreAngles; + + GetAttachment( attachment, coreOrigin, coreAngles ); + + SimpleParticle *sParticle; + + // Do the core effects + for ( int i = 0; i < 4; i++ ) + { + sParticle = (SimpleParticle *) m_pLocalEmitter->AddParticle( sizeof(SimpleParticle), m_pLocalEmitter->GetPMaterial( "effects/strider_muzzle" ), vec3_origin ); + + if ( sParticle == NULL ) + return 1; + + sParticle->m_vecVelocity = vec3_origin; + sParticle->m_flDieTime = 0.1f; + sParticle->m_flLifetime = 0.0f; + + sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); + sParticle->m_flRollDelta = 0.0f; + + float alpha = 255; + + sParticle->m_uchColor[0] = alpha; + sParticle->m_uchColor[1] = alpha; + sParticle->m_uchColor[2] = alpha; + sParticle->m_uchStartAlpha = alpha; + sParticle->m_uchEndAlpha = 0; + + if ( i < 2 ) + { + sParticle->m_uchStartSize = random->RandomFloat( 1, 2 ) * (i+1); + sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f; + } + else + { + if ( random->RandomInt( 0, 20 ) == 0 ) + { + sParticle->m_uchStartSize = random->RandomFloat( 1, 2 ) * (i+1); + sParticle->m_uchEndSize = sParticle->m_uchStartSize * 4.0f; + sParticle->m_flDieTime = 0.25f; + } + else + { + sParticle->m_uchStartSize = random->RandomFloat( 1, 2 ) * (i+1); + sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f; + } + } + } + + if ( m_bWasUpgraded && m_bIsCurrentlyUpgrading ) + { + // Update our attractor point + m_pAttractor->SetAttractorOrigin( coreOrigin ); + + Vector offset; + + for ( int i = 0; i < 4; i++ ) + { + offset = coreOrigin + RandomVector( -32.0f, 32.0f ); + + sParticle = (SimpleParticle *) m_pAttractor->AddParticle( sizeof(SimpleParticle), m_pAttractor->GetPMaterial( "effects/strider_muzzle" ), offset ); + + if ( sParticle == NULL ) + return 1; + + sParticle->m_vecVelocity = Vector(0,0,8); + sParticle->m_flDieTime = 0.5f; + sParticle->m_flLifetime = 0.0f; + + sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); + sParticle->m_flRollDelta = 0.0f; + + float alpha = 255; + + sParticle->m_uchColor[0] = alpha; + sParticle->m_uchColor[1] = alpha; + sParticle->m_uchColor[2] = alpha; + sParticle->m_uchStartAlpha = alpha; + sParticle->m_uchEndAlpha = 0; + + sParticle->m_uchStartSize = random->RandomFloat( 1, 2 ); + sParticle->m_uchEndSize = 0; + } + } + + return BaseClass::DrawModel( flags ); +} + +//--------------------------------------------------------- +// On 360, raise up the player's view if the server has +// asked us to. +//--------------------------------------------------------- +#define PHYSCANNON_RAISE_VIEW_GOAL 0.0f +void C_WeaponPhysCannon::ClientThink( void ) +{ + if( m_flTimeIgnoreForceView > gpGlobals->curtime ) + return; + + float flTime = (m_flTimeForceView - gpGlobals->curtime); + + if( flTime < 0.0f ) + return; + + float flDT = 1.0f - flTime; + if( flDT > 0.0f ) + { + QAngle viewangles; + engine->GetViewAngles( viewangles ); + + if( viewangles.x > PHYSCANNON_RAISE_VIEW_GOAL + 1.0f ) + { + float flDelta = PHYSCANNON_RAISE_VIEW_GOAL - viewangles.x; + viewangles.x += (flDelta * flDT); + engine->SetViewAngles(viewangles); + } + else + { + // We've reached our goal. Ignore the forced view angles for now. + m_flTimeIgnoreForceView = m_flTimeForceView + 0.1f; + } + } + + return BaseClass::ClientThink(); +} + + diff --git a/game/client/hl2/c_weapon_stunstick.cpp b/game/client/hl2/c_weapon_stunstick.cpp new file mode 100644 index 0000000..28359c3 --- /dev/null +++ b/game/client/hl2/c_weapon_stunstick.cpp @@ -0,0 +1,187 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// +#include "cbase.h" +#include "c_basehlcombatweapon.h" +#include "iviewrender_beams.h" +#include "beam_shared.h" +#include "c_weapon__stubs.h" +#include "materialsystem/imaterial.h" +#include "clienteffectprecachesystem.h" +#include "beamdraw.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectStunstick ) +CLIENTEFFECT_MATERIAL( "effects/stunstick" ) +CLIENTEFFECT_REGISTER_END() + +class C_WeaponStunStick : public C_BaseHLBludgeonWeapon +{ + DECLARE_CLASS( C_WeaponStunStick, C_BaseHLBludgeonWeapon ); +public: + DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); + + int DrawModel( int flags ) + { + //FIXME: This sucks, but I can't easily create temp ents... + + if ( m_bActive ) + { + Vector vecOrigin; + QAngle vecAngles; + float color[3]; + + color[0] = color[1] = color[2] = random->RandomFloat( 0.1f, 0.2f ); + + GetAttachment( 1, vecOrigin, vecAngles ); + + Vector vForward; + AngleVectors( vecAngles, &vForward ); + + Vector vEnd = vecOrigin - vForward * 1.0f; + + IMaterial *pMaterial = materials->FindMaterial( "effects/stunstick", NULL, false ); + + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->Bind( pMaterial ); + DrawHalo( pMaterial, vEnd, random->RandomFloat( 4.0f, 6.0f ), color ); + + color[0] = color[1] = color[2] = random->RandomFloat( 0.9f, 1.0f ); + + DrawHalo( pMaterial, vEnd, random->RandomFloat( 2.0f, 3.0f ), color ); + } + + return BaseClass::DrawModel( flags ); + } + + // Do part of our effect + void ClientThink( void ) + { + // Update our effects + if ( m_bActive && + gpGlobals->frametime != 0.0f && + ( random->RandomInt( 0, 5 ) == 0 ) ) + { + Vector vecOrigin; + QAngle vecAngles; + + GetAttachment( 1, vecOrigin, vecAngles ); + + Vector vForward; + AngleVectors( vecAngles, &vForward ); + + Vector vEnd = vecOrigin - vForward * 1.0f; + + // Inner beams + BeamInfo_t beamInfo; + + beamInfo.m_vecStart = vEnd; + Vector offset = RandomVector( -6, 2 ); + + offset += Vector(2,2,2); + beamInfo.m_vecEnd = vecOrigin + offset; + + beamInfo.m_pStartEnt= cl_entitylist->GetEnt( BEAMENT_ENTITY( entindex() ) ); + beamInfo.m_pEndEnt = cl_entitylist->GetEnt( BEAMENT_ENTITY( entindex() ) ); + beamInfo.m_nStartAttachment = 1; + beamInfo.m_nEndAttachment = 2; + + beamInfo.m_nType = TE_BEAMTESLA; + beamInfo.m_pszModelName = "sprites/physbeam.vmt"; + beamInfo.m_flHaloScale = 0.0f; + beamInfo.m_flLife = 0.01f; + beamInfo.m_flWidth = random->RandomFloat( 0.5f, 2.0f ); + beamInfo.m_flEndWidth = 0; + beamInfo.m_flFadeLength = 0.0f; + beamInfo.m_flAmplitude = random->RandomFloat( 1, 2 ); + beamInfo.m_flBrightness = 255.0; + beamInfo.m_flSpeed = 0.0; + beamInfo.m_nStartFrame = 0.0; + beamInfo.m_flFrameRate = 1.0f; + beamInfo.m_flRed = 255.0f;; + beamInfo.m_flGreen = 255.0f; + beamInfo.m_flBlue = 255.0f; + beamInfo.m_nSegments = 8; + beamInfo.m_bRenderable = true; + beamInfo.m_nFlags = (FBEAM_ONLYNOISEONCE|FBEAM_SHADEOUT); + + beams->CreateBeamPoints( beamInfo ); + } + } + + void OnDataChanged( DataUpdateType_t updateType ) + { + BaseClass::OnDataChanged( updateType ); + if ( updateType == DATA_UPDATE_CREATED ) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } + } + + //----------------------------------------------------------------------------- + // Purpose: + //----------------------------------------------------------------------------- + void StartStunEffect( void ) + { + //TODO: Play startup sound + } + + //----------------------------------------------------------------------------- + // Purpose: + //----------------------------------------------------------------------------- + void StopStunEffect( void ) + { + //TODO: Play shutdown sound + } + + //----------------------------------------------------------------------------- + // Purpose: + // Output : RenderGroup_t + //----------------------------------------------------------------------------- + RenderGroup_t GetRenderGroup( void ) + { + return RENDER_GROUP_TRANSLUCENT_ENTITY; + } + +private: + CNetworkVar( bool, m_bActive ); +}; + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pData - +// *pStruct - +// *pOut - +//----------------------------------------------------------------------------- +void RecvProxy_StunActive( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + bool state = *((bool *)&pData->m_Value.m_Int); + + C_WeaponStunStick *pWeapon = (C_WeaponStunStick *) pStruct; + + if ( state ) + { + // Turn on the effect + pWeapon->StartStunEffect(); + } + else + { + // Turn off the effect + pWeapon->StopStunEffect(); + } + + *(bool *)pOut = state; +} + +STUB_WEAPON_CLASS_IMPLEMENT( weapon_stunstick, C_WeaponStunStick ); + +IMPLEMENT_CLIENTCLASS_DT( C_WeaponStunStick, DT_WeaponStunStick, CWeaponStunStick ) + RecvPropInt( RECVINFO(m_bActive), 0, RecvProxy_StunActive ), +END_RECV_TABLE() + diff --git a/game/client/hl2/clientmode_hlnormal.cpp b/game/client/hl2/clientmode_hlnormal.cpp new file mode 100644 index 0000000..dc1415a --- /dev/null +++ b/game/client/hl2/clientmode_hlnormal.cpp @@ -0,0 +1,99 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Draws the normal TF2 or HL2 HUD. +// +//============================================================================= +#include "cbase.h" +#include "clientmode_hlnormal.h" +#include "vgui_int.h" +#include "hud.h" +#include <vgui/IInput.h> +#include <vgui/IPanel.h> +#include <vgui/ISurface.h> +#include <vgui_controls/AnimationController.h> +#include "iinput.h" +#include "ienginevgui.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +extern bool g_bRollingCredits; + +ConVar fov_desired( "fov_desired", "75", FCVAR_ARCHIVE | FCVAR_USERINFO, "Sets the base field-of-view.", true, 75.0, true, 90.0 ); + +//----------------------------------------------------------------------------- +// Globals +//----------------------------------------------------------------------------- +vgui::HScheme g_hVGuiCombineScheme = 0; + + +// Instance the singleton and expose the interface to it. +IClientMode *GetClientModeNormal() +{ + static ClientModeHLNormal g_ClientModeNormal; + return &g_ClientModeNormal; +} + + +//----------------------------------------------------------------------------- +// Purpose: this is the viewport that contains all the hud elements +//----------------------------------------------------------------------------- +class CHudViewport : public CBaseViewport +{ +private: + DECLARE_CLASS_SIMPLE( CHudViewport, CBaseViewport ); + +protected: + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ) + { + BaseClass::ApplySchemeSettings( pScheme ); + + gHUD.InitColors( pScheme ); + + SetPaintBackgroundEnabled( false ); + } + + virtual void CreateDefaultPanels( void ) { /* don't create any panels yet*/ }; +}; + + +//----------------------------------------------------------------------------- +// ClientModeHLNormal implementation +//----------------------------------------------------------------------------- +ClientModeHLNormal::ClientModeHLNormal() +{ + m_pViewport = new CHudViewport(); + m_pViewport->Start( gameuifuncs, gameeventmanager ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +ClientModeHLNormal::~ClientModeHLNormal() +{ +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void ClientModeHLNormal::Init() +{ + BaseClass::Init(); + + // Load up the combine control panel scheme + g_hVGuiCombineScheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), IsXbox() ? "resource/ClientScheme.res" : "resource/CombinePanelScheme.res", "CombineScheme" ); + if (!g_hVGuiCombineScheme) + { + Warning( "Couldn't load combine panel scheme!\n" ); + } +} + +bool ClientModeHLNormal::ShouldDrawCrosshair( void ) +{ + return ( g_bRollingCredits == false ); +} + + + diff --git a/game/client/hl2/clientmode_hlnormal.h b/game/client/hl2/clientmode_hlnormal.h new file mode 100644 index 0000000..623da43 --- /dev/null +++ b/game/client/hl2/clientmode_hlnormal.h @@ -0,0 +1,45 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// +#if !defined( CLIENTMODE_HLNORMAL_H ) +#define CLIENTMODE_HLNORMAL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "clientmode_shared.h" +#include <vgui_controls/EditablePanel.h> +#include <vgui/Cursor.h> + +class CHudViewport; + +namespace vgui +{ + typedef unsigned long HScheme; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class ClientModeHLNormal : public ClientModeShared +{ +public: + DECLARE_CLASS( ClientModeHLNormal, ClientModeShared ); + + ClientModeHLNormal(); + ~ClientModeHLNormal(); + + virtual void Init(); + virtual bool ShouldDrawCrosshair( void ); +}; + +extern IClientMode *GetClientModeNormal(); +extern vgui::HScheme g_hVGuiCombineScheme; + +#endif // CLIENTMODE_HLNORMAL_H diff --git a/game/client/hl2/fx_antlion.cpp b/game/client/hl2/fx_antlion.cpp new file mode 100644 index 0000000..eafca9b --- /dev/null +++ b/game/client/hl2/fx_antlion.cpp @@ -0,0 +1,334 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "fx.h" +#include "c_gib.h" +#include "c_te_effect_dispatch.h" +#include "iefx.h" +#include "decals.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +PMaterialHandle g_Material_Blood[2] = { NULL, NULL }; + +#ifdef _XBOX + +// XBox only uses a few gibs +#define NUM_ANTLION_GIBS 3 +const char *pszAntlionGibs[NUM_ANTLION_GIBS] = { + "models/gibs/antlion_gib_large_2.mdl", // Head + "models/gibs/antlion_gib_medium_1.mdl", // Pincher + "models/gibs/antlion_gib_medium_2.mdl", // Leg +}; + +#else + +// Use all the gibs +#define NUM_ANTLION_GIBS_UNIQUE 3 +const char *pszAntlionGibs_Unique[NUM_ANTLION_GIBS_UNIQUE] = { + "models/gibs/antlion_gib_large_1.mdl", + "models/gibs/antlion_gib_large_2.mdl", + "models/gibs/antlion_gib_large_3.mdl" +}; + +#define NUM_ANTLION_GIBS_MEDIUM 3 +const char *pszAntlionGibs_Medium[NUM_ANTLION_GIBS_MEDIUM] = { + "models/gibs/antlion_gib_medium_1.mdl", + "models/gibs/antlion_gib_medium_2.mdl", + "models/gibs/antlion_gib_medium_3.mdl" +}; + +// XBox doesn't use the smaller gibs, so don't cache them +#define NUM_ANTLION_GIBS_SMALL 3 +const char *pszAntlionGibs_Small[NUM_ANTLION_GIBS_SMALL] = { + "models/gibs/antlion_gib_small_1.mdl", + "models/gibs/antlion_gib_small_2.mdl", + "models/gibs/antlion_gib_small_3.mdl" +}; +#endif + +ConVar g_antlion_maxgibs( "g_antlion_maxgibs", "16", FCVAR_ARCHIVE ); + +void CAntlionGibManager::LevelInitPreEntity( void ) +{ + m_LRU.Purge(); +} + +CAntlionGibManager s_AntlionGibManager( "CAntlionGibManager" ); + +void CAntlionGibManager::AddGib( C_BaseEntity *pEntity ) +{ + m_LRU.AddToTail( pEntity ); +} + +void CAntlionGibManager::RemoveGib( C_BaseEntity *pEntity ) +{ + m_LRU.FindAndRemove( pEntity ); +} + + +//----------------------------------------------------------------------------- +// Methods of IGameSystem +//----------------------------------------------------------------------------- +void CAntlionGibManager::Update( float frametime ) +{ + if ( m_LRU.Count() < g_antlion_maxgibs.GetInt() ) + return; + + int i = 0; + i = m_LRU.Head(); + + if ( m_LRU[ i ].Get() ) + { + m_LRU[ i ].Get()->SetNextClientThink( gpGlobals->curtime ); + } + + m_LRU.Remove(i); +} + +// Antlion gib - marks surfaces when it bounces + +class C_AntlionGib : public C_Gib +{ + typedef C_Gib BaseClass; +public: + + static C_AntlionGib *CreateClientsideGib( const char *pszModelName, Vector vecOrigin, Vector vecForceDir, AngularImpulse vecAngularImp, float m_flLifetime = DEFAULT_GIB_LIFETIME ) + { + C_AntlionGib *pGib = new C_AntlionGib; + + if ( pGib == NULL ) + return NULL; + + if ( pGib->InitializeGib( pszModelName, vecOrigin, vecForceDir, vecAngularImp, m_flLifetime ) == false ) + return NULL; + + s_AntlionGibManager.AddGib( pGib ); + + return pGib; + } + + // Decal the surface + virtual void HitSurface( C_BaseEntity *pOther ) + { + //JDW: Removed for the time being + + /* + int index = decalsystem->GetDecalIndexForName( "YellowBlood" ); + + if (index >= 0 ) + { + effects->DecalShoot( index, pOther->entindex(), pOther->GetModel(), pOther->GetAbsOrigin(), pOther->GetAbsAngles(), GetAbsOrigin(), 0, 0 ); + } + */ + } +}; + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &origin - +//----------------------------------------------------------------------------- +void FX_AntlionGib( const Vector &origin, const Vector &direction, float scale ) +{ + Vector offset; + +#ifdef _XBOX + + // Throw less gibs for XBox + for ( int i = 0; i < NUM_ANTLION_GIBS; i++ ) + { + offset = RandomVector( -32, 32 ) + origin; + C_AntlionGib::CreateClientsideGib( pszAntlionGibs[i], offset, ( direction + RandomVector( -0.8f, 0.8f ) ) * ( 250 * scale ), RandomAngularImpulse( -32, 32 ), 1.0f ); + } + +#else + + int numGibs = random->RandomInt( 1, NUM_ANTLION_GIBS_UNIQUE ); + + // Spawn all the unique gibs + for ( int i = 0; i < numGibs; i++ ) + { + offset = RandomVector( -16, 16 ) + origin; + + C_AntlionGib::CreateClientsideGib( pszAntlionGibs_Unique[i], offset, ( direction + RandomVector( -0.8f, 0.8f ) ) * ( 150 * scale ), RandomAngularImpulse( -32, 32 ), 2.0f); + } + + numGibs = random->RandomInt( 1, NUM_ANTLION_GIBS_MEDIUM ); + + // Spawn all the medium gibs + for ( int i = 0; i < numGibs; i++ ) + { + offset = RandomVector( -16, 16 ) + origin; + + C_AntlionGib::CreateClientsideGib( pszAntlionGibs_Medium[i], offset, ( direction + RandomVector( -0.8f, 0.8f ) ) * ( 250 * scale ), RandomAngularImpulse( -200, 200 ), 1.0f ); + } + + numGibs = random->RandomInt( 1, NUM_ANTLION_GIBS_SMALL ); + + // Spawn all the small gibs + for ( int i = 0; i < NUM_ANTLION_GIBS_SMALL; i++ ) + { + offset = RandomVector( -16, 16 ) + origin; + + C_AntlionGib::CreateClientsideGib( pszAntlionGibs_Small[i], offset, ( direction + RandomVector( -0.8f, 0.8f ) ) * ( 400 * scale ), RandomAngularImpulse( -300, 300 ), 0.5f ); + } + +#endif + +#ifdef _XBOX + + // + // Throw some blood + // + + CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "FX_AntlionGib" ); + pSimple->SetSortOrigin( origin ); + pSimple->GetBinding().SetBBox( origin - Vector(64,64,64), origin + Vector(64,64,64) ); + + // Cache this if we're not already + if ( g_Material_Blood[0] == NULL ) + { + g_Material_Blood[0] = g_Mat_BloodPuff[0]; + } + + if ( g_Material_Blood[1] == NULL ) + { + g_Material_Blood[1] = g_Mat_BloodPuff[1]; + } + + Vector vDir; + vDir.Random( -1.0f, 1.0f ); + + // Gore bits + for ( int i = 0; i < 4; i++ ) + { + SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Material_Blood[0], origin + RandomVector(-16,16)); + if ( sParticle == NULL ) + return; + + sParticle->m_flLifetime = 0.0f; + sParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f ); + + float speed = random->RandomFloat( 16.0f, 64.0f ); + + sParticle->m_vecVelocity.Init(); + + sParticle->m_uchColor[0] = 255; + sParticle->m_uchColor[1] = 200; + sParticle->m_uchColor[2] = 32; + sParticle->m_uchStartAlpha = 255; + sParticle->m_uchEndAlpha = 0; + sParticle->m_uchStartSize = random->RandomInt( 4, 16 ); + sParticle->m_uchEndSize = sParticle->m_uchStartSize * 4; + sParticle->m_flRoll = random->RandomInt( 0, 360 ); + sParticle->m_flRollDelta = 0.0f; + } + + // Middle core + SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Material_Blood[1], origin ); + if ( sParticle == NULL ) + return; + + sParticle->m_flLifetime = 0.0f; + sParticle->m_flDieTime = random->RandomFloat( 0.5f, 0.75f ); + + float speed = random->RandomFloat( 16.0f, 64.0f ); + + sParticle->m_vecVelocity = vDir * -speed; + sParticle->m_vecVelocity[2] += 16.0f; + + sParticle->m_uchColor[0] = 255; + sParticle->m_uchColor[1] = 200; + sParticle->m_uchColor[2] = 32; + sParticle->m_uchStartAlpha = random->RandomInt( 64, 128 ); + sParticle->m_uchEndAlpha = 0; + sParticle->m_uchStartSize = random->RandomInt( 16, 32 ); + sParticle->m_uchEndSize = sParticle->m_uchStartSize * 3; + sParticle->m_flRoll = random->RandomInt( 0, 360 ); + sParticle->m_flRollDelta = random->RandomFloat( -0.2f, 0.2f ); + +#else + + // + // Non-XBox blood + // + + CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "FX_AntlionGib" ); + pSimple->SetSortOrigin( origin ); + + Vector vDir; + + vDir.Random( -1.0f, 1.0f ); + + for ( int i = 0; i < 4; i++ ) + { + SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[0], origin ); + + if ( sParticle == NULL ) + return; + + sParticle->m_flLifetime = 0.0f; + sParticle->m_flDieTime = random->RandomFloat( 0.5f, 0.75f ); + + float speed = random->RandomFloat( 16.0f, 64.0f ); + + sParticle->m_vecVelocity = vDir * -speed; + sParticle->m_vecVelocity[2] += 16.0f; + + sParticle->m_uchColor[0] = 255; + sParticle->m_uchColor[1] = 200; + sParticle->m_uchColor[2] = 32; + sParticle->m_uchStartAlpha = 255; + sParticle->m_uchEndAlpha = 0; + sParticle->m_uchStartSize = random->RandomInt( 16, 32 ); + sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2; + sParticle->m_flRoll = random->RandomInt( 0, 360 ); + sParticle->m_flRollDelta = random->RandomFloat( -1.0f, 1.0f ); + } + + for ( int i = 0; i < 4; i++ ) + { + SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[1], origin ); + + if ( sParticle == NULL ) + { + return; + } + + sParticle->m_flLifetime = 0.0f; + sParticle->m_flDieTime = random->RandomFloat( 0.5f, 0.75f ); + + float speed = random->RandomFloat( 16.0f, 64.0f ); + + sParticle->m_vecVelocity = vDir * -speed; + sParticle->m_vecVelocity[2] += 16.0f; + + sParticle->m_uchColor[0] = 255; + sParticle->m_uchColor[1] = 200; + sParticle->m_uchColor[2] = 32; + sParticle->m_uchStartAlpha = random->RandomInt( 64, 128 ); + sParticle->m_uchEndAlpha = 0; + sParticle->m_uchStartSize = random->RandomInt( 16, 32 ); + sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2; + sParticle->m_flRoll = random->RandomInt( 0, 360 ); + sParticle->m_flRollDelta = random->RandomFloat( -1.0f, 1.0f ); + } + +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &data - +//----------------------------------------------------------------------------- +void AntlionGibCallback( const CEffectData &data ) +{ + FX_AntlionGib( data.m_vOrigin, data.m_vNormal, data.m_flScale ); +} + +DECLARE_CLIENT_EFFECT( "AntlionGib", AntlionGibCallback ); diff --git a/game/client/hl2/fx_bugbait.cpp b/game/client/hl2/fx_bugbait.cpp new file mode 100644 index 0000000..6d12a1c --- /dev/null +++ b/game/client/hl2/fx_bugbait.cpp @@ -0,0 +1,63 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "particlemgr.h" +#include "particle_prototype.h" +#include "particle_util.h" +#include "particles_simple.h" +#include "c_baseentity.h" +#include "baseparticleentity.h" +#include "engine/ivdebugoverlay.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//================================================== +// SporeSmokeEffect +//================================================== + +class SporeSmokeEffect : public CSimpleEmitter +{ +public: + SporeSmokeEffect( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {} + + static SporeSmokeEffect* Create( const char *pDebugName ); + + virtual void UpdateVelocity( SimpleParticle *pParticle, float timeDelta ); + virtual float UpdateAlpha( const SimpleParticle *pParticle ); + +private: + SporeSmokeEffect( const SporeSmokeEffect & ); +}; + + +SporeSmokeEffect* SporeSmokeEffect::Create( const char *pDebugName ) +{ + return new SporeSmokeEffect( pDebugName ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pParticle - +// timeDelta - +// Output : float +//----------------------------------------------------------------------------- +float SporeSmokeEffect::UpdateAlpha( const SimpleParticle *pParticle ) +{ + //return ( ((float)pParticle->m_uchStartAlpha/255.0f) * sin( M_PI * (pParticle->m_flLifetime / pParticle->m_flDieTime) ) ); + return (pParticle->m_uchStartAlpha/255.0f) + ( (float)(pParticle->m_uchEndAlpha/255.0f) - (float)(pParticle->m_uchStartAlpha/255.0f) ) * (pParticle->m_flLifetime / pParticle->m_flDieTime); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pParticle - +// timeDelta - +//----------------------------------------------------------------------------- +void SporeSmokeEffect::UpdateVelocity( SimpleParticle *pParticle, float timeDelta ) +{ +} + diff --git a/game/client/hl2/fx_hl2_impacts.cpp b/game/client/hl2/fx_hl2_impacts.cpp new file mode 100644 index 0000000..ac75b85 --- /dev/null +++ b/game/client/hl2/fx_hl2_impacts.cpp @@ -0,0 +1,275 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Game-specific impact effect hooks +// +//=============================================================================// +#include "cbase.h" +#include "fx_impact.h" +#include "fx.h" +#include "decals.h" +#include "fx_quad.h" +#include "fx_sparks.h" + +#include "tier0/vprof.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: Handle jeep impacts +//----------------------------------------------------------------------------- +void ImpactJeepCallback( const CEffectData &data ) +{ + trace_t tr; + Vector vecOrigin, vecStart, vecShotDir; + int iMaterial, iDamageType, iHitbox; + short nSurfaceProp; + C_BaseEntity *pEntity = ParseImpactData( data, &vecOrigin, &vecStart, &vecShotDir, nSurfaceProp, iMaterial, iDamageType, iHitbox ); + + if ( !pEntity ) + { + // This happens for impacts that occur on an object that's then destroyed. + // Clear out the fraction so it uses the server's data + tr.fraction = 1.0; + PlayImpactSound( pEntity, tr, vecOrigin, nSurfaceProp ); + return; + } + + // If we hit, perform our custom effects and play the sound + if ( Impact( vecOrigin, vecStart, iMaterial, iDamageType, iHitbox, pEntity, tr ) ) + { + // Check for custom effects based on the Decal index + PerformCustomEffects( vecOrigin, tr, vecShotDir, iMaterial, 2 ); + } + + PlayImpactSound( pEntity, tr, vecOrigin, nSurfaceProp ); +} + +DECLARE_CLIENT_EFFECT( "ImpactJeep", ImpactJeepCallback ); + + +//----------------------------------------------------------------------------- +// Purpose: Handle gauss impacts +//----------------------------------------------------------------------------- +void ImpactGaussCallback( const CEffectData &data ) +{ + trace_t tr; + Vector vecOrigin, vecStart, vecShotDir; + int iMaterial, iDamageType, iHitbox; + short nSurfaceProp; + C_BaseEntity *pEntity = ParseImpactData( data, &vecOrigin, &vecStart, &vecShotDir, nSurfaceProp, iMaterial, iDamageType, iHitbox ); + + if ( !pEntity ) + { + // This happens for impacts that occur on an object that's then destroyed. + // Clear out the fraction so it uses the server's data + tr.fraction = 1.0; + PlayImpactSound( pEntity, tr, vecOrigin, nSurfaceProp ); + return; + } + + // If we hit, perform our custom effects and play the sound + if ( Impact( vecOrigin, vecStart, iMaterial, iDamageType, iHitbox, pEntity, tr ) ) + { + // Check for custom effects based on the Decal index + PerformCustomEffects( vecOrigin, tr, vecShotDir, iMaterial, 2 ); + } + + PlayImpactSound( pEntity, tr, vecOrigin, nSurfaceProp ); +} + +DECLARE_CLIENT_EFFECT( "ImpactGauss", ImpactGaussCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Handle weapon impacts +//----------------------------------------------------------------------------- +void ImpactCallback( const CEffectData &data ) +{ + VPROF_BUDGET( "ImpactCallback", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); + + trace_t tr; + Vector vecOrigin, vecStart, vecShotDir; + int iMaterial, iDamageType, iHitbox; + short nSurfaceProp; + C_BaseEntity *pEntity = ParseImpactData( data, &vecOrigin, &vecStart, &vecShotDir, nSurfaceProp, iMaterial, iDamageType, iHitbox ); + + if ( !pEntity ) + { + // This happens for impacts that occur on an object that's then destroyed. + // Clear out the fraction so it uses the server's data + tr.fraction = 1.0; + PlayImpactSound( pEntity, tr, vecOrigin, nSurfaceProp ); + return; + } + + // If we hit, perform our custom effects and play the sound + if ( Impact( vecOrigin, vecStart, iMaterial, iDamageType, iHitbox, pEntity, tr ) ) + { + // Check for custom effects based on the Decal index + PerformCustomEffects( vecOrigin, tr, vecShotDir, iMaterial, 1.0 ); + } + + PlayImpactSound( pEntity, tr, vecOrigin, nSurfaceProp ); +} + +DECLARE_CLIENT_EFFECT( "Impact", ImpactCallback ); + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &origin - +// &normal - +// scale - +//----------------------------------------------------------------------------- +void FX_AirboatGunImpact( const Vector &origin, const Vector &normal, float scale ) +{ +#ifdef _XBOX + + Vector offset = origin + ( normal * 1.0f ); + + CSmartPtr<CTrailParticles> sparkEmitter = CTrailParticles::Create( "FX_MetalSpark 1" ); + + if ( sparkEmitter == NULL ) + return; + + //Setup our information + sparkEmitter->SetSortOrigin( offset ); + sparkEmitter->SetFlag( bitsPARTICLE_TRAIL_VELOCITY_DAMPEN ); + sparkEmitter->SetVelocityDampen( 8.0f ); + sparkEmitter->SetGravity( 800.0f ); + sparkEmitter->SetCollisionDamped( 0.25f ); + sparkEmitter->GetBinding().SetBBox( offset - Vector( 32, 32, 32 ), offset + Vector( 32, 32, 32 ) ); + + int numSparks = random->RandomInt( 4, 8 ); + + TrailParticle *pParticle; + PMaterialHandle hMaterial = sparkEmitter->GetPMaterial( "effects/spark" ); + Vector dir; + + float length = 0.1f; + + //Dump out sparks + for ( int i = 0; i < numSparks; i++ ) + { + pParticle = (TrailParticle *) sparkEmitter->AddParticle( sizeof(TrailParticle), hMaterial, offset ); + + if ( pParticle == NULL ) + return; + + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = random->RandomFloat( 0.05f, 0.1f ); + + float spreadOfs = random->RandomFloat( 0.0f, 2.0f ); + + dir[0] = normal[0] + random->RandomFloat( -(0.5f*spreadOfs), (0.5f*spreadOfs) ); + dir[1] = normal[1] + random->RandomFloat( -(0.5f*spreadOfs), (0.5f*spreadOfs) ); + dir[2] = normal[2] + random->RandomFloat( -(0.5f*spreadOfs), (0.5f*spreadOfs) ); + + VectorNormalize( dir ); + + pParticle->m_flWidth = random->RandomFloat( 1.0f, 4.0f ); + pParticle->m_flLength = random->RandomFloat( length*0.25f, length ); + + pParticle->m_vecVelocity = dir * random->RandomFloat( (128.0f*(2.0f-spreadOfs)), (512.0f*(2.0f-spreadOfs)) ); + + Color32Init( pParticle->m_color, 255, 255, 255, 255 ); + } + +#else + + // Normal metal spark + FX_MetalSpark( origin, normal, normal, (int) scale ); + +#endif // _XBOX + + // Add a quad to highlite the hit point + FX_AddQuad( origin, + normal, + random->RandomFloat( 16, 32 ), + random->RandomFloat( 32, 48 ), + 0.75f, + 1.0f, + 0.0f, + 0.4f, + random->RandomInt( 0, 360 ), + 0, + Vector( 1.0f, 1.0f, 1.0f ), + 0.05f, + "effects/combinemuzzle2_nocull", + (FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) ); +} + +//----------------------------------------------------------------------------- +// Purpose: Handle weapon impacts from the airboat gun shooting (cheaper versions) +//----------------------------------------------------------------------------- +void ImpactAirboatGunCallback( const CEffectData &data ) +{ + VPROF_BUDGET( "ImpactAirboatGunCallback", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); + + trace_t tr; + Vector vecOrigin, vecStart, vecShotDir; + int iMaterial, iDamageType, iHitbox; + short nSurfaceProp; + C_BaseEntity *pEntity = ParseImpactData( data, &vecOrigin, &vecStart, &vecShotDir, nSurfaceProp, iMaterial, iDamageType, iHitbox ); + + if ( !pEntity ) + { + // This happens for impacts that occur on an object that's then destroyed. + // Clear out the fraction so it uses the server's data + tr.fraction = 1.0; + PlayImpactSound( pEntity, tr, vecOrigin, nSurfaceProp ); + return; + } + +#if !defined( _XBOX ) + // If we hit, perform our custom effects and play the sound. Don't create decals + if ( Impact( vecOrigin, vecStart, iMaterial, iDamageType, iHitbox, pEntity, tr, IMPACT_NODECAL | IMPACT_REPORT_RAGDOLL_IMPACTS ) ) + { + FX_AirboatGunImpact( vecOrigin, tr.plane.normal, 2 ); + } +#else + FX_AirboatGunImpact( vecOrigin, tr.plane.normal, 1 ); +#endif +} + +DECLARE_CLIENT_EFFECT( "AirboatGunImpact", ImpactAirboatGunCallback ); + + +//----------------------------------------------------------------------------- +// Purpose: Handle weapon impacts from the helicopter shooting (cheaper versions) +//----------------------------------------------------------------------------- +void ImpactHelicopterCallback( const CEffectData &data ) +{ + VPROF_BUDGET( "ImpactHelicopterCallback", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); + + trace_t tr; + Vector vecOrigin, vecStart, vecShotDir; + int iMaterial, iDamageType, iHitbox; + short nSurfaceProp; + C_BaseEntity *pEntity = ParseImpactData( data, &vecOrigin, &vecStart, &vecShotDir, nSurfaceProp, iMaterial, iDamageType, iHitbox ); + + if ( !pEntity ) + { + // This happens for impacts that occur on an object that's then destroyed. + // Clear out the fraction so it uses the server's data + tr.fraction = 1.0; + PlayImpactSound( pEntity, tr, vecOrigin, nSurfaceProp ); + return; + } + + // If we hit, perform our custom effects and play the sound. Don't create decals + if ( Impact( vecOrigin, vecStart, iMaterial, iDamageType, iHitbox, pEntity, tr, IMPACT_NODECAL | IMPACT_REPORT_RAGDOLL_IMPACTS ) ) + { + FX_AirboatGunImpact( vecOrigin, tr.plane.normal, IsXbox() ? 1 : 2 ); + + // Only do metal + computer custom effects + if ( (iMaterial == CHAR_TEX_METAL) || (iMaterial == CHAR_TEX_COMPUTER) ) + { + PerformCustomEffects( vecOrigin, tr, vecShotDir, iMaterial, 1.0, FLAGS_CUSTIOM_EFFECTS_NOFLECKS ); + } + } + + PlayImpactSound( pEntity, tr, vecOrigin, nSurfaceProp ); +} + +DECLARE_CLIENT_EFFECT( "HelicopterImpact", ImpactHelicopterCallback ); + diff --git a/game/client/hl2/fx_hl2_tracers.cpp b/game/client/hl2/fx_hl2_tracers.cpp new file mode 100644 index 0000000..c252937 --- /dev/null +++ b/game/client/hl2/fx_hl2_tracers.cpp @@ -0,0 +1,695 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Game-specific impact effect hooks +// +//=============================================================================// +#include "cbase.h" +#include "fx.h" +#include "c_te_effect_dispatch.h" +#include "tier0/vprof.h" +#include "fx_line.h" +#include "fx_quad.h" +#include "view.h" +#include "particles_localspace.h" +#include "dlight.h" +#include "iefx.h" +#include "clienteffectprecachesystem.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +extern Vector GetTracerOrigin( const CEffectData &data ); +extern void FX_TracerSound( const Vector &start, const Vector &end, int iTracerType ); + +extern ConVar muzzleflash_light; + + +CLIENTEFFECT_REGISTER_BEGIN( PrecacheTracers ) +CLIENTEFFECT_MATERIAL( "effects/gunshiptracer" ) +CLIENTEFFECT_MATERIAL( "effects/combinemuzzle1" ) +CLIENTEFFECT_MATERIAL( "effects/combinemuzzle2_nocull" ) +CLIENTEFFECT_REGISTER_END() + +//----------------------------------------------------------------------------- +// Purpose: Gunship's Tracer +//----------------------------------------------------------------------------- +void GunshipTracerCallback( const CEffectData &data ) +{ + float flVelocity = data.m_flScale; + bool bWhiz = (data.m_fFlags & TRACER_FLAG_WHIZ); + FX_GunshipTracer( (Vector&)data.m_vStart, (Vector&)data.m_vOrigin, flVelocity, bWhiz ); +} + +DECLARE_CLIENT_EFFECT( "GunshipTracer", GunshipTracerCallback ); + + +//----------------------------------------------------------------------------- +// Purpose: Strider's Tracer +//----------------------------------------------------------------------------- +void StriderTracerCallback( const CEffectData &data ) +{ + float flVelocity = data.m_flScale; + bool bWhiz = (data.m_fFlags & TRACER_FLAG_WHIZ); + FX_StriderTracer( (Vector&)data.m_vStart, (Vector&)data.m_vOrigin, flVelocity, bWhiz ); +} + +DECLARE_CLIENT_EFFECT( "StriderTracer", StriderTracerCallback ); + + +//----------------------------------------------------------------------------- +// Purpose: Hunter's Tracer +//----------------------------------------------------------------------------- +void HunterTracerCallback( const CEffectData &data ) +{ + float flVelocity = data.m_flScale; + bool bWhiz = (data.m_fFlags & TRACER_FLAG_WHIZ); + FX_HunterTracer( (Vector&)data.m_vStart, (Vector&)data.m_vOrigin, flVelocity, bWhiz ); +} + +DECLARE_CLIENT_EFFECT( "HunterTracer", HunterTracerCallback ); + + +//----------------------------------------------------------------------------- +// Purpose: Gauss Gun's Tracer +//----------------------------------------------------------------------------- +void GaussTracerCallback( const CEffectData &data ) +{ + float flVelocity = data.m_flScale; + bool bWhiz = (data.m_fFlags & TRACER_FLAG_WHIZ); + FX_GaussTracer( (Vector&)data.m_vStart, (Vector&)data.m_vOrigin, flVelocity, bWhiz ); +} + +DECLARE_CLIENT_EFFECT( "GaussTracer", GaussTracerCallback ); + + +//----------------------------------------------------------------------------- +// Purpose: Airboat gun tracers +//----------------------------------------------------------------------------- +void AirboatGunHeavyTracerCallback( const CEffectData &data ) +{ + // Grab the data + Vector vecStart = GetTracerOrigin( data ); + float flVelocity = data.m_flScale; + + // Use default velocity if none specified + if ( !flVelocity ) + { + flVelocity = 8000; + } + + //Get out shot direction and length + Vector vecShotDir; + VectorSubtract( data.m_vOrigin, vecStart, vecShotDir ); + float flTotalDist = VectorNormalize( vecShotDir ); + + // Don't make small tracers + if ( flTotalDist <= 64 ) + return; + + float flLength = random->RandomFloat( 300.0f, 400.0f ); + float flLife = ( flTotalDist + flLength ) / flVelocity; //NOTENOTE: We want the tail to finish its run as well + + // Add it + FX_AddDiscreetLine( vecStart, vecShotDir, flVelocity, flLength, flTotalDist, 5.0f, flLife, "effects/gunshiptracer" ); +} + +DECLARE_CLIENT_EFFECT( "AirboatGunHeavyTracer", AirboatGunHeavyTracerCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Airboat gun tracers +//----------------------------------------------------------------------------- +void AirboatGunTracerCallback( const CEffectData &data ) +{ + // Grab the data + Vector vecStart = GetTracerOrigin( data ); + float flVelocity = data.m_flScale; + + // Use default velocity if none specified + if ( !flVelocity ) + { + flVelocity = 10000; + } + + //Get out shot direction and length + Vector vecShotDir; + VectorSubtract( data.m_vOrigin, vecStart, vecShotDir ); + float flTotalDist = VectorNormalize( vecShotDir ); + + // Don't make small tracers + if ( flTotalDist <= 64 ) + return; + + float flLength = random->RandomFloat( 256.0f, 384.0f ); + float flLife = ( flTotalDist + flLength ) / flVelocity; //NOTENOTE: We want the tail to finish its run as well + + // Add it + FX_AddDiscreetLine( vecStart, vecShotDir, flVelocity, flLength, flTotalDist, 2.0f, flLife, "effects/gunshiptracer" ); +} + +DECLARE_CLIENT_EFFECT( "AirboatGunTracer", AirboatGunTracerCallback ); + + +//----------------------------------------------------------------------------- +// Purpose: Airboat gun tracers +//----------------------------------------------------------------------------- +void HelicopterTracerCallback( const CEffectData &data ) +{ + // Grab the data + Vector vecStart = GetTracerOrigin( data ); + float flVelocity = data.m_flScale; + + // Use default velocity if none specified + if ( !flVelocity ) + { + flVelocity = 8000; + } + + //Get out shot direction and length + Vector vecShotDir; + VectorSubtract( data.m_vOrigin, vecStart, vecShotDir ); + float flTotalDist = VectorNormalize( vecShotDir ); + + // Don't make small tracers + if ( flTotalDist <= 256 ) + return; + + float flLength = random->RandomFloat( 256.0f, 384.0f ); + float flLife = ( flTotalDist + flLength ) / flVelocity; //NOTENOTE: We want the tail to finish its run as well + + // Add it + FX_AddDiscreetLine( vecStart, vecShotDir, flVelocity, flLength, flTotalDist, 5.0f, flLife, "effects/gunshiptracer" ); + + if (data.m_fFlags & TRACER_FLAG_WHIZ) + { + FX_TracerSound( vecStart, data.m_vOrigin, TRACER_TYPE_GUNSHIP ); + } +} + +DECLARE_CLIENT_EFFECT( "HelicopterTracer", HelicopterTracerCallback ); + +//----------------------------------------------------------------------------- +// Purpose: +// Input : start - +// end - +//----------------------------------------------------------------------------- +void FX_PlayerAR2Tracer( const Vector &start, const Vector &end ) +{ + VPROF_BUDGET( "FX_PlayerAR2Tracer", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); + + Vector shotDir, dStart, dEnd; + float length; + + //Find the direction of the tracer + VectorSubtract( end, start, shotDir ); + length = VectorNormalize( shotDir ); + + //We don't want to draw them if they're too close to us + if ( length < 128 ) + return; + + //Randomly place the tracer along this line, with a random length + VectorMA( start, random->RandomFloat( 0.0f, 8.0f ), shotDir, dStart ); + VectorMA( dStart, MIN( length, random->RandomFloat( 256.0f, 1024.0f ) ), shotDir, dEnd ); + + //Create the line + CFXStaticLine *tracerLine = new CFXStaticLine( "Tracer", dStart, dEnd, random->RandomFloat( 6.0f, 12.0f ), 0.01f, "effects/gunshiptracer", 0 ); + assert( tracerLine ); + + //Throw it into the list + clienteffects->AddEffect( tracerLine ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : start - +// end - +// velocity - +// makeWhiz - +//----------------------------------------------------------------------------- +void FX_AR2Tracer( Vector& start, Vector& end, int velocity, bool makeWhiz ) +{ + VPROF_BUDGET( "FX_AR2Tracer", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); + + //Don't make small tracers + float dist; + Vector dir; + + VectorSubtract( end, start, dir ); + dist = VectorNormalize( dir ); + + // Don't make short tracers. + if ( dist < 128 ) + return; + + float length = random->RandomFloat( 128.0f, 256.0f ); + float life = ( dist + length ) / velocity; //NOTENOTE: We want the tail to finish its run as well + + //Add it + FX_AddDiscreetLine( start, dir, velocity, length, dist, random->RandomFloat( 0.5f, 1.5f ), life, "effects/gunshiptracer" ); + + if( makeWhiz ) + { + FX_TracerSound( start, end, TRACER_TYPE_GUNSHIP ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void AR2TracerCallback( const CEffectData &data ) +{ + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + + if ( player == NULL ) + return; + + // Grab the data + Vector vecStart = GetTracerOrigin( data ); + float flVelocity = data.m_flScale; + bool bWhiz = (data.m_fFlags & TRACER_FLAG_WHIZ); + int iEntIndex = data.entindex(); + + if ( iEntIndex && iEntIndex == player->index ) + { + Vector foo = data.m_vStart; + QAngle vangles; + Vector vforward, vright, vup; + + engine->GetViewAngles( vangles ); + AngleVectors( vangles, &vforward, &vright, &vup ); + + VectorMA( data.m_vStart, 4, vright, foo ); + foo[2] -= 0.5f; + + FX_PlayerAR2Tracer( foo, (Vector&)data.m_vOrigin ); + return; + } + + // Use default velocity if none specified + if ( !flVelocity ) + { + flVelocity = 8000; + } + + // Do tracer effect + FX_AR2Tracer( (Vector&)vecStart, (Vector&)data.m_vOrigin, flVelocity, bWhiz ); +} + +DECLARE_CLIENT_EFFECT( "AR2Tracer", AR2TracerCallback ); + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &data - +//----------------------------------------------------------------------------- +void AR2ExplosionCallback( const CEffectData &data ) +{ + float lifetime = random->RandomFloat( 0.4f, 0.75f ); + + // Ground splash + FX_AddQuad( data.m_vOrigin, + data.m_vNormal, + data.m_flRadius, + data.m_flRadius * 4.0f, + 0.85f, + 1.0f, + 0.0f, + 0.25f, + random->RandomInt( 0, 360 ), + random->RandomFloat( -4, 4 ), + Vector( 1.0f, 1.0f, 1.0f ), + lifetime, + "effects/combinemuzzle1", + (FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) ); + + Vector vRight, vUp; + VectorVectors( data.m_vNormal, vRight, vUp ); + + Vector start, end; + + float radius = data.m_flRadius * 0.15f; + + // Base vertical shaft + FXLineData_t lineData; + + start = data.m_vOrigin; + end = start + ( data.m_vNormal * random->RandomFloat( radius*2.0f, radius*4.0f ) ); + + lineData.m_flDieTime = lifetime; + + lineData.m_flStartAlpha= 1.0f; + lineData.m_flEndAlpha = 0.0f; + + lineData.m_flStartScale = radius*4; + lineData.m_flEndScale = radius*5; + + lineData.m_pMaterial = materials->FindMaterial( "effects/ar2ground2", 0, 0 ); + + lineData.m_vecStart = start; + lineData.m_vecStartVelocity = vec3_origin; + + lineData.m_vecEnd = end; + lineData.m_vecEndVelocity = data.m_vNormal * random->RandomFloat( 200, 350 ); + + FX_AddLine( lineData ); + + // Inner filler shaft + start = data.m_vOrigin; + end = start + ( data.m_vNormal * random->RandomFloat( 16, radius*0.25f ) ); + + lineData.m_flDieTime = lifetime - 0.1f; + + lineData.m_flStartAlpha= 1.0f; + lineData.m_flEndAlpha = 0.0f; + + lineData.m_flStartScale = radius*2; + lineData.m_flEndScale = radius*4; + + lineData.m_pMaterial = materials->FindMaterial( "effects/ar2ground2", 0, 0 ); + + lineData.m_vecStart = start; + lineData.m_vecStartVelocity = vec3_origin; + + lineData.m_vecEnd = end; + lineData.m_vecEndVelocity = data.m_vNormal * random->RandomFloat( 64, 128 ); + + FX_AddLine( lineData ); +} + +DECLARE_CLIENT_EFFECT( "AR2Explosion", AR2ExplosionCallback ); + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &data - +//----------------------------------------------------------------------------- +void AR2ImpactCallback( const CEffectData &data ) +{ + FX_AddQuad( data.m_vOrigin, + data.m_vNormal, + random->RandomFloat( 24, 32 ), + 0, + 0.75f, + 1.0f, + 0.0f, + 0.4f, + random->RandomInt( 0, 360 ), + 0, + Vector( 1.0f, 1.0f, 1.0f ), + 0.25f, + "effects/combinemuzzle2_nocull", + (FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) ); +} + +DECLARE_CLIENT_EFFECT( "AR2Impact", AR2ImpactCallback ); + +//----------------------------------------------------------------------------- +// Creates a muzzleflash elight +//----------------------------------------------------------------------------- +void CreateMuzzleflashELight( const Vector &origin, int exponent, int nMinRadius, int nMaxRadius, ClientEntityHandle_t hEntity ) +{ + if ( muzzleflash_light.GetInt() ) + { + int entityIndex = ClientEntityList().HandleToEntIndex( hEntity ); + if ( entityIndex >= 0 ) + { + dlight_t *el = effects->CL_AllocElight( LIGHT_INDEX_MUZZLEFLASH + entityIndex ); + + el->origin = origin; + + el->color.r = 255; + el->color.g = 192; + el->color.b = 64; + el->color.exponent = exponent; + + el->radius = random->RandomInt( nMinRadius, nMaxRadius ); + el->decay = el->radius / 0.05f; + el->die = gpGlobals->curtime + 0.1f; + } + } +} + + +//----------------------------------------------------------------------------- +// Airboat muzzle flashes +//----------------------------------------------------------------------------- +void MuzzleFlash_Airboat( ClientEntityHandle_t hEntity, int attachmentIndex ) +{ + VPROF_BUDGET( "MuzzleFlash_Airboat", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); + + CSmartPtr<CLocalSpaceEmitter> pSimple = CLocalSpaceEmitter::Create( "MuzzleFlash", hEntity, attachmentIndex ); + + SimpleParticle *pParticle; + Vector forward(1,0,0), offset; //NOTENOTE: All coords are in local space + + float flScale = random->RandomFloat( 0.75f, IsXbox() ? 2.0f : 2.5f ); + + PMaterialHandle pMuzzle[2]; + pMuzzle[0] = pSimple->GetPMaterial( "effects/combinemuzzle1" ); + pMuzzle[1] = pSimple->GetPMaterial( "effects/combinemuzzle2" ); + + // Flash + for ( int i = 1; i < 7; i++ ) + { + offset = (forward * (i*6.0f*flScale)); + + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pMuzzle[random->RandomInt(0,1)], offset ); + + if ( pParticle == NULL ) + return; + + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = IsXbox() ? 0.0001f : 0.01f; + + pParticle->m_vecVelocity.Init(); + + pParticle->m_uchColor[0] = 255; + pParticle->m_uchColor[1] = 255; + pParticle->m_uchColor[2] = 255; + + pParticle->m_uchStartAlpha = 255; + pParticle->m_uchEndAlpha = 128; + + pParticle->m_uchStartSize = ( (random->RandomFloat( 6.0f, 8.0f ) * (9-(i))/7) * flScale ); + pParticle->m_uchEndSize = pParticle->m_uchStartSize; + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = 0.0f; + } + + // Tack on the smoke + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "sprites/ar2_muzzle1" ), vec3_origin ); + + if ( pParticle == NULL ) + return; + + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = 0.05f; + + pParticle->m_vecVelocity.Init(); + + pParticle->m_uchColor[0] = 255; + pParticle->m_uchColor[1] = 255; + pParticle->m_uchColor[2] = 255; + + pParticle->m_uchStartAlpha = 255; + pParticle->m_uchEndAlpha = 128; + + pParticle->m_uchStartSize = random->RandomFloat( 16.0f, 24.0f ); + pParticle->m_uchEndSize = pParticle->m_uchStartSize; + + float spokePos = random->RandomInt( 0, 5 ); + + pParticle->m_flRoll = (360.0/6.0f)*spokePos; + pParticle->m_flRollDelta = 0.0f; + +#ifndef _XBOX + // Grab the origin out of the transform for the attachment + if ( muzzleflash_light.GetInt() ) + { + // If the client hasn't seen this entity yet, bail. + matrix3x4_t matAttachment; + if ( FX_GetAttachmentTransform( hEntity, attachmentIndex, matAttachment ) ) + { + Vector origin; + MatrixGetColumn( matAttachment, 3, &origin ); + CreateMuzzleflashELight( origin, 5, 64, 128, hEntity ); + } + } +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void AirboatMuzzleFlashCallback( const CEffectData &data ) +{ + MuzzleFlash_Airboat( data.m_hEntity, data.m_nAttachmentIndex ); +} + +DECLARE_CLIENT_EFFECT( "AirboatMuzzleFlash", AirboatMuzzleFlashCallback ); + + +//----------------------------------------------------------------------------- +// Chopper muzzle flashes +//----------------------------------------------------------------------------- +void MuzzleFlash_Chopper( ClientEntityHandle_t hEntity, int attachmentIndex ) +{ + VPROF_BUDGET( "MuzzleFlash_Chopper", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); + + matrix3x4_t matAttachment; + // If the client hasn't seen this entity yet, bail. + if ( !FX_GetAttachmentTransform( hEntity, attachmentIndex, matAttachment ) ) + return; + + CSmartPtr<CLocalSpaceEmitter> pSimple = CLocalSpaceEmitter::Create( "MuzzleFlash", hEntity, attachmentIndex ); + + SimpleParticle *pParticle; + Vector forward(1,0,0), offset; //NOTENOTE: All coords are in local space + + float flScale = random->RandomFloat( 2.5f, 4.5f ); + + // Flash + for ( int i = 1; i < 7; i++ ) + { + offset = (forward * (i*2.0f*flScale)); + + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( VarArgs( "effects/combinemuzzle%d", random->RandomInt(1,2) ) ), offset ); + + if ( pParticle == NULL ) + return; + + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = random->RandomFloat( 0.05f, 0.1f ); + + pParticle->m_vecVelocity.Init(); + + pParticle->m_uchColor[0] = 255; + pParticle->m_uchColor[1] = 255; + pParticle->m_uchColor[2] = 255; + + pParticle->m_uchStartAlpha = 255; + pParticle->m_uchEndAlpha = 128; + + pParticle->m_uchStartSize = ( (random->RandomFloat( 6.0f, 8.0f ) * (10-(i))/7) * flScale ); + pParticle->m_uchEndSize = pParticle->m_uchStartSize; + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = 0.0f; + } + + // Grab the origin out of the transform for the attachment + Vector origin; + MatrixGetColumn( matAttachment, 3, &origin ); + CreateMuzzleflashELight( origin, 6, 128, 256, hEntity ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void ChopperMuzzleFlashCallback( const CEffectData &data ) +{ + MuzzleFlash_Chopper( data.m_hEntity, data.m_nAttachmentIndex ); +} + +DECLARE_CLIENT_EFFECT( "ChopperMuzzleFlash", ChopperMuzzleFlashCallback ); + + +//----------------------------------------------------------------------------- +// Gunship muzzle flashes +//----------------------------------------------------------------------------- +void MuzzleFlash_Gunship( ClientEntityHandle_t hEntity, int attachmentIndex ) +{ + VPROF_BUDGET( "MuzzleFlash_Gunship", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); + + // If the client hasn't seen this entity yet, bail. + matrix3x4_t matAttachment; + if ( !FX_GetAttachmentTransform( hEntity, attachmentIndex, matAttachment ) ) + return; + + CSmartPtr<CLocalSpaceEmitter> pSimple = CLocalSpaceEmitter::Create( "MuzzleFlash", hEntity, attachmentIndex ); + + SimpleParticle *pParticle; + Vector forward(1,0,0), offset; //NOTENOTE: All coords are in local space + + float flScale = random->RandomFloat( 2.5f, 4.5f ); + + // Flash + offset = (forward * (2.0f*flScale)); + + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "effects/gunshipmuzzle" ), offset ); + if ( pParticle == NULL ) + return; + + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = random->RandomFloat( 0.05f, 0.1f ); + + pParticle->m_vecVelocity.Init(); + + pParticle->m_uchColor[0] = 255; + pParticle->m_uchColor[1] = 255; + pParticle->m_uchColor[2] = 255; + + pParticle->m_uchStartAlpha = 255; + pParticle->m_uchEndAlpha = 128; + + pParticle->m_uchStartSize = ( (random->RandomFloat( 6.0f, 8.0f ) * 10.0/7.0) * flScale ); + pParticle->m_uchEndSize = pParticle->m_uchStartSize; + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = 0.0f; + + // Grab the origin out of the transform for the attachment + Vector origin; + MatrixGetColumn( matAttachment, 3, &origin ); + CreateMuzzleflashELight( origin, 6, 128, 256, hEntity ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void GunshipMuzzleFlashCallback( const CEffectData &data ) +{ + MuzzleFlash_Gunship( data.m_hEntity, data.m_nAttachmentIndex ); +} + +DECLARE_CLIENT_EFFECT( "GunshipMuzzleFlash", GunshipMuzzleFlashCallback ); + + +//----------------------------------------------------------------------------- +// Hunter muzzle flashes +//----------------------------------------------------------------------------- +void MuzzleFlash_Hunter( ClientEntityHandle_t hEntity, int attachmentIndex ) +{ + VPROF_BUDGET( "MuzzleFlash_Hunter", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); + + // If the client hasn't seen this entity yet, bail. + matrix3x4_t matAttachment; + if ( !FX_GetAttachmentTransform( hEntity, attachmentIndex, matAttachment ) ) + return; + + // Grab the origin out of the transform for the attachment + Vector origin; + MatrixGetColumn( matAttachment, 3, &origin ); + + dlight_t *el = effects->CL_AllocElight( LIGHT_INDEX_MUZZLEFLASH ); + el->origin = origin;// + Vector( 12.0f, 0, 0 ); + + el->color.r = 50; + el->color.g = 222; + el->color.b = 213; + el->color.exponent = 5; + + el->radius = random->RandomInt( 120, 200 ); + el->decay = el->radius / 0.05f; + el->die = gpGlobals->curtime + 0.05f; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void HunterMuzzleFlashCallback( const CEffectData &data ) +{ + MuzzleFlash_Hunter( data.m_hEntity, data.m_nAttachmentIndex ); +} + +DECLARE_CLIENT_EFFECT( "HunterMuzzleFlash", HunterMuzzleFlashCallback ); diff --git a/game/client/hl2/hl2_clientmode.cpp b/game/client/hl2/hl2_clientmode.cpp new file mode 100644 index 0000000..26650ce --- /dev/null +++ b/game/client/hl2/hl2_clientmode.cpp @@ -0,0 +1,77 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#include "cbase.h" +#include "ivmodemanager.h" +#include "clientmode_hlnormal.h" +#include "panelmetaclassmgr.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// default FOV for HL2 +ConVar default_fov( "default_fov", "75", FCVAR_CHEAT ); + +// The current client mode. Always ClientModeNormal in HL. +IClientMode *g_pClientMode = NULL; + +#define SCREEN_FILE "scripts/vgui_screens.txt" + +class CHLModeManager : public IVModeManager +{ +public: + CHLModeManager( void ); + virtual ~CHLModeManager( void ); + + virtual void Init( void ); + virtual void SwitchMode( bool commander, bool force ); + virtual void OverrideView( CViewSetup *pSetup ); + virtual void CreateMove( float flInputSampleTime, CUserCmd *cmd ); + virtual void LevelInit( const char *newmap ); + virtual void LevelShutdown( void ); +}; + +CHLModeManager::CHLModeManager( void ) +{ +} + +CHLModeManager::~CHLModeManager( void ) +{ +} + +void CHLModeManager::Init( void ) +{ + g_pClientMode = GetClientModeNormal(); + PanelMetaClassMgr()->LoadMetaClassDefinitionFile( SCREEN_FILE ); +} + +void CHLModeManager::SwitchMode( bool commander, bool force ) +{ +} + +void CHLModeManager::OverrideView( CViewSetup *pSetup ) +{ +} + +void CHLModeManager::CreateMove( float flInputSampleTime, CUserCmd *cmd ) +{ +} + +void CHLModeManager::LevelInit( const char *newmap ) +{ + g_pClientMode->LevelInit( newmap ); +} + +void CHLModeManager::LevelShutdown( void ) +{ + g_pClientMode->LevelShutdown(); +} + + +static CHLModeManager g_HLModeManager; +IVModeManager *modemanager = &g_HLModeManager; + diff --git a/game/client/hl2/hl_in_main.cpp b/game/client/hl2/hl_in_main.cpp new file mode 100644 index 0000000..7cdf4e0 --- /dev/null +++ b/game/client/hl2/hl_in_main.cpp @@ -0,0 +1,25 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: HL2 specific input handling +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "kbutton.h" +#include "input.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: HL Input interface +//----------------------------------------------------------------------------- +class CHLInput : public CInput +{ +public: +}; + +static CHLInput g_Input; + +// Expose this interface +IInput *input = ( IInput * )&g_Input; diff --git a/game/client/hl2/hl_prediction.cpp b/game/client/hl2/hl_prediction.cpp new file mode 100644 index 0000000..090598f --- /dev/null +++ b/game/client/hl2/hl_prediction.cpp @@ -0,0 +1,24 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "prediction.h" +#include "hl_movedata.h" +#include "c_basehlplayer.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +static CHLMoveData g_HLMoveData; +CMoveData *g_pMoveData = &g_HLMoveData; + +// Expose interface to engine +static CPrediction g_Prediction; + +EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CPrediction, IPrediction, VCLIENT_PREDICTION_INTERFACE_VERSION, g_Prediction ); + +CPrediction *prediction = &g_Prediction; + diff --git a/game/client/hl2/hud_ammo.cpp b/game/client/hl2/hud_ammo.cpp new file mode 100644 index 0000000..9e9e913 --- /dev/null +++ b/game/client/hl2/hud_ammo.cpp @@ -0,0 +1,502 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "hud.h" +#include "hudelement.h" +#include "hud_macros.h" +#include "hud_numericdisplay.h" +#include "iclientmode.h" +#include "iclientvehicle.h" +#include <vgui_controls/AnimationController.h> +#include <vgui/ILocalize.h> +#include <vgui/ISurface.h> +#include "ihudlcd.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Purpose: Displays current ammunition level +//----------------------------------------------------------------------------- +class CHudAmmo : public CHudNumericDisplay, public CHudElement +{ + DECLARE_CLASS_SIMPLE( CHudAmmo, CHudNumericDisplay ); + +public: + CHudAmmo( const char *pElementName ); + void Init( void ); + void VidInit( void ); + void Reset(); + + void SetAmmo(int ammo, bool playAnimation); + void SetAmmo2(int ammo2, bool playAnimation); + virtual void Paint( void ); + +protected: + virtual void OnThink(); + + void UpdateAmmoDisplays(); + void UpdatePlayerAmmo( C_BasePlayer *player ); + void UpdateVehicleAmmo( C_BasePlayer *player, IClientVehicle *pVehicle ); + +private: + CHandle< C_BaseCombatWeapon > m_hCurrentActiveWeapon; + CHandle< C_BaseEntity > m_hCurrentVehicle; + int m_iAmmo; + int m_iAmmo2; + CHudTexture *m_iconPrimaryAmmo; +}; + +DECLARE_HUDELEMENT( CHudAmmo ); + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CHudAmmo::CHudAmmo( const char *pElementName ) : BaseClass(NULL, "HudAmmo"), CHudElement( pElementName ) +{ + SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD | HIDEHUD_NEEDSUIT | HIDEHUD_WEAPONSELECTION ); + + hudlcd->SetGlobalStat( "(ammo_primary)", "0" ); + hudlcd->SetGlobalStat( "(ammo_secondary)", "0" ); + hudlcd->SetGlobalStat( "(weapon_print_name)", "" ); + hudlcd->SetGlobalStat( "(weapon_name)", "" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudAmmo::Init( void ) +{ + m_iAmmo = -1; + m_iAmmo2 = -1; + + m_iconPrimaryAmmo = NULL; + + wchar_t *tempString = g_pVGuiLocalize->Find("#Valve_Hud_AMMO"); + if (tempString) + { + SetLabelText(tempString); + } + else + { + SetLabelText(L"AMMO"); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudAmmo::VidInit( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Resets hud after save/restore +//----------------------------------------------------------------------------- +void CHudAmmo::Reset() +{ + BaseClass::Reset(); + + m_hCurrentActiveWeapon = NULL; + m_hCurrentVehicle = NULL; + m_iAmmo = 0; + m_iAmmo2 = 0; + + UpdateAmmoDisplays(); +} + +//----------------------------------------------------------------------------- +// Purpose: called every frame to get ammo info from the weapon +//----------------------------------------------------------------------------- +void CHudAmmo::UpdatePlayerAmmo( C_BasePlayer *player ) +{ + // Clear out the vehicle entity + m_hCurrentVehicle = NULL; + + C_BaseCombatWeapon *wpn = GetActiveWeapon(); + + hudlcd->SetGlobalStat( "(weapon_print_name)", wpn ? wpn->GetPrintName() : " " ); + hudlcd->SetGlobalStat( "(weapon_name)", wpn ? wpn->GetName() : " " ); + + if ( !wpn || !player || !wpn->UsesPrimaryAmmo() ) + { + hudlcd->SetGlobalStat( "(ammo_primary)", "n/a" ); + hudlcd->SetGlobalStat( "(ammo_secondary)", "n/a" ); + + SetPaintEnabled(false); + SetPaintBackgroundEnabled(false); + return; + } + + SetPaintEnabled(true); + SetPaintBackgroundEnabled(true); + + // Get our icons for the ammo types + m_iconPrimaryAmmo = gWR.GetAmmoIconFromWeapon( wpn->GetPrimaryAmmoType() ); + + // get the ammo in our clip + int ammo1 = wpn->Clip1(); + int ammo2; + if (ammo1 < 0) + { + // we don't use clip ammo, just use the total ammo count + ammo1 = player->GetAmmoCount(wpn->GetPrimaryAmmoType()); + ammo2 = 0; + } + else + { + // we use clip ammo, so the second ammo is the total ammo + ammo2 = player->GetAmmoCount(wpn->GetPrimaryAmmoType()); + } + + hudlcd->SetGlobalStat( "(ammo_primary)", VarArgs( "%d", ammo1 ) ); + hudlcd->SetGlobalStat( "(ammo_secondary)", VarArgs( "%d", ammo2 ) ); + + if (wpn == m_hCurrentActiveWeapon) + { + // same weapon, just update counts + SetAmmo(ammo1, true); + SetAmmo2(ammo2, true); + } + else + { + // diferent weapon, change without triggering + SetAmmo(ammo1, false); + SetAmmo2(ammo2, false); + + // update whether or not we show the total ammo display + if (wpn->UsesClipsForAmmo1()) + { + SetShouldDisplaySecondaryValue(true); + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponUsesClips"); + } + else + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponDoesNotUseClips"); + SetShouldDisplaySecondaryValue(false); + } + + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponChanged"); + m_hCurrentActiveWeapon = wpn; + } +} + +void CHudAmmo::UpdateVehicleAmmo( C_BasePlayer *player, IClientVehicle *pVehicle ) +{ + m_hCurrentActiveWeapon = NULL; + CBaseEntity *pVehicleEnt = pVehicle->GetVehicleEnt(); + + if ( !pVehicleEnt || pVehicle->GetPrimaryAmmoType() < 0 ) + { + SetPaintEnabled(false); + SetPaintBackgroundEnabled(false); + return; + } + + SetPaintEnabled(true); + SetPaintBackgroundEnabled(true); + + // get the ammo in our clip + int ammo1 = pVehicle->GetPrimaryAmmoClip(); + int ammo2; + if (ammo1 < 0) + { + // we don't use clip ammo, just use the total ammo count + ammo1 = pVehicle->GetPrimaryAmmoCount(); + ammo2 = 0; + } + else + { + // we use clip ammo, so the second ammo is the total ammo + ammo2 = pVehicle->GetPrimaryAmmoCount(); + } + + if (pVehicleEnt == m_hCurrentVehicle) + { + // same weapon, just update counts + SetAmmo(ammo1, true); + SetAmmo2(ammo2, true); + } + else + { + // diferent weapon, change without triggering + SetAmmo(ammo1, false); + SetAmmo2(ammo2, false); + + // update whether or not we show the total ammo display + if (pVehicle->PrimaryAmmoUsesClips()) + { + SetShouldDisplaySecondaryValue(true); + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponUsesClips"); + } + else + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponDoesNotUseClips"); + SetShouldDisplaySecondaryValue(false); + } + + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponChanged"); + m_hCurrentVehicle = pVehicleEnt; + } +} + +//----------------------------------------------------------------------------- +// Purpose: called every frame to get ammo info from the weapon +//----------------------------------------------------------------------------- +void CHudAmmo::OnThink() +{ + UpdateAmmoDisplays(); +} + +//----------------------------------------------------------------------------- +// Purpose: updates the ammo display counts +//----------------------------------------------------------------------------- +void CHudAmmo::UpdateAmmoDisplays() +{ + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + IClientVehicle *pVehicle = player ? player->GetVehicle() : NULL; + + if ( !pVehicle ) + { + UpdatePlayerAmmo( player ); + } + else + { + UpdateVehicleAmmo( player, pVehicle ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Updates ammo display +//----------------------------------------------------------------------------- +void CHudAmmo::SetAmmo(int ammo, bool playAnimation) +{ + if (ammo != m_iAmmo) + { + if (ammo == 0) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("AmmoEmpty"); + } + else if (ammo < m_iAmmo) + { + // ammo has decreased + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("AmmoDecreased"); + } + else + { + // ammunition has increased + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("AmmoIncreased"); + } + + m_iAmmo = ammo; + } + + SetDisplayValue(ammo); +} + +//----------------------------------------------------------------------------- +// Purpose: Updates 2nd ammo display +//----------------------------------------------------------------------------- +void CHudAmmo::SetAmmo2(int ammo2, bool playAnimation) +{ + if (ammo2 != m_iAmmo2) + { + if (ammo2 == 0) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("Ammo2Empty"); + } + else if (ammo2 < m_iAmmo2) + { + // ammo has decreased + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("Ammo2Decreased"); + } + else + { + // ammunition has increased + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("Ammo2Increased"); + } + + m_iAmmo2 = ammo2; + } + + SetSecondaryValue(ammo2); +} + +//----------------------------------------------------------------------------- +// Purpose: We add an icon into the +//----------------------------------------------------------------------------- +void CHudAmmo::Paint( void ) +{ + BaseClass::Paint(); + +#ifndef HL2MP + if ( m_hCurrentVehicle == NULL && m_iconPrimaryAmmo ) + { + int nLabelHeight; + int nLabelWidth; + surface()->GetTextSize( m_hTextFont, m_LabelText, nLabelWidth, nLabelHeight ); + + // Figure out where we're going to put this + int x = text_xpos + ( nLabelWidth - m_iconPrimaryAmmo->Width() ) / 2; + int y = text_ypos - ( nLabelHeight + ( m_iconPrimaryAmmo->Height() / 2 ) ); + + m_iconPrimaryAmmo->DrawSelf( x, y, GetFgColor() ); + } +#endif // HL2MP +} + +//----------------------------------------------------------------------------- +// Purpose: Displays the secondary ammunition level +//----------------------------------------------------------------------------- +class CHudSecondaryAmmo : public CHudNumericDisplay, public CHudElement +{ + DECLARE_CLASS_SIMPLE( CHudSecondaryAmmo, CHudNumericDisplay ); + +public: + CHudSecondaryAmmo( const char *pElementName ) : BaseClass( NULL, "HudAmmoSecondary" ), CHudElement( pElementName ) + { + m_iAmmo = -1; + + SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_WEAPONSELECTION | HIDEHUD_PLAYERDEAD | HIDEHUD_NEEDSUIT ); + } + + void Init( void ) + { +#ifndef HL2MP + wchar_t *tempString = g_pVGuiLocalize->Find("#Valve_Hud_AMMO_ALT"); + if (tempString) + { + SetLabelText(tempString); + } + else + { + SetLabelText(L"ALT"); + } +#endif // HL2MP + } + + void VidInit( void ) + { + } + + void SetAmmo( int ammo ) + { + if (ammo != m_iAmmo) + { + if (ammo == 0) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("AmmoSecondaryEmpty"); + } + else if (ammo < m_iAmmo) + { + // ammo has decreased + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("AmmoSecondaryDecreased"); + } + else + { + // ammunition has increased + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("AmmoSecondaryIncreased"); + } + + m_iAmmo = ammo; + } + SetDisplayValue( ammo ); + } + + void Reset() + { + // hud reset, update ammo state + BaseClass::Reset(); + m_iAmmo = 0; + m_hCurrentActiveWeapon = NULL; + SetAlpha( 0 ); + UpdateAmmoState(); + } + + virtual void Paint( void ) + { + BaseClass::Paint(); + +#ifndef HL2MP + if ( m_iconSecondaryAmmo ) + { + int nLabelHeight; + int nLabelWidth; + surface()->GetTextSize( m_hTextFont, m_LabelText, nLabelWidth, nLabelHeight ); + + // Figure out where we're going to put this + int x = text_xpos + ( nLabelWidth - m_iconSecondaryAmmo->Width() ) / 2; + int y = text_ypos - ( nLabelHeight + ( m_iconSecondaryAmmo->Height() / 2 ) ); + + m_iconSecondaryAmmo->DrawSelf( x, y, GetFgColor() ); + } +#endif // HL2MP + } + +protected: + + virtual void OnThink() + { + // set whether or not the panel draws based on if we have a weapon that supports secondary ammo + C_BaseCombatWeapon *wpn = GetActiveWeapon(); + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + IClientVehicle *pVehicle = player ? player->GetVehicle() : NULL; + if (!wpn || !player || pVehicle) + { + m_hCurrentActiveWeapon = NULL; + SetPaintEnabled(false); + SetPaintBackgroundEnabled(false); + return; + } + else + { + SetPaintEnabled(true); + SetPaintBackgroundEnabled(true); + } + + UpdateAmmoState(); + } + + void UpdateAmmoState() + { + C_BaseCombatWeapon *wpn = GetActiveWeapon(); + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + + if (player && wpn && wpn->UsesSecondaryAmmo()) + { + SetAmmo(player->GetAmmoCount(wpn->GetSecondaryAmmoType())); + } + + if ( m_hCurrentActiveWeapon != wpn ) + { + if ( wpn->UsesSecondaryAmmo() ) + { + // we've changed to a weapon that uses secondary ammo + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponUsesSecondaryAmmo"); + } + else + { + // we've changed away from a weapon that uses secondary ammo + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponDoesNotUseSecondaryAmmo"); + } + m_hCurrentActiveWeapon = wpn; + + // Get the icon we should be displaying + m_iconSecondaryAmmo = gWR.GetAmmoIconFromWeapon( m_hCurrentActiveWeapon->GetSecondaryAmmoType() ); + } + } + +private: + CHandle< C_BaseCombatWeapon > m_hCurrentActiveWeapon; + CHudTexture *m_iconSecondaryAmmo; + int m_iAmmo; +}; + +DECLARE_HUDELEMENT( CHudSecondaryAmmo ); + diff --git a/game/client/hl2/hud_autoaim.cpp b/game/client/hl2/hud_autoaim.cpp new file mode 100644 index 0000000..aa808ac --- /dev/null +++ b/game/client/hl2/hud_autoaim.cpp @@ -0,0 +1,472 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "hudelement.h" +#include "iclientmode.h" +#include "c_basehlplayer.h" +#include "view_scene.h" +#include "engine/IEngineSound.h" +#include "vgui_controls/AnimationController.h" +#include "vgui_controls/Controls.h" +#include "vgui_controls/Panel.h" +#include "vgui/ISurface.h" +#include "iviewrender.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +ConVar hud_draw_active_reticle("hud_draw_active_reticle", "0" ); +ConVar hud_draw_fixed_reticle("hud_draw_fixed_reticle", "0", FCVAR_ARCHIVE ); +ConVar hud_autoaim_scale_icon( "hud_autoaim_scale_icon", "0" ); +ConVar hud_autoaim_method( "hud_autoaim_method", "1" ); + +ConVar hud_reticle_scale("hud_reticle_scale", "1.0" ); +ConVar hud_reticle_minalpha( "hud_reticle_minalpha", "125" ); +ConVar hud_reticle_maxalpha( "hud_reticle_maxalpha", "255" ); +ConVar hud_alpha_speed("hud_reticle_alpha_speed", "700" ); +ConVar hud_magnetism("hud_magnetism", "0.3" ); + +enum +{ + AUTOAIM_METHOD_RETICLE = 1, + AUTOAIM_METHOD_DRIFT, +}; + +using namespace vgui; + +class CHUDAutoAim : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHUDAutoAim, vgui::Panel ); +public: + CHUDAutoAim( const char *pElementName ); + virtual ~CHUDAutoAim( void ); + + void ApplySchemeSettings( IScheme *scheme ); + void Init( void ); + void VidInit( void ); + bool ShouldDraw( void ); + virtual void OnThink(); + virtual void Paint(); + +private: + void ResetAlpha() { m_alpha = 0; } + void ResetScale() { m_scale = 1.0f; } + + void ResetPosition() + { + m_vecPos.x = ScreenWidth() / 2; + m_vecPos.y = ScreenHeight() / 2; + m_vecPos.z = 0; + } + + Vector m_vecPos; + float m_alpha; + float m_scale; + + float m_alphaFixed; // alpha value for the fixed element. + + int m_textureID_ActiveReticle; + int m_textureID_FixedReticle; +}; + +DECLARE_HUDELEMENT( CHUDAutoAim ); + +CHUDAutoAim::CHUDAutoAim( const char *pElementName ) : + CHudElement( pElementName ), BaseClass( NULL, "HUDAutoAim" ) +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + SetHiddenBits( HIDEHUD_CROSSHAIR ); + + m_textureID_ActiveReticle = -1; + m_textureID_FixedReticle = -1; +} + +CHUDAutoAim::~CHUDAutoAim( void ) +{ + if ( vgui::surface() ) + { + if ( m_textureID_ActiveReticle != -1 ) + { + vgui::surface()->DestroyTextureID( m_textureID_ActiveReticle ); + m_textureID_ActiveReticle = -1; + } + + if ( m_textureID_FixedReticle != -1 ) + { + vgui::surface()->DestroyTextureID( m_textureID_FixedReticle ); + m_textureID_FixedReticle = -1; + } + } +} + + +void CHUDAutoAim::ApplySchemeSettings( IScheme *scheme ) +{ + BaseClass::ApplySchemeSettings( scheme ); + + SetPaintBackgroundEnabled( false ); +} + +void CHUDAutoAim::Init( void ) +{ + ResetPosition(); + ResetAlpha(); + ResetScale(); +} + +void CHUDAutoAim::VidInit( void ) +{ + SetAlpha( 255 ); + Init(); + + if ( m_textureID_ActiveReticle == -1 ) + { + m_textureID_ActiveReticle = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_textureID_ActiveReticle, "vgui/hud/autoaim", true, false ); + } + + if ( m_textureID_FixedReticle == -1 ) + { + m_textureID_FixedReticle = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_textureID_FixedReticle, "vgui/hud/xbox_reticle", true, false ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Save CPU cycles by letting the HUD system early cull +// costly traversal. Called per frame, return true if thinking and +// painting need to occur. +//----------------------------------------------------------------------------- +bool CHUDAutoAim::ShouldDraw( void ) +{ +#ifndef HL1_CLIENT_DLL + C_BaseHLPlayer *pLocalPlayer = (C_BaseHLPlayer *)C_BasePlayer::GetLocalPlayer(); + if ( pLocalPlayer ) + { + if( !pLocalPlayer->m_HL2Local.m_bDisplayReticle ) + { + return false; + } + } +#endif + + return ( (hud_draw_fixed_reticle.GetBool() || hud_draw_active_reticle.GetBool()) && CHudElement::ShouldDraw() && !engine->IsDrawingLoadingImage() ); +} + +#define AUTOAIM_ALPHA_UP_SPEED 1000 +#define AUTOAIM_ALPHA_DOWN_SPEED 300 +#define AUTOAIM_MAX_ALPHA 120 +#define AUTOAIM_MAX_SCALE 1.0f +#define AUTOAIM_MIN_SCALE 0.5f +#define AUTOAIM_SCALE_SPEED 10.0f +#define AUTOAIM_ONTARGET_CROSSHAIR_SPEED (ScreenWidth() / 3) // Can cross the whole screen in 3 seconds. +#define AUTOAIM_OFFTARGET_CROSSHAIR_SPEED (ScreenWidth() / 4) + +void CHUDAutoAim::OnThink() +{ + int wide, tall; + GetSize( wide, tall ); + + BaseClass::OnThink(); + + // Get the HL2 player + C_BaseHLPlayer *pLocalPlayer = (C_BaseHLPlayer *)C_BasePlayer::GetLocalPlayer(); + if ( pLocalPlayer == NULL ) + { + // Just turn the autoaim crosshair off. + ResetPosition(); + ResetAlpha(); + ResetScale(); + + m_alphaFixed = 0.0f; + return; + } + + // Get the autoaim target. + CBaseEntity *pTarget = pLocalPlayer->m_HL2Local.m_hAutoAimTarget.Get(); + + // Fixed element stuff + float flFixedAlphaGoal; + + if( pTarget ) + { + flFixedAlphaGoal = hud_reticle_maxalpha.GetFloat(); + } + else + { + flFixedAlphaGoal = hud_reticle_minalpha.GetFloat(); + } + + if( pLocalPlayer->m_HL2Local.m_bZooming || pLocalPlayer->m_HL2Local.m_bWeaponLowered ) + { + flFixedAlphaGoal = 0.0f; + } + + m_alphaFixed = Approach( flFixedAlphaGoal, m_alphaFixed, (hud_alpha_speed.GetFloat() * gpGlobals->frametime) ); + + + switch( hud_autoaim_method.GetInt() ) + { + case AUTOAIM_METHOD_RETICLE: + { + if( pLocalPlayer->m_HL2Local.m_hAutoAimTarget.Get() && pLocalPlayer->m_HL2Local.m_bStickyAutoAim ) + { + if( !pLocalPlayer->IsInAVehicle() ) + { + Vector vecLook; + pLocalPlayer->EyeVectors( &vecLook, NULL, NULL ); + + Vector vecMove = pLocalPlayer->GetAbsVelocity(); + float flSpeed = VectorNormalize( vecMove ); + float flDot = DotProduct( vecLook, vecMove ); + + if( flSpeed >= 100 && fabs(flDot) <= 0.707f ) + { + QAngle viewangles; + QAngle targetangles; + QAngle delta; + + engine->GetViewAngles( viewangles ); + + Vector vecDir = pLocalPlayer->m_HL2Local.m_vecAutoAimPoint - pLocalPlayer->EyePosition(); + VectorNormalize(vecDir); + VectorAngles( vecDir, targetangles ); + + float magnetism = hud_magnetism.GetFloat(); + + delta[0] = ApproachAngle( targetangles[0], viewangles[0], magnetism ); + delta[1] = ApproachAngle( targetangles[1], viewangles[1], magnetism ); + delta[2] = targetangles[2]; + + //viewangles[PITCH] = clamp( viewangles[ PITCH ], -cl_pitchup.GetFloat(), cl_pitchdown.GetFloat() ); + engine->SetViewAngles( delta ); + } + } + } + +#if 0 + bool doScaling = hud_autoaim_scale_icon.GetBool(); + + // These are the X & Y coords of where the crosshair should be. Default to + // returning to the center of the screen if there is no target. + int goalx = ScreenWidth() / 2; + int goaly = ScreenHeight() / 2; + int goalalpha = 0; + float goalscale = AUTOAIM_MIN_SCALE; + float speed = AUTOAIM_OFFTARGET_CROSSHAIR_SPEED; + + if( pTarget ) + { + // Get the autoaim crosshair onto the target. + Vector screen; + + // Center the crosshair on the entity. + if( doScaling ) + { + // Put the crosshair over the center of the target. + ScreenTransform( pTarget->WorldSpaceCenter(), screen ); + } + else + { + // Put the crosshair exactly where the player is aiming. + ScreenTransform( pLocalPlayer->m_HL2Local.m_vecAutoAimPoint, screen ); + } + + // Set Goal Position and speed. + goalx += 0.5f * screen[0] * ScreenWidth() + 0.5f; + goaly -= 0.5f * screen[1] * ScreenHeight() + 0.5f; + speed = AUTOAIM_ONTARGET_CROSSHAIR_SPEED; + + goalalpha = AUTOAIM_MAX_ALPHA; + + if( doScaling ) + { + // Scale the crosshair to envelope the entity's bounds on screen. + Vector vecMins, vecMaxs; + Vector vecScreenMins, vecScreenMaxs; + + // Get mins and maxs in world space + vecMins = pTarget->GetAbsOrigin() + pTarget->WorldAlignMins(); + vecMaxs = pTarget->GetAbsOrigin() + pTarget->WorldAlignMaxs(); + + // Project them to screen + ScreenTransform( vecMins, vecScreenMins ); + ScreenTransform( vecMaxs, vecScreenMaxs ); + + vecScreenMins.y = (ScreenWidth()/2) - 0.5f * vecScreenMins.y * ScreenWidth() + 0.5f; + vecScreenMaxs.y = (ScreenWidth()/2) - 0.5f * vecScreenMaxs.y * ScreenWidth() + 0.5f; + + float screenSize = vecScreenMins.y - vecScreenMaxs.y; + + // Set goal scale + goalscale = screenSize / 64.0f; // 64 is the width of the crosshair art. + } + else + { + goalscale = 1.0f; + } + } + + // Now approach the goal, alpha, and scale + Vector vecGoal( goalx, goaly, 0 ); + Vector vecDir = vecGoal - m_vecPos; + float flDistRemaining = VectorNormalize( vecDir ); + m_vecPos += vecDir * min(flDistRemaining, (speed * gpGlobals->frametime) ); + + // Lerp and Clamp scale + float scaleDelta = fabs( goalscale - m_scale ); + float scaleMove = MIN( AUTOAIM_SCALE_SPEED * gpGlobals->frametime, scaleDelta ); + if( m_scale < goalscale ) + { + m_scale += scaleMove; + } + else if( m_scale > goalscale ) + { + m_scale -= scaleMove; + } + if( m_scale > AUTOAIM_MAX_SCALE ) + { + m_scale = AUTOAIM_MAX_SCALE; + } + else if( m_scale < AUTOAIM_MIN_SCALE ) + { + m_scale = AUTOAIM_MIN_SCALE; + } + + if( goalalpha > m_alpha ) + { + m_alpha += AUTOAIM_ALPHA_UP_SPEED * gpGlobals->frametime; + } + else if( goalalpha < m_alpha ) + { + m_alpha -= AUTOAIM_ALPHA_DOWN_SPEED * gpGlobals->frametime; + } + + // Clamp alpha + if( m_alpha < 0 ) + { + m_alpha = 0; + } + else if( m_alpha > AUTOAIM_MAX_ALPHA ) + { + m_alpha = AUTOAIM_MAX_ALPHA; + } +#endif + } + break; + + case AUTOAIM_METHOD_DRIFT: + { + if( pLocalPlayer->m_HL2Local.m_hAutoAimTarget.Get() ) + { + QAngle viewangles; + + engine->GetViewAngles( viewangles ); + + Vector vecDir = pLocalPlayer->m_HL2Local.m_vecAutoAimPoint - pLocalPlayer->EyePosition(); + VectorNormalize(vecDir); + + VectorAngles( vecDir, viewangles ); + + //viewangles[PITCH] = clamp( viewangles[ PITCH ], -cl_pitchup.GetFloat(), cl_pitchdown.GetFloat() ); + engine->SetViewAngles( viewangles ); + } + } + break; + } +} + +void CHUDAutoAim::Paint() +{ + if( hud_draw_active_reticle.GetBool() ) + { + int xCenter = m_vecPos.x; + int yCenter = m_vecPos.y; + + int width, height; + float xMod, yMod; + + vgui::surface()->DrawSetTexture( m_textureID_ActiveReticle ); + vgui::surface()->DrawSetColor( 255, 255, 255, m_alpha ); + vgui::surface()->DrawGetTextureSize( m_textureID_ActiveReticle, width, height ); + + float uv1 = 0.5f / width, uv2 = 1.0f - uv1; + + vgui::Vertex_t vert[4]; + + Vector2D uv11( uv1, uv1 ); + Vector2D uv12( uv1, uv2 ); + Vector2D uv21( uv2, uv1 ); + Vector2D uv22( uv2, uv2 ); + + xMod = width; + yMod = height; + + xMod *= m_scale; + yMod *= m_scale; + + xMod /= 2; + yMod /= 2; + + vert[0].Init( Vector2D( xCenter + xMod, yCenter + yMod ), uv21 ); + vert[1].Init( Vector2D( xCenter - xMod, yCenter + yMod ), uv11 ); + vert[2].Init( Vector2D( xCenter - xMod, yCenter - yMod ), uv12 ); + vert[3].Init( Vector2D( xCenter + xMod, yCenter - yMod ), uv22 ); + vgui::surface()->DrawTexturedPolygon( 4, vert ); + } + + if( hud_draw_fixed_reticle.GetBool() ) + { + int width, height; + float xMod, yMod; + + vgui::surface()->DrawSetTexture( m_textureID_FixedReticle ); + vgui::surface()->DrawGetTextureSize( m_textureID_FixedReticle, width, height ); + + int xCenter = ScreenWidth() / 2; + int yCenter = ScreenHeight() / 2; + + vgui::Vertex_t vert[4]; + + Vector2D uv11( 0, 0 ); + Vector2D uv12( 0, 1 ); + Vector2D uv21( 1, 0 ); + Vector2D uv22( 1, 1 ); + + xMod = width; + yMod = height; + + xMod /= 2; + yMod /= 2; + + vert[0].Init( Vector2D( xCenter + xMod, yCenter + yMod ), uv21 ); + vert[1].Init( Vector2D( xCenter - xMod, yCenter + yMod ), uv11 ); + vert[2].Init( Vector2D( xCenter - xMod, yCenter - yMod ), uv12 ); + vert[3].Init( Vector2D( xCenter + xMod, yCenter - yMod ), uv22 ); + + Color clr; + clr = gHUD.m_clrNormal; + int r,g,b,a; + clr.GetColor( r,g,b,a ); + + C_BaseHLPlayer *pLocalPlayer = (C_BaseHLPlayer *)C_BasePlayer::GetLocalPlayer(); + if( pLocalPlayer && pLocalPlayer->m_HL2Local.m_hAutoAimTarget.Get() ) + { + r = 250; + g = 138; + b = 4; + } + + clr.SetColor( r,g,b,m_alphaFixed); + + vgui::surface()->DrawSetColor( clr ); + vgui::surface()->DrawTexturedPolygon( 4, vert ); + } +}
\ No newline at end of file diff --git a/game/client/hl2/hud_battery.cpp b/game/client/hl2/hud_battery.cpp new file mode 100644 index 0000000..c07943c --- /dev/null +++ b/game/client/hl2/hud_battery.cpp @@ -0,0 +1,147 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// +// battery.cpp +// +// implementation of CHudBattery class +// +#include "cbase.h" +#include "hud.h" +#include "hudelement.h" +#include "hud_macros.h" +#include "hud_numericdisplay.h" +#include "iclientmode.h" + +#include "vgui_controls/AnimationController.h" +#include "vgui/ILocalize.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define INIT_BAT -1 + +//----------------------------------------------------------------------------- +// Purpose: Displays suit power (armor) on hud +//----------------------------------------------------------------------------- +class CHudBattery : public CHudNumericDisplay, public CHudElement +{ + DECLARE_CLASS_SIMPLE( CHudBattery, CHudNumericDisplay ); + +public: + CHudBattery( const char *pElementName ); + void Init( void ); + void Reset( void ); + void VidInit( void ); + void OnThink( void ); + void MsgFunc_Battery(bf_read &msg ); + bool ShouldDraw(); + +private: + int m_iBat; + int m_iNewBat; +}; + +DECLARE_HUDELEMENT( CHudBattery ); +DECLARE_HUD_MESSAGE( CHudBattery, Battery ); + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CHudBattery::CHudBattery( const char *pElementName ) : BaseClass(NULL, "HudSuit"), CHudElement( pElementName ) +{ + SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_NEEDSUIT ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudBattery::Init( void ) +{ + HOOK_HUD_MESSAGE( CHudBattery, Battery); + Reset(); + m_iBat = INIT_BAT; + m_iNewBat = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudBattery::Reset( void ) +{ + SetLabelText(g_pVGuiLocalize->Find("#Valve_Hud_SUIT")); + SetDisplayValue(m_iBat); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudBattery::VidInit( void ) +{ + Reset(); +} + +//----------------------------------------------------------------------------- +// Purpose: Save CPU cycles by letting the HUD system early cull +// costly traversal. Called per frame, return true if thinking and +// painting need to occur. +//----------------------------------------------------------------------------- +bool CHudBattery::ShouldDraw( void ) +{ + bool bNeedsDraw = ( m_iBat != m_iNewBat ) || ( GetAlpha() > 0 ); + + return ( bNeedsDraw && CHudElement::ShouldDraw() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudBattery::OnThink( void ) +{ + if ( m_iBat == m_iNewBat ) + return; + + if ( !m_iNewBat ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("SuitPowerZero"); + } + else if ( m_iNewBat < m_iBat ) + { + // battery power has decreased, so play the damaged animation + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("SuitDamageTaken"); + + // play an extra animation if we're super low + if ( m_iNewBat < 20 ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("SuitArmorLow"); + } + } + else + { + // battery power has increased (if we had no previous armor, or if we just loaded the game, don't use alert state) + if ( m_iBat == INIT_BAT || m_iBat == 0 || m_iNewBat >= 20) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("SuitPowerIncreasedAbove20"); + } + else + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("SuitPowerIncreasedBelow20"); + } + } + + m_iBat = m_iNewBat; + + SetDisplayValue(m_iBat); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudBattery::MsgFunc_Battery( bf_read &msg ) +{ + m_iNewBat = msg.ReadShort(); +} diff --git a/game/client/hl2/hud_blood.cpp b/game/client/hl2/hud_blood.cpp new file mode 100644 index 0000000..e3528b5 --- /dev/null +++ b/game/client/hl2/hud_blood.cpp @@ -0,0 +1,34 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "clienteffectprecachesystem.h" +#include "c_te_effect_dispatch.h" +#include "hud.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +void BloodSplatCallback( const CEffectData & data ) +{ +/* + Msg("SPLAT!\n"); + + int x,y; + + // Find our screen position to start from + x = XRES(320); + y = YRES(240); + + // Draw the ammo label + CHudTexture *pSplat = gHUD.GetIcon( "hud_blood1" ); + + // FIXME: This can only occur during vgui::Paint() stuff + pSplat->DrawSelf( x, y, gHUD.m_clrNormal); +*/ +} + +DECLARE_CLIENT_EFFECT( "HudBloodSplat", BloodSplatCallback ); diff --git a/game/client/hl2/hud_bonusprogress.cpp b/game/client/hl2/hud_bonusprogress.cpp new file mode 100644 index 0000000..c7569e0 --- /dev/null +++ b/game/client/hl2/hud_bonusprogress.cpp @@ -0,0 +1,197 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// +// BonusProgress.cpp +// +// implementation of CHudBonusProgress class +// +#include "cbase.h" +#include "hud.h" +#include "hud_macros.h" +#include "view.h" + +#include "iclientmode.h" + +#include <KeyValues.h> +#include <vgui/ISurface.h> +#include <vgui/ISystem.h> +#include <vgui_controls/AnimationController.h> + +#include <vgui/ILocalize.h> + +using namespace vgui; + +#include "hudelement.h" +#include "hud_numericdisplay.h" + +#include "convar.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define INIT_BONUS_PROGRESS -1 + + +//----------------------------------------------------------------------------- +// Purpose: BonusProgress panel +//----------------------------------------------------------------------------- +class CHudBonusProgress : public CHudElement, public CHudNumericDisplay +{ + DECLARE_CLASS_SIMPLE( CHudBonusProgress, CHudNumericDisplay ); + +public: + CHudBonusProgress( const char *pElementName ); + virtual void Init( void ); + virtual void VidInit( void ); + virtual void Reset( void ); + virtual void OnThink(); + +private: + void SetChallengeLabel( void ); + +private: + // old variables + int m_iBonusProgress; + + int m_iLastChallenge; +}; + +DECLARE_HUDELEMENT( CHudBonusProgress ); + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CHudBonusProgress::CHudBonusProgress( const char *pElementName ) : CHudElement( pElementName ), CHudNumericDisplay(NULL, "HudBonusProgress") +{ + SetHiddenBits( HIDEHUD_BONUS_PROGRESS ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudBonusProgress::Init() +{ + Reset(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudBonusProgress::Reset() +{ + m_iBonusProgress = INIT_BONUS_PROGRESS; + + C_BasePlayer *local = C_BasePlayer::GetLocalPlayer(); + if ( local ) + m_iLastChallenge = local->GetBonusChallenge(); + + SetChallengeLabel(); + + SetDisplayValue(m_iBonusProgress); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudBonusProgress::VidInit() +{ + Reset(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudBonusProgress::OnThink() +{ + C_GameRules *pGameRules = GameRules(); + + if ( !pGameRules ) + { + // Not ready to init! + return; + } + + int newBonusProgress = 0; + int iBonusChallenge = 0; + + C_BasePlayer *local = C_BasePlayer::GetLocalPlayer(); + if ( !local ) + { + // Not ready to init! + return; + } + + // Never below zero + newBonusProgress = MAX( local->GetBonusProgress(), 0 ); + iBonusChallenge = local->GetBonusChallenge(); + + // Only update the fade if we've changed bonusProgress + if ( newBonusProgress == m_iBonusProgress && m_iLastChallenge == iBonusChallenge ) + { + return; + } + + m_iBonusProgress = newBonusProgress; + + if ( m_iLastChallenge != iBonusChallenge ) + { + m_iLastChallenge = iBonusChallenge; + SetChallengeLabel(); + } + + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("BonusProgressFlash"); + + if ( pGameRules->IsBonusChallengeTimeBased() ) + { + SetIsTime( true ); + SetIndent( false ); + } + else + { + SetIsTime( false ); + SetIndent( true ); + } + + SetDisplayValue(m_iBonusProgress); +} + +void CHudBonusProgress::SetChallengeLabel( void ) +{ + // Blank for no challenge + if ( m_iLastChallenge == 0 ) + { + SetLabelText(L""); + return; + } + + char szBonusTextName[] = "#Valve_Hud_BONUS_PROGRESS00"; + + int iStringLength = Q_strlen( szBonusTextName ); + + szBonusTextName[ iStringLength - 2 ] = ( m_iLastChallenge / 10 ) + '0'; + szBonusTextName[ iStringLength - 1 ] = ( m_iLastChallenge % 10 ) + '0'; + + wchar_t *tempString = g_pVGuiLocalize->Find(szBonusTextName); + + if (tempString) + { + SetLabelText(tempString); + return; + } + + // Couldn't find a special string for this challenge + tempString = g_pVGuiLocalize->Find("#Valve_Hud_BONUS_PROGRESS"); + if (tempString) + { + SetLabelText(tempString); + return; + } + + // Couldn't find any localizable string + SetLabelText(L"BONUS"); +}
\ No newline at end of file diff --git a/game/client/hl2/hud_credits.cpp b/game/client/hl2/hud_credits.cpp new file mode 100644 index 0000000..6ad1488 --- /dev/null +++ b/game/client/hl2/hud_credits.cpp @@ -0,0 +1,735 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "hudelement.h" +#include "hud_numericdisplay.h" +#include <vgui_controls/Panel.h> +#include "hud.h" +#include "hud_suitpower.h" +#include "hud_macros.h" +#include "iclientmode.h" +#include <vgui_controls/AnimationController.h> +#include <vgui/ISurface.h> +#include <vgui/ILocalize.h> +#include "KeyValues.h" +#include "filesystem.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +struct creditname_t +{ + char szCreditName[256]; + char szFontName[256]; + float flYPos; + float flXPos; + bool bActive; + float flTime; + float flTimeAdd; + float flTimeStart; + int iSlot; +}; + +#define CREDITS_FILE "scripts/credits.txt" + +enum +{ + LOGO_FADEIN = 0, + LOGO_FADEHOLD, + LOGO_FADEOUT, + LOGO_FADEOFF, +}; + +#define CREDITS_LOGO 1 +#define CREDITS_INTRO 2 +#define CREDITS_OUTRO 3 + +bool g_bRollingCredits = false; + +int g_iCreditsPixelHeight = 0; + +//----------------------------------------------------------------------------- +// Purpose: Shows the flashlight icon +//----------------------------------------------------------------------------- +class CHudCredits : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudCredits, vgui::Panel ); + +public: + CHudCredits( const char *pElementName ); + virtual void Init( void ); + virtual void LevelShutdown( void ); + + int GetStringPixelWidth ( wchar_t *pString, vgui::HFont hFont ); + + void MsgFunc_CreditsMsg( bf_read &msg ); + void MsgFunc_LogoTimeMsg( bf_read &msg ); + + virtual bool ShouldDraw( void ) + { + g_bRollingCredits = IsActive(); + + if ( g_bRollingCredits && m_iCreditsType == CREDITS_INTRO ) + g_bRollingCredits = false; + + return IsActive(); + } + +protected: + virtual void Paint(); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + +private: + + void Clear(); + + void ReadNames( KeyValues *pKeyValue ); + void ReadParams( KeyValues *pKeyValue ); + void PrepareCredits( const char *pKeyName ); + void DrawOutroCreditsName( void ); + void DrawIntroCreditsName( void ); + void DrawLogo( void ); + + void PrepareLogo( float flTime ); + void PrepareOutroCredits( void ); + void PrepareIntroCredits( void ); + + float FadeBlend( float fadein, float fadeout, float hold, float localTime ); + + void PrepareLine( vgui::HFont hFont, char const *pchLine ); + + CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "Default" ); + CPanelAnimationVar( Color, m_TextColor, "TextColor", "FgColor" ); + + CUtlVector<creditname_t> m_CreditsList; + + float m_flScrollTime; + float m_flSeparation; + float m_flFadeTime; + bool m_bLastOneInPlace; + int m_Alpha; + + int m_iCreditsType; + int m_iLogoState; + + float m_flFadeInTime; + float m_flFadeHoldTime; + float m_flFadeOutTime; + float m_flNextStartTime; + float m_flPauseBetweenWaves; + + float m_flLogoTimeMod; + float m_flLogoTime; + float m_flLogoDesiredLength; + + float m_flX; + float m_flY; + + char m_szLogo[256]; + char m_szLogo2[256]; + + Color m_cColor; +}; + + +void CHudCredits::PrepareCredits( const char *pKeyName ) +{ + Clear(); + + KeyValues *pKV= new KeyValues( "CreditsFile" ); + if ( !pKV->LoadFromFile( filesystem, CREDITS_FILE, "MOD" ) ) + { + pKV->deleteThis(); + + Assert( !"env_credits couldn't be initialized!" ); + return; + } + + KeyValues *pKVSubkey; + if ( pKeyName ) + { + pKVSubkey = pKV->FindKey( pKeyName ); + ReadNames( pKVSubkey ); + } + + pKVSubkey = pKV->FindKey( "CreditsParams" ); + ReadParams( pKVSubkey ); + + pKV->deleteThis(); +} + +using namespace vgui; + +DECLARE_HUDELEMENT( CHudCredits ); +DECLARE_HUD_MESSAGE( CHudCredits, CreditsMsg ); +DECLARE_HUD_MESSAGE( CHudCredits, LogoTimeMsg ); + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CHudCredits::CHudCredits( const char *pElementName ) : CHudElement( pElementName ), BaseClass( NULL, "HudCredits" ) +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); +} + +void CHudCredits::LevelShutdown() +{ + Clear(); +} + +void CHudCredits::Clear( void ) +{ + SetActive( false ); + m_CreditsList.RemoveAll(); + m_bLastOneInPlace = false; + m_Alpha = m_TextColor[3]; + m_iLogoState = LOGO_FADEOFF; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudCredits::Init() +{ + HOOK_HUD_MESSAGE( CHudCredits, CreditsMsg ); + HOOK_HUD_MESSAGE( CHudCredits, LogoTimeMsg ); + SetActive( false ); +} + +void CHudCredits::ReadNames( KeyValues *pKeyValue ) +{ + if ( pKeyValue == NULL ) + { + Assert( !"CHudCredits couldn't be initialized!" ); + return; + } + + // Now try and parse out each act busy anim + KeyValues *pKVNames = pKeyValue->GetFirstSubKey(); + + while ( pKVNames ) + { + creditname_t Credits; + V_strcpy_safe( Credits.szCreditName, pKVNames->GetName() ); + V_strcpy_safe( Credits.szFontName, pKeyValue->GetString( Credits.szCreditName, "Default" ) ); + + m_CreditsList.AddToTail( Credits ); + pKVNames = pKVNames->GetNextKey(); + } +} + +void CHudCredits::ReadParams( KeyValues *pKeyValue ) +{ + if ( pKeyValue == NULL ) + { + Assert( !"CHudCredits couldn't be initialized!" ); + return; + } + + m_flScrollTime = pKeyValue->GetFloat( "scrolltime", 57 ); + m_flSeparation = pKeyValue->GetFloat( "separation", 5 ); + + m_flFadeInTime = pKeyValue->GetFloat( "fadeintime", 1 ); + m_flFadeHoldTime = pKeyValue->GetFloat( "fadeholdtime", 3 ); + m_flFadeOutTime = pKeyValue->GetFloat( "fadeouttime", 2 ); + m_flNextStartTime = pKeyValue->GetFloat( "nextfadetime", 2 ); + m_flPauseBetweenWaves = pKeyValue->GetFloat( "pausebetweenwaves", 2 ); + + m_flLogoTimeMod = pKeyValue->GetFloat( "logotime", 2 ); + + m_flX = pKeyValue->GetFloat( "posx", 2 ); + m_flY = pKeyValue->GetFloat( "posy", 2 ); + + m_cColor = pKeyValue->GetColor( "color" ); + + Q_strncpy( m_szLogo, pKeyValue->GetString( "logo", "HALF-LIFE'" ), sizeof( m_szLogo ) ); + Q_strncpy( m_szLogo2, pKeyValue->GetString( "logo2", "" ), sizeof( m_szLogo2 ) ); +} + +int CHudCredits::GetStringPixelWidth( wchar_t *pString, vgui::HFont hFont ) +{ + int iLength = 0; + + for ( wchar_t *wch = pString; *wch != 0; wch++ ) + { + iLength += surface()->GetCharacterWidth( hFont, *wch ); + } + + return iLength; +} + +void CHudCredits::DrawOutroCreditsName( void ) +{ + if ( m_CreditsList.Count() == 0 ) + return; + + // fill the screen + int iWidth, iTall; + GetHudSize(iWidth, iTall); + SetSize( iWidth, iTall ); + + for ( int i = 0; i < m_CreditsList.Count(); i++ ) + { + creditname_t *pCredit = &m_CreditsList[i]; + + if ( pCredit == NULL ) + continue; + + vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); + vgui::HFont m_hTFont = vgui::scheme()->GetIScheme(scheme)->GetFont( pCredit->szFontName, true ); + + int iFontTall = surface()->GetFontTall ( m_hTFont ); + + if ( pCredit->flYPos < -iFontTall || pCredit->flYPos > iTall ) + { + pCredit->bActive = false; + } + else + { + pCredit->bActive = true; + } + + Color cColor = m_TextColor; + + //HACKHACK + //Last one stays on screen and fades out + if ( i == m_CreditsList.Count()-1 ) + { + if ( m_bLastOneInPlace == false ) + { + pCredit->flYPos -= gpGlobals->frametime * ( (float)g_iCreditsPixelHeight / m_flScrollTime ); + + if ( (int)pCredit->flYPos + ( iFontTall / 2 ) <= iTall / 2 ) + { + m_bLastOneInPlace = true; + + // 360 certification requires that we not hold a static image too long. + m_flFadeTime = gpGlobals->curtime + ( IsConsole() ? 2.0f : 10.0f ); + } + } + else + { + if ( m_flFadeTime <= gpGlobals->curtime ) + { + if ( m_Alpha > 0 ) + { + m_Alpha -= gpGlobals->frametime * ( m_flScrollTime * 2 ); + + if ( m_Alpha <= 0 ) + { + pCredit->bActive = false; + engine->ClientCmd( "creditsdone" ); + } + } + } + + cColor[3] = MAX( 0, m_Alpha ); + } + } + else + { + pCredit->flYPos -= gpGlobals->frametime * ( (float)g_iCreditsPixelHeight / m_flScrollTime ); + } + + if ( pCredit->bActive == false ) + continue; + + surface()->DrawSetTextFont( m_hTFont ); + surface()->DrawSetTextColor( cColor[0], cColor[1], cColor[2], cColor[3] ); + + wchar_t unicode[256]; + + if ( pCredit->szCreditName[0] == '#' ) + { + g_pVGuiLocalize->ConstructString( unicode, sizeof(unicode), g_pVGuiLocalize->Find(pCredit->szCreditName), 0 ); + } + else + { + g_pVGuiLocalize->ConvertANSIToUnicode( pCredit->szCreditName, unicode, sizeof( unicode ) ); + } + + int iStringWidth = GetStringPixelWidth( unicode, m_hTFont ); + + surface()->DrawSetTextPos( ( iWidth / 2 ) - ( iStringWidth / 2 ), pCredit->flYPos ); + surface()->DrawUnicodeString( unicode ); + } +} + +void CHudCredits::DrawLogo( void ) +{ + if( m_iLogoState == LOGO_FADEOFF ) + { + SetActive( false ); + return; + } + + switch( m_iLogoState ) + { + case LOGO_FADEIN: + { + float flDeltaTime = ( m_flFadeTime - gpGlobals->curtime ); + + m_Alpha = MAX( 0, RemapValClamped( flDeltaTime, 5.0f, 0, -128, 255 ) ); + + if ( flDeltaTime <= 0.0f ) + { + m_iLogoState = LOGO_FADEHOLD; + m_flFadeTime = gpGlobals->curtime + m_flLogoDesiredLength; + } + + break; + } + + case LOGO_FADEHOLD: + { + if ( m_flFadeTime <= gpGlobals->curtime ) + { + m_iLogoState = LOGO_FADEOUT; + m_flFadeTime = gpGlobals->curtime + 2.0f; + } + break; + } + + case LOGO_FADEOUT: + { + float flDeltaTime = ( m_flFadeTime - gpGlobals->curtime ); + + m_Alpha = RemapValClamped( flDeltaTime, 0.0f, 2.0f, 0, 255 ); + + if ( flDeltaTime <= 0.0f ) + { + m_iLogoState = LOGO_FADEOFF; + SetActive( false ); + } + + break; + } + } + + // fill the screen + int iWidth, iTall; + GetHudSize(iWidth, iTall); + SetSize( iWidth, iTall ); + + char szLogoFont[64]; + + if ( IsXbox() ) + { + Q_snprintf( szLogoFont, sizeof( szLogoFont ), "WeaponIcons_Small" ); + } + else if ( hl2_episodic.GetBool() ) + { + Q_snprintf( szLogoFont, sizeof( szLogoFont ), "ClientTitleFont" ); + } + else + { + Q_snprintf( szLogoFont, sizeof( szLogoFont ), "WeaponIcons" ); + } + + vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); + vgui::HFont m_hTFont = vgui::scheme()->GetIScheme(scheme)->GetFont( szLogoFont ); + + int iFontTall = surface()->GetFontTall ( m_hTFont ); + + Color cColor = m_TextColor; + cColor[3] = m_Alpha; + + surface()->DrawSetTextFont( m_hTFont ); + surface()->DrawSetTextColor( cColor[0], cColor[1], cColor[2], cColor[3] ); + + wchar_t unicode[256]; + g_pVGuiLocalize->ConvertANSIToUnicode( m_szLogo, unicode, sizeof( unicode ) ); + + int iStringWidth = GetStringPixelWidth( unicode, m_hTFont ); + + surface()->DrawSetTextPos( ( iWidth / 2 ) - ( iStringWidth / 2 ), ( iTall / 2 ) - ( iFontTall / 2 ) ); + surface()->DrawUnicodeString( unicode ); + + if ( Q_strlen( m_szLogo2 ) > 0 ) + { + g_pVGuiLocalize->ConvertANSIToUnicode( m_szLogo2, unicode, sizeof( unicode ) ); + + iStringWidth = GetStringPixelWidth( unicode, m_hTFont ); + + surface()->DrawSetTextPos( ( iWidth / 2 ) - ( iStringWidth / 2 ), ( iTall / 2 ) + ( iFontTall / 2 )); + surface()->DrawUnicodeString( unicode ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +float CHudCredits::FadeBlend( float fadein, float fadeout, float hold, float localTime ) +{ + float fadeTime = fadein + hold; + float fadeBlend; + + if ( localTime < 0 ) + return 0; + + if ( localTime < fadein ) + { + fadeBlend = 1 - ((fadein - localTime) / fadein); + } + else if ( localTime > fadeTime ) + { + if ( fadeout > 0 ) + fadeBlend = 1 - ((localTime - fadeTime) / fadeout); + else + fadeBlend = 0; + } + else + fadeBlend = 1; + + if ( fadeBlend < 0 ) + fadeBlend = 0; + + return fadeBlend; +} + +void CHudCredits::DrawIntroCreditsName( void ) +{ + if ( m_CreditsList.Count() == 0 ) + return; + + // fill the screen + int iWidth, iTall; + GetHudSize(iWidth, iTall); + SetSize( iWidth, iTall ); + + for ( int i = 0; i < m_CreditsList.Count(); i++ ) + { + creditname_t *pCredit = &m_CreditsList[i]; + + if ( pCredit == NULL ) + continue; + + if ( pCredit->bActive == false ) + continue; + + vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); + vgui::HFont m_hTFont = vgui::scheme()->GetIScheme(scheme)->GetFont( pCredit->szFontName ); + + float localTime = gpGlobals->curtime - pCredit->flTimeStart; + + surface()->DrawSetTextFont( m_hTFont ); + surface()->DrawSetTextColor( m_cColor[0], m_cColor[1], m_cColor[2], FadeBlend( m_flFadeInTime, m_flFadeOutTime, m_flFadeHoldTime + pCredit->flTimeAdd, localTime ) * m_cColor[3] ); + + wchar_t unicode[256]; + g_pVGuiLocalize->ConvertANSIToUnicode( pCredit->szCreditName, unicode, sizeof( unicode ) ); + + surface()->DrawSetTextPos( XRES( pCredit->flXPos ), YRES( pCredit->flYPos ) ); + surface()->DrawUnicodeString( unicode ); + + if ( m_flLogoTime > gpGlobals->curtime ) + continue; + + if ( pCredit->flTime - m_flNextStartTime <= gpGlobals->curtime ) + { + if ( m_CreditsList.IsValidIndex( i + 3 ) ) + { + creditname_t *pNextCredits = &m_CreditsList[i + 3]; + + if ( pNextCredits && pNextCredits->flTime == 0.0f ) + { + pNextCredits->bActive = true; + + if ( i < 3 ) + { + pNextCredits->flTimeAdd = ( i + 1.0f ); + pNextCredits->flTime = gpGlobals->curtime + m_flFadeInTime + m_flFadeOutTime + m_flFadeHoldTime + pNextCredits->flTimeAdd; + } + else + { + pNextCredits->flTimeAdd = m_flPauseBetweenWaves; + pNextCredits->flTime = gpGlobals->curtime + m_flFadeInTime + m_flFadeOutTime + m_flFadeHoldTime + pNextCredits->flTimeAdd; + } + + pNextCredits->flTimeStart = gpGlobals->curtime; + + pNextCredits->iSlot = pCredit->iSlot; + } + } + } + + if ( pCredit->flTime <= gpGlobals->curtime ) + { + pCredit->bActive = false; + + if ( i == m_CreditsList.Count()-1 ) + { + Clear(); + } + } + } +} + +void CHudCredits::ApplySchemeSettings( IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + SetVisible( ShouldDraw() ); + + SetBgColor( Color(0, 0, 0, 0) ); +} + +void CHudCredits::Paint() +{ + if ( m_iCreditsType == CREDITS_LOGO ) + { + DrawLogo(); + } + else if ( m_iCreditsType == CREDITS_INTRO ) + { + DrawIntroCreditsName(); + } + else if ( m_iCreditsType == CREDITS_OUTRO ) + { + DrawOutroCreditsName(); + } +} + +void CHudCredits::PrepareLogo( float flTime ) +{ + // Only showing the logo. Just load the CreditsParams section. + PrepareCredits( NULL ); + + m_Alpha = 0; + m_flLogoDesiredLength = flTime; + m_flFadeTime = gpGlobals->curtime + 5.0f; + m_iLogoState = LOGO_FADEIN; + SetActive( true ); +} + +void CHudCredits::PrepareLine( vgui::HFont hFont, char const *pchLine ) +{ + Assert( pchLine ); + + wchar_t unicode[256]; + + if ( pchLine[0] == '#' ) + { + g_pVGuiLocalize->ConstructString( unicode, sizeof(unicode), g_pVGuiLocalize->Find(pchLine), 0 ); + } + else + { + g_pVGuiLocalize->ConvertANSIToUnicode( pchLine, unicode, sizeof( unicode ) ); + } + + surface()->PrecacheFontCharacters( hFont, unicode ); +} + +void CHudCredits::PrepareOutroCredits( void ) +{ + PrepareCredits( "OutroCreditsNames" ); + + if ( m_CreditsList.Count() == 0 ) + return; + + // fill the screen + int iWidth, iTall; + GetHudSize(iWidth, iTall); + SetSize( iWidth, iTall ); + + int iHeight = iTall; + + for ( int i = 0; i < m_CreditsList.Count(); i++ ) + { + creditname_t *pCredit = &m_CreditsList[i]; + + if ( pCredit == NULL ) + continue; + + vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); + vgui::HFont m_hTFont = vgui::scheme()->GetIScheme(scheme)->GetFont( pCredit->szFontName, true ); + + pCredit->flYPos = iHeight; + pCredit->bActive = false; + + iHeight += surface()->GetFontTall ( m_hTFont ) + m_flSeparation; + + PrepareLine( m_hTFont, pCredit->szCreditName ); + } + + SetActive( true ); + + g_iCreditsPixelHeight = iHeight; +} + +void CHudCredits::PrepareIntroCredits( void ) +{ + PrepareCredits( "IntroCreditsNames" ); + + int iSlot = 0; + + for ( int i = 0; i < m_CreditsList.Count(); i++ ) + { + creditname_t *pCredit = &m_CreditsList[i]; + + if ( pCredit == NULL ) + continue; + + vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); + vgui::HFont m_hTFont = vgui::scheme()->GetIScheme(scheme)->GetFont( pCredit->szFontName ); + + pCredit->flYPos = m_flY + ( iSlot * surface()->GetFontTall ( m_hTFont ) ); + pCredit->flXPos = m_flX; + + if ( i < 3 ) + { + pCredit->bActive = true; + pCredit->iSlot = iSlot; + pCredit->flTime = gpGlobals->curtime + m_flFadeInTime + m_flFadeOutTime + m_flFadeHoldTime; + pCredit->flTimeStart = gpGlobals->curtime; + m_flLogoTime = pCredit->flTime + m_flLogoTimeMod; + } + else + { + pCredit->bActive = false; + pCredit->flTime = 0.0f; + } + + iSlot = ( iSlot + 1 ) % 3; + + PrepareLine( m_hTFont, pCredit->szCreditName ); + } + + SetActive( true ); +} + +void CHudCredits::MsgFunc_CreditsMsg( bf_read &msg ) +{ + m_iCreditsType = msg.ReadByte(); + + switch ( m_iCreditsType ) + { + case CREDITS_LOGO: + { + PrepareLogo( 5.0f ); + break; + } + case CREDITS_INTRO: + { + PrepareIntroCredits(); + break; + } + case CREDITS_OUTRO: + { + PrepareOutroCredits(); + break; + } + } +} + +void CHudCredits::MsgFunc_LogoTimeMsg( bf_read &msg ) +{ + m_iCreditsType = CREDITS_LOGO; + PrepareLogo( msg.ReadFloat() ); +} + + diff --git a/game/client/hl2/hud_damageindicator.cpp b/game/client/hl2/hud_damageindicator.cpp new file mode 100644 index 0000000..b6d2a9b --- /dev/null +++ b/game/client/hl2/hud_damageindicator.cpp @@ -0,0 +1,461 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "hud.h" +#include "text_message.h" +#include "hud_macros.h" +#include "iclientmode.h" +#include "view.h" +#include <KeyValues.h> +#include <vgui_controls/AnimationController.h> +#include <vgui/ISurface.h> +#include "VGuiMatSurface/IMatSystemSurface.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/imesh.h" +#include "materialsystem/imaterialvar.h" +#include "IEffects.h" +#include "hudelement.h" +#include "clienteffectprecachesystem.h" +#include "sourcevr/isourcevirtualreality.h" + +using namespace vgui; + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +//----------------------------------------------------------------------------- +// Purpose: HDU Damage indication +//----------------------------------------------------------------------------- +class CHudDamageIndicator : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudDamageIndicator, vgui::Panel ); + +public: + CHudDamageIndicator( const char *pElementName ); + void Init( void ); + void Reset( void ); + virtual bool ShouldDraw( void ); + + // Handler for our message + void MsgFunc_Damage( bf_read &msg ); + +private: + virtual void Paint(); + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + +private: + CPanelAnimationVarAliasType( float, m_flDmgX, "dmg_xpos", "10", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flDmgY, "dmg_ypos", "80", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flDmgWide, "dmg_wide", "30", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flDmgTall1, "dmg_tall1", "300", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flDmgTall2, "dmg_tall2", "240", "proportional_float" ); + + CPanelAnimationVar( Color, m_DmgColorLeft, "DmgColorLeft", "255 0 0 0" ); + CPanelAnimationVar( Color, m_DmgColorRight, "DmgColorRight", "255 0 0 0" ); + + CPanelAnimationVar( Color, m_DmgHighColorLeft, "DmgHighColorLeft", "255 0 0 0" ); + CPanelAnimationVar( Color, m_DmgHighColorRight, "DmgHighColorRight", "255 0 0 0" ); + + CPanelAnimationVar( Color, m_DmgFullscreenColor, "DmgFullscreenColor", "255 0 0 0" ); + + void DrawDamageIndicator(int side); + void DrawFullscreenDamageIndicator(); + void GetDamagePosition( const Vector &vecDelta, float *flRotation ); + + CMaterialReference m_WhiteAdditiveMaterial; +}; + +DECLARE_HUDELEMENT( CHudDamageIndicator ); +DECLARE_HUD_MESSAGE( CHudDamageIndicator, Damage ); + +enum +{ + DAMAGE_ANY, + DAMAGE_LOW, + DAMAGE_HIGH, +}; + +#define ANGLE_ANY 0.0f +#define DMG_ANY 0 + +struct DamageAnimation_t +{ + const char *name; + int bitsDamage; + float angleMinimum; + float angleMaximum; + int damage; +}; + +//----------------------------------------------------------------------------- +// Purpose: List of damage animations, finds first that matches criteria +//----------------------------------------------------------------------------- +static DamageAnimation_t g_DamageAnimations[] = +{ + { "HudTakeDamageDrown", DMG_DROWN, ANGLE_ANY, ANGLE_ANY, DAMAGE_ANY }, + { "HudTakeDamagePoison", DMG_POISON, ANGLE_ANY, ANGLE_ANY, DAMAGE_ANY }, + { "HudTakeDamageBurn", DMG_BURN, ANGLE_ANY, ANGLE_ANY, DAMAGE_ANY }, + { "HudTakeDamageRadiation", DMG_RADIATION, ANGLE_ANY, ANGLE_ANY, DAMAGE_ANY }, + { "HudTakeDamageRadiation", DMG_ACID, ANGLE_ANY, ANGLE_ANY, DAMAGE_ANY }, + + { "HudTakeDamageHighLeft", DMG_ANY, 45.0f, 135.0f, DAMAGE_HIGH }, + { "HudTakeDamageHighRight", DMG_ANY, 225.0f, 315.0f, DAMAGE_HIGH }, + { "HudTakeDamageHigh", DMG_ANY, ANGLE_ANY, ANGLE_ANY, DAMAGE_HIGH }, + + { "HudTakeDamageLeft", DMG_ANY, 45.0f, 135.0f, DAMAGE_ANY }, + { "HudTakeDamageRight", DMG_ANY, 225.0f, 315.0f, DAMAGE_ANY }, + { "HudTakeDamageBehind", DMG_ANY, 135.0f, 225.0f, DAMAGE_ANY }, + + // fall through to front damage + { "HudTakeDamageFront", DMG_ANY, ANGLE_ANY, ANGLE_ANY, DAMAGE_ANY }, + { NULL }, +}; + + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CHudDamageIndicator::CHudDamageIndicator( const char *pElementName ) : CHudElement( pElementName ), BaseClass(NULL, "HudDamageIndicator") +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + + m_WhiteAdditiveMaterial.Init( "vgui/white_additive", TEXTURE_GROUP_VGUI ); + + SetHiddenBits( HIDEHUD_HEALTH ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudDamageIndicator::Reset( void ) +{ + m_DmgColorLeft[3] = 0; + m_DmgColorRight[3] = 0; + m_DmgHighColorLeft[3] = 0; + m_DmgHighColorRight[3] = 0; + m_DmgFullscreenColor[3] = 0; +} + +void CHudDamageIndicator::Init( void ) +{ + HOOK_HUD_MESSAGE( CHudDamageIndicator, Damage ); +} + +//----------------------------------------------------------------------------- +// Purpose: Save CPU cycles by letting the HUD system early cull +// costly traversal. Called per frame, return true if thinking and +// painting need to occur. +//----------------------------------------------------------------------------- +bool CHudDamageIndicator::ShouldDraw( void ) +{ + bool bNeedsDraw = m_DmgColorLeft[3] || + m_DmgColorRight[3] || + m_DmgHighColorLeft[3] || + m_DmgHighColorRight[3] || + m_DmgFullscreenColor[3]; + + return ( bNeedsDraw && CHudElement::ShouldDraw() ); +} + +//----------------------------------------------------------------------------- +// Purpose: Draws a damage quad +//----------------------------------------------------------------------------- +void CHudDamageIndicator::DrawDamageIndicator(int side) +{ + CMatRenderContextPtr pRenderContext( materials ); + IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_WhiteAdditiveMaterial ); + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); + + int insetY = (m_flDmgTall1 - m_flDmgTall2) / 2; + + int x1 = m_flDmgX; + int x2 = m_flDmgX + m_flDmgWide; + int y[4] = { (int)m_flDmgY, (int)(m_flDmgY + insetY), (int)(m_flDmgY + m_flDmgTall1 - insetY), (int)(m_flDmgY + m_flDmgTall1) }; + int alpha[4] = { 0, 1, 1, 0 }; + + // see if we're high damage + bool bHighDamage = false; + if ( m_DmgHighColorRight[3] > m_DmgColorRight[3] || m_DmgHighColorLeft[3] > m_DmgColorLeft[3] ) + { + // make more of the screen be covered by damage + x1 = GetWide() * 0.0f; + x2 = GetWide() * 0.5f; + y[0] = 0.0f; + y[1] = 0.0f; + y[2] = GetTall(); + y[3] = GetTall(); + alpha[0] = 1.0f; + alpha[1] = 0.0f; + alpha[2] = 0.0f; + alpha[3] = 1.0f; + bHighDamage = true; + } + + int r, g, b, a; + if (side == 1) + { + if ( bHighDamage ) + { + r = m_DmgHighColorRight[0], g = m_DmgHighColorRight[1], b = m_DmgHighColorRight[2], a = m_DmgHighColorRight[3]; + } + else + { + r = m_DmgColorRight[0], g = m_DmgColorRight[1], b = m_DmgColorRight[2], a = m_DmgColorRight[3]; + } + + // realign x coords + x1 = GetWide() - x1; + x2 = GetWide() - x2; + + meshBuilder.Color4ub( r, g, b, a * alpha[0]); + meshBuilder.TexCoord2f( 0,0,0 ); + meshBuilder.Position3f( x1, y[0], 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( r, g, b, a * alpha[3] ); + meshBuilder.TexCoord2f( 0,0,1 ); + meshBuilder.Position3f( x1, y[3], 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( r, g, b, a * alpha[2] ); + meshBuilder.TexCoord2f( 0,1,1 ); + meshBuilder.Position3f( x2, y[2], 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( r, g, b, a * alpha[1] ); + meshBuilder.TexCoord2f( 0,1,0 ); + meshBuilder.Position3f( x2, y[1], 0 ); + meshBuilder.AdvanceVertex(); + } + else + { + if ( bHighDamage ) + { + r = m_DmgHighColorLeft[0], g = m_DmgHighColorLeft[1], b = m_DmgHighColorLeft[2], a = m_DmgHighColorLeft[3]; + } + else + { + r = m_DmgColorLeft[0], g = m_DmgColorLeft[1], b = m_DmgColorLeft[2], a = m_DmgColorLeft[3]; + } + + meshBuilder.Color4ub( r, g, b, a * alpha[0] ); + meshBuilder.TexCoord2f( 0,0,0 ); + meshBuilder.Position3f( x1, y[0], 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( r, g, b, a * alpha[1] ); + meshBuilder.TexCoord2f( 0,1,0 ); + meshBuilder.Position3f( x2, y[1], 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( r, g, b, a * alpha[2] ); + meshBuilder.TexCoord2f( 0,1,1 ); + meshBuilder.Position3f( x2, y[2], 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( r, g, b, a * alpha[3] ); + meshBuilder.TexCoord2f( 0,0,1 ); + meshBuilder.Position3f( x1, y[3], 0 ); + meshBuilder.AdvanceVertex(); + } + + meshBuilder.End(); + pMesh->Draw(); +} + +//----------------------------------------------------------------------------- +// Purpose: Draws full screen damage fade +//----------------------------------------------------------------------------- +void CHudDamageIndicator::DrawFullscreenDamageIndicator() +{ + CMatRenderContextPtr pRenderContext( materials ); + IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_WhiteAdditiveMaterial ); + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); + int r = m_DmgFullscreenColor[0], g = m_DmgFullscreenColor[1], b = m_DmgFullscreenColor[2], a = m_DmgFullscreenColor[3]; + + float wide = GetWide(), tall = GetTall(); + + meshBuilder.Color4ub( r, g, b, a ); + meshBuilder.TexCoord2f( 0,0,0 ); + meshBuilder.Position3f( 0.0f, 0.0f, 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( r, g, b, a ); + meshBuilder.TexCoord2f( 0,1,0 ); + meshBuilder.Position3f( wide, 0.0f, 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( r, g, b, a ); + meshBuilder.TexCoord2f( 0,1,1 ); + meshBuilder.Position3f( wide, tall, 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( r, g, b, a ); + meshBuilder.TexCoord2f( 0,0,1 ); + meshBuilder.Position3f( 0.0f, tall, 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.End(); + pMesh->Draw(); +} + +//----------------------------------------------------------------------------- +// Purpose: Paints the damage display +//----------------------------------------------------------------------------- +void CHudDamageIndicator::Paint() +{ + // draw fullscreen damage indicators + DrawFullscreenDamageIndicator(); + + // draw side damage indicators + DrawDamageIndicator(0); + DrawDamageIndicator(1); +} + +//----------------------------------------------------------------------------- +// Purpose: Message handler for Damage message +//----------------------------------------------------------------------------- +void CHudDamageIndicator::MsgFunc_Damage( bf_read &msg ) +{ + int armor = msg.ReadByte(); // armor + int damageTaken = msg.ReadByte(); // health + long bitsDamage = msg.ReadLong(); // damage bits + + Vector vecFrom; + + vecFrom.x = msg.ReadFloat(); + vecFrom.y = msg.ReadFloat(); + vecFrom.z = msg.ReadFloat(); + + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + // player has just died, just run the dead damage animation + if ( pPlayer->GetHealth() <= 0 ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HudPlayerDeath" ); + return; + } + + // ignore damage without direction + // this should never happen, unless it's drowning damage, + // or the player is forcibly killed, handled above + if ( vecFrom == vec3_origin && !(bitsDamage & DMG_DROWN)) + return; + + Vector vecDelta = (vecFrom - MainViewOrigin()); + VectorNormalize( vecDelta ); + + int highDamage = DAMAGE_LOW; + if ( damageTaken > 25 ) + { + highDamage = DAMAGE_HIGH; + } + + // if we have no suit, all damage is high + if ( !pPlayer->IsSuitEquipped() ) + { + highDamage = DAMAGE_HIGH; + } + + if ( damageTaken > 0 || armor > 0 ) + { + // see which quandrant the effect is in + float angle; + GetDamagePosition( vecDelta, &angle ); + + // see which effect to play + DamageAnimation_t *dmgAnim = g_DamageAnimations; + for ( ; dmgAnim->name != NULL; ++dmgAnim ) + { + if ( dmgAnim->bitsDamage && !(bitsDamage & dmgAnim->bitsDamage) ) + continue; + + if ( dmgAnim->angleMinimum && angle < dmgAnim->angleMinimum ) + continue; + + if ( dmgAnim->angleMaximum && angle > dmgAnim->angleMaximum ) + continue; + + if ( dmgAnim->damage && dmgAnim->damage != highDamage ) + continue; + + // we have a match, break + break; + } + + if ( dmgAnim->name ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( dmgAnim->name ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Convert a damage position in world units to the screen's units +//----------------------------------------------------------------------------- +void CHudDamageIndicator::GetDamagePosition( const Vector &vecDelta, float *flRotation ) +{ + float flRadius = 360.0f; + + // Player Data + Vector playerPosition = MainViewOrigin(); + QAngle playerAngles = MainViewAngles(); + + Vector forward, right, up(0,0,1); + AngleVectors (playerAngles, &forward, NULL, NULL ); + forward.z = 0; + VectorNormalize(forward); + CrossProduct( up, forward, right ); + float front = DotProduct(vecDelta, forward); + float side = DotProduct(vecDelta, right); + float xpos = flRadius * -side; + float ypos = flRadius * -front; + + // Get the rotation (yaw) + *flRotation = atan2(xpos, ypos) + M_PI; + *flRotation *= 180 / M_PI; + + float yawRadians = -(*flRotation) * M_PI / 180.0f; + float ca = cos( yawRadians ); + float sa = sin( yawRadians ); + + // Rotate it around the circle + xpos = (int)((GetWide() / 2) + (flRadius * sa)); + ypos = (int)((GetTall() / 2) - (flRadius * ca)); +} + +//----------------------------------------------------------------------------- +// Purpose: hud scheme settings +//----------------------------------------------------------------------------- +void CHudDamageIndicator::ApplySchemeSettings(vgui::IScheme *pScheme) +{ + BaseClass::ApplySchemeSettings(pScheme); + SetPaintBackgroundEnabled(false); + + int vx, vy, vw, vh; + vgui::surface()->GetFullscreenViewport( vx, vy, vw, vh ); + + SetForceStereoRenderToFrameBuffer( true ); + + if( UseVR() ) + { + m_flDmgY = 0.125f * (float)vh; + m_flDmgTall1 = 0.625f * (float)vh; + m_flDmgTall2 = 0.4f * (float)vh; + m_flDmgWide = 0.1f * (float)vw; + } + + SetSize(vw, vh); +} diff --git a/game/client/hl2/hud_filmdemo.cpp b/game/client/hl2/hud_filmdemo.cpp new file mode 100644 index 0000000..ca21a85 --- /dev/null +++ b/game/client/hl2/hud_filmdemo.cpp @@ -0,0 +1,190 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// +#include "cbase.h" +#include "c_baseentity.h" +#include "hud.h" +#include "hudelement.h" +#include "clientmode.h" +#include <vgui_controls/Panel.h> +#include <vgui/IScheme.h> +#include <vgui/ISurface.h> +#include <vgui/ILocalize.h> +#include <vgui_controls/AnimationController.h> + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHudFilmDemo : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudFilmDemo, vgui::Panel ); +public: + CHudFilmDemo( const char *name ); + + // vgui overrides + virtual void ApplySchemeSettings(vgui::IScheme *pScheme ); + virtual void Paint( void ); + virtual bool ShouldDraw( void ); + + void SetFilmDemoActive( bool bActive ); + + void SetLeftStringID( const char *id ); + void SetRightStringID( const char *id ); + +private: + bool m_bFilmDemoActive; + + char m_pLeftStringID[ 256 ]; + char m_pRightStringID[ 256 ]; + + // Painting + //CPanelAnimationVar( float, m_flAlphaOverride, "Alpha", "0" ); + CPanelAnimationVar( Color, m_BorderColor, "BorderColor", "0 0 0 255" ); + CPanelAnimationVar( Color, m_TextColor, "TextColor", "255 255 255 255" ); + CPanelAnimationVarAliasType( int, m_iBorderLeft, "BorderLeft", "8", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iBorderRight, "BorderRight", "8", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iBorderTop, "BorderTop", "8", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iBorderBottom, "BorderBottom", "48", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iBorderCenter, "BorderCenter", "8", "proportional_int" ); + + CPanelAnimationVarAliasType( int, m_iLeftY, "LeftTitleY", "440", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iRightY, "RightTitleY", "440", "proportional_int" ); +}; + +DECLARE_HUDELEMENT( CHudFilmDemo ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CHudFilmDemo::CHudFilmDemo( const char *name ) : vgui::Panel( NULL, "HudHDRDemo" ), CHudElement( name ) +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + + SetPaintBorderEnabled( false ); + SetPaintBackgroundEnabled( false ); + + m_bFilmDemoActive = false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudFilmDemo::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings(pScheme); + SetSize( ScreenWidth(), ScreenHeight() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudFilmDemo::Paint() +{ + int x, y, wide, tall; + GetBounds( x, y, wide, tall ); + + // Draw the borders + vgui::surface()->DrawSetColor( m_BorderColor ); + vgui::surface()->DrawFilledRect( 0, 0, m_iBorderLeft, tall ); // Left + vgui::surface()->DrawFilledRect( wide-m_iBorderRight, 0, wide, tall ); // Right + vgui::surface()->DrawFilledRect( m_iBorderLeft, 0, wide-m_iBorderRight, m_iBorderTop ); // Top + vgui::surface()->DrawFilledRect( m_iBorderLeft, tall-m_iBorderBottom, wide-m_iBorderRight, tall ); // Bottom + vgui::surface()->DrawFilledRect( ((wide-m_iBorderCenter)/2), m_iBorderTop, ((wide+m_iBorderCenter)/2), tall-m_iBorderBottom ); // Center + + // Get our scheme and font information + vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); + vgui::HFont hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "MenuTitle" ); + vgui::surface()->DrawSetTextFont( hFont ); + vgui::surface()->DrawSetTextColor( m_TextColor ); + + wchar_t *tempString = g_pVGuiLocalize->Find( m_pLeftStringID ); + if( tempString ) + { + int iLength = 0; + for ( wchar_t *wch = tempString; *wch != 0; wch++ ) + { + iLength += vgui::surface()->GetCharacterWidth( hFont, *wch ); + } + vgui::surface()->DrawSetTextPos( floor(wide * 0.25) - (iLength / 2), m_iLeftY ); + vgui::surface()->DrawPrintText( tempString, wcslen(tempString) ); + } + + tempString = g_pVGuiLocalize->Find( m_pRightStringID ); + if( tempString ) + { + int iLength = 0; + for ( wchar_t *wch = tempString; *wch != 0; wch++ ) + { + iLength += vgui::surface()->GetCharacterWidth( hFont, *wch ); + } + vgui::surface()->DrawSetTextPos( ceil(wide * 0.75) - (iLength / 2), m_iRightY ); + vgui::surface()->DrawPrintText( tempString, wcslen(tempString) ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CHudFilmDemo::ShouldDraw() +{ + return ( m_bFilmDemoActive ); //&& m_flAlphaOverride > 0 ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : bActive - +//----------------------------------------------------------------------------- +void CHudFilmDemo::SetFilmDemoActive( bool bActive ) +{ + if ( bActive && !m_bFilmDemoActive ) + { + ConVarRef hideHud( "hidehud" ); + hideHud.SetValue( 15 ); + } + else if ( !bActive && m_bFilmDemoActive ) + { + ConVarRef hideHud( "hidehud" ); + hideHud.SetValue( 0 ); + } + + m_bFilmDemoActive = bActive; +} + +void CHudFilmDemo::SetLeftStringID( const char *id ) +{ + Q_strcpy( m_pLeftStringID, id ); +} + +void CHudFilmDemo::SetRightStringID( const char *id ) +{ + Q_strcpy( m_pRightStringID, id ); +} + +void EnableHUDFilmDemo( bool bEnable, const char *left_string_id, const char *right_string_id ) +{ + CHudFilmDemo *pHudDemo = (CHudFilmDemo*)GET_HUDELEMENT( CHudFilmDemo ); + if ( pHudDemo ) + { + if( left_string_id ) + { + pHudDemo->SetLeftStringID( left_string_id ); + } + + if( right_string_id ) + { + pHudDemo->SetRightStringID( right_string_id ); + } + + pHudDemo->SetFilmDemoActive( bEnable ); + } +} + + diff --git a/game/client/hl2/hud_flashlight.cpp b/game/client/hl2/hud_flashlight.cpp new file mode 100644 index 0000000..7c63f7a --- /dev/null +++ b/game/client/hl2/hud_flashlight.cpp @@ -0,0 +1,162 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "hudelement.h" +#include "hud_numericdisplay.h" +#include <vgui_controls/Panel.h> +#include "hud.h" +#include "hud_suitpower.h" +#include "hud_macros.h" +#include "iclientmode.h" +#include <vgui_controls/AnimationController.h> +#include <vgui/ISurface.h> +#include "c_basehlplayer.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: Shows the flashlight icon +//----------------------------------------------------------------------------- +class CHudFlashlight : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudFlashlight, vgui::Panel ); + +public: + CHudFlashlight( const char *pElementName ); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + +protected: + virtual void Paint(); + +private: + void SetFlashlightState( bool flashlightOn ); + void Reset( void ); + + bool m_bFlashlightOn; + CPanelAnimationVar( vgui::HFont, m_hFont, "Font", "WeaponIconsSmall" ); + CPanelAnimationVarAliasType( float, m_IconX, "icon_xpos", "4", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_IconY, "icon_ypos", "4", "proportional_float" ); + + CPanelAnimationVarAliasType( float, m_flBarInsetX, "BarInsetX", "2", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flBarInsetY, "BarInsetY", "18", "proportional_float" ); + + CPanelAnimationVarAliasType( float, m_flBarWidth, "BarWidth", "28", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flBarHeight, "BarHeight", "2", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flBarChunkWidth, "BarChunkWidth", "2", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flBarChunkGap, "BarChunkGap", "2", "proportional_float" ); +}; + +using namespace vgui; + +#ifdef HL2_EPISODIC +DECLARE_HUDELEMENT( CHudFlashlight ); +#endif // HL2_EPISODIC + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CHudFlashlight::CHudFlashlight( const char *pElementName ) : CHudElement( pElementName ), BaseClass( NULL, "HudFlashlight" ) +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + + SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD | HIDEHUD_NEEDSUIT ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pScheme - +//----------------------------------------------------------------------------- +void CHudFlashlight::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings(pScheme); +} + +//----------------------------------------------------------------------------- +// Purpose: Start with our background off +//----------------------------------------------------------------------------- +void CHudFlashlight::Reset( void ) +{ + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "SuitFlashlightOn" ); +} + +//----------------------------------------------------------------------------- +// Purpose: data accessor +//----------------------------------------------------------------------------- +void CHudFlashlight::SetFlashlightState( bool flashlightOn ) +{ + if ( m_bFlashlightOn == flashlightOn ) + return; + + m_bFlashlightOn = flashlightOn; +} + +#define WCHAR_FLASHLIGHT_ON 169 +#define WCHAR_FLASHLIGHT_OFF 174 + +//----------------------------------------------------------------------------- +// Purpose: draws the flashlight icon +//----------------------------------------------------------------------------- +void CHudFlashlight::Paint() +{ +#ifdef HL2_EPISODIC + C_BaseHLPlayer *pPlayer = (C_BaseHLPlayer *)C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + // Only paint if we're using the new flashlight code + if ( pPlayer->m_HL2Local.m_flFlashBattery < 0.0f ) + { + SetPaintBackgroundEnabled( false ); + return; + } + + bool bIsOn = pPlayer->IsEffectActive( EF_DIMLIGHT ); + SetFlashlightState( bIsOn ); + + // get bar chunks + int chunkCount = m_flBarWidth / (m_flBarChunkWidth + m_flBarChunkGap); + int enabledChunks = (int)((float)chunkCount * (pPlayer->m_HL2Local.m_flFlashBattery * 1.0f/100.0f) + 0.5f ); + + Color clrFlashlight; + clrFlashlight = ( enabledChunks < ( chunkCount / 4 ) ) ? gHUD.m_clrCaution : gHUD.m_clrNormal; + clrFlashlight[3] = ( bIsOn ) ? 255: 32; + + // Pick the right character given our current state + wchar_t pState = ( bIsOn ) ? WCHAR_FLASHLIGHT_ON : WCHAR_FLASHLIGHT_OFF; + + surface()->DrawSetTextFont( m_hFont ); + surface()->DrawSetTextColor( clrFlashlight ); + surface()->DrawSetTextPos( m_IconX, m_IconY ); + surface()->DrawUnicodeChar( pState ); + + // Don't draw the progress bar is we're fully charged + if ( bIsOn == false && chunkCount == enabledChunks ) + return; + + // draw the suit power bar + surface()->DrawSetColor( clrFlashlight ); + int xpos = m_flBarInsetX, ypos = m_flBarInsetY; + for (int i = 0; i < enabledChunks; i++) + { + surface()->DrawFilledRect( xpos, ypos, xpos + m_flBarChunkWidth, ypos + m_flBarHeight ); + xpos += (m_flBarChunkWidth + m_flBarChunkGap); + } + + // Be even less transparent than we already are + clrFlashlight[3] = clrFlashlight[3] / 8; + + // draw the exhausted portion of the bar. + surface()->DrawSetColor( clrFlashlight ); + for (int i = enabledChunks; i < chunkCount; i++) + { + surface()->DrawFilledRect( xpos, ypos, xpos + m_flBarChunkWidth, ypos + m_flBarHeight ); + xpos += (m_flBarChunkWidth + m_flBarChunkGap); + } +#endif // HL2_EPISODIC +} diff --git a/game/client/hl2/hud_hdrdemo.cpp b/game/client/hl2/hud_hdrdemo.cpp new file mode 100644 index 0000000..eaaaf1f --- /dev/null +++ b/game/client/hl2/hud_hdrdemo.cpp @@ -0,0 +1,174 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#include "cbase.h" +#include "c_baseentity.h" +#include "hud.h" +#include "hudelement.h" +#include "clientmode.h" +#include <vgui_controls/Panel.h> +#include <vgui/IScheme.h> +#include <vgui/ISurface.h> +#include <vgui/ILocalize.h> +#include <vgui_controls/AnimationController.h> +#include "materialsystem/imaterialsystemhardwareconfig.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHudHDRDemo : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudHDRDemo, vgui::Panel ); +public: + CHudHDRDemo( const char *name ); + + // vgui overrides + virtual void ApplySchemeSettings(vgui::IScheme *pScheme ); + virtual void Paint( void ); + virtual bool ShouldDraw( void ); + + void SetHDRDemoActive( bool bActive ); + +private: + bool m_bHDRDemoActive; + + // Painting + //CPanelAnimationVar( float, m_flAlphaOverride, "Alpha", "0" ); + CPanelAnimationVar( Color, m_BorderColor, "BorderColor", "0 0 0 255" ); + CPanelAnimationVar( Color, m_TextColor, "TextColor", "255 255 255 255" ); + CPanelAnimationVarAliasType( int, m_iBorderLeft, "BorderLeft", "8", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iBorderRight, "BorderRight", "8", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iBorderTop, "BorderTop", "8", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iBorderBottom, "BorderBottom", "8", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iBorderCenter, "BorderCenter", "8", "proportional_int" ); + + CPanelAnimationVarAliasType( int, m_iLeftY, "LeftTitleY", "8", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iRightY, "RightTitleY", "8", "proportional_int" ); +}; + +DECLARE_HUDELEMENT( CHudHDRDemo ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CHudHDRDemo::CHudHDRDemo( const char *name ) : vgui::Panel( NULL, "HudHDRDemo" ), CHudElement( name ) +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + + SetPaintBorderEnabled( false ); + SetPaintBackgroundEnabled( false ); + + m_bHDRDemoActive = false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudHDRDemo::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings(pScheme); + SetSize( ScreenWidth(), ScreenHeight() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudHDRDemo::Paint() +{ + int x, y, wide, tall; + GetBounds( x, y, wide, tall ); + + // Draw the borders + vgui::surface()->DrawSetColor( m_BorderColor ); + vgui::surface()->DrawFilledRect( 0, 0, m_iBorderLeft, tall ); // Left + vgui::surface()->DrawFilledRect( wide-m_iBorderRight, 0, wide, tall ); // Right + vgui::surface()->DrawFilledRect( m_iBorderLeft, 0, wide-m_iBorderRight, m_iBorderTop ); // Top + vgui::surface()->DrawFilledRect( m_iBorderLeft, tall-m_iBorderBottom, wide-m_iBorderRight, tall ); // Bottom + vgui::surface()->DrawFilledRect( ((wide-m_iBorderCenter)/2), m_iBorderTop, ((wide+m_iBorderCenter)/2), tall-m_iBorderBottom ); // Center + + // Get our scheme and font information + vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); + vgui::HFont hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "HDRDemoText" ); + vgui::surface()->DrawSetTextFont( hFont ); + vgui::surface()->DrawSetTextColor( m_TextColor ); + + // Left Title + wchar_t *tempString = g_pVGuiLocalize->Find("#Valve_HDRDEMO_LeftTitle"); + if (tempString) + { + int iLength = 0; + for ( wchar_t *wch = tempString; *wch != 0; wch++ ) + { + iLength += vgui::surface()->GetCharacterWidth( hFont, *wch ); + } + vgui::surface()->DrawSetTextPos( floor(wide * 0.25) - (iLength / 2), m_iLeftY ); + vgui::surface()->DrawPrintText(tempString, wcslen(tempString)); + } + + // Right Title + tempString = g_pVGuiLocalize->Find("#Valve_HDRDEMO_RightTitle"); + if (tempString) + { + int iLength = 0; + for ( wchar_t *wch = tempString; *wch != 0; wch++ ) + { + iLength += vgui::surface()->GetCharacterWidth( hFont, *wch ); + } + vgui::surface()->DrawSetTextPos( ceil(wide * 0.75) - (iLength / 2), m_iRightY ); + vgui::surface()->DrawPrintText(tempString, wcslen(tempString)); + } + +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CHudHDRDemo::ShouldDraw() +{ + return ( + // no split screen hud if not hdr + (g_pMaterialSystemHardwareConfig->GetHDRType() != HDR_TYPE_NONE) && + m_bHDRDemoActive + ); //&& m_flAlphaOverride > 0 ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : bActive - +//----------------------------------------------------------------------------- +void CHudHDRDemo::SetHDRDemoActive( bool bActive ) +{ + if ( bActive && !m_bHDRDemoActive ) + { + ConVarRef pHideHud( "hidehud" ); + pHideHud.SetValue( 15 ); + } + else if ( !bActive && m_bHDRDemoActive ) + { + ConVarRef pHideHud( "hidehud" ); + pHideHud.SetValue( 0 ); + } + + m_bHDRDemoActive = bActive; +} + +//======================================================================================================= +// CONVAR to toggle this hud element +void mat_show_ab_hdr_hudelement_changed( IConVar *pConVar, const char *pOldString, float flOldValue ) +{ + CHudHDRDemo *pHudDemo = (CHudHDRDemo*)GET_HUDELEMENT( CHudHDRDemo ); + if ( pHudDemo ) + { + ConVarRef var( pConVar ); + pHudDemo->SetHDRDemoActive( var.GetBool() ); + } +} +ConVar mat_show_ab_hdr_hudelement( "mat_show_ab_hdr_hudelement", "0", FCVAR_CHEAT, "HDR Demo HUD Element toggle.", mat_show_ab_hdr_hudelement_changed ); diff --git a/game/client/hl2/hud_health.cpp b/game/client/hl2/hud_health.cpp new file mode 100644 index 0000000..c25da7b --- /dev/null +++ b/game/client/hl2/hud_health.cpp @@ -0,0 +1,170 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// +// Health.cpp +// +// implementation of CHudHealth class +// +#include "cbase.h" +#include "hud.h" +#include "hud_macros.h" +#include "view.h" + +#include "iclientmode.h" + +#include <KeyValues.h> +#include <vgui/ISurface.h> +#include <vgui/ISystem.h> +#include <vgui_controls/AnimationController.h> + +#include <vgui/ILocalize.h> + +using namespace vgui; + +#include "hudelement.h" +#include "hud_numericdisplay.h" + +#include "convar.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define INIT_HEALTH -1 + +//----------------------------------------------------------------------------- +// Purpose: Health panel +//----------------------------------------------------------------------------- +class CHudHealth : public CHudElement, public CHudNumericDisplay +{ + DECLARE_CLASS_SIMPLE( CHudHealth, CHudNumericDisplay ); + +public: + CHudHealth( const char *pElementName ); + virtual void Init( void ); + virtual void VidInit( void ); + virtual void Reset( void ); + virtual void OnThink(); + void MsgFunc_Damage( bf_read &msg ); + +private: + // old variables + int m_iHealth; + + int m_bitsDamage; +}; + +DECLARE_HUDELEMENT( CHudHealth ); +DECLARE_HUD_MESSAGE( CHudHealth, Damage ); + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CHudHealth::CHudHealth( const char *pElementName ) : CHudElement( pElementName ), CHudNumericDisplay(NULL, "HudHealth") +{ + SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD | HIDEHUD_NEEDSUIT ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudHealth::Init() +{ + HOOK_HUD_MESSAGE( CHudHealth, Damage ); + Reset(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudHealth::Reset() +{ + m_iHealth = INIT_HEALTH; + m_bitsDamage = 0; + + wchar_t *tempString = g_pVGuiLocalize->Find("#Valve_Hud_HEALTH"); + + if (tempString) + { + SetLabelText(tempString); + } + else + { + SetLabelText(L"HEALTH"); + } + SetDisplayValue(m_iHealth); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudHealth::VidInit() +{ + Reset(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudHealth::OnThink() +{ + int newHealth = 0; + C_BasePlayer *local = C_BasePlayer::GetLocalPlayer(); + if ( local ) + { + // Never below zero + newHealth = MAX( local->GetHealth(), 0 ); + } + + // Only update the fade if we've changed health + if ( newHealth == m_iHealth ) + { + return; + } + + m_iHealth = newHealth; + + if ( m_iHealth >= 20 ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("HealthIncreasedAbove20"); + } + else if ( m_iHealth > 0 ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("HealthIncreasedBelow20"); + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("HealthLow"); + } + + SetDisplayValue(m_iHealth); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudHealth::MsgFunc_Damage( bf_read &msg ) +{ + + int armor = msg.ReadByte(); // armor + int damageTaken = msg.ReadByte(); // health + long bitsDamage = msg.ReadLong(); // damage bits + bitsDamage; // variable still sent but not used + + Vector vecFrom; + + vecFrom.x = msg.ReadBitCoord(); + vecFrom.y = msg.ReadBitCoord(); + vecFrom.z = msg.ReadBitCoord(); + + // Actually took damage? + if ( damageTaken > 0 || armor > 0 ) + { + if ( damageTaken > 0 ) + { + // start the animation + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("HealthDamageTaken"); + } + } +}
\ No newline at end of file diff --git a/game/client/hl2/hud_locator.cpp b/game/client/hl2/hud_locator.cpp new file mode 100644 index 0000000..2b8dd88 --- /dev/null +++ b/game/client/hl2/hud_locator.cpp @@ -0,0 +1,319 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Hud locator element, helps direct the player to objects in the world +// +//=============================================================================// + +#include "cbase.h" +#include "hudelement.h" +#include "hud_numericdisplay.h" +#include <vgui_controls/Panel.h> +#include "hud.h" +#include "hud_suitpower.h" +#include "hud_macros.h" +#include "iclientmode.h" +#include <vgui_controls/AnimationController.h> +#include <vgui/ISurface.h> +#include "c_basehlplayer.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define LOCATOR_MATERIAL_JALOPY "vgui/icons/icon_jalopy" +#define LOCATOR_MATERIAL_BIG_TICK "vgui/icons/tick_long" +#define LOCATOR_MATERIAL_SMALL_TICK "vgui/icons/tick_short" + +ConVar hud_locator_alpha( "hud_locator_alpha", "230" ); +ConVar hud_locator_fov("hud_locator_fov", "350" ); + +//----------------------------------------------------------------------------- +// Purpose: Shows positions of objects relative to the player. +//----------------------------------------------------------------------------- +class CHudLocator : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudLocator, vgui::Panel ); + +public: + CHudLocator( const char *pElementName ); + virtual ~CHudLocator( void ); + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + void VidInit( void ); + bool ShouldDraw(); + +protected: + void FillRect( int x, int y, int w, int h ); + float LocatorXPositionForYawDiff( float yawDiff ); + void DrawGraduations( float flYawPlayerFacing ); + virtual void Paint(); + +private: + void Reset( void ); + + int m_textureID_IconJalopy; + int m_textureID_IconBigTick; + int m_textureID_IconSmallTick; + + Vector m_vecLocation; +}; + +using namespace vgui; + +#ifdef HL2_EPISODIC +DECLARE_HUDELEMENT( CHudLocator ); +#endif + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CHudLocator::CHudLocator( const char *pElementName ) : CHudElement( pElementName ), BaseClass( NULL, "HudLocator" ) +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + + SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD | HIDEHUD_NEEDSUIT ); + + m_textureID_IconJalopy = -1; + m_textureID_IconSmallTick = -1; + m_textureID_IconBigTick = -1; +} + +CHudLocator::~CHudLocator( void ) +{ + if ( vgui::surface() ) + { + if ( m_textureID_IconJalopy != -1 ) + { + vgui::surface()->DestroyTextureID( m_textureID_IconJalopy ); + m_textureID_IconJalopy = -1; + } + + if ( m_textureID_IconSmallTick != -1 ) + { + vgui::surface()->DestroyTextureID( m_textureID_IconSmallTick ); + m_textureID_IconSmallTick = -1; + } + + if ( m_textureID_IconBigTick != -1 ) + { + vgui::surface()->DestroyTextureID( m_textureID_IconBigTick ); + m_textureID_IconBigTick = -1; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pScheme - +//----------------------------------------------------------------------------- +void CHudLocator::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings(pScheme); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CHudLocator::VidInit( void ) +{ +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool CHudLocator::ShouldDraw( void ) +{ + C_BaseHLPlayer *pPlayer = (C_BaseHLPlayer *)C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return false; + + if( pPlayer->GetVehicle() ) + return false; + + if( pPlayer->m_HL2Local.m_vecLocatorOrigin == vec3_invalid ) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Start with our background off +//----------------------------------------------------------------------------- +void CHudLocator::Reset( void ) +{ + m_vecLocation = Vector( 0, 0, 0 ); +} + +//----------------------------------------------------------------------------- +// Purpose: Make it a bit more convenient to do a filled rect. +//----------------------------------------------------------------------------- +void CHudLocator::FillRect( int x, int y, int w, int h ) +{ + int panel_x, panel_y, panel_w, panel_h; + GetBounds( panel_x, panel_y, panel_w, panel_h ); + vgui::surface()->DrawFilledRect( x, y, x+w, y+h ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +float CHudLocator::LocatorXPositionForYawDiff( float yawDiff ) +{ + float fov = hud_locator_fov.GetFloat() / 2; + float remappedAngle = RemapVal( yawDiff, -fov, fov, -90, 90 ); + float cosine = sin(DEG2RAD(remappedAngle)); + int element_wide = GetWide(); + + float position = (element_wide>>1) + ((element_wide>>1) * cosine); + + return position; +} + +//----------------------------------------------------------------------------- +// Draw the tickmarks on the locator +//----------------------------------------------------------------------------- +#define NUM_GRADUATIONS 16.0f +void CHudLocator::DrawGraduations( float flYawPlayerFacing ) +{ + int icon_wide, icon_tall; + int xPos, yPos; + float fov = hud_locator_fov.GetFloat() / 2; + + if( m_textureID_IconBigTick == -1 ) + { + m_textureID_IconBigTick = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_textureID_IconBigTick, LOCATOR_MATERIAL_BIG_TICK, true, false ); + } + + if( m_textureID_IconSmallTick == -1 ) + { + m_textureID_IconSmallTick = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_textureID_IconSmallTick, LOCATOR_MATERIAL_SMALL_TICK, true, false ); + } + + int element_tall = GetTall(); // Height of the VGUI element + + surface()->DrawSetColor( 255, 255, 255, 255 ); + + // Tick Icons + + float angleStep = 360.0f / NUM_GRADUATIONS; + bool tallLine = true; + + for( float angle = -180 ; angle <= 180 ; angle += angleStep ) + { + yPos = (element_tall>>1); + + if( tallLine ) + { + vgui::surface()->DrawSetTexture( m_textureID_IconBigTick ); + vgui::surface()->DrawGetTextureSize( m_textureID_IconBigTick, icon_wide, icon_tall ); + tallLine = false; + } + else + { + vgui::surface()->DrawSetTexture( m_textureID_IconSmallTick ); + vgui::surface()->DrawGetTextureSize( m_textureID_IconSmallTick, icon_wide, icon_tall ); + tallLine = true; + } + + float flDiff = UTIL_AngleDiff( flYawPlayerFacing, angle ); + + if( fabs(flDiff) > fov ) + continue; + + float xPosition = LocatorXPositionForYawDiff( flDiff ); + + xPos = (int)xPosition; + xPos -= (icon_wide>>1); + + vgui::surface()->DrawTexturedRect(xPos, yPos, xPos+icon_wide, yPos+icon_tall); + } +} + +//----------------------------------------------------------------------------- +// Purpose: draws the locator icons on the VGUI element. +//----------------------------------------------------------------------------- +void CHudLocator::Paint() +{ +#ifdef HL2_EPISODIC + + if( m_textureID_IconJalopy == -1 ) + { + m_textureID_IconJalopy = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_textureID_IconJalopy, LOCATOR_MATERIAL_JALOPY, true, false ); + } + + int alpha = hud_locator_alpha.GetInt(); + + SetAlpha( alpha ); + + C_BaseHLPlayer *pPlayer = (C_BaseHLPlayer *)C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + if( pPlayer->m_HL2Local.m_vecLocatorOrigin == vec3_origin ) + return; + + int element_tall = GetTall(); // Height of the VGUI element + + float fov = (hud_locator_fov.GetFloat()) / 2.0f; + + // Compute the relative position of objects we're tracking + // We'll need the player's yaw for comparison. + float flYawPlayerForward = pPlayer->EyeAngles().y; + + // Copy this value out of the member variable in case we decide to expand this + // feature later and want to iterate some kind of list. + Vector vecLocation = pPlayer->m_HL2Local.m_vecLocatorOrigin; + + Vector vecToLocation = vecLocation - pPlayer->GetAbsOrigin(); + QAngle locationAngles; + + VectorAngles( vecToLocation, locationAngles ); + float yawDiff = UTIL_AngleDiff( flYawPlayerForward, locationAngles.y ); + bool bObjectInFOV = (yawDiff > -fov && yawDiff < fov); + + // Draw the icons! + int icon_wide, icon_tall; + int xPos, yPos; + surface()->DrawSetColor( 255, 255, 255, 255 ); + + DrawGraduations( flYawPlayerForward ); + + if( bObjectInFOV ) + { + // The object's location maps to a valid position along the tape, so draw an icon. + float tapePosition = LocatorXPositionForYawDiff(yawDiff); + + // derive a scale for the locator icon + yawDiff = fabs(yawDiff); + float scale = 1.0f; + scale = RemapValClamped( yawDiff, (fov/4), fov, 1.0f, 0.25f ); + + vgui::surface()->DrawSetTexture( m_textureID_IconJalopy ); + vgui::surface()->DrawGetTextureSize( m_textureID_IconJalopy, icon_wide, icon_tall ); + + float flIconWide = ((float)element_tall * 1.25f); + float flIconTall = ((float)element_tall * 1.25f); + + // Scale the icon as desired... + + // Put back into ints + icon_wide = (int)flIconWide; + icon_tall = (int)flIconTall; + + icon_wide *= scale; + + //Msg("yawDiff:%f xPos:%d scale:%f\n", yawDiff, xPos, scale ); + + // Center the icon around its position. + xPos = (int)tapePosition; + xPos -= (icon_wide >> 1); + yPos = (element_tall>>1) - (icon_tall >> 1); + + //Msg("Drawing at %f %f\n", x, y ); + vgui::surface()->DrawTexturedRect(xPos, yPos, xPos+icon_wide, yPos+icon_tall); + } + +#endif // HL2_EPISODIC +} + + diff --git a/game/client/hl2/hud_poisondamageindicator.cpp b/game/client/hl2/hud_poisondamageindicator.cpp new file mode 100644 index 0000000..f0ed7ea --- /dev/null +++ b/game/client/hl2/hud_poisondamageindicator.cpp @@ -0,0 +1,155 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "hud.h" +#include "text_message.h" +#include "hud_macros.h" +#include "iclientmode.h" +#include "view.h" +#include "KeyValues.h" +#include "vgui_controls/AnimationController.h" +#include "vgui/ILocalize.h" +#include "vgui/ISurface.h" +#include "VGuiMatSurface/IMatSystemSurface.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/imesh.h" +#include "materialsystem/imaterialvar.h" +#include "IEffects.h" +#include "hudelement.h" + +using namespace vgui; + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: HDU Damage indication +//----------------------------------------------------------------------------- +class CHudPoisonDamageIndicator : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudPoisonDamageIndicator, vgui::Panel ); + +public: + CHudPoisonDamageIndicator( const char *pElementName ); + void Reset( void ); + virtual bool ShouldDraw( void ); + +private: + virtual void OnThink(); + virtual void Paint(); + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + +private: + CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "Default" ); + CPanelAnimationVar( Color, m_TextColor, "TextColor", "FgColor" ); + CPanelAnimationVarAliasType( float, text_xpos, "text_xpos", "8", "proportional_float" ); + CPanelAnimationVarAliasType( float, text_ypos, "text_ypos", "8", "proportional_float" ); + CPanelAnimationVarAliasType( float, text_ygap, "text_ygap", "14", "proportional_float" ); + + bool m_bDamageIndicatorVisible; +}; + +DECLARE_HUDELEMENT( CHudPoisonDamageIndicator ); + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CHudPoisonDamageIndicator::CHudPoisonDamageIndicator( const char *pElementName ) : CHudElement( pElementName ), BaseClass(NULL, "HudPoisonDamageIndicator") +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + + SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD | HIDEHUD_NEEDSUIT ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudPoisonDamageIndicator::Reset( void ) +{ + SetAlpha( 0 ); + m_bDamageIndicatorVisible = false; +} + +//----------------------------------------------------------------------------- +// Purpose: Save CPU cycles by letting the HUD system early cull +// costly traversal. Called per frame, return true if thinking and +// painting need to occur. +//----------------------------------------------------------------------------- +bool CHudPoisonDamageIndicator::ShouldDraw( void ) +{ + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return false; + + bool bNeedsDraw = ( ( pPlayer->IsPoisoned() != m_bDamageIndicatorVisible ) || ( GetAlpha() > 0 ) ); + + return ( bNeedsDraw && CHudElement::ShouldDraw() ); +} + +//----------------------------------------------------------------------------- +// Purpose: updates poison damage +//----------------------------------------------------------------------------- +void CHudPoisonDamageIndicator::OnThink() +{ + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + // update poison damage indicator + bool bShouldIndicatorBeVisible = pPlayer->IsPoisoned(); + if (bShouldIndicatorBeVisible == m_bDamageIndicatorVisible) + return; + + // state change + m_bDamageIndicatorVisible = bShouldIndicatorBeVisible; + + if (m_bDamageIndicatorVisible) + { + SetVisible(true); + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "PoisonDamageTaken" ); + } + else + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "PoisonDamageCured" ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Paints the damage display +//----------------------------------------------------------------------------- +void CHudPoisonDamageIndicator::Paint() +{ + // draw the text + surface()->DrawSetTextFont( m_hTextFont ); + surface()->DrawSetTextColor( m_TextColor ); + surface()->DrawSetTextPos(text_xpos, text_ypos); + int ypos = text_ypos; + + const wchar_t *labelText = g_pVGuiLocalize->Find("Valve_HudPoisonDamage"); + Assert( labelText ); + for (const wchar_t *wch = labelText; wch && *wch != 0; wch++) + { + if (*wch == '\n') + { + ypos += text_ygap; + surface()->DrawSetTextPos(text_xpos, ypos); + } + else + { + surface()->DrawUnicodeChar(*wch); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: hud scheme settings +//----------------------------------------------------------------------------- +void CHudPoisonDamageIndicator::ApplySchemeSettings(vgui::IScheme *pScheme) +{ + BaseClass::ApplySchemeSettings(pScheme); +} diff --git a/game/client/hl2/hud_quickinfo.cpp b/game/client/hl2/hud_quickinfo.cpp new file mode 100644 index 0000000..37db4c3 --- /dev/null +++ b/game/client/hl2/hud_quickinfo.cpp @@ -0,0 +1,408 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#include "cbase.h" +#include "hud.h" +#include "hudelement.h" +#include "iclientmode.h" +#include "engine/IEngineSound.h" +#include "vgui_controls/AnimationController.h" +#include "vgui_controls/Controls.h" +#include "vgui_controls/Panel.h" +#include "vgui/ISurface.h" +#include "../hud_crosshair.h" +#include "VGuiMatSurface/IMatSystemSurface.h" + +#ifdef SIXENSE +#include "sixense/in_sixense.h" +#include "view.h" +int ScreenTransform( const Vector& point, Vector& screen ); +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define HEALTH_WARNING_THRESHOLD 25 + +static ConVar hud_quickinfo( "hud_quickinfo", "1", FCVAR_ARCHIVE ); + +extern ConVar crosshair; + +#define QUICKINFO_EVENT_DURATION 1.0f +#define QUICKINFO_BRIGHTNESS_FULL 255 +#define QUICKINFO_BRIGHTNESS_DIM 64 +#define QUICKINFO_FADE_IN_TIME 0.5f +#define QUICKINFO_FADE_OUT_TIME 2.0f + +/* +================================================== +CHUDQuickInfo +================================================== +*/ + +using namespace vgui; + +class CHUDQuickInfo : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHUDQuickInfo, vgui::Panel ); +public: + CHUDQuickInfo( const char *pElementName ); + void Init( void ); + void VidInit( void ); + bool ShouldDraw( void ); + virtual void OnThink(); + virtual void Paint(); + + virtual void ApplySchemeSettings( IScheme *scheme ); +private: + + void DrawWarning( int x, int y, CHudTexture *icon, float &time ); + void UpdateEventTime( void ); + bool EventTimeElapsed( void ); + + int m_lastAmmo; + int m_lastHealth; + + float m_ammoFade; + float m_healthFade; + + bool m_warnAmmo; + bool m_warnHealth; + + bool m_bFadedOut; + + bool m_bDimmed; // Whether or not we are dimmed down + float m_flLastEventTime; // Last active event (controls dimmed state) + + CHudTexture *m_icon_c; + + CHudTexture *m_icon_rbn; // right bracket + CHudTexture *m_icon_lbn; // left bracket + + CHudTexture *m_icon_rb; // right bracket, full + CHudTexture *m_icon_lb; // left bracket, full + CHudTexture *m_icon_rbe; // right bracket, empty + CHudTexture *m_icon_lbe; // left bracket, empty +}; + +DECLARE_HUDELEMENT( CHUDQuickInfo ); + +CHUDQuickInfo::CHUDQuickInfo( const char *pElementName ) : + CHudElement( pElementName ), BaseClass( NULL, "HUDQuickInfo" ) +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + + SetHiddenBits( HIDEHUD_CROSSHAIR ); +} + +void CHUDQuickInfo::ApplySchemeSettings( IScheme *scheme ) +{ + BaseClass::ApplySchemeSettings( scheme ); + + SetPaintBackgroundEnabled( false ); + SetForceStereoRenderToFrameBuffer( true ); +} + + +void CHUDQuickInfo::Init( void ) +{ + m_ammoFade = 0.0f; + m_healthFade = 0.0f; + + m_lastAmmo = 0; + m_lastHealth = 100; + + m_warnAmmo = false; + m_warnHealth = false; + + m_bFadedOut = false; + m_bDimmed = false; + m_flLastEventTime = 0.0f; +} + + +void CHUDQuickInfo::VidInit( void ) +{ + Init(); + + m_icon_c = gHUD.GetIcon( "crosshair" ); + m_icon_rb = gHUD.GetIcon( "crosshair_right_full" ); + m_icon_lb = gHUD.GetIcon( "crosshair_left_full" ); + m_icon_rbe = gHUD.GetIcon( "crosshair_right_empty" ); + m_icon_lbe = gHUD.GetIcon( "crosshair_left_empty" ); + m_icon_rbn = gHUD.GetIcon( "crosshair_right" ); + m_icon_lbn = gHUD.GetIcon( "crosshair_left" ); +} + + +void CHUDQuickInfo::DrawWarning( int x, int y, CHudTexture *icon, float &time ) +{ + float scale = (int)( fabs(sin(gpGlobals->curtime*8.0f)) * 128.0); + + // Only fade out at the low point of our blink + if ( time <= (gpGlobals->frametime * 200.0f) ) + { + if ( scale < 40 ) + { + time = 0.0f; + return; + } + else + { + // Counteract the offset below to survive another frame + time += (gpGlobals->frametime * 200.0f); + } + } + + // Update our time + time -= (gpGlobals->frametime * 200.0f); + Color caution = gHUD.m_clrCaution; + caution[3] = scale * 255; + + icon->DrawSelf( x, y, caution ); +} + +//----------------------------------------------------------------------------- +// Purpose: Save CPU cycles by letting the HUD system early cull +// costly traversal. Called per frame, return true if thinking and +// painting need to occur. +//----------------------------------------------------------------------------- +bool CHUDQuickInfo::ShouldDraw( void ) +{ + if ( !m_icon_c || !m_icon_rb || !m_icon_rbe || !m_icon_lb || !m_icon_lbe ) + return false; + + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + if ( player == NULL ) + return false; + + if ( !crosshair.GetBool() && !IsX360() ) + return false; + + return ( CHudElement::ShouldDraw() && !engine->IsDrawingLoadingImage() ); +} + +//----------------------------------------------------------------------------- +// Purpose: Checks if the hud element needs to fade out +//----------------------------------------------------------------------------- +void CHUDQuickInfo::OnThink() +{ + BaseClass::OnThink(); + + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + if ( player == NULL ) + return; + + // see if we should fade in/out + bool bFadeOut = player->IsZoomed(); + + // check if the state has changed + if ( m_bFadedOut != bFadeOut ) + { + m_bFadedOut = bFadeOut; + + m_bDimmed = false; + + if ( bFadeOut ) + { + g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( this, "Alpha", 0.0f, 0.0f, 0.25f, vgui::AnimationController::INTERPOLATOR_LINEAR ); + } + else + { + g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( this, "Alpha", QUICKINFO_BRIGHTNESS_FULL, 0.0f, QUICKINFO_FADE_IN_TIME, vgui::AnimationController::INTERPOLATOR_LINEAR ); + } + } + else if ( !m_bFadedOut ) + { + // If we're dormant, fade out + if ( EventTimeElapsed() ) + { + if ( !m_bDimmed ) + { + m_bDimmed = true; + g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( this, "Alpha", QUICKINFO_BRIGHTNESS_DIM, 0.0f, QUICKINFO_FADE_OUT_TIME, vgui::AnimationController::INTERPOLATOR_LINEAR ); + } + } + else if ( m_bDimmed ) + { + // Fade back up, we're active + m_bDimmed = false; + g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( this, "Alpha", QUICKINFO_BRIGHTNESS_FULL, 0.0f, QUICKINFO_FADE_IN_TIME, vgui::AnimationController::INTERPOLATOR_LINEAR ); + } + } +} + +void CHUDQuickInfo::Paint() +{ + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + if ( player == NULL ) + return; + + C_BaseCombatWeapon *pWeapon = GetActiveWeapon(); + if ( pWeapon == NULL ) + return; + + float fX, fY; + bool bBehindCamera = false; + CHudCrosshair::GetDrawPosition( &fX, &fY, &bBehindCamera ); + + // if the crosshair is behind the camera, don't draw it + if( bBehindCamera ) + return; + + int xCenter = (int)fX; + int yCenter = (int)fY - m_icon_lb->Height() / 2; + + float scalar = 138.0f/255.0f; + + // Check our health for a warning + int health = player->GetHealth(); + if ( health != m_lastHealth ) + { + UpdateEventTime(); + m_lastHealth = health; + + if ( health <= HEALTH_WARNING_THRESHOLD ) + { + if ( m_warnHealth == false ) + { + m_healthFade = 255; + m_warnHealth = true; + + CLocalPlayerFilter filter; + C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "HUDQuickInfo.LowHealth" ); + } + } + else + { + m_warnHealth = false; + } + } + + // Check our ammo for a warning + int ammo = pWeapon->Clip1(); + if ( ammo != m_lastAmmo ) + { + UpdateEventTime(); + m_lastAmmo = ammo; + + // Find how far through the current clip we are + float ammoPerc = (float) ammo / (float) pWeapon->GetMaxClip1(); + + // Warn if we're below a certain percentage of our clip's size + if (( pWeapon->GetMaxClip1() > 1 ) && ( ammoPerc <= ( 1.0f - CLIP_PERC_THRESHOLD ))) + { + if ( m_warnAmmo == false ) + { + m_ammoFade = 255; + m_warnAmmo = true; + + CLocalPlayerFilter filter; + C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "HUDQuickInfo.LowAmmo" ); + } + } + else + { + m_warnAmmo = false; + } + } + + Color clrNormal = gHUD.m_clrNormal; + clrNormal[3] = 255 * scalar; + m_icon_c->DrawSelf( xCenter, yCenter, clrNormal ); + + if( IsX360() ) + { + // Because the fixed reticle draws on half-texels, this rather unsightly hack really helps + // center the appearance of the quickinfo on 360 displays. + xCenter += 1; + } + + if ( !hud_quickinfo.GetInt() ) + return; + + int sinScale = (int)( fabs(sin(gpGlobals->curtime*8.0f)) * 128.0f ); + + // Update our health + if ( m_healthFade > 0.0f ) + { + DrawWarning( xCenter - (m_icon_lb->Width() * 2), yCenter, m_icon_lb, m_healthFade ); + } + else + { + float healthPerc = (float) health / 100.0f; + healthPerc = clamp( healthPerc, 0.0f, 1.0f ); + + Color healthColor = m_warnHealth ? gHUD.m_clrCaution : gHUD.m_clrNormal; + + if ( m_warnHealth ) + { + healthColor[3] = 255 * sinScale; + } + else + { + healthColor[3] = 255 * scalar; + } + + gHUD.DrawIconProgressBar( xCenter - (m_icon_lb->Width() * 2), yCenter, m_icon_lb, m_icon_lbe, ( 1.0f - healthPerc ), healthColor, CHud::HUDPB_VERTICAL ); + } + + // Update our ammo + if ( m_ammoFade > 0.0f ) + { + DrawWarning( xCenter + m_icon_rb->Width(), yCenter, m_icon_rb, m_ammoFade ); + } + else + { + float ammoPerc; + + if ( pWeapon->GetMaxClip1() <= 0 ) + { + ammoPerc = 0.0f; + } + else + { + ammoPerc = 1.0f - ( (float) ammo / (float) pWeapon->GetMaxClip1() ); + ammoPerc = clamp( ammoPerc, 0.0f, 1.0f ); + } + + Color ammoColor = m_warnAmmo ? gHUD.m_clrCaution : gHUD.m_clrNormal; + + if ( m_warnAmmo ) + { + ammoColor[3] = 255 * sinScale; + } + else + { + ammoColor[3] = 255 * scalar; + } + + gHUD.DrawIconProgressBar( xCenter + m_icon_rb->Width(), yCenter, m_icon_rb, m_icon_rbe, ammoPerc, ammoColor, CHud::HUDPB_VERTICAL ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHUDQuickInfo::UpdateEventTime( void ) +{ + m_flLastEventTime = gpGlobals->curtime; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CHUDQuickInfo::EventTimeElapsed( void ) +{ + if (( gpGlobals->curtime - m_flLastEventTime ) > QUICKINFO_EVENT_DURATION ) + return true; + + return false; +} + diff --git a/game/client/hl2/hud_radar.cpp b/game/client/hl2/hud_radar.cpp new file mode 100644 index 0000000..2f0fd7e --- /dev/null +++ b/game/client/hl2/hud_radar.cpp @@ -0,0 +1,587 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include <vgui/ISurface.h> +#include "hud_numericdisplay.h" +#include "iclientmode.h" +#include <coordsize.h> +#include "hud_macros.h" +#include "vgui/IVGui.h" +#include "vgui/ILocalize.h" +#include "mapoverview.h" +#include "hud_radar.h" +#include "iclientvehicle.h" + +#define RADAR_DOT_NORMAL 0 +#define RADAR_IGNORE_Z (1<<6) //always draw this item as if it was at the same Z as the player +#define RADAR_MAX_GHOST_ALPHA 25 + +DECLARE_VGUI_SCREEN_FACTORY( CHudRadar, "jalopy_radar_panel" ); + +#define RADAR_PANEL_MATERIAL "vgui/screens/radar" +#define RADAR_CONTACT_LAMBDA_MATERIAL "vgui/icons/icon_lambda" // Lambda cache +#define RADAR_CONTACT_BUSTER_MATERIAL "vgui/icons/icon_buster" // Striderbuster +#define RADAR_CONTACT_STRIDER_MATERIAL "vgui/icons/icon_strider" // Strider +#define RADAR_CONTACT_DOG_MATERIAL "vgui/icons/icon_dog" // Dog +#define RADAR_CONTACT_BASE_MATERIAL "vgui/icons/icon_base" // Ally base + +static CHudRadar *s_Radar = NULL; + +CHudRadar *GetHudRadar() +{ + return s_Radar; +} + +DECLARE_HUDELEMENT( CMapOverview ); + +//--------------------------------------------------------- +//--------------------------------------------------------- +CHudRadar::CHudRadar( vgui::Panel *parent, const char *panelName ) : BaseClass( parent, panelName ) +{ + m_pVehicle = NULL; + m_iImageID = -1; + m_textureID_IconLambda = -1; + m_textureID_IconBuster = -1; + m_textureID_IconStrider = -1; + m_textureID_IconDog = -1; + m_textureID_IconBase = -1; +} + +//--------------------------------------------------------- +//--------------------------------------------------------- +CHudRadar::~CHudRadar() +{ + s_Radar = NULL; + +#if defined(_X360) + if( m_iImageID != -1 ) + { + vgui::surface()->DestroyTextureID( m_iImageID ); + m_iImageID = -1; + } + + if( m_textureID_IconLambda != -1 ) + { + vgui::surface()->DestroyTextureID( m_textureID_IconLambda ); + m_textureID_IconLambda = -1; + } + + if( m_textureID_IconBuster != -1 ) + { + vgui::surface()->DestroyTextureID( m_textureID_IconBuster ); + m_textureID_IconBuster = -1; + } + + if( m_textureID_IconStrider != -1 ) + { + vgui::surface()->DestroyTextureID( m_textureID_IconStrider ); + m_textureID_IconStrider = -1; + } + + if( m_textureID_IconDog != -1 ) + { + vgui::surface()->DestroyTextureID( m_textureID_IconDog ); + m_textureID_IconDog = -1; + } + + if( m_textureID_IconBase != -1 ) + { + vgui::surface()->DestroyTextureID( m_textureID_IconBase ); + m_textureID_IconBase = -1; + } +#endif//_X360 +} + +//--------------------------------------------------------- +//--------------------------------------------------------- +bool CHudRadar::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ) +{ + bool result = BaseClass::Init( pKeyValues, pInitData ); + ClearAllRadarContacts(); + s_Radar = this; + + m_ghostAlpha = 0; + m_flTimeStartGhosting = gpGlobals->curtime + 1.0f; + + return result; +} + +//--------------------------------------------------------- +//--------------------------------------------------------- +void CHudRadar::VidInit(void) +{ +} + +//--------------------------------------------------------- +//--------------------------------------------------------- +void CHudRadar::MsgFunc_UpdateRadar(bf_read &msg ) +{ +} + +//--------------------------------------------------------- +// Purpose: Register a radar contact in the list of contacts +//--------------------------------------------------------- +void CHudRadar::AddRadarContact( const Vector &vecOrigin, int iType, float flTimeToLive ) +{ + if( m_iNumRadarContacts == RADAR_MAX_CONTACTS ) + return; + + Vector v = vecOrigin; + int iExistingContact = FindRadarContact( vecOrigin ); + + if( iExistingContact > -1 ) + { + // Just update this contact. + m_radarContacts[iExistingContact].m_flTimeToRemove = gpGlobals->curtime + flTimeToLive; + return; + } + + m_radarContacts[m_iNumRadarContacts].m_vecOrigin = vecOrigin; + m_radarContacts[m_iNumRadarContacts].m_iType = iType; + m_radarContacts[m_iNumRadarContacts].m_flTimeToRemove = gpGlobals->curtime + flTimeToLive; + m_iNumRadarContacts++; +} + +//--------------------------------------------------------- +// Purpose: Search the contact list for a specific contact +//--------------------------------------------------------- +int CHudRadar::FindRadarContact( const Vector &vecOrigin ) +{ + for( int i = 0 ; i < m_iNumRadarContacts ; i++ ) + { + if( m_radarContacts[ i ].m_vecOrigin == vecOrigin ) + return i; + } + + return -1; +} + +//--------------------------------------------------------- +// Purpose: Go through all radar targets and see if any +// have expired. If yes, remove them from the +// list. +//--------------------------------------------------------- +void CHudRadar::MaintainRadarContacts() +{ + bool bKeepWorking = true; + while( bKeepWorking ) + { + bKeepWorking = false; + for( int i = 0 ; i < m_iNumRadarContacts ; i++ ) + { + CRadarContact *pContact = &m_radarContacts[ i ]; + if( gpGlobals->curtime >= pContact->m_flTimeToRemove ) + { + // Time for this guy to go. Easiest thing is just to copy the last element + // into this element's spot and then decrement the count of entities. + bKeepWorking = true; + + m_radarContacts[ i ] = m_radarContacts[ m_iNumRadarContacts - 1 ]; + m_iNumRadarContacts--; + break; + } + } + } +} + +//--------------------------------------------------------- +//--------------------------------------------------------- +void CHudRadar::SetVisible(bool state) +{ + BaseClass::SetVisible(state); + + if( g_pMapOverview && g_pMapOverview->GetMode() == CMapOverview::MAP_MODE_RADAR ) + { + // We are the hud element still, but he is in charge of the new style now. + g_pMapOverview->SetVisible( state ); + } +} + +#define RADAR_BLIP_FADE_TIME 1.0f +#define RADAR_USE_ICONS 1 +//--------------------------------------------------------- +// Purpose: Draw the radar panel. +// We're probably doing too much other work in here +//--------------------------------------------------------- +void CHudRadar::Paint() +{ + if (m_iImageID == -1 ) + { + // Set up the image ID's if they've somehow gone bad. + m_textureID_IconLambda = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_textureID_IconLambda, RADAR_CONTACT_LAMBDA_MATERIAL, true, false ); + + m_textureID_IconBuster = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_textureID_IconBuster, RADAR_CONTACT_BUSTER_MATERIAL, true, false ); + + m_textureID_IconStrider = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_textureID_IconStrider, RADAR_CONTACT_STRIDER_MATERIAL, true, false ); + + m_textureID_IconDog = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_textureID_IconDog, RADAR_CONTACT_DOG_MATERIAL, true, false ); + + m_textureID_IconBase = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_textureID_IconBase, RADAR_CONTACT_BASE_MATERIAL, true, false ); + + m_iImageID = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_iImageID, RADAR_PANEL_MATERIAL, true, false ); + } + + // Draw the radar background. + int wide, tall; + GetSize(wide, tall); + int alpha = 255; + vgui::surface()->DrawSetColor(255, 255, 255, alpha); + vgui::surface()->DrawSetTexture(m_iImageID); + vgui::surface()->DrawTexturedRect(0, 0, wide, tall); + + // Manage the CRT 'ghosting' effect + if( gpGlobals->curtime > m_flTimeStartGhosting ) + { + if( m_ghostAlpha < RADAR_MAX_GHOST_ALPHA ) + { + m_ghostAlpha++; + } + else + { + m_flTimeStartGhosting = FLT_MAX; + m_flTimeStopGhosting = gpGlobals->curtime + RandomFloat( 1.0f, 2.0f );// How long to ghost for + } + } + else if( gpGlobals->curtime > m_flTimeStopGhosting ) + { + // We're supposed to stop ghosting now. + if( m_ghostAlpha > 0 ) + { + // Still fading the effects. + m_ghostAlpha--; + } + else + { + // DONE fading the effects. Now stop ghosting for a short while + m_flTimeStartGhosting = gpGlobals->curtime + RandomFloat( 2.0f, 3.0f );// how long between ghosts + m_flTimeStopGhosting = FLT_MAX; + } + } + + // Now go through the list of radar targets and represent them on the radar screen + // by drawing their icons on top of the background. + C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); + + for( int i = 0 ; i < m_iNumRadarContacts ; i++ ) + { + int alpha = 90; + CRadarContact *pContact = &m_radarContacts[ i ]; + float deltaT = pContact->m_flTimeToRemove - gpGlobals->curtime; + if ( deltaT < RADAR_BLIP_FADE_TIME ) + { + float factor = deltaT / RADAR_BLIP_FADE_TIME; + + alpha = (int) ( ((float)alpha) * factor ); + + if( alpha < 10 ) + alpha = 10; + } + + if( RADAR_USE_ICONS ) + { + int flicker = RandomInt( 0, 30 ); + DrawIconOnRadar( pContact->m_vecOrigin, pLocalPlayer, pContact->m_iType, RADAR_IGNORE_Z, 255, 255, 255, alpha + flicker ); + } + else + { + DrawPositionOnRadar( pContact->m_vecOrigin, pLocalPlayer, pContact->m_iType, RADAR_IGNORE_Z, 255, 255, 255, alpha ); + } + } + + MaintainRadarContacts(); +} + +ConVar radar_range("radar_range", "3000" ); // 180 feet +//--------------------------------------------------------- +// Scale maps the distance of the target from the radar +// source. +// +// 1.0 = target at or beyond radar range. +// 0.5 = target at (radar_range * 0.5) units distance +// 0.25 = target at (radar_range * 0.25) units distance +// -etc- +//--------------------------------------------------------- +bool CHudRadar::WorldToRadar( const Vector location, const Vector origin, const QAngle angles, float &x, float &y, float &z_delta, float &scale ) +{ + bool bInRange = true; + + float x_diff = location.x - origin.x; + float y_diff = location.y - origin.y; + + // Supply epsilon values to avoid divide-by-zero + if(x_diff == 0) + x_diff = 0.00001f; + + if(y_diff == 0) + y_diff = 0.00001f; + + int iRadarRadius = GetWide(); //width of the panel + float fRange = radar_range.GetFloat(); + + // This magic /2.15 makes the radar scale seem smaller than the VGUI panel so the icons clamp + // to the outer ring in the radar graphic, not the very edge of the panel itself. + float fScale = (iRadarRadius/2.15f) / fRange; + + float flOffset = atan(y_diff/x_diff); + flOffset *= 180; + flOffset /= M_PI; + + if ((x_diff < 0) && (y_diff >= 0)) + flOffset = 180 + flOffset; + else if ((x_diff < 0) && (y_diff < 0)) + flOffset = 180 + flOffset; + else if ((x_diff >= 0) && (y_diff < 0)) + flOffset = 360 + flOffset; + + y_diff = -1*(sqrt((x_diff)*(x_diff) + (y_diff)*(y_diff))); + x_diff = 0; + + flOffset = angles.y - flOffset; + + flOffset *= M_PI; + flOffset /= 180; // now theta is in radians + + // Transform relative to radar source + float xnew_diff = x_diff * cos(flOffset) - y_diff * sin(flOffset); + float ynew_diff = x_diff * sin(flOffset) + y_diff * cos(flOffset); + + if ( (-1 * y_diff) > fRange ) + { + float flScale; + + flScale = ( -1 * y_diff) / fRange; + + xnew_diff /= (flScale); + ynew_diff /= (flScale); + + bInRange = false; + + scale = 1.0f; + } + else + { + // scale + float flDist = sqrt( ((xnew_diff)*(xnew_diff) + (ynew_diff)*(ynew_diff)) ); + scale = flDist / fRange; + } + + + // Scale the dot's position to match radar scale + xnew_diff *= fScale; + ynew_diff *= fScale; + + // Translate to screen coordinates + x = (iRadarRadius/2) + (int)xnew_diff; + y = (iRadarRadius/2) + (int)ynew_diff; + z_delta = 0.0f; + + return bInRange; +} + +void CHudRadar::DrawPositionOnRadar( Vector vecPos, C_BasePlayer *pLocalPlayer, int type, int flags, int r, int g, int b, int a ) +{ + float x, y, z_delta; + int iBaseDotSize = 3; + + QAngle viewAngle = pLocalPlayer->EyeAngles(); + + if( m_pVehicle != NULL ) + { + viewAngle = m_pVehicle->GetAbsAngles(); + viewAngle.y += 90.0f; + } + + float flScale; + + WorldToRadar( vecPos, pLocalPlayer->GetAbsOrigin(), viewAngle, x, y, z_delta, flScale ); + + if( flags & RADAR_IGNORE_Z ) + z_delta = 0; + + switch( type ) + { + case RADAR_CONTACT_GENERIC: + r = 255; g = 170; b = 0; + iBaseDotSize *= 2; + break; + case RADAR_CONTACT_MAGNUSSEN_RDU: + r = 0; g = 200; b = 255; + iBaseDotSize *= 2; + break; + case RADAR_CONTACT_ENEMY: + r = 255; g = 0; b = 0; + iBaseDotSize *= 2; + break; + case RADAR_CONTACT_LARGE_ENEMY: + r = 255; g = 0; b = 0; + iBaseDotSize *= 3; + break; + } + + DrawRadarDot( x, y, z_delta, iBaseDotSize, flags, r, g, b, a ); +} + +//--------------------------------------------------------- +// Purpose: Compute the proper position on the radar screen +// for this object's position relative to the player. +// Then draw the icon in the proper location on the +// radar screen. +//--------------------------------------------------------- +#define RADAR_ICON_MIN_SCALE 0.75f +#define RADAR_ICON_MAX_SCALE 1.0f +void CHudRadar::DrawIconOnRadar( Vector vecPos, C_BasePlayer *pLocalPlayer, int type, int flags, int r, int g, int b, int a ) +{ + float x, y, z_delta; + int wide, tall; + + // for 'ghosting' CRT effects: + int xmod; + int ymod; + int xoffset; + int yoffset; + + // Assume we're going to use the player's location and orientation + QAngle viewAngle = pLocalPlayer->EyeAngles(); + Vector viewOrigin = pLocalPlayer->GetAbsOrigin(); + + // However, happily use those of the vehicle if available! + if( m_pVehicle != NULL ) + { + viewAngle = m_pVehicle->GetAbsAngles(); + viewAngle.y += 90.0f; + viewOrigin = m_pVehicle->WorldSpaceCenter(); + } + + float flScale; + + WorldToRadar( vecPos, viewOrigin, viewAngle, x, y, z_delta, flScale ); + + flScale = RemapVal( flScale, 1.0f, 0.0f, RADAR_ICON_MIN_SCALE, RADAR_ICON_MAX_SCALE ); + + // Get the correct icon for this type of contact + int iTextureID_Icon = -1; + + switch( type ) + { + case RADAR_CONTACT_GENERIC: + iTextureID_Icon = m_textureID_IconLambda; + break; + case RADAR_CONTACT_MAGNUSSEN_RDU: + iTextureID_Icon = m_textureID_IconBuster; + break; + case RADAR_CONTACT_LARGE_ENEMY: + case RADAR_CONTACT_ENEMY: + iTextureID_Icon = m_textureID_IconStrider; + break; + case RADAR_CONTACT_DOG: + iTextureID_Icon = m_textureID_IconDog; + break; + case RADAR_CONTACT_ALLY_INSTALLATION: + iTextureID_Icon = m_textureID_IconBase; + break; + default: + return; + break; + } + + vgui::surface()->DrawSetColor( r, g, b, a ); + vgui::surface()->DrawSetTexture( iTextureID_Icon ); + vgui::surface()->DrawGetTextureSize( iTextureID_Icon, wide, tall ); + + wide = ( int((float)wide * flScale) ); + tall = ( int((float)tall * flScale) ); + + if( type == RADAR_CONTACT_LARGE_ENEMY ) + { + wide *= 2; + tall *= 2; + } + + // Center the icon around its position. + x -= (wide >> 1); + y -= (tall >> 1); + + vgui::surface()->DrawTexturedRect(x, y, x+wide, y+tall); + + // Draw the crt 'ghost' if the icon is not pegged to the outer rim + if( flScale > RADAR_ICON_MIN_SCALE && m_ghostAlpha > 0 ) + { + vgui::surface()->DrawSetColor( r, g, b, m_ghostAlpha ); + xmod = RandomInt( 1, 4 ); + ymod = RandomInt( 1, 4 ); + xoffset = RandomInt( -1, 1 ); + yoffset = RandomInt( -1, 1 ); + x -= (xmod - xoffset); + y -= (ymod - yoffset); + wide += (xmod + xoffset); + tall += (ymod + yoffset); + vgui::surface()->DrawTexturedRect(x, y, x+wide, y+tall); + } +} + +void CHudRadar::FillRect( int x, int y, int w, int h ) +{ + int panel_x, panel_y, panel_w, panel_h; + GetBounds( panel_x, panel_y, panel_w, panel_h ); + vgui::surface()->DrawFilledRect( x, y, x+w, y+h ); +} + +void CHudRadar::DrawRadarDot( int x, int y, float z_diff, int iBaseDotSize, int flags, int r, int g, int b, int a ) +{ + vgui::surface()->DrawSetColor( r, g, b, a ); + + if ( z_diff < -128 ) // below the player + { + z_diff *= -1; + + if ( z_diff > 3096 ) + { + z_diff = 3096; + } + + int iBar = (int)( z_diff / 400 ) + 2; + + // Draw an upside-down T shape to symbolize the dot is below the player. + + iBaseDotSize /= 2; + + //horiz + FillRect( x-(2*iBaseDotSize), y, 5*iBaseDotSize, iBaseDotSize ); + + //vert + FillRect( x, y - iBar*iBaseDotSize, iBaseDotSize, iBar*iBaseDotSize ); + } + else if ( z_diff > 128 ) // above the player + { + if ( z_diff > 3096 ) + { + z_diff = 3096; + } + + int iBar = (int)( z_diff / 400 ) + 2; + + iBaseDotSize /= 2; + + // Draw a T shape to symbolize the dot is above the player. + + //horiz + FillRect( x-(2*iBaseDotSize), y, 5*iBaseDotSize, iBaseDotSize ); + + //vert + FillRect( x, y, iBaseDotSize, iBar*iBaseDotSize ); + } + else + { + FillRect( x, y, iBaseDotSize, iBaseDotSize ); + } +} diff --git a/game/client/hl2/hud_radar.h b/game/client/hl2/hud_radar.h new file mode 100644 index 0000000..81134ca --- /dev/null +++ b/game/client/hl2/hud_radar.h @@ -0,0 +1,78 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef HUD_RADAR_H +#define HUD_RADAR_H +#ifdef _WIN32 +#pragma once +#endif + +#include <vgui_controls/Panel.h> +#include <vgui_controls/Label.h> +#include "hl2_vehicle_radar.h" +#include "c_vguiscreen.h" + +class CRadarContact +{ +public: + Vector m_vecOrigin; + int m_iType; + float m_flTimeToRemove; +}; + +class CHudRadar : public CVGuiScreenPanel +{ +public: + DECLARE_CLASS_SIMPLE( CHudRadar, CVGuiScreenPanel ); + + + CHudRadar( vgui::Panel *parent, const char *panelName ); + ~CHudRadar(); + + virtual void Paint(); + void VidInit(void); + virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); + virtual void SetVisible(bool state); + + void MsgFunc_UpdateRadar(bf_read &msg ); + void SetVehicle( C_BaseEntity *pVehicle ) { m_pVehicle = pVehicle; } + + void AddRadarContact( const Vector &vecOrigin, int iType, float flTimeToLive ); + int FindRadarContact( const Vector &vecOrigin ); + void MaintainRadarContacts(); + + + void ClearAllRadarContacts() { m_iNumRadarContacts = 0; } + +public: + bool m_bUseFastUpdate; + int m_ghostAlpha; // How intense the alpha channel is for CRT ghosts + float m_flTimeStopGhosting; + float m_flTimeStartGhosting; + +private: + + bool WorldToRadar( const Vector location, const Vector origin, const QAngle angles, float &x, float &y, float &z_delta, float &scale ); + + void DrawPositionOnRadar( Vector vecPos, C_BasePlayer *pLocalPlayer, int type, int flags, int r, int g, int b, int a ); + void DrawIconOnRadar( Vector vecPos, C_BasePlayer *pLocalPlayer, int type, int flags, int r, int g, int b, int a ); + + void FillRect( int x, int y, int w, int h ); + void DrawRadarDot( int x, int y, float z_diff, int iBaseDotSize, int flags, int r, int g, int b, int a ); + + CRadarContact m_radarContacts[RADAR_MAX_CONTACTS]; + int m_iNumRadarContacts; + C_BaseEntity *m_pVehicle; + int m_iImageID; + int m_textureID_IconLambda; + int m_textureID_IconBuster; + int m_textureID_IconStrider; + int m_textureID_IconDog; + int m_textureID_IconBase; +}; + +extern CHudRadar *GetHudRadar(); +#endif // HUD_RADAR_H diff --git a/game/client/hl2/hud_suitpower.cpp b/game/client/hl2/hud_suitpower.cpp new file mode 100644 index 0000000..416c930 --- /dev/null +++ b/game/client/hl2/hud_suitpower.cpp @@ -0,0 +1,257 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "hud.h" +#include "hud_suitpower.h" +#include "hud_macros.h" +#include "c_basehlplayer.h" +#include "iclientmode.h" +#include <vgui_controls/AnimationController.h> +#include <vgui/ISurface.h> +#include <vgui/ILocalize.h> + +using namespace vgui; + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +DECLARE_HUDELEMENT( CHudSuitPower ); + +#define SUITPOWER_INIT -1 + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CHudSuitPower::CHudSuitPower( const char *pElementName ) : CHudElement( pElementName ), BaseClass( NULL, "HudSuitPower" ) +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + + SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD | HIDEHUD_NEEDSUIT ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudSuitPower::Init( void ) +{ + m_flSuitPower = SUITPOWER_INIT; + m_nSuitPowerLow = -1; + m_iActiveSuitDevices = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudSuitPower::Reset( void ) +{ + Init(); +} + +//----------------------------------------------------------------------------- +// Purpose: Save CPU cycles by letting the HUD system early cull +// costly traversal. Called per frame, return true if thinking and +// painting need to occur. +//----------------------------------------------------------------------------- +bool CHudSuitPower::ShouldDraw() +{ + bool bNeedsDraw = false; + + C_BaseHLPlayer *pPlayer = (C_BaseHLPlayer *)C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return false; + + // needs draw if suit power changed or animation in progress + bNeedsDraw = ( ( pPlayer->m_HL2Local.m_flSuitPower != m_flSuitPower ) || ( m_AuxPowerColor[3] > 0 ) ); + + return ( bNeedsDraw && CHudElement::ShouldDraw() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudSuitPower::OnThink( void ) +{ + float flCurrentPower = 0; + C_BaseHLPlayer *pPlayer = (C_BaseHLPlayer *)C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + flCurrentPower = pPlayer->m_HL2Local.m_flSuitPower; + + // Only update if we've changed suit power + if ( flCurrentPower == m_flSuitPower ) + return; + + if ( flCurrentPower >= 100.0f && m_flSuitPower < 100.0f ) + { + // we've reached max power + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("SuitAuxPowerMax"); + } + else if ( flCurrentPower < 100.0f && (m_flSuitPower >= 100.0f || m_flSuitPower == SUITPOWER_INIT) ) + { + // we've lost power + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("SuitAuxPowerNotMax"); + } + + bool flashlightActive = pPlayer->IsFlashlightActive(); + bool sprintActive = pPlayer->IsSprinting(); + bool breatherActive = pPlayer->IsBreatherActive(); + int activeDevices = (int)flashlightActive + (int)sprintActive + (int)breatherActive; + + if (activeDevices != m_iActiveSuitDevices) + { + m_iActiveSuitDevices = activeDevices; + + switch ( m_iActiveSuitDevices ) + { + default: + case 3: + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("SuitAuxPowerThreeItemsActive"); + break; + case 2: + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("SuitAuxPowerTwoItemsActive"); + break; + case 1: + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("SuitAuxPowerOneItemActive"); + break; + case 0: + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("SuitAuxPowerNoItemsActive"); + break; + } + } + + m_flSuitPower = flCurrentPower; +} + +//----------------------------------------------------------------------------- +// Purpose: draws the power bar +//----------------------------------------------------------------------------- +void CHudSuitPower::Paint() +{ + C_BaseHLPlayer *pPlayer = (C_BaseHLPlayer *)C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + // get bar chunks + int chunkCount = m_flBarWidth / (m_flBarChunkWidth + m_flBarChunkGap); + int enabledChunks = (int)((float)chunkCount * (m_flSuitPower * 1.0f/100.0f) + 0.5f ); + + // see if we've changed power state + int lowPower = 0; + if (enabledChunks <= (chunkCount / 4)) + { + lowPower = 1; + } + if (m_nSuitPowerLow != lowPower) + { + if (m_iActiveSuitDevices || m_flSuitPower < 100.0f) + { + if (lowPower) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("SuitAuxPowerDecreasedBelow25"); + } + else + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("SuitAuxPowerIncreasedAbove25"); + } + m_nSuitPowerLow = lowPower; + } + } + + // draw the suit power bar + surface()->DrawSetColor( m_AuxPowerColor ); + int xpos = m_flBarInsetX, ypos = m_flBarInsetY; + for (int i = 0; i < enabledChunks; i++) + { + surface()->DrawFilledRect( xpos, ypos, xpos + m_flBarChunkWidth, ypos + m_flBarHeight ); + xpos += (m_flBarChunkWidth + m_flBarChunkGap); + } + // draw the exhausted portion of the bar. + surface()->DrawSetColor( Color( m_AuxPowerColor[0], m_AuxPowerColor[1], m_AuxPowerColor[2], m_iAuxPowerDisabledAlpha ) ); + for (int i = enabledChunks; i < chunkCount; i++) + { + surface()->DrawFilledRect( xpos, ypos, xpos + m_flBarChunkWidth, ypos + m_flBarHeight ); + xpos += (m_flBarChunkWidth + m_flBarChunkGap); + } + + // draw our name + surface()->DrawSetTextFont(m_hTextFont); + surface()->DrawSetTextColor(m_AuxPowerColor); + surface()->DrawSetTextPos(text_xpos, text_ypos); + + wchar_t *tempString = g_pVGuiLocalize->Find("#Valve_Hud_AUX_POWER"); + + if (tempString) + { + surface()->DrawPrintText(tempString, wcslen(tempString)); + } + else + { + surface()->DrawPrintText(L"AUX POWER", wcslen(L"AUX POWER")); + } + + if ( m_iActiveSuitDevices ) + { + // draw the additional text + int ypos = text2_ypos; + + if (pPlayer->IsBreatherActive()) + { + tempString = g_pVGuiLocalize->Find("#Valve_Hud_OXYGEN"); + + surface()->DrawSetTextPos(text2_xpos, ypos); + + if (tempString) + { + surface()->DrawPrintText(tempString, wcslen(tempString)); + } + else + { + surface()->DrawPrintText(L"OXYGEN", wcslen(L"OXYGEN")); + } + ypos += text2_gap; + } + + if (pPlayer->IsFlashlightActive()) + { + tempString = g_pVGuiLocalize->Find("#Valve_Hud_FLASHLIGHT"); + + surface()->DrawSetTextPos(text2_xpos, ypos); + + if (tempString) + { + surface()->DrawPrintText(tempString, wcslen(tempString)); + } + else + { + surface()->DrawPrintText(L"FLASHLIGHT", wcslen(L"FLASHLIGHT")); + } + ypos += text2_gap; + } + + if (pPlayer->IsSprinting()) + { + tempString = g_pVGuiLocalize->Find("#Valve_Hud_SPRINT"); + + surface()->DrawSetTextPos(text2_xpos, ypos); + + if (tempString) + { + surface()->DrawPrintText(tempString, wcslen(tempString)); + } + else + { + surface()->DrawPrintText(L"SPRINT", wcslen(L"SPRINT")); + } + ypos += text2_gap; + } + } +} + + diff --git a/game/client/hl2/hud_suitpower.h b/game/client/hl2/hud_suitpower.h new file mode 100644 index 0000000..83af2be --- /dev/null +++ b/game/client/hl2/hud_suitpower.h @@ -0,0 +1,57 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( HUD_SUITPOWER_H ) +#define HUD_SUITPOWER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "hudelement.h" +#include "hud_numericdisplay.h" +#include <vgui_controls/Panel.h> + +//----------------------------------------------------------------------------- +// Purpose: Shows the sprint power bar +//----------------------------------------------------------------------------- +class CHudSuitPower : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudSuitPower, vgui::Panel ); + +public: + CHudSuitPower( const char *pElementName ); + virtual void Init( void ); + virtual void Reset( void ); + virtual void OnThink( void ); + bool ShouldDraw( void ); + +protected: + virtual void Paint(); + +private: + CPanelAnimationVar( Color, m_AuxPowerColor, "AuxPowerColor", "255 0 0 255" ); + CPanelAnimationVar( int, m_iAuxPowerDisabledAlpha, "AuxPowerDisabledAlpha", "70" ); + + CPanelAnimationVarAliasType( float, m_flBarInsetX, "BarInsetX", "8", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flBarInsetY, "BarInsetY", "8", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flBarWidth, "BarWidth", "80", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flBarHeight, "BarHeight", "10", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flBarChunkWidth, "BarChunkWidth", "10", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flBarChunkGap, "BarChunkGap", "2", "proportional_float" ); + + CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "Default" ); + CPanelAnimationVarAliasType( float, text_xpos, "text_xpos", "8", "proportional_float" ); + CPanelAnimationVarAliasType( float, text_ypos, "text_ypos", "20", "proportional_float" ); + CPanelAnimationVarAliasType( float, text2_xpos, "text2_xpos", "8", "proportional_float" ); + CPanelAnimationVarAliasType( float, text2_ypos, "text2_ypos", "40", "proportional_float" ); + CPanelAnimationVarAliasType( float, text2_gap, "text2_gap", "10", "proportional_float" ); + + float m_flSuitPower; + int m_nSuitPowerLow; + int m_iActiveSuitDevices; +}; + +#endif // HUD_SUITPOWER_H diff --git a/game/client/hl2/hud_weaponselection.cpp b/game/client/hl2/hud_weaponselection.cpp new file mode 100644 index 0000000..f560070 --- /dev/null +++ b/game/client/hl2/hud_weaponselection.cpp @@ -0,0 +1,1525 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "weapon_selection.h" +#include "iclientmode.h" +#include "history_resource.h" +#include "input.h" +#include "../hud_crosshair.h" + +#include "VGuiMatSurface/IMatSystemSurface.h" +#include <KeyValues.h> +#include <vgui/IScheme.h> +#include <vgui/ISurface.h> +#include <vgui/ISystem.h> +#include <vgui_controls/AnimationController.h> +#include <vgui_controls/Panel.h> + +#include "vgui/ILocalize.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +ConVar hud_showemptyweaponslots( "hud_showemptyweaponslots", "1", FCVAR_ARCHIVE, "Shows slots for missing weapons when recieving weapons out of order" ); + +#define SELECTION_TIMEOUT_THRESHOLD 0.5f // Seconds +#define SELECTION_FADEOUT_TIME 0.75f + +#define PLUS_DISPLAY_TIMEOUT 0.5f // Seconds +#define PLUS_FADEOUT_TIME 0.75f + +#define FASTSWITCH_DISPLAY_TIMEOUT 1.5f +#define FASTSWITCH_FADEOUT_TIME 1.5f + +#define CAROUSEL_SMALL_DISPLAY_ALPHA 200.0f +#define FASTSWITCH_SMALL_DISPLAY_ALPHA 160.0f + +#define MAX_CAROUSEL_SLOTS 5 + +//----------------------------------------------------------------------------- +// Purpose: hl2 weapon selection hud element +//----------------------------------------------------------------------------- +class CHudWeaponSelection : public CBaseHudWeaponSelection, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudWeaponSelection, vgui::Panel ); + +public: + CHudWeaponSelection(const char *pElementName ); + + virtual bool ShouldDraw(); + virtual void OnWeaponPickup( C_BaseCombatWeapon *pWeapon ); + + virtual void CycleToNextWeapon( void ); + virtual void CycleToPrevWeapon( void ); + + virtual C_BaseCombatWeapon *GetWeaponInSlot( int iSlot, int iSlotPos ); + virtual void SelectWeaponSlot( int iSlot ); + + virtual C_BaseCombatWeapon *GetSelectedWeapon( void ) + { + return m_hSelectedWeapon; + } + + virtual void OpenSelection( void ); + virtual void HideSelection( void ); + + virtual void LevelInit(); + +protected: + virtual void OnThink(); + virtual void Paint(); + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + + virtual bool IsWeaponSelectable() + { + if (IsInSelectionMode()) + return true; + + return false; + } + + virtual void SetWeaponSelected() + { + CBaseHudWeaponSelection::SetWeaponSelected(); + + switch( hud_fastswitch.GetInt() ) + { + case HUDTYPE_FASTSWITCH: + case HUDTYPE_CAROUSEL: + ActivateFastswitchWeaponDisplay( GetSelectedWeapon() ); + break; + case HUDTYPE_PLUS: + ActivateWeaponHighlight( GetSelectedWeapon() ); + break; + default: + // do nothing + break; + } + } + +private: + C_BaseCombatWeapon *FindNextWeaponInWeaponSelection(int iCurrentSlot, int iCurrentPosition); + C_BaseCombatWeapon *FindPrevWeaponInWeaponSelection(int iCurrentSlot, int iCurrentPosition); + + void DrawLargeWeaponBox( C_BaseCombatWeapon *pWeapon, bool bSelected, int x, int y, int wide, int tall, Color color, float alpha, int number ); + void ActivateFastswitchWeaponDisplay( C_BaseCombatWeapon *pWeapon ); + void ActivateWeaponHighlight( C_BaseCombatWeapon *pWeapon ); + float GetWeaponBoxAlpha( bool bSelected ); + int GetLastPosInSlot( int iSlot ) const; + + void FastWeaponSwitch( int iWeaponSlot ); + void PlusTypeFastWeaponSwitch( int iWeaponSlot ); + + virtual void SetSelectedWeapon( C_BaseCombatWeapon *pWeapon ) + { + m_hSelectedWeapon = pWeapon; + } + + virtual void SetSelectedSlot( int slot ) + { + m_iSelectedSlot = slot; + } + + void SetSelectedSlideDir( int dir ) + { + m_iSelectedSlideDir = dir; + } + + void DrawBox(int x, int y, int wide, int tall, Color color, float normalizedAlpha, int number); + + CPanelAnimationVar( vgui::HFont, m_hNumberFont, "NumberFont", "HudSelectionNumbers" ); + CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "HudSelectionText" ); + CPanelAnimationVar( float, m_flBlur, "Blur", "0" ); + + CPanelAnimationVarAliasType( float, m_flSmallBoxSize, "SmallBoxSize", "32", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flLargeBoxWide, "LargeBoxWide", "108", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flLargeBoxTall, "LargeBoxTall", "72", "proportional_float" ); + + CPanelAnimationVarAliasType( float, m_flMediumBoxWide, "MediumBoxWide", "75", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flMediumBoxTall, "MediumBoxTall", "50", "proportional_float" ); + + CPanelAnimationVarAliasType( float, m_flBoxGap, "BoxGap", "12", "proportional_float" ); + + CPanelAnimationVarAliasType( float, m_flSelectionNumberXPos, "SelectionNumberXPos", "4", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flSelectionNumberYPos, "SelectionNumberYPos", "4", "proportional_float" ); + + CPanelAnimationVarAliasType( float, m_flTextYPos, "TextYPos", "54", "proportional_float" ); + + CPanelAnimationVar( float, m_flAlphaOverride, "Alpha", "0" ); + CPanelAnimationVar( float, m_flSelectionAlphaOverride, "SelectionAlpha", "0" ); + + CPanelAnimationVar( Color, m_TextColor, "TextColor", "SelectionTextFg" ); + CPanelAnimationVar( Color, m_NumberColor, "NumberColor", "SelectionNumberFg" ); + CPanelAnimationVar( Color, m_EmptyBoxColor, "EmptyBoxColor", "SelectionEmptyBoxBg" ); + CPanelAnimationVar( Color, m_BoxColor, "BoxColor", "SelectionBoxBg" ); + CPanelAnimationVar( Color, m_SelectedBoxColor, "SelectedBoxColor", "SelectionSelectedBoxBg" ); + CPanelAnimationVar( Color, m_SelectedFgColor, "SelectedFgColor", "FgColor" ); + CPanelAnimationVar( Color, m_BrightBoxColor, "SelectedFgColor", "BgColor" ); + + CPanelAnimationVar( float, m_flWeaponPickupGrowTime, "SelectionGrowTime", "0.1" ); + + CPanelAnimationVar( float, m_flTextScan, "TextScan", "1.0" ); + + bool m_bFadingOut; + + // fastswitch weapon display + struct WeaponBox_t + { + int m_iSlot; + int m_iSlotPos; + }; + CUtlVector<WeaponBox_t> m_WeaponBoxes; + int m_iSelectedWeaponBox; + int m_iSelectedSlideDir; + int m_iSelectedBoxPosition; + int m_iSelectedSlot; + C_BaseCombatWeapon *m_pLastWeapon; + CPanelAnimationVar( float, m_flHorizWeaponSelectOffsetPoint, "WeaponBoxOffset", "0" ); +}; + +DECLARE_HUDELEMENT( CHudWeaponSelection ); + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CHudWeaponSelection::CHudWeaponSelection( const char *pElementName ) : CBaseHudWeaponSelection(pElementName), BaseClass(NULL, "HudWeaponSelection") +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + m_bFadingOut = false; +} + +//----------------------------------------------------------------------------- +// Purpose: sets up display for showing weapon pickup +//----------------------------------------------------------------------------- +void CHudWeaponSelection::OnWeaponPickup( C_BaseCombatWeapon *pWeapon ) +{ + // add to pickup history + CHudHistoryResource *pHudHR = GET_HUDELEMENT( CHudHistoryResource ); + if ( pHudHR ) + { + pHudHR->AddToHistory( pWeapon ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: updates animation status +//----------------------------------------------------------------------------- +void CHudWeaponSelection::OnThink( void ) +{ + float flSelectionTimeout = SELECTION_TIMEOUT_THRESHOLD; + float flSelectionFadeoutTime = SELECTION_FADEOUT_TIME; + if ( hud_fastswitch.GetBool() ) + { + flSelectionTimeout = FASTSWITCH_DISPLAY_TIMEOUT; + flSelectionFadeoutTime = FASTSWITCH_FADEOUT_TIME; + } + + // Time out after awhile of inactivity + if ( ( gpGlobals->curtime - m_flSelectionTime ) > flSelectionTimeout ) + { + if (!m_bFadingOut) + { + // start fading out + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "FadeOutWeaponSelectionMenu" ); + m_bFadingOut = true; + } + else if ( gpGlobals->curtime - m_flSelectionTime > flSelectionTimeout + flSelectionFadeoutTime ) + { + // finished fade, close + HideSelection(); + } + } + else if (m_bFadingOut) + { + // stop us fading out, show the animation again + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "OpenWeaponSelectionMenu" ); + m_bFadingOut = false; + } +} + +//----------------------------------------------------------------------------- +// Purpose: returns true if the panel should draw +//----------------------------------------------------------------------------- +bool CHudWeaponSelection::ShouldDraw() +{ + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + { + if ( IsInSelectionMode() ) + { + HideSelection(); + } + return false; + } + + bool bret = CBaseHudWeaponSelection::ShouldDraw(); + if ( !bret ) + return false; + + // draw weapon selection a little longer if in fastswitch so we can see what we've selected + if ( hud_fastswitch.GetBool() && ( gpGlobals->curtime - m_flSelectionTime ) < (FASTSWITCH_DISPLAY_TIMEOUT + FASTSWITCH_FADEOUT_TIME) ) + return true; + + return ( m_bSelectionVisible ) ? true : false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudWeaponSelection::LevelInit() +{ + CHudElement::LevelInit(); + + m_iSelectedWeaponBox = -1; + m_iSelectedSlideDir = 0; + m_pLastWeapon = NULL; +} + + +//----------------------------------------------------------------------------- +// Purpose: starts animating the center of the draw point to the newly selected weapon +//----------------------------------------------------------------------------- +void CHudWeaponSelection::ActivateFastswitchWeaponDisplay( C_BaseCombatWeapon *pSelectedWeapon ) +{ + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + // make sure all our configuration data is read + MakeReadyForUse(); + + m_WeaponBoxes.RemoveAll(); + m_iSelectedWeaponBox = 0; + + // find out where our selected weapon is in the full list + int cWeapons = 0; + int iLastSelectedWeaponBox = -1; + for ( int i = 0; i < MAX_WEAPON_SLOTS; i++ ) + { + for (int slotpos = 0; slotpos < MAX_WEAPON_POSITIONS; slotpos++) + { + C_BaseCombatWeapon *pWeapon = GetWeaponInSlot( i, slotpos ); + if ( !pWeapon ) + continue; + + WeaponBox_t box = { i, slotpos }; + m_WeaponBoxes.AddToTail( box ); + + if ( pWeapon == pSelectedWeapon ) + { + m_iSelectedWeaponBox = cWeapons; + } + if ( pWeapon == m_pLastWeapon ) + { + iLastSelectedWeaponBox = cWeapons; + } + cWeapons++; + } + } + + if ( iLastSelectedWeaponBox == -1 ) + { + // unexpected failure, no last weapon to scroll from, default to snap behavior + m_pLastWeapon = NULL; + } + + // calculate where we would have to start drawing for this weapon to slide into center + float flStart, flStop, flTime; + if ( !m_pLastWeapon || m_iSelectedSlideDir == 0 || m_flHorizWeaponSelectOffsetPoint != 0 ) + { + // no previous weapon or weapon selected directly or selection during slide, snap to exact position + m_pLastWeapon = pSelectedWeapon; + flStart = flStop = flTime = 0; + } + else + { + // offset display for a scroll + // causing selected weapon to slide into position + // scroll direction based on user's "previous" or "next" selection + int numIcons = 0; + int start = iLastSelectedWeaponBox; + for (int i=0; i<cWeapons; i++) + { + // count icons in direction of slide to destination + if ( start == m_iSelectedWeaponBox ) + break; + if ( m_iSelectedSlideDir < 0 ) + { + start--; + } + else + { + start++; + } + // handle wraparound in either direction + start = ( start + cWeapons ) % cWeapons; + numIcons++; + } + + flStart = numIcons * (m_flLargeBoxWide + m_flBoxGap); + if ( m_iSelectedSlideDir < 0 ) + flStart *= -1; + flStop = 0; + + // shorten duration for scrolling when desired weapon is farther away + // otherwise a large skip in the same duration causes the scroll to fly too fast + flTime = numIcons * 0.20f; + if ( numIcons > 1 ) + flTime *= 0.5f; + } + m_flHorizWeaponSelectOffsetPoint = flStart; + g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( this, "WeaponBoxOffset", flStop, 0, flTime, AnimationController::INTERPOLATOR_LINEAR ); + + // start the highlight after the scroll completes + m_flBlur = 7.f; + g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( this, "Blur", 0, flTime, 0.75f, AnimationController::INTERPOLATOR_DEACCEL ); +} + +//----------------------------------------------------------------------------- +// Purpose: starts animating the highlight for the selected weapon +//----------------------------------------------------------------------------- +void CHudWeaponSelection::ActivateWeaponHighlight( C_BaseCombatWeapon *pSelectedWeapon ) +{ + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + // make sure all our configuration data is read + MakeReadyForUse(); + + C_BaseCombatWeapon *pWeapon = GetWeaponInSlot( m_iSelectedSlot, m_iSelectedBoxPosition ); + if ( !pWeapon ) + return; + + // start the highlight after the scroll completes + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "WeaponHighlight" ); +} + +//----------------------------------------------------------------------------- +// Purpose: returns an (per frame animating) alpha value for different weapon boxes +//----------------------------------------------------------------------------- +float CHudWeaponSelection::GetWeaponBoxAlpha( bool bSelected ) +{ + float alpha; + if ( bSelected ) + { + alpha = m_flSelectionAlphaOverride; + } + else + { + alpha = m_flSelectionAlphaOverride * (m_flAlphaOverride / 255.0f); + } + return alpha; +} + + +//------------------------------------------------------------------------- +// Purpose: draws the selection area +//------------------------------------------------------------------------- +void CHudWeaponSelection::Paint() +{ + int width; + int xpos; + int ypos; + + if (!ShouldDraw()) + return; + + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + // find and display our current selection + C_BaseCombatWeapon *pSelectedWeapon = NULL; + switch ( hud_fastswitch.GetInt() ) + { + case HUDTYPE_FASTSWITCH: + case HUDTYPE_CAROUSEL: + pSelectedWeapon = pPlayer->GetActiveWeapon(); + break; + default: + pSelectedWeapon = GetSelectedWeapon(); + break; + } + if ( !pSelectedWeapon ) + return; + + bool bPushedViewport = false; + if( hud_fastswitch.GetInt() == HUDTYPE_FASTSWITCH || hud_fastswitch.GetInt() == HUDTYPE_PLUS ) + { + CMatRenderContextPtr pRenderContext( materials ); + if( pRenderContext->GetRenderTarget() ) + { + surface()->PushFullscreenViewport(); + bPushedViewport = true; + } + } + + // interpolate the selected box size between the small box size and the large box size + // interpolation has been removed since there is no weapon pickup animation anymore, so it's all at the largest size + float percentageDone = 1.0f; //min(1.0f, (gpGlobals->curtime - m_flPickupStartTime) / m_flWeaponPickupGrowTime); + int largeBoxWide = m_flSmallBoxSize + ((m_flLargeBoxWide - m_flSmallBoxSize) * percentageDone); + int largeBoxTall = m_flSmallBoxSize + ((m_flLargeBoxTall - m_flSmallBoxSize) * percentageDone); + Color selectedColor; + for (int i = 0; i < 4; i++) + { + selectedColor[i] = m_BoxColor[i] + ((m_SelectedBoxColor[i] - m_BoxColor[i]) * percentageDone); + } + + switch ( hud_fastswitch.GetInt() ) + { + case HUDTYPE_CAROUSEL: + { + // carousel style - flat line of items + ypos = 0; + if ( m_iSelectedWeaponBox == -1 || m_WeaponBoxes.Count() <= 1 ) + { + // nothing to do + return; + } + else if ( m_WeaponBoxes.Count() < MAX_CAROUSEL_SLOTS ) + { + // draw the selected weapon as a 1 of n style + width = (m_WeaponBoxes.Count()-1) * (m_flLargeBoxWide+m_flBoxGap) + m_flLargeBoxWide; + xpos = (GetWide() - width)/2; + for ( int i=0; i<m_WeaponBoxes.Count(); i++ ) + { + C_BaseCombatWeapon *pWeapon = GetWeaponInSlot( m_WeaponBoxes[i].m_iSlot, m_WeaponBoxes[i].m_iSlotPos ); + if ( !pWeapon ) + break; + + float alpha = GetWeaponBoxAlpha( i == m_iSelectedWeaponBox ); + if ( i == m_iSelectedWeaponBox ) + { + // draw selected in highlighted style + DrawLargeWeaponBox( pWeapon, true, xpos, ypos, m_flLargeBoxWide, m_flLargeBoxTall, selectedColor, alpha, -1 ); + } + else + { + DrawLargeWeaponBox( pWeapon, false, xpos, ypos, m_flLargeBoxWide, m_flLargeBoxTall / 1.5f, m_BoxColor, alpha, -1 ); + } + + xpos += (m_flLargeBoxWide + m_flBoxGap); + } + } + else + { + // draw the selected weapon in the center, as a continuous scrolling carosuel + // draw at center the current selected and all items to its right + xpos = GetWide()/2 + m_flHorizWeaponSelectOffsetPoint - largeBoxWide/2; + int i = m_iSelectedWeaponBox; + while ( 1 ) + { + C_BaseCombatWeapon *pWeapon = GetWeaponInSlot( m_WeaponBoxes[i].m_iSlot, m_WeaponBoxes[i].m_iSlotPos ); + if ( !pWeapon ) + break; + + float alpha; + if ( i == m_iSelectedWeaponBox && !m_flHorizWeaponSelectOffsetPoint ) + { + // draw selected in highlighted style + alpha = GetWeaponBoxAlpha( true ); + DrawLargeWeaponBox( pWeapon, true, xpos, ypos, largeBoxWide, largeBoxTall, selectedColor, alpha, -1 ); + } + else + { + alpha = GetWeaponBoxAlpha( false ); + DrawLargeWeaponBox( pWeapon, false, xpos, ypos, largeBoxWide, largeBoxTall / 1.5f, m_BoxColor, alpha, -1 ); + } + + // advance until past edge + xpos += (largeBoxWide + m_flBoxGap); + if ( xpos >= GetWide() ) + break; + + ++i; + if ( i >= m_WeaponBoxes.Count() ) + { + // wraparound + i = 0; + } + } + + // draw all items left of center + xpos = GetWide()/2 + m_flHorizWeaponSelectOffsetPoint - (3*largeBoxWide/2 + m_flBoxGap); + i = m_iSelectedWeaponBox - 1; + while ( 1 ) + { + if ( i < 0 ) + { + // wraparound + i = m_WeaponBoxes.Count() - 1; + } + + C_BaseCombatWeapon *pWeapon = GetWeaponInSlot( m_WeaponBoxes[i].m_iSlot, m_WeaponBoxes[i].m_iSlotPos ); + if ( !pWeapon ) + break; + + float alpha; + if ( i == m_iSelectedWeaponBox && !m_flHorizWeaponSelectOffsetPoint ) + { + // draw selected in highlighted style + alpha = GetWeaponBoxAlpha( true ); + DrawLargeWeaponBox( pWeapon, true, xpos, ypos, largeBoxWide, largeBoxTall, selectedColor, alpha, -1 ); + } + else + { + alpha = GetWeaponBoxAlpha( false ); + DrawLargeWeaponBox( pWeapon, false, xpos, ypos, largeBoxWide, largeBoxTall / 1.5f, m_BoxColor, alpha, -1 ); + } + + // retreat until past edge + xpos -= (largeBoxWide + m_flBoxGap); + if ( xpos + largeBoxWide <= 0 ) + break; + + --i; + } + } + } + break; + + case HUDTYPE_PLUS: + { + float fCenterX, fCenterY; + bool bBehindCamera = false; + CHudCrosshair::GetDrawPosition( &fCenterX, &fCenterY, &bBehindCamera ); + + // if the crosshair is behind the camera, don't draw it + if( bBehindCamera ) + return; + + // bucket style + int screenCenterX = (int) fCenterX; + int screenCenterY = (int) fCenterY - 15; // Height isn't quite screen height, so adjust for center alignment + + // Modifiers for the four directions. Used to change the x and y offsets + // of each box based on which bucket we're drawing. Bucket directions are + // 0 = UP, 1 = RIGHT, 2 = DOWN, 3 = LEFT + int xModifiers[] = { 0, 1, 0, -1, -1, 1 }; + int yModifiers[] = { -1, 0, 1, 0, 1, 1 }; + + // Draw the four buckets + for ( int i = 0; i < MAX_WEAPON_SLOTS; ++i ) + { + // Set the top left corner so the first box would be centered in the screen. + int xPos = screenCenterX -( m_flMediumBoxWide / 2 ); + int yPos = screenCenterY -( m_flMediumBoxTall / 2 ); + + // Find out how many positions to draw - an empty position should still + // be drawn if there is an active weapon in any slots past it. + int lastSlotPos = -1; + for ( int slotPos = 0; slotPos < MAX_WEAPON_POSITIONS; ++slotPos ) + { + C_BaseCombatWeapon *pWeapon = GetWeaponInSlot( i, slotPos ); + if ( pWeapon ) + { + lastSlotPos = slotPos; + } + } + + // Draw the weapons in this bucket + for ( int slotPos = 0; slotPos <= lastSlotPos; ++slotPos ) + { + // Offset the box position + xPos += ( m_flMediumBoxWide + 5 ) * xModifiers[ i ]; + yPos += ( m_flMediumBoxTall + 5 ) * yModifiers[ i ]; + + int boxWide = m_flMediumBoxWide; + int boxTall = m_flMediumBoxTall; + int x = xPos; + int y = yPos; + + C_BaseCombatWeapon *pWeapon = GetWeaponInSlot( i, slotPos ); + bool selectedWeapon = false; + if ( i == m_iSelectedSlot && slotPos == m_iSelectedBoxPosition ) + { + // This is a bit of a misnomer... we really are asking "Is this the selected slot"? + selectedWeapon = true; + } + + // Draw the box with the appropriate icon + DrawLargeWeaponBox( pWeapon, + selectedWeapon, + x, + y, + boxWide, + boxTall, + selectedWeapon ? selectedColor : m_BoxColor, + GetWeaponBoxAlpha( selectedWeapon ), + -1 ); + } + } + } + break; + + case HUDTYPE_BUCKETS: + { + // bucket style + width = (MAX_WEAPON_SLOTS - 1) * (m_flSmallBoxSize + m_flBoxGap) + largeBoxWide; + xpos = (GetWide() - width) / 2; + ypos = 0; + + int iActiveSlot = (pSelectedWeapon ? pSelectedWeapon->GetSlot() : -1); + + // draw the bucket set + // iterate over all the weapon slots + for ( int i = 0; i < MAX_WEAPON_SLOTS; i++ ) + { + if ( i == iActiveSlot ) + { + bool bDrawBucketNumber = true; + int iLastPos = GetLastPosInSlot( i ); + + for (int slotpos = 0; slotpos <= iLastPos; slotpos++) + { + C_BaseCombatWeapon *pWeapon = GetWeaponInSlot( i, slotpos ); + if ( !pWeapon ) + { + if ( !hud_showemptyweaponslots.GetBool() ) + continue; + DrawBox( xpos, ypos, largeBoxWide, largeBoxTall, m_EmptyBoxColor, m_flAlphaOverride, bDrawBucketNumber ? i + 1 : -1 ); + } + else + { + bool bSelected = (pWeapon == pSelectedWeapon); + DrawLargeWeaponBox( pWeapon, + bSelected, + xpos, + ypos, + largeBoxWide, + largeBoxTall, + bSelected ? selectedColor : m_BoxColor, + GetWeaponBoxAlpha( bSelected ), + bDrawBucketNumber ? i + 1 : -1 ); + } + + // move down to the next bucket + ypos += (largeBoxTall + m_flBoxGap); + bDrawBucketNumber = false; + } + + xpos += largeBoxWide; + } + else + { + // check to see if there is a weapons in this bucket + if ( GetFirstPos( i ) ) + { + // draw has weapon in slot + DrawBox(xpos, ypos, m_flSmallBoxSize, m_flSmallBoxSize, m_BoxColor, m_flAlphaOverride, i + 1); + } + else + { + // draw empty slot + DrawBox(xpos, ypos, m_flSmallBoxSize, m_flSmallBoxSize, m_EmptyBoxColor, m_flAlphaOverride, -1); + } + + xpos += m_flSmallBoxSize; + } + + // reset position + ypos = 0; + xpos += m_flBoxGap; + } + } + break; + + default: + { + // do nothing + } + break; + } + + if( bPushedViewport ) + { + surface()->PopFullscreenViewport(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: draws a single weapon selection box +//----------------------------------------------------------------------------- +void CHudWeaponSelection::DrawLargeWeaponBox( C_BaseCombatWeapon *pWeapon, bool bSelected, int xpos, int ypos, int boxWide, int boxTall, Color selectedColor, float alpha, int number ) +{ + Color col = bSelected ? m_SelectedFgColor : GetFgColor(); + + switch ( hud_fastswitch.GetInt() ) + { + case HUDTYPE_BUCKETS: + { + // draw box for selected weapon + DrawBox( xpos, ypos, boxWide, boxTall, selectedColor, alpha, number ); + + // draw icon + col[3] *= (alpha / 255.0f); + if ( pWeapon->GetSpriteActive() ) + { + // find the center of the box to draw in + int iconWidth = pWeapon->GetSpriteActive()->Width(); + int iconHeight = pWeapon->GetSpriteActive()->Height(); + + int x_offs = (boxWide - iconWidth) / 2; + + int y_offs; + if ( bSelected && hud_fastswitch.GetInt() != 0 ) + { + // place the icon aligned with the non-selected version + y_offs = (boxTall / 1.5f - iconHeight) / 2; + } + else + { + y_offs = (boxTall - iconHeight) / 2; + } + + if (!pWeapon->CanBeSelected()) + { + // unselectable weapon, display as such + col = Color(255, 0, 0, col[3]); + } + else if (bSelected) + { + // currently selected weapon, display brighter + col[3] = alpha; + + // draw an active version over the top + pWeapon->GetSpriteActive()->DrawSelf( xpos + x_offs, ypos + y_offs, col ); + } + + // draw the inactive version + pWeapon->GetSpriteInactive()->DrawSelf( xpos + x_offs, ypos + y_offs, col ); + } + } + break; + + case HUDTYPE_PLUS: + case HUDTYPE_CAROUSEL: + { + if ( !pWeapon ) + { + // draw red box for an empty bubble + if( bSelected ) + { + selectedColor.SetColor( 255, 0, 0, 40 ); + } + + DrawBox( xpos, ypos, boxWide, boxTall, selectedColor, alpha, number ); + return; + } + else + { + // draw box for selected weapon + DrawBox( xpos, ypos, boxWide, boxTall, selectedColor, alpha, number ); + } + + int iconWidth; + int iconHeight; + int x_offs; + int y_offs; + + // draw icon + col[3] *= (alpha / 255.0f); + + if ( pWeapon->GetSpriteInactive() ) + { + iconWidth = pWeapon->GetSpriteInactive()->Width(); + iconHeight = pWeapon->GetSpriteInactive()->Height(); + + x_offs = (boxWide - iconWidth) / 2; + if ( bSelected && HUDTYPE_CAROUSEL == hud_fastswitch.GetInt() ) + { + // place the icon aligned with the non-selected version + y_offs = (boxTall/1.5f - iconHeight) / 2; + } + else + { + y_offs = (boxTall - iconHeight) / 2; + } + + if ( !pWeapon->CanBeSelected() ) + { + // unselectable weapon, display as such + col = Color(255, 0, 0, col[3]); + } + + // draw the inactive version + pWeapon->GetSpriteInactive()->DrawSelf( xpos + x_offs, ypos + y_offs, iconWidth, iconHeight, col ); + } + + if ( bSelected && pWeapon->GetSpriteActive() ) + { + // find the center of the box to draw in + iconWidth = pWeapon->GetSpriteActive()->Width(); + iconHeight = pWeapon->GetSpriteActive()->Height(); + + x_offs = (boxWide - iconWidth) / 2; + if ( HUDTYPE_CAROUSEL == hud_fastswitch.GetInt() ) + { + // place the icon aligned with the non-selected version + y_offs = (boxTall/1.5f - iconHeight) / 2; + } + else + { + y_offs = (boxTall - iconHeight) / 2; + } + + col[3] = 255; + for (float fl = m_flBlur; fl > 0.0f; fl -= 1.0f) + { + if (fl >= 1.0f) + { + pWeapon->GetSpriteActive()->DrawSelf( xpos + x_offs, ypos + y_offs, col ); + } + else + { + // draw a percentage of the last one + col[3] *= fl; + pWeapon->GetSpriteActive()->DrawSelf( xpos + x_offs, ypos + y_offs, col ); + } + } + } + } + break; + + default: + { + // do nothing + } + break; + } + + if ( HUDTYPE_PLUS == hud_fastswitch.GetInt() ) + { + // No text in plus bucket method + return; + } + + // draw text + col = m_TextColor; + const FileWeaponInfo_t &weaponInfo = pWeapon->GetWpnData(); + + if ( bSelected ) + { + wchar_t text[128]; + wchar_t *tempString = g_pVGuiLocalize->Find(weaponInfo.szPrintName); + + // setup our localized string + if ( tempString ) + { +#ifdef WIN32 + _snwprintf(text, sizeof(text)/sizeof(wchar_t) - 1, L"%s", tempString); +#else + _snwprintf(text, sizeof(text)/sizeof(wchar_t) - 1, L"%S", tempString); +#endif + text[sizeof(text)/sizeof(wchar_t) - 1] = 0; + } + else + { + // string wasn't found by g_pVGuiLocalize->Find() + g_pVGuiLocalize->ConvertANSIToUnicode(weaponInfo.szPrintName, text, sizeof(text)); + } + + surface()->DrawSetTextColor( col ); + surface()->DrawSetTextFont( m_hTextFont ); + + // count the position + int slen = 0, charCount = 0, maxslen = 0; + int firstslen = 0; + { + for (wchar_t *pch = text; *pch != 0; pch++) + { + if (*pch == '\n') + { + // newline character, drop to the next line + if (slen > maxslen) + { + maxslen = slen; + } + if (!firstslen) + { + firstslen = slen; + } + + slen = 0; + } + else if (*pch == '\r') + { + // do nothing + } + else + { + slen += surface()->GetCharacterWidth( m_hTextFont, *pch ); + charCount++; + } + } + } + if (slen > maxslen) + { + maxslen = slen; + } + if (!firstslen) + { + firstslen = maxslen; + } + + int tx = xpos + ((m_flLargeBoxWide - firstslen) / 2); + int ty = ypos + (int)m_flTextYPos; + surface()->DrawSetTextPos( tx, ty ); + // adjust the charCount by the scan amount + charCount *= m_flTextScan; + for (wchar_t *pch = text; charCount > 0; pch++) + { + if (*pch == '\n') + { + // newline character, move to the next line + surface()->DrawSetTextPos( xpos + ((boxWide - slen) / 2), ty + (surface()->GetFontTall(m_hTextFont) * 1.1f)); + } + else if (*pch == '\r') + { + // do nothing + } + else + { + surface()->DrawUnicodeChar(*pch); + charCount--; + } + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: draws a selection box +//----------------------------------------------------------------------------- +void CHudWeaponSelection::DrawBox(int x, int y, int wide, int tall, Color color, float normalizedAlpha, int number) +{ + BaseClass::DrawBox( x, y, wide, tall, color, normalizedAlpha / 255.0f ); + + // draw the number + if (number >= 0) + { + Color numberColor = m_NumberColor; + numberColor[3] *= normalizedAlpha / 255.0f; + surface()->DrawSetTextColor(numberColor); + surface()->DrawSetTextFont(m_hNumberFont); + wchar_t wch = '0' + number; + surface()->DrawSetTextPos(x + m_flSelectionNumberXPos, y + m_flSelectionNumberYPos); + surface()->DrawUnicodeChar(wch); + } +} + +//----------------------------------------------------------------------------- +// Purpose: hud scheme settings +//----------------------------------------------------------------------------- +void CHudWeaponSelection::ApplySchemeSettings(vgui::IScheme *pScheme) +{ + BaseClass::ApplySchemeSettings(pScheme); + SetPaintBackgroundEnabled(false); + + // set our size + int screenWide, screenTall; + int x, y; + GetPos(x, y); + GetHudSize(screenWide, screenTall); + + if ( hud_fastswitch.GetInt() == HUDTYPE_CAROUSEL ) + { + // need bounds to be exact width for proper clipping during scroll + int width = MAX_CAROUSEL_SLOTS*m_flLargeBoxWide + (MAX_CAROUSEL_SLOTS-1)*m_flBoxGap; + SetBounds( (screenWide-width)/2, y, width, screenTall - y); + } + else + { + SetBounds( x, y, screenWide - x, screenTall - y ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Opens weapon selection control +//----------------------------------------------------------------------------- +void CHudWeaponSelection::OpenSelection( void ) +{ + Assert(!IsInSelectionMode()); + + CBaseHudWeaponSelection::OpenSelection(); + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("OpenWeaponSelectionMenu"); + m_iSelectedBoxPosition = 0; + m_iSelectedSlot = -1; +} + +//----------------------------------------------------------------------------- +// Purpose: Closes weapon selection control immediately +//----------------------------------------------------------------------------- +void CHudWeaponSelection::HideSelection( void ) +{ + CBaseHudWeaponSelection::HideSelection(); + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("CloseWeaponSelectionMenu"); + m_bFadingOut = false; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns the next available weapon item in the weapon selection +//----------------------------------------------------------------------------- +C_BaseCombatWeapon *CHudWeaponSelection::FindNextWeaponInWeaponSelection(int iCurrentSlot, int iCurrentPosition) +{ + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return NULL; + + C_BaseCombatWeapon *pNextWeapon = NULL; + + // search all the weapons looking for the closest next + int iLowestNextSlot = MAX_WEAPON_SLOTS; + int iLowestNextPosition = MAX_WEAPON_POSITIONS; + for ( int i = 0; i < MAX_WEAPONS; i++ ) + { + C_BaseCombatWeapon *pWeapon = pPlayer->GetWeapon(i); + if ( !pWeapon ) + continue; + + if ( CanBeSelectedInHUD( pWeapon ) ) + { + int weaponSlot = pWeapon->GetSlot(), weaponPosition = pWeapon->GetPosition(); + + // see if this weapon is further ahead in the selection list + if ( weaponSlot > iCurrentSlot || (weaponSlot == iCurrentSlot && weaponPosition > iCurrentPosition) ) + { + // see if this weapon is closer than the current lowest + if ( weaponSlot < iLowestNextSlot || (weaponSlot == iLowestNextSlot && weaponPosition < iLowestNextPosition) ) + { + iLowestNextSlot = weaponSlot; + iLowestNextPosition = weaponPosition; + pNextWeapon = pWeapon; + } + } + } + } + + return pNextWeapon; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns the prior available weapon item in the weapon selection +//----------------------------------------------------------------------------- +C_BaseCombatWeapon *CHudWeaponSelection::FindPrevWeaponInWeaponSelection(int iCurrentSlot, int iCurrentPosition) +{ + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return NULL; + + C_BaseCombatWeapon *pPrevWeapon = NULL; + + // search all the weapons looking for the closest next + int iLowestPrevSlot = -1; + int iLowestPrevPosition = -1; + for ( int i = 0; i < MAX_WEAPONS; i++ ) + { + C_BaseCombatWeapon *pWeapon = pPlayer->GetWeapon(i); + if ( !pWeapon ) + continue; + + if ( CanBeSelectedInHUD( pWeapon ) ) + { + int weaponSlot = pWeapon->GetSlot(), weaponPosition = pWeapon->GetPosition(); + + // see if this weapon is further ahead in the selection list + if ( weaponSlot < iCurrentSlot || (weaponSlot == iCurrentSlot && weaponPosition < iCurrentPosition) ) + { + // see if this weapon is closer than the current lowest + if ( weaponSlot > iLowestPrevSlot || (weaponSlot == iLowestPrevSlot && weaponPosition > iLowestPrevPosition) ) + { + iLowestPrevSlot = weaponSlot; + iLowestPrevPosition = weaponPosition; + pPrevWeapon = pWeapon; + } + } + } + } + + return pPrevWeapon; +} + +//----------------------------------------------------------------------------- +// Purpose: Moves the selection to the next item in the menu +//----------------------------------------------------------------------------- +void CHudWeaponSelection::CycleToNextWeapon( void ) +{ + // Get the local player. + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + m_pLastWeapon = pPlayer->GetActiveWeapon(); + + C_BaseCombatWeapon *pNextWeapon = NULL; + if ( IsInSelectionMode() ) + { + // find the next selection spot + C_BaseCombatWeapon *pWeapon = GetSelectedWeapon(); + if ( !pWeapon ) + return; + + pNextWeapon = FindNextWeaponInWeaponSelection( pWeapon->GetSlot(), pWeapon->GetPosition() ); + } + else + { + // open selection at the current place + pNextWeapon = pPlayer->GetActiveWeapon(); + if ( pNextWeapon ) + { + pNextWeapon = FindNextWeaponInWeaponSelection( pNextWeapon->GetSlot(), pNextWeapon->GetPosition() ); + } + } + + if ( !pNextWeapon ) + { + // wrap around back to start + pNextWeapon = FindNextWeaponInWeaponSelection(-1, -1); + } + + if ( pNextWeapon ) + { + SetSelectedWeapon( pNextWeapon ); + SetSelectedSlideDir( 1 ); + + if ( !IsInSelectionMode() ) + { + OpenSelection(); + } + + // Play the "cycle to next weapon" sound + pPlayer->EmitSound( "Player.WeaponSelectionMoveSlot" ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Moves the selection to the previous item in the menu +//----------------------------------------------------------------------------- +void CHudWeaponSelection::CycleToPrevWeapon( void ) +{ + // Get the local player. + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + m_pLastWeapon = pPlayer->GetActiveWeapon(); + + C_BaseCombatWeapon *pNextWeapon = NULL; + if ( IsInSelectionMode() ) + { + // find the next selection spot + C_BaseCombatWeapon *pWeapon = GetSelectedWeapon(); + if ( !pWeapon ) + return; + + pNextWeapon = FindPrevWeaponInWeaponSelection( pWeapon->GetSlot(), pWeapon->GetPosition() ); + } + else + { + // open selection at the current place + pNextWeapon = pPlayer->GetActiveWeapon(); + if ( pNextWeapon ) + { + pNextWeapon = FindPrevWeaponInWeaponSelection( pNextWeapon->GetSlot(), pNextWeapon->GetPosition() ); + } + } + + if ( !pNextWeapon ) + { + // wrap around back to end of weapon list + pNextWeapon = FindPrevWeaponInWeaponSelection(MAX_WEAPON_SLOTS, MAX_WEAPON_POSITIONS); + } + + if ( pNextWeapon ) + { + SetSelectedWeapon( pNextWeapon ); + SetSelectedSlideDir( -1 ); + + if ( !IsInSelectionMode() ) + { + OpenSelection(); + } + + // Play the "cycle to next weapon" sound + pPlayer->EmitSound( "Player.WeaponSelectionMoveSlot" ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: returns the # of the last weapon in the specified slot +//----------------------------------------------------------------------------- +int CHudWeaponSelection::GetLastPosInSlot( int iSlot ) const +{ + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + int iMaxSlotPos; + + if ( !player ) + return -1; + + iMaxSlotPos = -1; + for ( int i = 0; i < MAX_WEAPONS; i++ ) + { + C_BaseCombatWeapon *pWeapon = player->GetWeapon(i); + + if ( pWeapon == NULL ) + continue; + + if ( pWeapon->GetSlot() == iSlot && pWeapon->GetPosition() > iMaxSlotPos ) + iMaxSlotPos = pWeapon->GetPosition(); + } + + return iMaxSlotPos; +} + +//----------------------------------------------------------------------------- +// Purpose: returns the weapon in the specified slot +//----------------------------------------------------------------------------- +C_BaseCombatWeapon *CHudWeaponSelection::GetWeaponInSlot( int iSlot, int iSlotPos ) +{ + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + if ( !player ) + return NULL; + + for ( int i = 0; i < MAX_WEAPONS; i++ ) + { + C_BaseCombatWeapon *pWeapon = player->GetWeapon(i); + + if ( pWeapon == NULL ) + continue; + + if ( pWeapon->GetSlot() == iSlot && pWeapon->GetPosition() == iSlotPos ) + return pWeapon; + } + + return NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: Opens the next weapon in the slot +//----------------------------------------------------------------------------- +void CHudWeaponSelection::FastWeaponSwitch( int iWeaponSlot ) +{ + // get the slot the player's weapon is in + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + m_pLastWeapon = NULL; + + // see where we should start selection + int iPosition = -1; + C_BaseCombatWeapon *pActiveWeapon = pPlayer->GetActiveWeapon(); + if ( pActiveWeapon && pActiveWeapon->GetSlot() == iWeaponSlot ) + { + // start after this weapon + iPosition = pActiveWeapon->GetPosition(); + } + + C_BaseCombatWeapon *pNextWeapon = NULL; + + // search for the weapon after the current one + pNextWeapon = FindNextWeaponInWeaponSelection(iWeaponSlot, iPosition); + // make sure it's in the same bucket + if ( !pNextWeapon || pNextWeapon->GetSlot() != iWeaponSlot ) + { + // just look for any weapon in this slot + pNextWeapon = FindNextWeaponInWeaponSelection(iWeaponSlot, -1); + } + + // see if we found a weapon that's different from the current and in the selected slot + if ( pNextWeapon && pNextWeapon != pActiveWeapon && pNextWeapon->GetSlot() == iWeaponSlot ) + { + // select the new weapon + ::input->MakeWeaponSelection( pNextWeapon ); + } + else if ( pNextWeapon != pActiveWeapon ) + { + // error sound + pPlayer->EmitSound( "Player.DenyWeaponSelection" ); + } + + if ( HUDTYPE_CAROUSEL != hud_fastswitch.GetInt() ) + { + // kill any fastswitch display + m_flSelectionTime = 0.0f; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Opens the next weapon in the slot +//----------------------------------------------------------------------------- +void CHudWeaponSelection::PlusTypeFastWeaponSwitch( int iWeaponSlot ) +{ + // get the slot the player's weapon is in + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + m_pLastWeapon = NULL; + int newSlot = m_iSelectedSlot; + + // Changing slot number does not necessarily mean we need to change the slot - the player could be + // scrolling through the same slot but in the opposite direction. Slot pairs are 0,2 and 1,3 - so + // compare the 0 bits to see if we're within a pair. Otherwise, reset the box to the zero position. + if ( -1 == m_iSelectedSlot || ( ( m_iSelectedSlot ^ iWeaponSlot ) & 1 ) ) + { + // Changing vertical/horizontal direction. Reset the selected box position to zero. + m_iSelectedBoxPosition = 0; + m_iSelectedSlot = iWeaponSlot; + } + else + { + // Still in the same horizontal/vertical direction. Determine which way we're moving in the slot. + int increment = 1; + if ( m_iSelectedSlot != iWeaponSlot ) + { + // Decrementing within the slot. If we're at the zero position in this slot, + // jump to the zero position of the opposite slot. This also counts as our increment. + increment = -1; + if ( 0 == m_iSelectedBoxPosition ) + { + newSlot = ( m_iSelectedSlot + 2 ) % 4; + increment = 0; + } + } + + // Find out of the box position is at the end of the slot + int lastSlotPos = -1; + for ( int slotPos = 0; slotPos < MAX_WEAPON_POSITIONS; ++slotPos ) + { + C_BaseCombatWeapon *pWeapon = GetWeaponInSlot( newSlot, slotPos ); + if ( pWeapon ) + { + lastSlotPos = slotPos; + } + } + + // Increment/Decrement the selected box position + if ( m_iSelectedBoxPosition + increment <= lastSlotPos ) + { + m_iSelectedBoxPosition += increment; + m_iSelectedSlot = newSlot; + } + else + { + // error sound + pPlayer->EmitSound( "Player.DenyWeaponSelection" ); + return; + } + } + + // Select the weapon in this position + bool bWeaponSelected = false; + C_BaseCombatWeapon *pActiveWeapon = pPlayer->GetActiveWeapon(); + C_BaseCombatWeapon *pWeapon = GetWeaponInSlot( m_iSelectedSlot, m_iSelectedBoxPosition ); + if ( pWeapon ) + { + if ( pWeapon != pActiveWeapon ) + { + // Select the new weapon + ::input->MakeWeaponSelection( pWeapon ); + SetSelectedWeapon( pWeapon ); + bWeaponSelected = true; + } + } + + if ( !bWeaponSelected ) + { + // Still need to set this to make hud display appear + SetSelectedWeapon( pPlayer->GetActiveWeapon() ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Moves selection to the specified slot +//----------------------------------------------------------------------------- +void CHudWeaponSelection::SelectWeaponSlot( int iSlot ) +{ + // iSlot is one higher than it should be, since it's the number key, not the 0-based index into the weapons + --iSlot; + + // Get the local player. + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + // Don't try and read past our possible number of slots + if ( iSlot >= MAX_WEAPON_SLOTS ) + return; + + // Make sure the player's allowed to switch weapons + if ( pPlayer->IsAllowedToSwitchWeapons() == false ) + return; + + switch( hud_fastswitch.GetInt() ) + { + case HUDTYPE_FASTSWITCH: + case HUDTYPE_CAROUSEL: + { + FastWeaponSwitch( iSlot ); + return; + } + + case HUDTYPE_PLUS: + { + if ( !IsInSelectionMode() ) + { + // open the weapon selection + OpenSelection(); + } + + PlusTypeFastWeaponSwitch( iSlot ); + ActivateWeaponHighlight( GetSelectedWeapon() ); + } + break; + + case HUDTYPE_BUCKETS: + { + int slotPos = 0; + C_BaseCombatWeapon *pActiveWeapon = GetSelectedWeapon(); + + // start later in the list + if ( IsInSelectionMode() && pActiveWeapon && pActiveWeapon->GetSlot() == iSlot ) + { + slotPos = pActiveWeapon->GetPosition() + 1; + } + + // find the weapon in this slot + pActiveWeapon = GetNextActivePos( iSlot, slotPos ); + if ( !pActiveWeapon ) + { + pActiveWeapon = GetNextActivePos( iSlot, 0 ); + } + + if ( pActiveWeapon != NULL ) + { + if ( !IsInSelectionMode() ) + { + // open the weapon selection + OpenSelection(); + } + + // Mark the change + SetSelectedWeapon( pActiveWeapon ); + SetSelectedSlideDir( 0 ); + } + } + + default: + { + // do nothing + } + break; + } + + pPlayer->EmitSound( "Player.WeaponSelectionMoveSlot" ); +} diff --git a/game/client/hl2/hud_zoom.cpp b/game/client/hl2/hud_zoom.cpp new file mode 100644 index 0000000..8b47e87 --- /dev/null +++ b/game/client/hl2/hud_zoom.cpp @@ -0,0 +1,272 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "hud.h" +#include "hudelement.h" +#include "hud_macros.h" +#include "hud_numericdisplay.h" +#include "iclientmode.h" +#include "c_basehlplayer.h" +#include "VGuiMatSurface/IMatSystemSurface.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/imesh.h" +#include "materialsystem/imaterialvar.h" +#include "../hud_crosshair.h" + +#include <vgui/IScheme.h> +#include <vgui/ISurface.h> +#include <KeyValues.h> +#include <vgui_controls/AnimationController.h> + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: Draws the zoom screen +//----------------------------------------------------------------------------- +class CHudZoom : public vgui::Panel, public CHudElement +{ + DECLARE_CLASS_SIMPLE( CHudZoom, vgui::Panel ); + +public: + CHudZoom( const char *pElementName ); + + bool ShouldDraw( void ); + void Init( void ); + void LevelInit( void ); + +protected: + virtual void ApplySchemeSettings(vgui::IScheme *scheme); + virtual void Paint( void ); + +private: + bool m_bZoomOn; + float m_flZoomStartTime; + bool m_bPainted; + + CPanelAnimationVarAliasType( float, m_flCircle1Radius, "Circle1Radius", "66", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flCircle2Radius, "Circle2Radius", "74", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flDashGap, "DashGap", "16", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flDashHeight, "DashHeight", "4", "proportional_float" ); + + CMaterialReference m_ZoomMaterial; +}; + +DECLARE_HUDELEMENT( CHudZoom ); + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CHudZoom::CHudZoom( const char *pElementName ) : CHudElement(pElementName), BaseClass(NULL, "HudZoom") +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + + SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD | HIDEHUD_NEEDSUIT ); +} + +//----------------------------------------------------------------------------- +// Purpose: standard hud element init function +//----------------------------------------------------------------------------- +void CHudZoom::Init( void ) +{ + m_bZoomOn = false; + m_bPainted = false; + m_flZoomStartTime = -999.0f; + m_ZoomMaterial.Init( "vgui/zoom", TEXTURE_GROUP_VGUI ); +} + +//----------------------------------------------------------------------------- +// Purpose: standard hud element init function +//----------------------------------------------------------------------------- +void CHudZoom::LevelInit( void ) +{ + Init(); +} + +//----------------------------------------------------------------------------- +// Purpose: sets scheme colors +//----------------------------------------------------------------------------- +void CHudZoom::ApplySchemeSettings( vgui::IScheme *scheme ) +{ + BaseClass::ApplySchemeSettings(scheme); + + SetPaintBackgroundEnabled(false); + SetPaintBorderEnabled(false); + SetFgColor(scheme->GetColor("ZoomReticleColor", GetFgColor())); + + SetForceStereoRenderToFrameBuffer( true ); + int x, y; + int screenWide, screenTall; + surface()->GetFullscreenViewport( x, y, screenWide, screenTall ); + SetBounds(0, 0, screenWide, screenTall); +} + +//----------------------------------------------------------------------------- +// Purpose: Save CPU cycles by letting the HUD system early cull +// costly traversal. Called per frame, return true if thinking and +// painting need to occur. +//----------------------------------------------------------------------------- +bool CHudZoom::ShouldDraw( void ) +{ + bool bNeedsDraw = false; + + C_BaseHLPlayer *pPlayer = dynamic_cast<C_BaseHLPlayer *>(C_BasePlayer::GetLocalPlayer()); + if ( pPlayer == NULL ) + return false; + + if ( pPlayer->m_HL2Local.m_bZooming ) + { + // need to paint + bNeedsDraw = true; + } + else if ( m_bPainted ) + { + // keep painting until state is finished + bNeedsDraw = true; + } + + return ( bNeedsDraw && CHudElement::ShouldDraw() ); +} + +#define ZOOM_FADE_TIME 0.4f +//----------------------------------------------------------------------------- +// Purpose: draws the zoom effect +//----------------------------------------------------------------------------- +void CHudZoom::Paint( void ) +{ + m_bPainted = false; + + // see if we're zoomed any + C_BaseHLPlayer *pPlayer = dynamic_cast<C_BaseHLPlayer *>(C_BasePlayer::GetLocalPlayer()); + if ( pPlayer == NULL ) + return; + + if ( pPlayer->m_HL2Local.m_bZooming && m_bZoomOn == false ) + { + m_bZoomOn = true; + m_flZoomStartTime = gpGlobals->curtime; + } + else if ( pPlayer->m_HL2Local.m_bZooming == false && m_bZoomOn ) + { + m_bZoomOn = false; + m_flZoomStartTime = gpGlobals->curtime; + } + + // draw the appropriately scaled zoom animation + float deltaTime = ( gpGlobals->curtime - m_flZoomStartTime ); + float scale = clamp( deltaTime / ZOOM_FADE_TIME, 0.0f, 1.0f ); + + float alpha; + + if ( m_bZoomOn ) + { + alpha = scale; + } + else + { + if ( scale >= 1.0f ) + return; + + alpha = ( 1.0f - scale ) * 0.25f; + scale = 1.0f - ( scale * 0.5f ); + } + + Color col = GetFgColor(); + col[3] = alpha * 64; + + surface()->DrawSetColor( col ); + + // draw zoom circles + float fX, fY; + bool bBehindCamera = false; + CHudCrosshair::GetDrawPosition( &fX, &fY, &bBehindCamera ); + if( bBehindCamera ) + return; + int xCrosshair = (int)fX; + int yCrosshair = (int)fY; + int wide, tall; + GetSize( wide, tall ); + + surface()->DrawOutlinedCircle( xCrosshair, yCrosshair, m_flCircle1Radius * scale, 48); + surface()->DrawOutlinedCircle( xCrosshair, yCrosshair, m_flCircle2Radius * scale, 64); + + // draw dashed lines + int dashCount = 2; + int ypos = yCrosshair - m_flDashHeight / 2.f; + float fGap = m_flDashGap * MAX(scale,0.1f); + int dashMax = Max(fX, (float)wide - fX ) / fGap; + while ( dashCount < dashMax ) + { + int xpos = (int)(fX - fGap * dashCount + 0.5f); + surface()->DrawFilledRect(xpos, ypos, xpos + 1, ypos + m_flDashHeight); + xpos = (int)(fX + fGap * dashCount + 0.5f); + surface()->DrawFilledRect(xpos, ypos, xpos + 1, ypos + m_flDashHeight); + dashCount++; + } + + // draw the darkened edges, with a rotated texture in the four corners + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->Bind( m_ZoomMaterial ); + IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, NULL ); + + float x0 = 0.0f, x1 = fX, x2 = wide; + float y0 = 0.0f, y1 = fY, y2 = tall; + + float uv1 = 1.0f - (1.0f / 255.0f); + float uv2 = 0.0f + (1.0f / 255.0f); + + struct coord_t + { + float x, y; + float u, v; + }; + coord_t coords[16] = + { + // top-left + { x0, y0, uv1, uv2 }, + { x1, y0, uv2, uv2 }, + { x1, y1, uv2, uv1 }, + { x0, y1, uv1, uv1 }, + + // top-right + { x1, y0, uv2, uv2 }, + { x2, y0, uv1, uv2 }, + { x2, y1, uv1, uv1 }, + { x1, y1, uv2, uv1 }, + + // bottom-right + { x1, y1, uv2, uv1 }, + { x2, y1, uv1, uv1 }, + { x2, y2, uv1, uv2 }, + { x1, y2, uv2, uv2 }, + + // bottom-left + { x0, y1, uv1, uv1 }, + { x1, y1, uv2, uv1 }, + { x1, y2, uv2, uv2 }, + { x0, y2, uv1, uv2 }, + }; + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_QUADS, 4 ); + + for (int i = 0; i < 16; i++) + { + meshBuilder.Color4f( 0.0, 0.0, 0.0, alpha ); + meshBuilder.TexCoord2f( 0, coords[i].u, coords[i].v ); + meshBuilder.Position3f( coords[i].x, coords[i].y, 0.0f ); + meshBuilder.AdvanceVertex(); + } + + meshBuilder.End(); + pMesh->Draw(); + + m_bPainted = true; +} diff --git a/game/client/hl2/shieldproxy.cpp b/game/client/hl2/shieldproxy.cpp new file mode 100644 index 0000000..ff3a582 --- /dev/null +++ b/game/client/hl2/shieldproxy.cpp @@ -0,0 +1,110 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "proxyentity.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/imaterialvar.h" +#include "materialsystem/imaterialsystem.h" +#include <KeyValues.h> + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// $sineVar : name of variable that controls the alpha level (float) +class CShieldProxy : public CEntityMaterialProxy +{ +public: + CShieldProxy(); + virtual ~CShieldProxy(); + virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); + virtual void OnBind( C_BaseEntity *pC_BaseEntity ); + virtual IMaterial *GetMaterial(); + +private: + IMaterialVar *m_AlphaVar; + IMaterialVar *m_pTextureScrollVar; + float m_ScrollRate; + float m_ScrollAngle; +}; + +CShieldProxy::CShieldProxy() +{ + m_AlphaVar = NULL; + m_pTextureScrollVar = NULL; + m_ScrollRate = 0; + m_ScrollAngle = 0; +} + +CShieldProxy::~CShieldProxy() +{ +} + + +bool CShieldProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) +{ + bool foundVar; + + m_AlphaVar = pMaterial->FindVar( "$translucency", &foundVar, false ); + if( !foundVar ) + return false; + + char const* pScrollVarName = pKeyValues->GetString( "textureScrollVar" ); + if (!pScrollVarName) + return false; + + m_pTextureScrollVar = pMaterial->FindVar( pScrollVarName, &foundVar, false ); + if( !foundVar ) + return false; + + m_ScrollRate = pKeyValues->GetFloat( "textureScrollRate", 1 ); + m_ScrollAngle = pKeyValues->GetFloat( "textureScrollAngle", 0 ); + return true; +} + +void CShieldProxy::OnBind( C_BaseEntity *pEnt ) +{ + if (m_AlphaVar) + { + m_AlphaVar->SetFloatValue( pEnt->m_clrRender->a ); + } + + if( !m_pTextureScrollVar ) + { + return; + } + + float sOffset, tOffset; + + sOffset = gpGlobals->curtime * sin( m_ScrollAngle * ( M_PI / 180.0f ) ) * m_ScrollRate; + tOffset = gpGlobals->curtime * cos( m_ScrollAngle * ( M_PI / 180.0f ) ) * m_ScrollRate; + + // make sure that we are positive + if( sOffset < 0.0f ) + { + sOffset += 1.0f + -( int )sOffset; + } + if( tOffset < 0.0f ) + { + tOffset += 1.0f + -( int )tOffset; + } + + // make sure that we are in a [0,1] range + sOffset = sOffset - ( int )sOffset; + tOffset = tOffset - ( int )tOffset; + + m_pTextureScrollVar->SetVecValue( sOffset, tOffset, 0.0f ); +} + +IMaterial *CShieldProxy::GetMaterial() +{ + if ( !m_AlphaVar ) + return NULL; + + return m_AlphaVar->GetOwningMaterial(); +} + +EXPOSE_INTERFACE( CShieldProxy, IMaterialProxy, "Shield" IMATERIAL_PROXY_INTERFACE_VERSION ); diff --git a/game/client/hl2/vgui_rootpanel_hl2.cpp b/game/client/hl2/vgui_rootpanel_hl2.cpp new file mode 100644 index 0000000..fbb952d --- /dev/null +++ b/game/client/hl2/vgui_rootpanel_hl2.cpp @@ -0,0 +1,37 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "vgui_int.h" +#include "ienginevgui.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void VGUI_CreateClientDLLRootPanel( void ) +{ + // Just using PANEL_ROOT in HL2 right now +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void VGUI_DestroyClientDLLRootPanel( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Game specific root panel +// Output : vgui::Panel +//----------------------------------------------------------------------------- +vgui::VPANEL VGui_GetClientDLLRootPanel( void ) +{ + vgui::VPANEL root = enginevgui->GetPanel( PANEL_CLIENTDLL ); + return root; +} |